or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cloudformation-init.mdec2-instances.mdflow-logs.mdindex.mdlaunch-templates.mdmachine-images.mdnetwork-acl.mdsecurity-groups.mdstorage-volumes.mdsubnets-networking.mduser-data.mdvpc-endpoints.mdvpc-management.mdvpn-connectivity.md
tile.json

security-groups.mddocs/

Security Groups

Security groups in AWS CDK EC2 provide network-level security through stateful firewall rules that control inbound and outbound traffic for AWS resources.

SecurityGroup Class

The SecurityGroup class creates and manages security groups with ingress and egress rules:

class SecurityGroup extends Resource implements ISecurityGroup {
  constructor(scope: Construct, id: string, props: SecurityGroupProps);
  
  // Security group properties
  readonly securityGroupName: string;
  readonly securityGroupId: string;
  readonly securityGroupVpcId: string;
  readonly allowAllOutbound: boolean;
  readonly connections: Connections;
  
  // Static factory methods
  static fromLookupById(scope: Construct, id: string, securityGroupId: string): SecurityGroup;
  static fromLookupByName(scope: Construct, id: string, securityGroupName: string, vpc: IVpc): SecurityGroup;
  static fromSecurityGroupId(scope: Construct, id: string, securityGroupId: string, options?: SecurityGroupImportOptions): ISecurityGroup;
  
  // Rule management
  addIngressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean): void;
  addEgressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean): void;
}

interface SecurityGroupProps {
  readonly vpc: IVpc;
  readonly securityGroupName?: string;
  readonly description?: string;
  readonly allowAllOutbound?: boolean;
  readonly disableInlineRules?: boolean;
}

Security Group Interface

The ISecurityGroup interface defines the contract for security group-like objects:

interface ISecurityGroup extends IResource, IPeer {
  readonly securityGroupId: string;
  readonly allowAllOutbound: boolean;
  readonly connections: Connections;
  
  addIngressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean): void;
  addEgressRule(peer: IPeer, connection: Port, description?: string, remoteRule?: boolean): void;
}

interface SecurityGroupImportOptions {
  readonly allowAllOutbound?: boolean;
  readonly mutable?: boolean;
}

Peers

Peers define the source or destination for security group rules:

class Peer {
  // IPv4 peers
  static ipv4(cidrIp: string): IPeer;
  static anyIpv4(): IPeer;
  
  // IPv6 peers
  static ipv6(cidrIp: string): IPeer;
  static anyIpv6(): IPeer;
  
  // Prefix list peers
  static prefixList(prefixListId: string): IPeer;
  
  // Security group peers
  static securityGroupId(securityGroupId: string, sourceSecurityGroupOwnerId?: string): IPeer;
}

interface IPeer extends IConnectable {
  readonly canInlineRule: boolean;
  readonly uniqueId: string;
  
  toIngressRuleConfig(): any;
  toEgressRuleConfig(): any;
}

Ports

Ports define the protocol and port ranges for security group rules:

class Port {
  constructor(props: PortProps);
  readonly canInlineRule: boolean;
  
  // TCP ports
  static tcp(port: number): Port;
  static tcpRange(startPort: number, endPort: number): Port;
  static allTcp(): Port;
  
  // UDP ports
  static udp(port: number): Port;
  static udpRange(startPort: number, endPort: number): Port;
  static allUdp(): Port;
  
  // ICMP
  static icmpTypeAndCode(type: number, code: number): Port;
  static icmpType(type: number): Port;
  static icmpPing(): Port;
  static allIcmp(): Port;
  
  // Other protocols
  static esp(): Port;
  static ah(): Port;
  static allTraffic(): Port;
  
  toRuleJson(): any;
  toString(): string;
}

interface PortProps {
  readonly protocol: Protocol;
  readonly fromPort?: number;
  readonly toPort?: number;
  readonly stringRepresentation: string;
}

enum Protocol {
  ALL = '-1',
  ICMP = 'icmp',
  TCP = 'tcp',
  UDP = 'udp',
  IPV6_ICMP = 'icmpv6',
  // ... and many numbered protocols
}

