My current objective is to utilize CDK to create an EC2 instance for automation. Thus far, I have been successful in creating an EC2 instance with CDK, complete with VPC, security group, and key.
However, after deploying the instance via CDK, I have encountered issues attempting to execute commands on the instance, as they fail to execute properly. To elaborate, the commands in question do not execute on the EC2 instance as intended.
For reference, I attached the code below :
from aws_cdk import (
Stack,
aws_ec2 as ec2,
CfnOutput,
CfnTag,
aws_iam as iam,
aws_route53 as route53,
aws_route53_targets as targets
)
from constructs import Construct
class CdkTrsting1Stack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# VPC
vpc = ec2.Vpc.from_vpc_attributes(
self, "VPC",
vpc_id="vpc-",
availability_zones=['us-east-1a'],
public_subnet_ids=['subnet-'] # Specify the actual subnet IDs here
)
# Security Group with inbound rule from everywhere
security_group = ec2.SecurityGroup(
self, "SecurityGroup",
vpc=vpc,
allow_all_outbound=True,
security_group_name="AllowAllInbound",
)
security_group.add_ingress_rule(
ec2.Peer.any_ipv4(),
ec2.Port.tcp(22),
)
security_group.add_ingress_rule(
ec2.Peer.any_ipv4(),
ec2.Port.tcp(80),
)
security_group.add_ingress_rule(
ec2.Peer.any_ipv4(),
ec2.Port.tcp(443) # SSH port
)
# IAM Role
role = iam.Role(
self, "EC2FullAccessRole",
assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
)
# Attach policy with full EC2 access to the role
policy = iam.PolicyStatement(
actions=["ec2:*"],
resources=["*"]
)
role.add_to_policy(policy)
# Create EC2 instance
instance = ec2.Instance(
self,
"MyInstance",
instance_type=ec2.InstanceType("t2.micro"),
machine_image=ec2.MachineImage.generic_linux({
"us-east-1": "ami-07d9b9ddc6cd8dd30"
}),
vpc=vpc,
security_group=security_group,
associate_public_ip_address=True,
key_name="<key>",
role=role,
user_data=ec2.UserData.custom(
"sudo mkdir Trial101"
)
)
user_data = ec2.UserData.for_linux()
user_data.add_commands(
"#!/bin/bash",
"sudo apt update && sudo apt upgrade -y",
"sudo apt install git",
"git clone <git_url>",
"cd <folder_path>",
"sh startup_run.sh"
)
publicIp = instance.instance_public_ip;
# Output Instance ID
CfnOutput(self, "InstanceId", value=instance.instance_id)
CfnOutput(self, "InstanceIp", value=instance.instance_public_dns_name)
user_data = ec2.UserData.for_linux()
user_data.add_commands(
"#!/bin/bash",
"sudo apt update && sudo apt upgrade -y", # Update all packages
"sudo apt install git", # Install Git
"git clone <git_link>",
"cd /<folder_path>",
"sh startup_run.sh"
)
#Attach user data to instance instance.user_data.add_commands(str(user_data))
You don't say if you get any errors to the log, but adding the extra shebang is unnecessary.
for_linux
already automatically uses #!/bin/bash
as the shebang. See CDK sources. Shebang can also be customized if needed (see Documentation), but that's not really needed here either.
That being said, the shebang is not necessarily the biggest problem. Running as sudo on the other hand might be.
From Documentation
Scripts entered as user data are run as the root user, so do not use the sudo command in the script.
So you need to remove the sudo
instructions as unnecessary too.
Third problem is running apt install
without automatic accept with -y
.
This should work:
user_data = ec2.UserData.for_linux()
user_data.add_commands(
"apt update && apt upgrade -y", # Update all packages
"apt -y install git", # Install Git
"git clone <git_link>",
"cd /<folder_path>",
"sh startup_run.sh"
)