Skip to content

Instantly share code, notes, and snippets.

@simonespa
Created April 28, 2026 14:16
Show Gist options
  • Select an option

  • Save simonespa/277cdbf0d79976772fb939675c2aaa37 to your computer and use it in GitHub Desktop.

Select an option

Save simonespa/277cdbf0d79976772fb939675c2aaa37 to your computer and use it in GitHub Desktop.
CDK code to spawn an EC2 instance
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
export class Ec2Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const keyPair = new ec2.KeyPair(this, 'KeyPair', {
keyPairName: 'ec2-key-pair',
type: ec2.KeyPairType.RSA,
format: ec2.KeyPairFormat.PEM,
});
const allowedSshCidr = new cdk.CfnParameter(this, 'AllowedSshCidr', {
type: 'String',
default: '0.0.0.0/0',
description: 'CIDR range allowed to SSH to the EC2 instance (recommend locking this down).',
allowedPattern: '^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$',
constraintDescription: 'Must be a valid IPv4 CIDR block (for example 203.0.113.10/32).',
});
const vpc = new ec2.Vpc(this, 'Vpc', {
availabilityZones: ['eu-west-1a'],
natGateways: 0,
subnetConfiguration: [
{
name: 'public',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
},
],
});
const securityGroup = new ec2.SecurityGroup(this, 'InstanceSecurityGroup', {
vpc,
description: 'Allow SSH access to the EC2 instance.',
allowAllOutbound: true,
});
securityGroup.addIngressRule(
ec2.Peer.ipv4(allowedSshCidr.valueAsString),
ec2.Port.tcp(22),
'Allow inbound SSH',
);
const instanceRole = new iam.Role(this, 'InstanceRole', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
],
});
const instanceProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
roles: [instanceRole.roleName],
});
const amiId = '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64}}';
const userDataScript = [
'#!/bin/bash',
'set -euxo pipefail',
'dnf update -y',
'dnf install -y git nodejs24',
'npm install --global corepack@latest',
'corepack prepare pnpm@latest --activate',
'corepack prepare yarn@stable --activate'
].join('\n');
const ec2Instance = new ec2.CfnInstance(this, 'Ec2Instance', {
imageId: amiId,
instanceType: 'm8g.medium',
keyName: keyPair.keyPairName,
iamInstanceProfile: instanceProfile.ref,
userData: cdk.Fn.base64(userDataScript),
networkInterfaces: [
{
associatePublicIpAddress: true,
deviceIndex: '0',
subnetId: vpc.publicSubnets[0].subnetId,
groupSet: [securityGroup.securityGroupId],
},
],
tags: [
{
key: 'Name',
value: 'ec2-instance',
},
],
});
const eip = new ec2.CfnEIP(this, 'ElasticIp', {
domain: 'vpc',
});
new ec2.CfnEIPAssociation(this, 'Ec2ElasticIpAssociation', {
allocationId: eip.attrAllocationId,
instanceId: ec2Instance.ref,
});
new cdk.CfnOutput(this, 'Ec2InstancePublicIp', {
value: eip.ref,
description: 'Elastic IP for the Linux EC2 instance.',
});
new cdk.CfnOutput(this, 'SshPrivateKeyCommand', {
value: `aws ssm get-parameter --name /ec2/keypair/${keyPair.keyPairId} --with-decryption --query Parameter.Value --output text > ec2-key.pem && chmod 400 ec2-key.pem`,
description: 'AWS CLI command to download the private key from SSM Parameter Store.',
});
new cdk.CfnOutput(this, 'SshCommand', {
value: cdk.Fn.join('', ['ssh -i ec2-key.pem ec2-user@', eip.ref]),
description: 'Example SSH command to connect to the EC2 instance.',
});
new cdk.CfnOutput(this, 'ScpCommandExample', {
value: cdk.Fn.join('', [
'scp -i ec2-key.pem <local-file> ec2-user@',
eip.ref,
':/home/ec2-user/',
]),
description: 'Example SCP command to copy files to the EC2 instance.',
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment