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

ec2-instances.mddocs/

EC2 Instances

EC2 instance management in AWS CDK provides comprehensive control over compute resources including instance creation, configuration, instance types, and connections.

Instance Class

The Instance class represents a single EC2 instance with full configuration capabilities:

class Instance extends Resource implements IInstance {
  constructor(scope: Construct, id: string, props: InstanceProps);
  
  // Instance identification
  readonly instanceId: string;
  readonly instanceAvailabilityZone: string;
  readonly instancePrivateDnsName: string;
  readonly instancePrivateIp: string;
  readonly instancePublicDnsName: string;
  readonly instancePublicIp: string;
  
  // Security and networking
  readonly connections: Connections;
  readonly role: IRole;
  readonly grantPrincipal: IPrincipal;
  
  // CloudFormation resource
  readonly instance: CfnInstance;
  readonly osType: OperatingSystemType;
  readonly userData: UserData;
  
  // Instance management methods
  addSecurityGroup(securityGroup: ISecurityGroup): void;
  addToRolePolicy(statement: PolicyStatement): void;
  addUserData(...commands: string[]): void;
}

interface InstanceProps {
  // Required properties
  readonly vpc: IVpc;
  readonly instanceType: InstanceType;
  readonly machineImage: IMachineImage;
  
  // Optional configuration
  readonly keyName?: string;
  readonly vpcSubnets?: SubnetSelection;
  readonly availabilityZone?: string;
  readonly allowAllOutbound?: boolean;
  readonly securityGroup?: ISecurityGroup;
  readonly instanceName?: string;
  readonly role?: IRole;
  readonly userData?: UserData;
  readonly userDataCausesReplacement?: boolean;
  readonly blockDevices?: BlockDevice[];
  
  // CloudFormation init
  readonly init?: CloudFormationInit;
  readonly initOptions?: ApplyCloudFormationInitOptions;
  
  // Security settings
  readonly requireImdsv2?: boolean;
  readonly resourceSignalTimeout?: Duration;
}

Instance Interface

The IInstance interface defines the contract for EC2 instance-like objects:

interface IInstance extends IResource, IConnectable, iam.IGrantable {
  readonly instanceId: string;
  readonly instanceAvailabilityZone: string;
  readonly instancePrivateDnsName: string;
  readonly instancePrivateIp: string;
  readonly instancePublicDnsName: string;
  readonly instancePublicIp: string;
}

Instance Types

Instance types define the compute capacity, memory, and network performance:

class InstanceType {
  constructor(instanceTypeIdentifier: string);
  readonly architecture: InstanceArchitecture;
  
  static of(instanceClass: InstanceClass, instanceSize: InstanceSize): InstanceType;
  toString(): string;
}

enum InstanceClass {
  // Burstable Performance Instances
  T2 = "t2",
  T3 = "t3",
  T3A = "t3a",
  T4G = "t4g",
  
  // General Purpose Instances
  M3 = "m3",
  M4 = "m4",
  M5 = "m5",
  M5A = "m5a",
  M5AD = "m5ad",
  M5D = "m5d",
  M5DN = "m5dn",
  M5N = "m5n",
  M5ZN = "m5zn",
  M6A = "m6a",
  M6G = "m6g",
  M6GD = "m6gd",
  M6I = "m6i",
  M6ID = "m6id",
  
  // Compute Optimized Instances
  C3 = "c3",
  C4 = "c4",
  C5 = "c5",
  C5A = "c5a",
  C5AD = "c5ad",
  C5D = "c5d",
  C5N = "c5n",
  C6A = "c6a",
  C6G = "c6g",
  C6GD = "c6gd",
  C6GN = "c6gn",
  C6I = "c6i",
  C6ID = "c6id",
  
  // Memory Optimized Instances
  R3 = "r3",
  R4 = "r4",
  R5 = "r5",
  R5A = "r5a",
  R5AD = "r5ad",
  R5B = "r5b",
  R5D = "r5d",
  R5DN = "r5dn",
  R5N = "r5n",
  R6A = "r6a",
  R6G = "r6g",
  R6GD = "r6gd",
  R6I = "r6i",
  R6ID = "r6id",
  
  // Storage Optimized Instances
  D2 = "d2",
  D3 = "d3",
  D3EN = "d3en",
  H1 = "h1",
  I2 = "i2",
  I3 = "i3",
  I3EN = "i3en",
  I4I = "i4i",
  
