Skip to content

Resource: awsSecurityGroup

Provides a security group resource.

\~> NOTE on Security Groups and Security Group Rules: Terraform currently provides a Security Group resource with ingress and egress rules defined in-line and a Security Group Rule resource which manages one or more ingress or egress rules. Both of these resource were added before AWS assigned a security group rule unique ID, and they do not work well in all scenarios using thedescription and tags attributes, which rely on the unique ID. The awsVpcSecurityGroupEgressRule and awsVpcSecurityGroupIngressRule resources have been added to address these limitations and should be used for all new security group rules. You should not use the awsVpcSecurityGroupEgressRule and awsVpcSecurityGroupIngressRule resources in conjunction with an awsSecurityGroup resource with in-line rules or with awsSecurityGroupRule resources defined for the same Security Group, as rule conflicts may occur and rules will be overwritten.

\~> NOTE: Referencing Security Groups across VPC peering has certain restrictions. More information is available in the VPC Peering User Guide.

\~> NOTE: Due to AWS Lambda improved VPC networking changes that began deploying in September 2019, security groups associated with Lambda Functions can take up to 45 minutes to successfully delete. Terraform AWS Provider version 2.31.0 and later automatically handles this increased timeout, however prior versions require setting the customizable deletion timeout to 45 minutes (delete = "45M"). AWS and HashiCorp are working together to reduce the amount of time required for resource deletion and updates can be tracked in this GitHub issue.

\~> NOTE: The cidrBlocks and ipv6CidrBlocks parameters are optional in the ingress and egress blocks. If nothing is specified, traffic will be blocked as described in NOTE on Egress rules later.

Example Usage

Basic Usage

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.securityGroup.SecurityGroup(this, "allow_tls", {
  description: "Allow TLS inbound traffic",
  egress: [
    {
      cidrBlocks: ["0.0.0.0/0"],
      fromPort: 0,
      ipv6CidrBlocks: ["::/0"],
      protocol: "-1",
      toPort: 0,
    },
  ],
  ingress: [
    {
      cidrBlocks: ["${aws_vpc.main.cidr_block}"],
      description: "TLS from VPC",
      fromPort: 443,
      ipv6CidrBlocks: ["${aws_vpc.main.ipv6_cidr_block}"],
      protocol: "tcp",
      toPort: 443,
    },
  ],
  name: "allow_tls",
  tags: {
    Name: "allow_tls",
  },
  vpcId: "${aws_vpc.main.id}",
});

\~> NOTE on Egress rules: By default, AWS creates an allowAll egress rule when creating a new Security Group inside of a VPC. When creating a new Security Group inside a VPC, Terraform will remove this default rule, and require you specifically re-create it if you desire that rule. We feel this leads to fewer surprises in terms of controlling your egress rules. If you desire this rule to be in place, you can use this egress block:

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.securityGroup.SecurityGroup(this, "example", {
  egress: [
    {
      cidrBlocks: ["0.0.0.0/0"],
      fromPort: 0,
      ipv6CidrBlocks: ["::/0"],
      protocol: "-1",
      toPort: 0,
    },
  ],
});

Usage With Prefix List IDs

Prefix Lists are either managed by AWS internally, or created by the customer using a Prefix List resource. Prefix Lists provided by AWS are associated with a prefix list name, or service name, that is linked to a specific region. Prefix list IDs are exported on VPC Endpoints, so you can use this format:

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsVpcEndpointMyEndpoint = new aws.vpcEndpoint.VpcEndpoint(
  this,
  "my_endpoint",
  {}
);
new aws.securityGroup.SecurityGroup(this, "example", {
  egress: [
    {
      fromPort: 0,
      prefixListIds: [awsVpcEndpointMyEndpoint.prefixListId],
      protocol: "-1",
      toPort: 0,
    },
  ],
});

You can also find a specific Prefix List using the awsPrefixList data source.

Recreating a Security Group

A simple security group name change "forces new" the security group--Terraform destroys the security group and creates a new one. (Likewise, description, namePrefix, or vpcId cannot be changed.) Attempting to recreate the security group leads to a variety of complications depending on how it is used.

Security groups are generally associated with other resources--more than 100 AWS Provider resources reference security groups. Referencing a resource from another resource creates a one-way dependency. For example, if you create an EC2 awsInstance that has a vpcSecurityGroupIds argument that refers to an awsSecurityGroup resource, the awsSecurityGroup is a dependent of the awsInstance. Because of this, Terraform will create the security group first so that it can then be associated with the EC2 instance.

However, the dependency relationship actually goes both directions causing the Security Group Deletion Problem. AWS does not allow you to delete the security group associated with another resource (e.g., the awsInstance).