Usage Examples

Basic Security Group Creation

import * as ec2 from "@aws-cdk/aws-ec2";

const vpc = new ec2.Vpc(this, "MyVpc");

const webSecurityGroup = new ec2.SecurityGroup(this, "WebSecurityGroup", {
  vpc,
  description: "Security group for web servers",
  allowAllOutbound: true
});

// Add HTTP access from anywhere
webSecurityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(80),
  "Allow HTTP traffic from anywhere"
);

// Add HTTPS access from anywhere
webSecurityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(443),
  "Allow HTTPS traffic from anywhere"
);

Database Security Group

const dbSecurityGroup = new ec2.SecurityGroup(this, "DatabaseSecurityGroup", {
  vpc,
  description: "Security group for database servers",
  allowAllOutbound: false // Explicitly deny all outbound traffic
});

// Allow MySQL access only from web security group
dbSecurityGroup.addIngressRule(
  webSecurityGroup,
  ec2.Port.tcp(3306),
  "Allow MySQL access from web servers"
);

// Allow PostgreSQL access from application security group
const appSecurityGroup = new ec2.SecurityGroup(this, "AppSecurityGroup", {
  vpc,
  description: "Security group for application servers"
});

dbSecurityGroup.addIngressRule(
  appSecurityGroup,
  ec2.Port.tcp(5432),
  "Allow PostgreSQL access from application servers"
);

SSH Access Management

const bastionSecurityGroup = new ec2.SecurityGroup(this, "BastionSecurityGroup", {
  vpc,
  description: "Security group for bastion host"
});

// Allow SSH from specific IP ranges
bastionSecurityGroup.addIngressRule(
  ec2.Peer.ipv4("203.0.113.0/24"),
  ec2.Port.tcp(22),
  "Allow SSH from office network"
);

bastionSecurityGroup.addIngressRule(
  ec2.Peer.ipv4("198.51.100.0/24"),
  ec2.Port.tcp(22),
  "Allow SSH from VPN network"
);

const privateSecurityGroup = new ec2.SecurityGroup(this, "PrivateSecurityGroup", {
  vpc,
  description: "Security group for private instances"
});

// Allow SSH only from bastion
privateSecurityGroup.addIngressRule(
  bastionSecurityGroup,
  ec2.Port.tcp(22),
  "Allow SSH from bastion host"
);

Application Load Balancer Security Group

const albSecurityGroup = new ec2.SecurityGroup(this, "ALBSecurityGroup", {
  vpc,
  description: "Security group for Application Load Balancer"
});

// Allow HTTP and HTTPS from anywhere
albSecurityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(80),
  "Allow HTTP from internet"
);

albSecurityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(443),
  "Allow HTTPS from internet"
);

const backendSecurityGroup = new ec2.SecurityGroup(this, "BackendSecurityGroup", {
  vpc,
  description: "Security group for backend instances"
});

// Allow traffic from ALB to backend on application port
backendSecurityGroup.addIngressRule(
  albSecurityGroup,
  ec2.Port.tcp(8080),
  "Allow traffic from ALB"
);

Complex Port Configurations

const customSecurityGroup = new ec2.SecurityGroup(this, "CustomSecurityGroup", {
  vpc,
  description: "Security group with custom port configurations"
});

// Custom port range
customSecurityGroup.addIngressRule(
  ec2.Peer.ipv4("10.0.0.0/16"),
  ec2.Port.tcpRange(8000, 8999),
  "Allow custom port range from VPC"
);

// ICMP ping
customSecurityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.icmpPing(),
  "Allow ping from anywhere"
);

// UDP port
customSecurityGroup.addIngressRule(
  ec2.Peer.ipv4("192.168.1.0/24"),
  ec2.Port.udp(53),
  "Allow DNS queries from private network"
);

// All traffic from same security group
customSecurityGroup.addIngressRule(
  customSecurityGroup,
  ec2.Port.allTraffic(),
  "Allow all traffic within security group"
);

IPv6 Support