  // Accelerated Computing Instances
  F1 = "f1",
  G3 = "g3",
  G4AD = "g4ad",
  G4DN = "g4dn",
  G5 = "g5",
  G5G = "g5g",
  P2 = "p2",
  P3 = "p3",
  P3DN = "p3dn",
  P4D = "p4d",
  
  // High Performance Computing
  HPC6A = "hpc6a",
  
  // Previous Generation
  A1 = "a1",
  
  // And many more...
}

enum InstanceSize {
  NANO = "nano",
  MICRO = "micro",
  SMALL = "small",
  MEDIUM = "medium",
  LARGE = "large",
  XLARGE = "xlarge",
  XLARGE2 = "2xlarge",
  XLARGE3 = "3xlarge",
  XLARGE4 = "4xlarge",
  XLARGE6 = "6xlarge",
  XLARGE8 = "8xlarge",
  XLARGE9 = "9xlarge",
  XLARGE10 = "10xlarge",
  XLARGE12 = "12xlarge",
  XLARGE16 = "16xlarge",
  XLARGE18 = "18xlarge",
  XLARGE24 = "24xlarge",
  XLARGE32 = "32xlarge",
  XLARGE48 = "48xlarge",
  XLARGE56 = "56xlarge",
  XLARGE112 = "112xlarge",
  METAL = "metal"
}

enum InstanceArchitecture {
  ARM_64 = "arm64",
  X86_64 = "x86_64"
}

Bastion Host

For secure access to private instances, CDK provides a specialized bastion host construct:

class BastionHostLinux extends Resource implements IInstance {
  constructor(scope: Construct, id: string, props: BastionHostLinuxProps);
  
  readonly stack: Stack;
  readonly connections: Connections;
  readonly role: IRole;
  readonly grantPrincipal: IPrincipal;
  readonly instance: Instance;
  
  // Instance properties
  readonly instanceId: string;
  readonly instanceAvailabilityZone: string;
  readonly instancePrivateDnsName: string;
  readonly instancePrivateIp: string;
  readonly instancePublicDnsName: string;
  readonly instancePublicIp: string;
  
  // Security methods
  allowSshAccessFrom(...peer: IPeer[]): void;
}

interface BastionHostLinuxProps {
  readonly vpc: IVpc;
  readonly availabilityZone?: string;
  readonly instanceName?: string;
  readonly subnetSelection?: SubnetSelection;
  readonly securityGroup?: ISecurityGroup;
  readonly instanceType?: InstanceType;
  readonly machineImage?: IMachineImage;
  readonly blockDevices?: BlockDevice[];
  readonly init?: CloudFormationInit;
  readonly initOptions?: ApplyCloudFormationInitOptions;
  readonly requireImdsv2?: boolean;
}

Connections Management

The Connections class manages network connectivity for instances:

class Connections {
  constructor(props: ConnectionsProps = {});
  
  readonly connections: Connections;
  readonly defaultPort?: Port;
  readonly securityGroups: ISecurityGroup[];
  
  // Security group management
  addSecurityGroup(...securityGroups: ISecurityGroup[]): void;
  
  // Outbound connections
  allowTo(other: IConnectable, portRange: Port, description?: string): void;
  allowToAnyIpv4(portRange: Port, description?: string): void;
  allowToDefaultPort(other: IConnectable, description?: string): void;
  allowDefaultPortTo(other: IConnectable, description?: string): void;
  
  // Inbound connections
  allowFrom(other: IConnectable, portRange: Port, description?: string): void;
  allowFromAnyIpv4(portRange: Port, description?: string): void;
  allowDefaultPortFrom(other: IConnectable, description?: string): void;
  allowDefaultPortFromAnyIpv4(description?: string): void;
  
  // Internal connections
  allowInternally(portRange: Port, description?: string): void;
  allowDefaultPortInternally(description?: string): void;
}

interface ConnectionsProps {
  readonly peer?: IPeer;
  readonly securityGroups?: ISecurityGroup[];
  readonly defaultPort?: Port;
}

interface IConnectable {
  readonly connections: Connections;
}

Usage Examples

Basic Instance Creation

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

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

const instance = new ec2.Instance(this, "MyInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(
    ec2.InstanceClass.T3,
    ec2.InstanceSize.MICRO
  ),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  keyName: "my-key-pair"
});

Instance with Custom Configuration

const role = new iam.Role(this, "InstanceRole", {
  assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
  ]
});

const securityGroup = new ec2.SecurityGroup(this, "InstanceSG", {
  vpc,
  description: "Security group for web server",
  allowAllOutbound: true
});