Terraform does not model bi-directional dependencies like this, but, even if it did, simply knowing the dependency situation would not be enough to solve it. For example, some resources must always have an associated security group while others don't need to. In addition, when the awsSecurityGroup resource attempts to recreate, it receives a dependent object error, which does not provide information on whether the dependent object is a security group rule or, for example, an associated EC2 instance. Within Terraform, the associated resource (e.g., awsInstance) does not receive an error when the awsSecurityGroup is trying to recreate even though that is where changes to the associated resource would need to take place (e.g., removing the security group association).

Despite these sticky problems, below are some ways to improve your experience when you find it necessary to recreate a security group.

createBeforeDestroy

(This example is one approach to recreating security groups. For more information on the challenges and the Security Group Deletion Problem, see the section above.)

Normally, Terraform first deletes the existing security group resource and then creates a new one. When a security group is associated with a resource, the delete won't succeed. You can invert the default behavior using the createBeforeDestroy meta argument:

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsSecurityGroupExample = new aws.securityGroup.SecurityGroup(
  this,
  "example",
  {
    name: "changeable-name",
  }
);
awsSecurityGroupExample.addOverride("lifecycle", [
  {
    create_before_destroy: true,
  },
]);

replaceTriggeredBy

(This example is one approach to recreating security groups. For more information on the challenges and the Security Group Deletion Problem, see the section above.)

To replace a resource when a security group changes, use the replaceTriggeredBy meta argument. Note that in this example, the awsInstance will be destroyed and created again when the awsSecurityGroup changes.

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
const awsSecurityGroupExample = new aws.securityGroup.SecurityGroup(
  this,
  "example",
  {
    name: "sg",
  }
);
const awsInstanceExample = new aws.instance.Instance(this, "example_1", {
  instanceType: "t3.small",
  vpcSecurityGroupIds: ["${aws_security_group.test.id}"],
});
awsInstanceExample.addOverride("lifecycle", [
  {
    replace_triggered_by: [`\${${awsSecurityGroupExample.fqn}}`],
  },
]);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsInstanceExample.overrideLogicalId("example");

Shorter timeout

(This example is one approach to recreating security groups. For more information on the challenges and the Security Group Deletion Problem, see the section above.)

If destroying a security group takes a long time, it may be because Terraform cannot distinguish between a dependent object (e.g., a security group rule or EC2 instance) that is in the process of being deleted and one that is not. In other words, it may be waiting for a train that isn't scheduled to arrive. To fail faster, shorten the delete timeout from the default timeout:

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
new aws.securityGroup.SecurityGroup(this, "example", {
  name: "izizavle",
  timeouts: [
    {
      delete: "2m",
    },
  ],
});

Provisioners

(This example is one approach to recreating security groups. For more information on the challenges and the Security Group Deletion Problem, see the section above.)

DISCLAIMER: We HIGHLY recommend using one of the above approaches and NOT using local provisioners. Provisioners, like the one shown below, should be considered a last resort since they are not readable, require skills outside standard Terraform configuration, are error prone and difficult to maintain, are not compatible with cloud environments and upgrade tools, require AWS CLI installation, and are subject to AWS CLI and Terraform changes outside the AWS Provider.

/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "./.gen/providers/aws";
import * as NullProvider from "./.gen/providers/null";
/*The following providers are missing schema information and might need manual adjustments to synthesize correctly: null.
For a more precise conversion please use the --provider flag in convert.*/
new NullProvider.resource.Resource(this, "example", {
  provisioner: [
    {
      "local-exec": [
        {
          command:
            "            aws ec2 modify-vpc-endpoint --vpc-endpoint-id ${aws_vpc_endpoint.example.id} --remove-security-group-ids ${data.aws_security_group.default.id}\n",
          on_failure: "${continue}",
        },
      ],
    },
  ],
  triggers: [
    {
      rerun_upon_change_of:
        '${join(",", aws_vpc_endpoint.example.security_group_ids)}',
    },
  ],
});
const dataAwsSecurityGroupDefault =
  new aws.dataAwsSecurityGroup.DataAwsSecurityGroup(this, "default", {
    name: "default",
  });
const awsSecurityGroupExample = new aws.securityGroup.SecurityGroup(
  this,
  "example_2",
  {
    name: "sg",
    provisioner: [
      {
        "local-exec": [
          {
            command:
              '            ENDPOINT_ID=`aws ec2 describe-vpc-endpoints --filters "Name=tag:Name,Values=${self.tags.workaround1}" --query "VpcEndpoints[0].VpcEndpointId" --output text` &&\n            aws ec2 modify-vpc-endpoint --vpc-endpoint-id ${ENDPOINT_ID} --add-security-group-ids ${self.tags.workaround2} --remove-security-group-ids ${self.id}\n',
            on_failure: "${continue}",
            when: "${destroy}",
          },
        ],
      },
    ],
    tags: {
      workaround1: "tagged-name",
      workaround2: dataAwsSecurityGroupDefault.id,
    },
  }
);
/*This allows the Terraform resource name to match the original name. You can remove the call if you don't need them to match.*/
awsSecurityGroupExample.overrideLogicalId("example");