const ipv6SecurityGroup = new ec2.SecurityGroup(this, "IPv6SecurityGroup", {
  vpc,
  description: "Security group with IPv6 support"
});

// Allow HTTP from any IPv6 address
ipv6SecurityGroup.addIngressRule(
  ec2.Peer.anyIpv6(),
  ec2.Port.tcp(80),
  "Allow HTTP from any IPv6"
);

// Allow specific IPv6 CIDR
ipv6SecurityGroup.addIngressRule(
  ec2.Peer.ipv6("2001:db8::/32"),
  ec2.Port.tcp(443),
  "Allow HTTPS from specific IPv6 network"
);

Security Group References

// Import existing security group
const existingSecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(
  this,
  "ExistingSecurityGroup",
  "sg-12345678",
  {
    allowAllOutbound: false,
    mutable: true
  }
);

// Use imported security group in rules
const newSecurityGroup = new ec2.SecurityGroup(this, "NewSecurityGroup", {
  vpc,
  description: "New security group"
});

newSecurityGroup.addIngressRule(
  existingSecurityGroup,
  ec2.Port.tcp(3306),
  "Allow database access from existing security group"
);

Cross-Account Security Group References

const crossAccountSecurityGroup = ec2.Peer.securityGroupId(
  "sg-87654321",
  "123456789012" // Source account ID
);

const securityGroup = new ec2.SecurityGroup(this, "CrossAccountSG", {
  vpc,
  description: "Security group allowing cross-account access"
});

securityGroup.addIngressRule(
  crossAccountSecurityGroup,
  ec2.Port.tcp(443),
  "Allow HTTPS from cross-account security group"
);

Egress Rules Management

const restrictedSecurityGroup = new ec2.SecurityGroup(this, "RestrictedSecurityGroup", {
  vpc,
  description: "Security group with restricted outbound access",
  allowAllOutbound: false // Start with no outbound rules
});

// Allow HTTPS to specific destinations
restrictedSecurityGroup.addEgressRule(
  ec2.Peer.ipv4("0.0.0.0/0"),
  ec2.Port.tcp(443),
  "Allow HTTPS outbound"
);

// Allow DNS queries
restrictedSecurityGroup.addEgressRule(
  ec2.Peer.ipv4("0.0.0.0/0"),
  ec2.Port.udp(53),
  "Allow DNS queries"
);

// Allow outbound to database security group
restrictedSecurityGroup.addEgressRule(
  dbSecurityGroup,
  ec2.Port.tcp(5432),
  "Allow outbound to database"
);

Security Group with Prefix Lists

const prefixListSecurityGroup = new ec2.SecurityGroup(this, "PrefixListSecurityGroup", {
  vpc,
  description: "Security group using prefix lists"
});

// Allow access from S3 prefix list
prefixListSecurityGroup.addIngressRule(
  ec2.Peer.prefixList("pl-12345678"),
  ec2.Port.tcp(443),
  "Allow HTTPS from S3 prefix list"
);

Dynamic Rule Creation

const ports = [80, 443, 8080, 8443];
const securityGroup = new ec2.SecurityGroup(this, "MultiPortSecurityGroup", {
  vpc,
  description: "Security group with multiple ports"
});

ports.forEach((port, index) => {
  securityGroup.addIngressRule(
    ec2.Peer.anyIpv4(),
    ec2.Port.tcp(port),
    `Allow traffic on port ${port}`
  );
});

Best Practices

  1. Principle of Least Privilege: Only allow the minimum required access
  2. Use Security Groups as Sources: Reference other security groups instead of IP ranges when possible
  3. Descriptive Names: Use clear, descriptive names for security groups and rules
  4. Separate by Function: Create separate security groups for different application tiers
  5. Regular Audits: Regularly review and audit security group rules
  6. Avoid 0.0.0.0/0: Minimize the use of "allow from anywhere" rules
  7. Document Rules: Provide meaningful descriptions for all rules
  8. Layered Security: Use security groups in combination with NACLs for defense in depth
  9. Group Management: Use security group references to simplify rule management
  10. Monitoring: Monitor security group changes and unusual traffic patterns