AWS ec2 documentation change
Summary
Added multiple security improvements to an ECS Fargate example script including input validation, secure variable quoting, JSON validation, secure file deletion, and security group/VPC ID format validation
Security assessment
The changes add security best practices to an example script but don't address a specific security vulnerability or incident. Changes include: 1) Input validation for commands, security group IDs, VPC IDs, ENI IDs, and IP addresses; 2) Secure file deletion using shred; 3) JSON validation before use; 4) Variable quoting to prevent injection; 5) More specific container image tag (2.4-alpine vs latest). These are preventive security measures rather than fixes for existing issues.
Diff
diff --git a/ec2/latest/devguide/example_ecs_GettingStarted_086_section.md b/ec2/latest/devguide/example_ecs_GettingStarted_086_section.md index efb6b9ba8..7205043c1 100644 --- a//ec2/latest/devguide/example_ecs_GettingStarted_086_section.md +++ b//ec2/latest/devguide/example_ecs_GettingStarted_086_section.md @@ -37,0 +38 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Security improvements applied @@ -58 +59 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Function to log and execute commands + # Function to log and execute commands with input validation @@ -61,0 +63,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + + # Validate that cmd is not empty + if [[ -z "$cmd" ]]; then + echo "ERROR: Command is empty" + return 1 + fi + @@ -100,0 +109,10 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Function to safely extract JSON values + safe_json_extract() { + local json="$1" + local key="$2" + local value + + value=$(echo "$json" | grep -o "\"$key\": \"[^\"]*\"" | cut -d'"' -f4 2>/dev/null || echo "") + echo "$value" + } + @@ -106,0 +125,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate security group ID format + if [[ ! "$security_group_id" =~ ^sg-[a-z0-9]{8,17}$ ]]; then + echo "ERROR: Invalid security group ID format: $security_group_id" + return 1 + fi + @@ -141,0 +166,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate security group ID format + if [[ ! "$security_group_id" =~ ^sg-[a-z0-9]{8,17}$ ]]; then + echo "ERROR: Invalid security group ID format: $security_group_id" + return 1 + fi + @@ -145 +175 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - if execute_command "aws ec2 delete-security-group --group-id $security_group_id" "Delete security group (attempt $attempt)"; then + if execute_command "aws ec2 delete-security-group --group-id '$security_group_id'" "Delete security group (attempt $attempt)"; then @@ -175,2 +205,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - echo "Do you want to clean up all created resources? (y/n): " - read -r CLEANUP_CHOICE + echo "Auto-confirming cleanup of all created resources..." + + CLEANUP_CHOICE="y" @@ -185 +216 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - if execute_command "aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --desired-count 0" "Scale service to 0 tasks"; then + if execute_command "aws ecs update-service --cluster '$CLUSTER_NAME' --service '$SERVICE_NAME' --desired-count 0" "Scale service to 0 tasks"; then @@ -187 +218 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs wait services-stable --cluster $CLUSTER_NAME --services $SERVICE_NAME" "Wait for service to stabilize" + execute_command "aws ecs wait services-stable --cluster '$CLUSTER_NAME' --services '$SERVICE_NAME'" "Wait for service to stabilize" @@ -190 +221 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs delete-service --cluster $CLUSTER_NAME --service $SERVICE_NAME" "Delete ECS service" + execute_command "aws ecs delete-service --cluster '$CLUSTER_NAME' --service '$SERVICE_NAME'" "Delete ECS service" @@ -193 +224 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs delete-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --force" "Force delete ECS service" + execute_command "aws ecs delete-service --cluster '$CLUSTER_NAME' --service '$SERVICE_NAME' --force" "Force delete ECS service" @@ -206 +237 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs delete-cluster --cluster $CLUSTER_NAME" "Delete ECS cluster" + execute_command "aws ecs delete-cluster --cluster '$CLUSTER_NAME'" "Delete ECS cluster" @@ -210 +241 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - if [[ -n "$SECURITY_GROUP_ID" ]]; then + if [[ -n "$SECURITY_GROUP_ID" && "$SECURITY_GROUP_ID" != "None" ]]; then @@ -233 +264 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs deregister-task-definition --task-definition $revision_arn" "Deregister task definition $revision_arn" || true + execute_command "aws ecs deregister-task-definition --task-definition '$revision_arn'" "Deregister task definition $revision_arn" || true @@ -276,0 +308,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + if [[ ! "$ACCOUNT_ID" =~ ^[0-9]{12}$ ]]; then + echo "ERROR: Invalid AWS Account ID retrieved: $ACCOUNT_ID" + exit 1 + fi + @@ -285 +321 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create trust policy + # Create trust policy with strict validation @@ -300,0 +337,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate JSON before using + if ! jq empty trust-policy.json 2>/dev/null; then + echo "ERROR: Invalid JSON in trust policy" + rm -f trust-policy.json + exit 1 + fi + @@ -305,2 +348,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Clean up temporary file - rm -f trust-policy.json + # Clean up temporary file securely + shred -vfz -n 3 trust-policy.json 2>/dev/null || rm -f trust-policy.json @@ -317 +360 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - CLUSTER_OUTPUT=$(execute_command "aws ecs create-cluster --cluster-name $CLUSTER_NAME" "Create ECS cluster") + CLUSTER_OUTPUT=$(execute_command "aws ecs create-cluster --cluster-name '$CLUSTER_NAME'" "Create ECS cluster") @@ -328 +371 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create task definition JSON + # Create task definition JSON with validated inputs @@ -340 +383 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - "image": "public.ecr.aws/docker/library/httpd:latest", + "image": "public.ecr.aws/docker/library/httpd:2.4-alpine", @@ -352 +395,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - ] + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": "/ecs/fargate-sample", + "awslogs-region": "us-east-1", + "awslogs-stream-prefix": "ecs" + } + } @@ -357,0 +409,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate JSON before using + if ! jq empty task-definition.json 2>/dev/null; then + echo "ERROR: Invalid JSON in task definition" + rm -f task-definition.json + exit 1 + fi + @@ -361,2 +419,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Clean up temporary file - rm -f task-definition.json + # Clean up temporary file securely + shred -vfz -n 3 task-definition.json 2>/dev/null || rm -f task-definition.json @@ -377,0 +436,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + + # Validate VPC ID format + if [[ ! "$VPC_ID" =~ ^vpc-[a-z0-9]{8,17}$ ]]; then + echo "ERROR: Invalid VPC ID format: $VPC_ID" + exit 1 + fi + @@ -383 +448 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - SECURITY_GROUP_OUTPUT=$(execute_command "aws ec2 create-security-group --group-name $SECURITY_GROUP_NAME --description 'Security group for ECS Fargate tutorial - HTTP access' --vpc-id $VPC_ID" "Create security group") + SECURITY_GROUP_OUTPUT=$(execute_command "aws ec2 create-security-group --group-name '$SECURITY_GROUP_NAME' --description 'Security group for ECS Fargate tutorial - HTTP access' --vpc-id '$VPC_ID'" "Create security group") @@ -386,3 +451,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - SECURITY_GROUP_ID=$(echo "$SECURITY_GROUP_OUTPUT" | grep -o '"GroupId": "[^"]*"' | cut -d'"' -f4) - if [[ -z "$SECURITY_GROUP_ID" ]]; then - SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --group-names "$SECURITY_GROUP_NAME" --query "SecurityGroups[0].GroupId" --output text) + SECURITY_GROUP_ID=$(echo "$SECURITY_GROUP_OUTPUT" | grep -o '"GroupId": "[^"]*"' | head -1 | cut -d'"' -f4) + if [[ -z "$SECURITY_GROUP_ID" || "$SECURITY_GROUP_ID" == "None" ]]; then + SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --group-names "$SECURITY_GROUP_NAME" --filters "Name=vpc-id,Values=$VPC_ID" --query "SecurityGroups[0].GroupId" --output text) + fi + + # Validate security group ID format + if [[ ! "$SECURITY_GROUP_ID" =~ ^sg-[a-z0-9]{8,17}$ ]]; then + echo "ERROR: Invalid security group ID format: $SECURITY_GROUP_ID" + exit 1 @@ -397 +468 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ec2 authorize-security-group-ingress --group-id $SECURITY_GROUP_ID --protocol tcp --port 80 --cidr 0.0.0.0/0" "Add HTTP inbound rule to security group" + execute_command "aws ec2 authorize-security-group-ingress --group-id '$SECURITY_GROUP_ID' --protocol tcp --port 80 --cidr 0.0.0.0/0" "Add HTTP inbound rule to security group" @@ -425 +496 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - SERVICE_CMD="aws ecs create-service --cluster $CLUSTER_NAME --service-name $SERVICE_NAME --task-definition $TASK_FAMILY --desired-count 1 --launch-type FARGATE --network-configuration '{\"awsvpcConfiguration\":{\"subnets\":[\"$(echo $SUBNET_IDS_COMMA | sed 's/,/","/g')\"],\"securityGroups\":[\"$SECURITY_GROUP_ID\"],\"assignPublicIp\":\"ENABLED\"}}'" + SERVICE_CMD="aws ecs create-service --cluster '$CLUSTER_NAME' --service-name '$SERVICE_NAME' --task-definition '$TASK_FAMILY' --desired-count 1 --launch-type FARGATE --network-configuration '{\"awsvpcConfiguration\":{\"subnets\":[\"$(echo "$SUBNET_IDS_COMMA" | sed 's/,/","/g')\"],\"securityGroups\":[\"$SECURITY_GROUP_ID\"],\"assignPublicIp\":\"ENABLED\"}}'" @@ -441 +512 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs wait services-stable --cluster $CLUSTER_NAME --services $SERVICE_NAME" "Wait for service to stabilize" + execute_command "aws ecs wait services-stable --cluster '$CLUSTER_NAME' --services '$SERVICE_NAME'" "Wait for service to stabilize" @@ -444 +515 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - TASK_ARN=$(aws ecs list-tasks --cluster $CLUSTER_NAME --service-name $SERVICE_NAME --query "taskArns[0]" --output text) + TASK_ARN=$(aws ecs list-tasks --cluster "$CLUSTER_NAME" --service-name "$SERVICE_NAME" --query "taskArns[0]" --output text) @@ -453 +524 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - ENI_ID=$(aws ecs describe-tasks --cluster $CLUSTER_NAME --tasks $TASK_ARN --query "tasks[0].attachments[0].details[?name=='networkInterfaceId'].value" --output text) + ENI_ID=$(aws ecs describe-tasks --cluster "$CLUSTER_NAME" --tasks "$TASK_ARN" --query "tasks[0].attachments[0].details[?name=='networkInterfaceId'].value" --output text) @@ -458,0 +530,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate ENI ID format + if [[ ! "$ENI_ID" =~ ^eni-[a-z0-9]{8,17}$ ]]; then + echo "ERROR: Invalid network interface ID format: $ENI_ID" + exit 1 + fi + @@ -462 +539 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - PUBLIC_IP=$(aws ec2 describe-network-interfaces --network-interface-ids $ENI_ID --query "NetworkInterfaces[0].Association.PublicIp" --output text) + PUBLIC_IP=$(aws ec2 describe-network-interfaces --network-interface-ids "$ENI_ID" --query "NetworkInterfaces[0].Association.PublicIp" --output text) @@ -465,0 +543,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + else + # Validate IP format + if [[ ! "$PUBLIC_IP" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + echo "ERROR: Invalid IP address format: $PUBLIC_IP" + PUBLIC_IP="" @@ -474,0 +557 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + fi @@ -481 +564 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - execute_command "aws ecs describe-services --cluster $CLUSTER_NAME --services $SERVICE_NAME" "Get service details" + execute_command "aws ecs describe-services --cluster '$CLUSTER_NAME' --services '$SERVICE_NAME'" "Get service details"