Argument Reference

The following arguments are supported:

  • description - (Optional, Forces new resource) Security group description. Defaults to managedByTerraform. Cannot be "". NOTE: This field maps to the AWS groupDescription attribute, for which there is no Update API. If you'd like to classify your security groups in a way that can be updated, use tags.
  • egress - (Optional, VPC only) Configuration block for egress rules. Can be specified multiple times for each egress rule. Each egress block supports fields documented below. This argument is processed in attribute-as-blocks mode.
  • ingress - (Optional) Configuration block for ingress rules. Can be specified multiple times for each ingress rule. Each ingress block supports fields documented below. This argument is processed in attribute-as-blocks mode.
  • namePrefix - (Optional, Forces new resource) Creates a unique name beginning with the specified prefix. Conflicts with name.
  • name - (Optional, Forces new resource) Name of the security group. If omitted, Terraform will assign a random, unique name.
  • revokeRulesOnDelete - (Optional) Instruct Terraform to revoke all of the Security Groups attached ingress and egress rules before deleting the rule itself. This is normally not needed, however certain AWS services such as Elastic Map Reduce may automatically add required rules to security groups used with the service, and those rules may contain a cyclic dependency that prevent the security groups from being destroyed without removing the dependency first. Default false.
  • tags - (Optional) Map of tags to assign to the resource. If configured with a provider defaultTags configuration block present, tags with matching keys will overwrite those defined at the provider-level.
  • vpcId - (Optional, Forces new resource) VPC ID. Defaults to the region's default VPC.

ingress

This argument is processed in attribute-as-blocks mode.

The following arguments are required:

  • fromPort - (Required) Start port (or ICMP type number if protocol is icmp or icmpv6).
  • toPort - (Required) End range port (or ICMP code if protocol is icmp).
  • protocol - (Required) Protocol. If you select a protocol of 1 (semantically equivalent to all, which is not a valid value here), you must specify a fromPort and toPort equal to 0. The supported values are defined in the ipProtocol argument on the IpPermission API reference. This argument is normalized to a lowercase value to match the AWS API requirement when using with Terraform 0.12.x and above, please make sure that the value of the protocol is specified as lowercase when using with older version of Terraform to avoid an issue during upgrade.

The following arguments are optional:

  • cidrBlocks - (Optional) List of CIDR blocks.
  • description - (Optional) Description of this ingress rule.
  • ipv6CidrBlocks - (Optional) List of IPv6 CIDR blocks.
  • prefixListIds - (Optional) List of Prefix List IDs.
  • securityGroups - (Optional) List of security groups. A group name can be used relative to the default VPC. Otherwise, group ID.
  • self - (Optional) Whether the security group itself will be added as a source to this ingress rule.

egress

This argument is processed in attribute-as-blocks mode.

The following arguments are required:

  • fromPort - (Required) Start port (or ICMP type number if protocol is icmp)
  • toPort - (Required) End range port (or ICMP code if protocol is icmp).

The following arguments are optional:

  • cidrBlocks - (Optional) List of CIDR blocks.
  • description - (Optional) Description of this egress rule.
  • ipv6CidrBlocks - (Optional) List of IPv6 CIDR blocks.
  • prefixListIds - (Optional) List of Prefix List IDs.
  • protocol - (Required) Protocol. If you select a protocol of 1 (semantically equivalent to all, which is not a valid value here), you must specify a fromPort and toPort equal to 0. The supported values are defined in the ipProtocol argument in the IpPermission API reference. This argument is normalized to a lowercase value to match the AWS API requirement when using Terraform 0.12.x and above. Please make sure that the value of the protocol is specified as lowercase when used with older version of Terraform to avoid issues during upgrade.
  • securityGroups - (Optional) List of security groups. A group name can be used relative to the default VPC. Otherwise, group ID.
  • self - (Optional) Whether the security group itself will be added as a source to this egress rule.

Attributes Reference

In addition to all arguments above, the following attributes are exported:

  • arn - ARN of the security group.
  • id - ID of the security group.
  • ownerId - Owner ID.
  • tagsAll - A map of tags assigned to the resource, including those inherited from the provider defaultTags configuration block.

Timeouts

Configuration options:

  • create - (Default 10M)
  • delete - (Default 15M)

Import

Security Groups can be imported using the securityGroupId, e.g.,

$ terraform import aws_security_group.elb_sg sg-903004f8