securityGroup.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(80),
  "Allow HTTP traffic"
);

const userData = ec2.UserData.forLinux();
userData.addCommands(
  "yum update -y",
  "yum install -y httpd",
  "systemctl start httpd",
  "systemctl enable httpd"
);

const instance = new ec2.Instance(this, "WebServer", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  securityGroup,
  role,
  userData,
  vpcSubnets: {
    subnetType: ec2.SubnetType.PUBLIC
  }
});

Instance with Block Device Mappings

const instance = new ec2.Instance(this, "InstanceWithStorage", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  blockDevices: [
    {
      deviceName: "/dev/xvda",
      volume: ec2.BlockDeviceVolume.ebs(50, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        encrypted: true
      })
    },
    {
      deviceName: "/dev/xvdb",
      volume: ec2.BlockDeviceVolume.ebs(100, {
        volumeType: ec2.EbsDeviceVolumeType.GP3,
        iops: 3000,
        throughput: 125
      })
    }
  ]
});

Bastion Host Setup

const bastion = new ec2.BastionHostLinux(this, "BastionHost", {
  vpc,
  subnetSelection: {
    subnetType: ec2.SubnetType.PUBLIC
  },
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.NANO)
});

// Allow SSH access from specific IP ranges
bastion.allowSshAccessFrom(ec2.Peer.ipv4("203.0.113.0/24"));

// Allow bastion to connect to private instances
bastion.connections.allowTo(
  privateInstance,
  ec2.Port.tcp(22),
  "SSH access to private instance"
);

Instance with CloudFormation Init

const init = ec2.CloudFormationInit.fromElements(
  ec2.InitConfig.fromElements(
    ec2.InitPackage.yum("httpd"),
    ec2.InitService.enable("httpd", {
      enabled: true,
      ensureRunning: true
    }),
    ec2.InitFile.fromString("/var/www/html/index.html", "<h1>Hello World</h1>")
  )
);

const instance = new ec2.Instance(this, "ConfiguredInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  init,
  initOptions: {
    timeout: cdk.Duration.minutes(10),
    includeUrl: true,
    includeRole: true,
    printLog: true
  }
});

Multiple Instance Types

// Burstable performance instance for development
const devInstance = new ec2.Instance(this, "DevInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
  machineImage: ec2.MachineImage.latestAmazonLinux()
});

// Compute optimized instance for CPU-intensive workloads
const computeInstance = new ec2.Instance(this, "ComputeInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.C5, ec2.InstanceSize.XLARGE),
  machineImage: ec2.MachineImage.latestAmazonLinux()
});

// Memory optimized instance for in-memory databases
const memoryInstance = new ec2.Instance(this, "MemoryInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.XLARGE2),
  machineImage: ec2.MachineImage.latestAmazonLinux()
});

Instance with IMDSv2

const secureInstance = new ec2.Instance(this, "SecureInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  requireImdsv2: true  // Require IMDSv2 for security
});

Cross-Instance Connectivity

const webServer = new ec2.Instance(this, "WebServer", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
  machineImage: ec2.MachineImage.latestAmazonLinux()
});

const database = new ec2.Instance(this, "Database", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  vpcSubnets: {
    subnetType: ec2.SubnetType.PRIVATE_WITH_NAT
  }
});

// Allow web server to connect to database
webServer.connections.allowTo(
  database,
  ec2.Port.tcp(3306),
  "Database connection"
);

// Allow SSH access from bastion to both instances
bastion.connections.allowTo(webServer, ec2.Port.tcp(22));
bastion.connections.allowTo(database, ec2.Port.tcp(22));

Best Practices

  1. Instance Sizing: Choose appropriate instance types based on workload requirements (CPU, memory, network, storage)
  2. Security Groups: Use the principle of least privilege for security group rules
  3. Key Pairs: Use EC2 key pairs for SSH access or preferably AWS Systems Manager Session Manager
  4. IMDSv2: Always enable IMDSv2 for enhanced security
  5. Subnet Placement: Place instances in private subnets unless they need direct internet access
  6. IAM Roles: Attach IAM roles instead of embedding credentials
  7. User Data: Keep user data scripts simple and use CloudFormation Init for complex configurations
  8. Monitoring: Enable detailed monitoring for production instances
  9. Backup Strategy: Configure automated snapshots for EBS volumes
  10. Updates: Regularly update instances with security patches and software updates