AWS CDK: Create EC2 Bastion with Ec2 Instance Connect
Published: 2022-12-18 13:42:40

---
title: AWS CDK: Create EC2 Bastion with Ec2 Instance Connect
published: true
date: 2022-08-01 19:31:12 UTC
---

An EC2 Bastion instance is a security-hardened virtual machine that you can use as a jump box.

A jump box is always useful when you have AWS running in a closed environment like a private VPC subnet but still have to access resources from your computer or the AWS CloudShell.

## Create a Bastion EC2 Instance

```
const machineImage = aws_ec2.MachineImage.latestAmazonLinux({
  generation: aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
});

// define instance type for the bastion EC2 instance
const instanceType = new aws_ec2.InstanceType('t3.micro');

// select a public subnet so we can access the Bastion from
// the internet
const publicSubnets = vpc.selectSubnets({
  subnetType: aws_ec2.SubnetType.PUBLIC,
});

// each EC2 instance must be deployed with a key pair
const keyName = new aws_ec2.CfnKeyPair(this, 'BastionKeyPair', {
  keyName: 'BastionKeyPair',
}).keyName;

// create service principal role
const role = new aws_iam.Role(this, 'BastionSericeRole', {
  assumedBy: new aws_iam.ServicePrincipal('ec2.amazonaws.com'),
});

// launch EC2 bastion instance
const bastion = new aws_ec2.Instance(this, 'Bastion', {
  vpc: vpc,
  vpcSubnets: publicSubnets,
  role: role,
  securityGroup: this.securityGroup,
  instanceName: 'Bastion',
  machineImage: machineImage,
  instanceType: instanceType,
  keyName: keyName,
  // enables detailed monitoring to Cloudwatch, 
  // not necessary but recommended
  detailedMonitoring: true,
});

```

> Find out how you can create a VPC with the AWS CDK [here](https://dev.to/gdenn/how-to-configure-a-vpc-in-aws-cdk-3ki6-temp-slug-2283659)

## Allow EC2 Instance Connect for User Group

We have our Bastion instance running but still need to grant our users enough IAM permissions to ssh into the instance.

We create an IAM User Group for this, so you are still flexible in the future an can easily add/remove IAM users from the group to grant/revoke ec2 instance connect access to the Bastion.

```

const region = Stack.of(this).region;
const accountId = Stack.of(this).account;

const bastionArn = `arn:aws:ec2:${region}:${accountId}:instance/${bastion.instanceId}`;

// create inline policy that allows EC2 connect
const instanceConnectPolicy = new aws_iam.Policy(this, 'BastionEc2ConnectPolicy', {
  statements: [
    new aws_iam.PolicyStatement({
      effect: aws_iam.Effect.ALLOW,
      actions: ['ec2-instance-connect:SendSSHPublicKey'],
      resources: [bastionArn],
      conditions: {
        StringEquals: {
          'ec2:osuser': 'ec2-user',
        },
      },
    }),
    new aws_iam.PolicyStatement({
      effect: aws_iam.Effect.ALLOW,
      actions: ['ec2:DescribeInstances'],
      resources: [bastionArn],
    }),
  ],
});

// create the user group, attach the inline policy
const userGroup = new aws_iam.Group(this, 'AccManagementGroup');
userGroup.attachInlinePolicy(instanceConnectPolicy);

// add a user to the group
const user = aws_iam.User.fromUserArn(this, 'BastionConnectUser', '<my-user-arn>');
userGroup.addUser(user);

```

> The policy in the code snippet forces you to ssh with the 'ec2-user' into the bastion

## Expose EKS Kubernetes API to Bastion

**coming soon**

## Add User Data Script with Template Substitution

**coming soon**