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
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
Top comments (0)