Configure AWS 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 optional inline rules. This guide focuses on four capabilities: companion rule resources (the recommended pattern), inline rule configuration, prefix list references, and rule removal.

Security groups belong to VPCs and may reference VPC endpoints for prefix lists. The examples are intentionally small. The documentation strongly recommends using companion SecurityGroupIngressRule and SecurityGroupEgressRule resources instead of inline rules to avoid conflicts when managing multiple CIDR blocks or rule descriptions.

Create a security group with separate rule resources

Most deployments create security groups as containers, then attach ingress and egress rules separately to avoid conflicts.

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 defines the container with a name and VPC. The SecurityGroupIngressRule and SecurityGroupEgressRule resources attach rules by referencing the security group’s ID. This pattern avoids the limitations of inline rules: each rule can have its own description, tags, and CIDR block without conflicts. The ipProtocol value “-1” means all protocols.

Allow all outbound traffic with inline rules

AWS creates a default egress rule allowing all outbound traffic when you create a security group. Pulumi removes this default, requiring you to recreate it explicitly.

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 inline rules. Setting protocol to “-1” allows all protocols, and the CIDR blocks “0.0.0.0/0” and “::/0” allow all IPv4 and IPv6 destinations. This recreates AWS’s default egress behavior, which Pulumi removes automatically.

Reference AWS-managed prefix lists for service endpoints

VPC endpoints expose prefix list IDs representing AWS service IP ranges, which security groups can reference instead of hardcoding CIDR blocks.

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, which AWS maintains automatically. When AWS updates service IP ranges, your security group rules update automatically without configuration changes.

Remove all rules by setting empty arrays

The ingress and egress arguments use attribute-as-blocks mode. Removing them from configuration doesn’t destroy managed rules; you must explicitly set 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 removes all managed rules. Without this explicit configuration, removing the arguments leaves existing rules in place.

Beyond these examples

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

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

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

  • Security group rule descriptions and tags
  • Self-referencing rules for intra-group traffic
  • Cross-security-group references
  • Rule priority and evaluation order

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 configure AWS 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/egress rules or separate rule resources?
Use separate rule resources (aws.vpc.SecurityGroupIngressRule and aws.vpc.SecurityGroupEgressRule) with one CIDR block per rule. Inline ingress and egress arguments struggle with multiple CIDR blocks and lack unique IDs, tags, and descriptions. Never mix inline rules with separate rule resources, as this causes rule conflicts, perpetual diffs, and rules being overwritten.
Why am I seeing perpetual diffs in my security group rules?
You’re likely mixing inline rules (using ingress/egress arguments) with separate rule resources (aws.vpc.SecurityGroupIngressRule, aws.vpc.SecurityGroupEgressRule, or aws.ec2.SecurityGroupRule). This combination causes conflicts and perpetual differences. Choose one approach and stick with it.
How do I remove all rules from a security group?
Explicitly set ingress: [] and egress: [] in your configuration. Due to attributes-as-blocks mode, simply removing these arguments won’t destroy the managed rules.
What happens if I don't specify CIDR blocks in my rules?
Traffic will be blocked. The cidrBlocks and ipv6CidrBlocks parameters are optional in ingress and egress blocks, but omitting them blocks all traffic.
Resource Lifecycle & Deletion
Why is deleting my security group taking 45 minutes or longer?
Security groups associated with Lambda Functions can take up to 45 minutes to delete due to AWS Lambda VPC networking changes. Pulumi waits at least 45 minutes even if you specify a shorter delete timeout.
Why can't I delete my security group even though I removed it from my configuration?
AWS prevents deleting security groups that are associated with other resources like EC2 instances. This creates a bidirectional dependency that Pulumi doesn’t fully model. You may need to remove the security group association from dependent resources first, or use a shorter delete timeout to fail faster and identify the blocking resource.
When should I use the revokeRulesOnDelete option?
Set revokeRulesOnDelete: true when using AWS services like Elastic MapReduce that automatically add rules to your security groups. These auto-added rules can create cyclic dependencies that prevent deletion. This option revokes all attached rules before deleting the security group itself. Default is false.
Configuration & Immutability
What properties force recreation of a security group?
Changing name, description, namePrefix, or vpcId forces Pulumi to destroy and recreate the security group. These properties are immutable in AWS and cannot be updated in place.
Why can't I update my security group's description?
The description field maps to AWS’s GroupDescription attribute, which has no Update API. It’s immutable and defaults to “Managed by Pulumi”. Use tags instead if you need updatable classification for your security groups.
How do I use prefix list IDs with security groups?
Use prefixListIds in your egress or ingress blocks. You can reference prefix lists from VPC endpoints (using vpcEndpoint.prefixListId) or find specific prefix lists using the aws.ec2.getPrefixList data source.
Default Behaviors
Why did Pulumi remove my default egress rule?
AWS creates a default ALLOW ALL egress rule when creating security groups in VPCs. Pulumi removes this default rule to give you explicit control over egress traffic. If you want the default behavior, explicitly add an egress rule with protocol: "-1", cidrBlocks: ["0.0.0.0/0"], and ipv6CidrBlocks: ["::/0"].

Using a different cloud?

Explore networking guides for other cloud providers: