Building an EC2 instance gives us a few challenges:
Building
Testing
Connecting
vpc := ec2.Vpc_FromLookup(stack, aws.String("vpc"), &ec2.VpcLookupOptions{
IsDefault: aws.Bool(true),
})
You have to set the right account data, so that the CDK can search the environment.
Therefore in main/main.go
you see:
awscdk.StackProps{
Env: util.Env(),
},
Which calls the Env
function, which gets the account from an environment var:
Account: aws.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
That means you have to export the account number before starting cdk deploy
monolithSG := ec2.NewSecurityGroup(stack, aws.String("monolithSG"),
&ec2.SecurityGroupProps{
Vpc: vpc,
AllowAllOutbound: aws.Bool(true),
Description: aws.String("SG for monolithSG"),
SecurityGroupName: aws.String("monolithSG"),
})
monolithSG.AddIngressRule(ec2.Peer_Ipv4(aws.String("0.0.0.0/0")),
ec2.NewPort(&ec2.PortProps{
Protocol: ec2.Protocol_TCP,
StringRepresentation: aws.String("Incoming web"),
FromPort: aws.Float64(80),
ToPort: aws.Float64(80),
}),
aws.String("Incoming http"),
aws.Bool(false),
)
You define a Security Group, then add some ingress rules. This group will then be referenced in the instance creation:
monolith := ec2.NewInstance(stack, aws.String("monolith"),
&ec2.InstanceProps{
...
SecurityGroup: monolithSG,
...
})
ssmPolicy := iam.ManagedPolicy_FromAwsManagedPolicyName(aws.String("AmazonSSMManagedInstanceCore"))
instanceRole := iam.NewRole(stack, aws.String("webinstancerole"),
&iam.RoleProps{
AssumedBy: iam.NewServicePrincipal(aws.String("ec2.amazonaws.com"), nil),
Description: aws.String("Instance Role"),
ManagedPolicies: &[]iam.IManagedPolicy{ssmPolicy},
},
)
To give the instances and all users on this instance, you create a instance role. This role will be assumed by “ec2.amazonaws.com”.
With the managed AWS IAM policy AmazonSSMManagedInstanceCore you may connect with the session manager to the instance.
With the standard instance CDK construct you get an EBS volume.
If you want to alter this, you have to create an additional volume. With the right device name this will be used as boot volume:
volume := ec2.BlockDeviceVolume_Ebs(aws.Float64(30), &ec2.EbsDeviceOptions{
VolumeType: ec2.EbsDeviceVolumeType_GP3,
})
rootVolume := &ec2.BlockDevice{
DeviceName: aws.String("/dev/xvda"),
Volume: volume,
};
As with all CDk constructs, the properties have their own type, ec2.InstanceProps
.
So the instance goes like:
monolith := ec2.NewInstance(stack, aws.String("monolith"),
&ec2.InstanceProps{
InstanceType: ec2.InstanceType_Of(ec2.InstanceClass_MEMORY5_AMD, ec2.InstanceSize_LARGE),
MachineImage: linuxImage,
BlockDevices: &[]*ec2.BlockDevice{rootVolume},
Vpc: vpc,
InstanceName: aws.String("monolith"),
Role: instanceRole,
SecurityGroup: monolithSG,
UserData: userdata,
VpcSubnets: &ec2.SubnetSelection{
SubnetType: ec2.SubnetType_PUBLIC,
},
})
And all prepared resources will be used in the properties.
Because we have given the instance profile the Systems Manager rights, we can just connect with the Session Manager Plugin:
If the instance has the id “i-0f4cec49522ba3f15” you get an terminal session with:
aws ssm start-session --target i-0f4cec49522ba3f15
Without ssh key and it makes no difference whether the instance is in public or private subnet.
This looks like:
aws ssm start-session --target i-0f4cec49522ba3f15
Starting session with SessionId: gglawe-039a13542185319ac
sh-4.2$
See the full source on github: