Create and Configure Security Groups

The aws:ec2/securityGroup:SecurityGroup resource, part of the Pulumi AWS provider, defines the security group container itself: its name, VPC placement, and optionally inline rules. This guide focuses on four capabilities: creating security groups with separate rule resources, inline rule configuration, prefix list references, and explicit rule removal.

Security groups belong to a VPC and may reference VPC endpoints or other security groups. The documentation recommends using separate SecurityGroupIngressRule and SecurityGroupEgressRule resources instead of inline rules to avoid management issues with multiple CIDR blocks. The examples are intentionally small. Combine them with your own VPC infrastructure and rule definitions.

Create a security group with separate rule resources

Most deployments create a security group container, then attach ingress and egress rules as separate resources to avoid inline rule limitations.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const allowTls = new aws.ec2.SecurityGroup("allow_tls", {
    name: "allow_tls",
    description: "Allow TLS inbound traffic and all outbound traffic",
    vpcId: main.id,
    tags: {
        Name: "allow_tls",
    },
});
const allowTlsIpv4 = new aws.vpc.SecurityGroupIngressRule("allow_tls_ipv4", {
    securityGroupId: allowTls.id,
    cidrIpv4: main.cidrBlock,
    fromPort: 443,
    ipProtocol: "tcp",
    toPort: 443,
});
const allowTlsIpv6 = new aws.vpc.SecurityGroupIngressRule("allow_tls_ipv6", {
    securityGroupId: allowTls.id,
    cidrIpv6: main.ipv6CidrBlock,
    fromPort: 443,
    ipProtocol: "tcp",
    toPort: 443,
});
const allowAllTrafficIpv4 = new aws.vpc.SecurityGroupEgressRule("allow_all_traffic_ipv4", {
    securityGroupId: allowTls.id,
    cidrIpv4: "0.0.0.0/0",
    ipProtocol: "-1",
});
const allowAllTrafficIpv6 = new aws.vpc.SecurityGroupEgressRule("allow_all_traffic_ipv6", {
    securityGroupId: allowTls.id,
    cidrIpv6: "::/0",
    ipProtocol: "-1",
});
import pulumi
import pulumi_aws as aws

allow_tls = aws.ec2.SecurityGroup("allow_tls",
    name="allow_tls",
    description="Allow TLS inbound traffic and all outbound traffic",
    vpc_id=main["id"],
    tags={
        "Name": "allow_tls",
    })
allow_tls_ipv4 = aws.vpc.SecurityGroupIngressRule("allow_tls_ipv4",
    security_group_id=allow_tls.id,
    cidr_ipv4=main["cidrBlock"],
    from_port=443,
    ip_protocol="tcp",
    to_port=443)
allow_tls_ipv6 = aws.vpc.SecurityGroupIngressRule("allow_tls_ipv6",
    security_group_id=allow_tls.id,
    cidr_ipv6=main["ipv6CidrBlock"],
    from_port=443,
    ip_protocol="tcp",
    to_port=443)
allow_all_traffic_ipv4 = aws.vpc.SecurityGroupEgressRule("allow_all_traffic_ipv4",
    security_group_id=allow_tls.id,
    cidr_ipv4="0.0.0.0/0",
    ip_protocol="-1")
