$npx -y skills add BagelHole/DevOps-Security-Agent-Skills --skill aws-ec2Manage EC2 instances, AMIs, and auto-scaling groups. Configure security groups, key pairs, and instance types. Use when deploying compute resources on AWS.
| 1 | # AWS EC2 |
| 2 | |
| 3 | Deploy and manage Amazon EC2 compute instances for production, staging, and development workloads. |
| 4 | |
| 5 | ## When to Use This Skill |
| 6 | |
| 7 | - Launching new compute instances for application hosting |
| 8 | - Building golden AMIs for consistent deployments |
| 9 | - Setting up auto-scaling groups behind load balancers |
| 10 | - Migrating workloads to Spot instances for cost savings |
| 11 | - Troubleshooting instance connectivity, performance, or launch failures |
| 12 | - Creating launch templates for repeatable infrastructure |
| 13 | |
| 14 | ## Prerequisites |
| 15 | |
| 16 | - AWS CLI v2 installed and configured (`aws configure`) |
| 17 | - IAM permissions: `ec2:*`, `autoscaling:*`, `elasticloadbalancing:*`, `iam:PassRole` |
| 18 | - An existing VPC with subnets (see [aws-vpc](../aws-vpc/)) |
| 19 | - SSH key pair created (`aws ec2 create-key-pair --key-name my-key --query 'KeyMaterial' --output text > my-key.pem`) |
| 20 | |
| 21 | ## Instance Type Selection Guide |
| 22 | |
| 23 | | Category | Types | Use Case | |
| 24 | |---|---|---| |
| 25 | | General Purpose | t3, t3a, m6i, m7g | Web servers, small databases, dev/test | |
| 26 | | Compute Optimized | c6i, c7g | Batch processing, media encoding, ML inference | |
| 27 | | Memory Optimized | r6i, r7g, x2idn | In-memory caches, large databases | |
| 28 | | Storage Optimized | i3, i4i, d3 | Data warehousing, distributed file systems | |
| 29 | | Accelerated | p4d, g5, inf2 | ML training, GPU rendering, inference | |
| 30 | | Burstable | t3.micro-t3.2xlarge | Low-steady-state with occasional bursts | |
| 31 | |
| 32 | ## Launch an Instance |
| 33 | |
| 34 | ```bash |
| 35 | # Launch a production web server |
| 36 | aws ec2 run-instances \ |
| 37 | --image-id ami-0abcdef1234567890 \ |
| 38 | --instance-type t3.medium \ |
| 39 | --key-name my-key \ |
| 40 | --security-group-ids sg-12345678 \ |
| 41 | --subnet-id subnet-12345678 \ |
| 42 | --iam-instance-profile Name=EC2AppProfile \ |
| 43 | --metadata-options "HttpTokens=required,HttpEndpoint=enabled" \ |
| 44 | --block-device-mappings '[{ |
| 45 | "DeviceName": "/dev/xvda", |
| 46 | "Ebs": { |
| 47 | "VolumeSize": 30, |
| 48 | "VolumeType": "gp3", |
| 49 | "Iops": 3000, |
| 50 | "Throughput": 125, |
| 51 | "Encrypted": true |
| 52 | } |
| 53 | }]' \ |
| 54 | --tag-specifications 'ResourceType=instance,Tags=[ |
| 55 | {Key=Name,Value=web-server-01}, |
| 56 | {Key=Environment,Value=production}, |
| 57 | {Key=Team,Value=platform} |
| 58 | ]' \ |
| 59 | --user-data file://userdata.sh |
| 60 | |
| 61 | # Launch with IMDSv2 required (security best practice) |
| 62 | aws ec2 run-instances \ |
| 63 | --image-id ami-0abcdef1234567890 \ |
| 64 | --instance-type t3.micro \ |
| 65 | --metadata-options "HttpTokens=required,HttpPutResponseHopLimit=1,HttpEndpoint=enabled" \ |
| 66 | --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=secure-instance}]' |
| 67 | ``` |
| 68 | |
| 69 | ## User Data Scripts |
| 70 | |
| 71 | ```bash |
| 72 | #!/bin/bash |
| 73 | # userdata.sh - Bootstrap a web server on Amazon Linux 2023 |
| 74 | set -euxo pipefail |
| 75 | |
| 76 | # System updates |
| 77 | dnf update -y |
| 78 | |
| 79 | # Install and start web server |
| 80 | dnf install -y nginx |
| 81 | systemctl enable nginx |
| 82 | systemctl start nginx |
| 83 | |
| 84 | # Install CloudWatch agent |
| 85 | dnf install -y amazon-cloudwatch-agent |
| 86 | /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \ |
| 87 | -a fetch-config -m ec2 \ |
| 88 | -s -c ssm:AmazonCloudWatch-linux |
| 89 | |
| 90 | # Install CodeDeploy agent |
| 91 | dnf install -y ruby wget |
| 92 | cd /home/ec2-user |
| 93 | wget https://aws-codedeploy-us-east-1.s3.us-east-1.amazonaws.com/latest/install |
| 94 | chmod +x ./install |
| 95 | ./install auto |
| 96 | |
| 97 | # Signal CloudFormation (if launched via CFN) |
| 98 | # /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ASG --region ${AWS::Region} |
| 99 | ``` |
| 100 | |
| 101 | ## Launch Templates |
| 102 | |
| 103 | ```bash |
| 104 | # Create a launch template with full configuration |
| 105 | aws ec2 create-launch-template \ |
| 106 | --launch-template-name web-server-template \ |
| 107 | --version-description "v1 - AL2023 with nginx" \ |
| 108 | --launch-template-data '{ |
| 109 | "ImageId": "ami-0abcdef1234567890", |
| 110 | "InstanceType": "t3.medium", |
| 111 | "KeyName": "my-key", |
| 112 | "SecurityGroupIds": ["sg-12345678"], |
| 113 | "IamInstanceProfile": {"Name": "EC2AppProfile"}, |
| 114 | "MetadataOptions": { |
| 115 | "HttpTokens": "required", |
| 116 | "HttpEndpoint": "enabled" |
| 117 | }, |
| 118 | "BlockDeviceMappings": [{ |
| 119 | "DeviceName": "/dev/xvda", |
| 120 | "Ebs": { |
| 121 | "VolumeSize": 30, |
| 122 | "VolumeType": "gp3", |
| 123 | "Encrypted": true |
| 124 | } |
| 125 | }], |
| 126 | "TagSpecifications": [{ |
| 127 | "ResourceType": "instance", |
| 128 | "Tags": [ |
| 129 | {"Key": "Environment", "Value": "production"}, |
| 130 | {"Key": "ManagedBy", "Value": "launch-template"} |
| 131 | ] |
| 132 | }], |
| 133 | "Monitoring": {"Enabled": true}, |
| 134 | "UserData": "'"$(base64 -w0 userdata.sh)"'" |
| 135 | }' |
| 136 | |
| 137 | # Create a new version of the launch template |
| 138 | aws ec2 create-launch-template-version \ |
| 139 | --launch-template-name web-server-template \ |
| 140 | --source-version 1 \ |
| 141 | --version-description "v2 - updated AMI" \ |
| 142 | --launch-template-data '{"ImageId": "ami-0newami1234567890"}' |
| 143 | |
| 144 | # Set the default version |
| 145 | aws ec2 modify-launch-template \ |
| 146 | --launch-template-name web-server-template \ |
| 147 | --default-version 2 |
| 148 | ``` |
| 149 | |
| 150 | ## Auto Scaling Group |
| 151 | |
| 152 | ```bash |
| 153 | # Create ASG with mixed instances (on-demand + spot) |
| 154 | aws au |