allow_all_traffic_ipv6 = aws.vpc.SecurityGroupEgressRule("allow_all_traffic_ipv6",
    security_group_id=allow_tls.id,
    cidr_ipv6="::/0",
    ip_protocol="-1")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/vpc"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		allowTls, err := ec2.NewSecurityGroup(ctx, "allow_tls", &ec2.SecurityGroupArgs{
			Name:        pulumi.String("allow_tls"),
			Description: pulumi.String("Allow TLS inbound traffic and all outbound traffic"),
			VpcId:       pulumi.Any(main.Id),
			Tags: pulumi.StringMap{
				"Name": pulumi.String("allow_tls"),
			},
		})
		if err != nil {
			return err
		}
		_, err = vpc.NewSecurityGroupIngressRule(ctx, "allow_tls_ipv4", &vpc.SecurityGroupIngressRuleArgs{
			SecurityGroupId: allowTls.ID(),
			CidrIpv4:        pulumi.Any(main.CidrBlock),
			FromPort:        pulumi.Int(443),
			IpProtocol:      pulumi.String("tcp"),
			ToPort:          pulumi.Int(443),
		})
		if err != nil {
			return err
		}
		_, err = vpc.NewSecurityGroupIngressRule(ctx, "allow_tls_ipv6", &vpc.SecurityGroupIngressRuleArgs{
			SecurityGroupId: allowTls.ID(),
			CidrIpv6:        pulumi.Any(main.Ipv6CidrBlock),
			FromPort:        pulumi.Int(443),
			IpProtocol:      pulumi.String("tcp"),
			ToPort:          pulumi.Int(443),
		})
		if err != nil {
			return err
		}
		_, err = vpc.NewSecurityGroupEgressRule(ctx, "allow_all_traffic_ipv4", &vpc.SecurityGroupEgressRuleArgs{
			SecurityGroupId: allowTls.ID(),
			CidrIpv4:        pulumi.String("0.0.0.0/0"),
			IpProtocol:      pulumi.String("-1"),
		})
		if err != nil {
			return err
		}
		_, err = vpc.NewSecurityGroupEgressRule(ctx, "allow_all_traffic_ipv6", &vpc.SecurityGroupEgressRuleArgs{
			SecurityGroupId: allowTls.ID(),
			CidrIpv6:        pulumi.String("::/0"),
			IpProtocol:      pulumi.String("-1"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var allowTls = new Aws.Ec2.SecurityGroup("allow_tls", new()
    {
        Name = "allow_tls",
        Description = "Allow TLS inbound traffic and all outbound traffic",
        VpcId = main.Id,
        Tags = 
        {
            { "Name", "allow_tls" },
        },
    });

    var allowTlsIpv4 = new Aws.Vpc.SecurityGroupIngressRule("allow_tls_ipv4", new()
    {
        SecurityGroupId = allowTls.Id,
        CidrIpv4 = main.CidrBlock,
        FromPort = 443,
        IpProtocol = "tcp",
        ToPort = 443,
    });

    var allowTlsIpv6 = new Aws.Vpc.SecurityGroupIngressRule("allow_tls_ipv6", new()
    {
        SecurityGroupId = allowTls.Id,
        CidrIpv6 = main.Ipv6CidrBlock,
        FromPort = 443,
        IpProtocol = "tcp",
        ToPort = 443,
    });

    var allowAllTrafficIpv4 = new Aws.Vpc.SecurityGroupEgressRule("allow_all_traffic_ipv4", new()
    {
        SecurityGroupId = allowTls.Id,
        CidrIpv4 = "0.0.0.0/0",
        IpProtocol = "-1",
    });

    var allowAllTrafficIpv6 = new Aws.Vpc.SecurityGroupEgressRule("allow_all_traffic_ipv6", new()
    {
        SecurityGroupId = allowTls.Id,
        CidrIpv6 = "::/0",
        IpProtocol = "-1",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.vpc.SecurityGroupIngressRule;
import com.pulumi.aws.vpc.SecurityGroupIngressRuleArgs;
import com.pulumi.aws.vpc.SecurityGroupEgressRule;
import com.pulumi.aws.vpc.SecurityGroupEgressRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var allowTls = new SecurityGroup("allowTls", SecurityGroupArgs.builder()
            .name("allow_tls")
            .description("Allow TLS inbound traffic and all outbound traffic")
            .vpcId(main.id())
            .tags(Map.of("Name", "allow_tls"))
            .build());

        var allowTlsIpv4 = new SecurityGroupIngressRule("allowTlsIpv4", SecurityGroupIngressRuleArgs.builder()
            .securityGroupId(allowTls.id())
            .cidrIpv4(main.cidrBlock())
            .fromPort(443)
            .ipProtocol("tcp")
            .toPort(443)
            .build());

        var allowTlsIpv6 = new SecurityGroupIngressRule("allowTlsIpv6", SecurityGroupIngressRuleArgs.builder()
            .securityGroupId(allowTls.id())
            .cidrIpv6(main.ipv6CidrBlock())
            .fromPort(443)
            .ipProtocol("tcp")
            .toPort(443)
            .build());

        var allowAllTrafficIpv4 = new SecurityGroupEgressRule("allowAllTrafficIpv4", SecurityGroupEgressRuleArgs.builder()
            .securityGroupId(allowTls.id())
            .cidrIpv4("0.0.0.0/0")
            .ipProtocol("-1")
            .build());

        var allowAllTrafficIpv6 = new SecurityGroupEgressRule("allowAllTrafficIpv6", SecurityGroupEgressRuleArgs.builder()
            .securityGroupId(allowTls.id())
            .cidrIpv6("::/0")
            .ipProtocol("-1")
            .build());

    }
}
resources:
  allowTls:
    type: aws:ec2:SecurityGroup
    name: allow_tls
    properties:
      name: allow_tls
      description: Allow TLS inbound traffic and all outbound traffic
      vpcId: ${main.id}
      tags:
        Name: allow_tls
  allowTlsIpv4:
    type: aws:vpc:SecurityGroupIngressRule
    name: allow_tls_ipv4
    properties:
      securityGroupId: ${allowTls.id}
      cidrIpv4: ${main.cidrBlock}
      fromPort: 443
      ipProtocol: tcp
      toPort: 443
  allowTlsIpv6:
    type: aws:vpc:SecurityGroupIngressRule
    name: allow_tls_ipv6
    properties:
      securityGroupId: ${allowTls.id}
      cidrIpv6: ${main.ipv6CidrBlock}
      fromPort: 443
      ipProtocol: tcp
      toPort: 443
  allowAllTrafficIpv4:
    type: aws:vpc:SecurityGroupEgressRule
    name: allow_all_traffic_ipv4
    properties:
      securityGroupId: ${allowTls.id}
      cidrIpv4: 0.0.0.0/0
      ipProtocol: '-1'
  allowAllTrafficIpv6:
    type: aws:vpc:SecurityGroupEgressRule
    name: allow_all_traffic_ipv6
    properties:
      securityGroupId: ${allowTls.id}
      cidrIpv6: ::/0
      ipProtocol: '-1'

The SecurityGroup resource creates the container with a name and vpcId. The SecurityGroupIngressRule and SecurityGroupEgressRule resources attach rules separately, each referencing the security group ID. This pattern handles multiple CIDR blocks cleanly and provides unique IDs for each rule. The ipProtocol value “-1” means all protocols; specific protocols use “tcp”, “udp”, or protocol numbers.

Allow all outbound traffic with inline rules

AWS removes the default egress rule when you create security groups in a VPC. To restore allow-all behavior, define an inline egress rule.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.ec2.SecurityGroup("example", {egress: [{
    fromPort: 0,
    toPort: 0,
    protocol: "-1",
    cidrBlocks: ["0.0.0.0/0"],
    ipv6CidrBlocks: ["::/0"],
}]});
import pulumi
import pulumi_aws as aws

example = aws.ec2.SecurityGroup("example", egress=[{
    "from_port": 0,
    "to_port": 0,
    "protocol": "-1",
    "cidr_blocks": ["0.0.0.0/0"],
    "ipv6_cidr_blocks": ["::/0"],
}])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ec2.NewSecurityGroup(ctx, "example", &ec2.SecurityGroupArgs{
			Egress: ec2.SecurityGroupEgressArray{
				&ec2.SecurityGroupEgressArgs{
					FromPort: pulumi.Int(0),
					ToPort:   pulumi.Int(0),
					Protocol: pulumi.String("-1"),
					CidrBlocks: pulumi.StringArray{
						pulumi.String("0.0.0.0/0"),
					},
					Ipv6CidrBlocks: pulumi.StringArray{
						pulumi.String("::/0"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ec2.SecurityGroup("example", new()
    {
        Egress = new[]
        {
            new Aws.Ec2.Inputs.SecurityGroupEgressArgs
            {
                FromPort = 0,
                ToPort = 0,
                Protocol = "-1",
                CidrBlocks = new[]
                {
                    "0.0.0.0/0",
                },
                Ipv6CidrBlocks = new[]
                {
                    "::/0",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new SecurityGroup("example", SecurityGroupArgs.builder()
            .egress(SecurityGroupEgressArgs.builder()
                .fromPort(0)
                .toPort(0)
                .protocol("-1")
                .cidrBlocks("0.0.0.0/0")
                .ipv6CidrBlocks("::/0")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ec2:SecurityGroup
    properties:
      egress:
        - fromPort: 0
          toPort: 0
          protocol: '-1'
          cidrBlocks:
            - 0.0.0.0/0
          ipv6CidrBlocks:
            - ::/0

The egress argument defines rules inline rather than as separate resources. Setting protocol to “-1”, fromPort and toPort to 0, and including both IPv4 and IPv6 CIDR blocks recreates AWS’s default allow-all egress behavior. Without this rule, the security group blocks all outbound traffic.

Reference VPC endpoints with prefix lists

VPC endpoints export prefix list IDs representing AWS service IP ranges. Security groups can reference these to allow traffic to AWS services.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const myEndpoint = new aws.ec2.VpcEndpoint("my_endpoint", {});
const example = new aws.ec2.SecurityGroup("example", {egress: [{
    fromPort: 0,
    toPort: 0,
    protocol: "-1",
    prefixListIds: [myEndpoint.prefixListId],
}]});
import pulumi
import pulumi_aws as aws

my_endpoint = aws.ec2.VpcEndpoint("my_endpoint")
example = aws.ec2.SecurityGroup("example", egress=[{
    "from_port": 0,
    "to_port": 0,
    "protocol": "-1",
    "prefix_list_ids": [my_endpoint.prefix_list_id],
}])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		myEndpoint, err := ec2.NewVpcEndpoint(ctx, "my_endpoint", nil)
		if err != nil {
			return err
		}
		_, err = ec2.NewSecurityGroup(ctx, "example", &ec2.SecurityGroupArgs{
			Egress: ec2.SecurityGroupEgressArray{
				&ec2.SecurityGroupEgressArgs{
					FromPort: pulumi.Int(0),
					ToPort:   pulumi.Int(0),
					Protocol: pulumi.String("-1"),
					PrefixListIds: pulumi.StringArray{
						myEndpoint.PrefixListId,
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var myEndpoint = new Aws.Ec2.VpcEndpoint("my_endpoint");

    var example = new Aws.Ec2.SecurityGroup("example", new()
    {
        Egress = new[]
        {
            new Aws.Ec2.Inputs.SecurityGroupEgressArgs
            {
                FromPort = 0,
                ToPort = 0,
                Protocol = "-1",
                PrefixListIds = new[]
                {
                    myEndpoint.PrefixListId,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.VpcEndpoint;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var myEndpoint = new VpcEndpoint("myEndpoint");

        var example = new SecurityGroup("example", SecurityGroupArgs.builder()
            .egress(SecurityGroupEgressArgs.builder()
                .fromPort(0)
                .toPort(0)
                .protocol("-1")
                .prefixListIds(myEndpoint.prefixListId())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:ec2:SecurityGroup
    properties:
      egress:
        - fromPort: 0
          toPort: 0
          protocol: '-1'
          prefixListIds:
            - ${myEndpoint.prefixListId}
  myEndpoint:
    type: aws:ec2:VpcEndpoint
    name: my_endpoint

The prefixListIds property references the VPC endpoint’s prefix list instead of explicit CIDR blocks. This automatically tracks AWS service IP ranges as they change. Prefix lists work with both ingress and egress rules.

Remove all managed rules from a security group

The ingress and egress arguments use attributes-as-blocks mode. Removing them from configuration doesn’t destroy rules; you must explicitly set them to empty arrays.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.ec2.SecurityGroup("example", {
    name: "sg",
    vpcId: exampleAwsVpc.id,
    ingress: [],
    egress: [],
});
import pulumi
import pulumi_aws as aws

example = aws.ec2.SecurityGroup("example",
    name="sg",
    vpc_id=example_aws_vpc["id"],
    ingress=[],
    egress=[])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := ec2.NewSecurityGroup(ctx, "example", &ec2.SecurityGroupArgs{
			Name:    pulumi.String("sg"),
			VpcId:   pulumi.Any(exampleAwsVpc.Id),
			Ingress: ec2.SecurityGroupIngressArray{},
			Egress:  ec2.SecurityGroupEgressArray{},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Ec2.SecurityGroup("example", new()
    {
        Name = "sg",
        VpcId = exampleAwsVpc.Id,
        Ingress = new[] {},
        Egress = new[] {},
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new SecurityGroup("example", SecurityGroupArgs.builder()
            .name("sg")
            .vpcId(exampleAwsVpc.id())
            .ingress()
            .egress()
            .build());

    }
}
resources:
  example:
    type: aws:ec2:SecurityGroup
    properties:
      name: sg
      vpcId: ${exampleAwsVpc.id}
      ingress: []
      egress: []

Setting ingress and egress to empty arrays explicitly removes all managed rules. This is necessary because the provider processes these arguments in attributes-as-blocks mode, where removing the argument doesn’t signal deletion.

Beyond these examples

These snippets focus on specific security group features: separate rule resources vs inline rules, prefix list references for AWS services, and explicit rule removal. They’re intentionally minimal rather than full network security configurations.

The examples may reference pre-existing infrastructure such as VPC with CIDR blocks configured, and VPC endpoints for prefix list examples. They focus on configuring the security group rather than provisioning the surrounding VPC infrastructure.

To keep things focused, common security group patterns are omitted, including:

  • Security group rule resources (SecurityGroupRule) as alternative to inline rules
  • Self-referencing rules for intra-group communication
  • Cross-security-group references
  • Rule descriptions and tags
  • Deletion challenges and workarounds (revokeRulesOnDelete, provisioners)

These omissions are intentional: the goal is to illustrate how each security group feature is wired, not provide drop-in network security modules. See the Security Group resource reference for all available configuration options.

Let's create and Configure Security Groups

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Rule Management & Best Practices
Should I use inline ingress and egress rules on my security group?
No. Inline rules (using ingress and egress arguments) struggle with managing multiple CIDR blocks and lack support for unique IDs, tags, and descriptions. Use aws.vpc.SecurityGroupIngressRule and aws.vpc.SecurityGroupEgressRule resources instead, with one CIDR block per rule.
What happens if I mix inline rules with separate rule resources?
Mixing inline rules with separate aws.vpc.SecurityGroupIngressRule, aws.vpc.SecurityGroupEgressRule, or aws.ec2.SecurityGroupRule resources causes rule conflicts, perpetual differences, and overwritten rules. Use one approach or the other, never both.
How do I remove all ingress and egress rules from my security group?
Set ingress: [] and egress: [] in your configuration. Due to attributes-as-blocks mode, simply removing these arguments won’t delete the managed rules.
What happens if I don't specify cidrBlocks or ipv6CidrBlocks in my rules?
Traffic will be blocked. Both cidrBlocks and ipv6CidrBlocks are optional in ingress and egress blocks, but omitting them blocks all traffic.
Deletion & Lifecycle Issues
Why can deleting my security group take up to 45 minutes?
Security groups associated with Lambda functions can take up to 45 minutes to delete due to AWS Lambda VPC networking changes. Pulumi automatically waits at least 45 minutes even if you specify a shorter delete timeout.
What is revokeRulesOnDelete and when should I use it?
revokeRulesOnDelete (default false) instructs Pulumi to revoke all attached ingress and egress rules before deleting the security group. Use this for services like Elastic Map Reduce that automatically add rules with cyclic dependencies.
Why does changing my security group name or description force recreation?
Changing name, description, namePrefix, or vpcId forces recreation because these properties are immutable. This can fail due to dependencies with other resources like EC2 instances, creating the “Security Group Deletion Problem.”
Immutable Properties & Configuration
What properties can't be changed after creating a security group?
Four properties are immutable: name, description, namePrefix, and vpcId. Changing any of these forces recreation of the security group.
Can I update my security group's description after creation?
No. The description property is immutable and maps to AWS’s GroupDescription attribute, which has no Update API. Use tags for classification that needs to be updated.
What's the default description for a security group?
The default description is “Managed by Pulumi” if you don’t specify one.
Networking & VPC
Why is my outbound traffic blocked by default?
AWS creates a default ALLOW ALL egress rule for new security groups in VPCs, but Pulumi removes this rule by default. You must explicitly recreate it using an egress rule with protocol -1, CIDR 0.0.0.0/0 (IPv4), and ::/0 (IPv6).
Can I reference security groups across VPC peering connections?
Yes, but with certain restrictions. Refer to the VPC Peering User Guide for details on cross-VPC security group references.

Using a different cloud?

Explore networking guides for other cloud providers: