14 lines
12 KiB
YAML
14 lines
12 KiB
YAML
model: claude:claude-sonnet-4-5-20250929
|
|
messages:
|
|
- role: user
|
|
content: |-
|
|
I have an AWS EC2 instance with a web service. I wish to have an ALB communicate with this instance using TLS and a self-signed cert. Please write a cloud-init script which uses openssl to create this certificate and update permissions when the instance boots. Here's an example openssl invocation: `openssl req -x509 -newkey rsa:4096 -nodes -sha256 -keyout ec2.key -out ec2.crt -days 365 \
|
|
-subj "/C=US/ST=State/L=City/O=Org/CN=ec2-1-2-3-4.us-east-1.compute.amazonaws.com"
|
|
`
|
|
- role: assistant
|
|
content: "Here's a cloud-init script that generates a self-signed certificate with the correct hostname for your EC2 instance:\n\n```yaml\n#cloud-config\n\nwrite_files:\n - path: /usr/local/bin/generate-ssl-cert.sh\n permissions: '0755'\n content: |\n #!/bin/bash\n set -e\n \n # Get instance metadata\n TOKEN=$(curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\")\n INSTANCE_ID=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/instance-id)\n AVAILABILITY_ZONE=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/placement/availability-zone)\n REGION=$(echo $AVAILABILITY_ZONE | sed 's/[a-z]$//')\n PUBLIC_HOSTNAME=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-hostname)\n PRIVATE_IP=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/local-ipv4)\n \n # Certificate directory\n CERT_DIR=\"/etc/ssl/private\"\n mkdir -p $CERT_DIR\n \n # Generate certificate\n openssl req -x509 -newkey rsa:4096 -nodes -sha256 \\\n -keyout $CERT_DIR/ec2.key \\\n -out $CERT_DIR/ec2.crt \\\n -days 365 \\\n -subj \"/C=US/ST=State/L=City/O=MyOrg/CN=$PUBLIC_HOSTNAME\" \\\n -addext \"subjectAltName=DNS:$PUBLIC_HOSTNAME,DNS:$INSTANCE_ID,IP:$PRIVATE_IP\"\n \n # Set proper permissions\n chmod 600 $CERT_DIR/ec2.key\n chmod 644 $CERT_DIR/ec2.crt\n chown root:root $CERT_DIR/ec2.key $CERT_DIR/ec2.crt\n \n echo \"Certificate generated successfully:\"\n echo \" Certificate: $CERT_DIR/ec2.crt\"\n echo \" Private Key: $CERT_DIR/ec2.key\"\n echo \" Hostname: $PUBLIC_HOSTNAME\"\n\nruncmd:\n - /usr/local/bin/generate-ssl-cert.sh\n - systemctl restart your-web-service # Replace with your actual service name\n\n```\n\n**Key features:**\n\n1. **Automatic hostname detection** - Uses EC2 instance metadata to get the correct public hostname\n2. **Subject Alternative Names (SAN)** - Includes the public hostname, instance ID, and private IP for flexibility\n3. **Secure permissions** - Private key is readable only by root (600), certificate is world-readable (644)\n4. **Certificate location** - Stores certs in `/etc/ssl/private/`\n\n**To use this:**\n\n1. Replace `your-web-service` with your actual service name (e.g., `nginx`, `apache2`, `httpd`)\n2. Configure your web service to use:\n - Certificate: `/etc/ssl/private/ec2.crt`\n - Private Key: `/etc/ssl/private/ec2.key`\n\n**For ALB target group configuration:**\n\n- Set the protocol to **HTTPS**\n- Set the health check protocol to **HTTPS**\n- The ALB won't validate the self-signed certificate by default when connecting to targets, but ensure your application is listening on the correct port with TLS enabled\n\n**Optional: If you need to restart multiple services:**\n\n```yaml\nruncmd:\n - /usr/local/bin/generate-ssl-cert.sh\n - systemctl restart nginx\n - systemctl restart your-app\n```"
|
|
- role: user
|
|
content: I wish to use terraform to provision the EC2 instance. Please provide the TF to create the instance and incorporate the cloud-init script.`
|
|
- role: assistant
|
|
content: "Here's a complete Terraform configuration to provision the EC2 instance with the cloud-init script:\n\n```hcl\n# variables.tf\nvariable \"vpc_id\" {\n description = \"VPC ID where the instance will be launched\"\n type = string\n}\n\nvariable \"subnet_id\" {\n description = \"Subnet ID where the instance will be launched\"\n type = string\n}\n\nvariable \"instance_type\" {\n description = \"EC2 instance type\"\n type = string\n default = \"t3.small\"\n}\n\nvariable \"ami_id\" {\n description = \"AMI ID for the EC2 instance (leave empty for latest Amazon Linux 2023)\"\n type = string\n default = \"\"\n}\n\nvariable \"key_name\" {\n description = \"SSH key pair name\"\n type = string\n default = \"\"\n}\n\nvariable \"allowed_cidr_blocks\" {\n description = \"CIDR blocks allowed to access the instance\"\n type = list(string)\n default = [\"10.0.0.0/8\"] # Adjust for your VPC/ALB security group\n}\n\n# data.tf\ndata \"aws_ami\" \"amazon_linux_2023\" {\n most_recent = true\n owners = [\"amazon\"]\n\n filter {\n name = \"name\"\n values = [\"al2023-ami-*-x86_64\"]\n }\n\n filter {\n name = \"virtualization-type\"\n values = [\"hvm\"]\n }\n}\n\n# cloud-init.yaml (embedded as template)\nlocals {\n cloud_init = <<-EOF\n #cloud-config\n \n write_files:\n - path: /usr/local/bin/generate-ssl-cert.sh\n permissions: '0755'\n content: |\n #!/bin/bash\n set -e\n \n # Get instance metadata\n TOKEN=$(curl -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\")\n INSTANCE_ID=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/instance-id)\n AVAILABILITY_ZONE=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/placement/availability-zone)\n REGION=$(echo $AVAILABILITY_ZONE | sed 's/[a-z]$//')\n PUBLIC_HOSTNAME=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/public-hostname)\n PRIVATE_IP=$(curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/local-ipv4)\n \n # Certificate directory\n CERT_DIR=\"/etc/ssl/private\"\n mkdir -p $CERT_DIR\n \n # Generate certificate\n openssl req -x509 -newkey rsa:4096 -nodes -sha256 \\\n -keyout $CERT_DIR/ec2.key \\\n -out $CERT_DIR/ec2.crt \\\n -days 365 \\\n -subj \"/C=US/ST=State/L=City/O=MyOrg/CN=$PUBLIC_HOSTNAME\" \\\n -addext \"subjectAltName=DNS:$PUBLIC_HOSTNAME,DNS:$INSTANCE_ID,IP:$PRIVATE_IP\"\n \n # Set proper permissions\n chmod 600 $CERT_DIR/ec2.key\n chmod 644 $CERT_DIR/ec2.crt\n chown root:root $CERT_DIR/ec2.key $CERT_DIR/ec2.crt\n \n echo \"Certificate generated successfully:\"\n echo \" Certificate: $CERT_DIR/ec2.crt\"\n echo \" Private Key: $CERT_DIR/ec2.key\"\n echo \" Hostname: $PUBLIC_HOSTNAME\"\n \n # Log output\n echo \"Certificate generation completed at $(date)\" >> /var/log/ssl-cert-generation.log\n \n runcmd:\n - /usr/local/bin/generate-ssl-cert.sh\n # - systemctl restart your-web-service # Uncomment and replace with your service name\n \n output:\n all: '| tee -a /var/log/cloud-init-output.log'\n EOF\n}\n\n# security_group.tf\nresource \"aws_security_group\" \"web_server\" {\n name_description = \"Security group for web server with TLS\"\n description = \"Allow HTTPS traffic from ALB\"\n vpc_id = var.vpc_id\n\n ingress {\n description = \"HTTPS from ALB\"\n from_port = 443\n to_port = 443\n protocol = \"tcp\"\n cidr_blocks = var.allowed_cidr_blocks\n }\n\n ingress {\n description = \"HTTP from ALB (optional)\"\n from_port = 80\n to_port = 80\n protocol = \"tcp\"\n cidr_blocks = var.allowed_cidr_blocks\n }\n\n ingress {\n description = \"SSH access (optional)\"\n from_port = 22\n to_port = 22\n protocol = \"tcp\"\n cidr_blocks = var.allowed_cidr_blocks\n }\n\n egress {\n description = \"Allow all outbound traffic\"\n from_port = 0\n to_port = 0\n protocol = \"-1\"\n cidr_blocks = [\"0.0.0.0/0\"]\n }\n\n tags = {\n Name = \"web-server-sg\"\n }\n}\n\n# iam.tf\nresource \"aws_iam_role\" \"ec2_role\" {\n name = \"ec2-web-server-role\"\n\n assume_role_policy = jsonencode({\n Version = \"2012-10-17\"\n Statement = [\n {\n Action = \"sts:AssumeRole\"\n Effect = \"Allow\"\n Principal = {\n Service = \"ec2.amazonaws.com\"\n }\n }\n ]\n })\n\n tags = {\n Name = \"ec2-web-server-role\"\n }\n}\n\nresource \"aws_iam_role_policy_attachment\" \"ssm_policy\" {\n role = aws_iam_role.ec2_role.name\n policy_arn = \"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\"\n}\n\nresource \"aws_iam_instance_profile\" \"ec2_profile\" {\n name = \"ec2-web-server-profile\"\n role = aws_iam_role.ec2_role.name\n}\n\n# main.tf\nresource \"aws_instance\" \"web_server\" {\n ami = var.ami_id != \"\" ? var.ami_id : data.aws_ami.amazon_linux_2023.id\n instance_type = var.instance_type\n subnet_id = var.subnet_id\n vpc_security_group_ids = [aws_security_group.web_server.id]\n iam_instance_profile = aws_iam_instance_profile.ec2_profile.name\n key_name = var.key_name != \"\" ? var.key_name : null\n\n user_data = local.cloud_init\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\" # IMDSv2\n http_put_response_hop_limit = 1\n }\n\n root_block_device {\n volume_type = \"gp3\"\n volume_size = 20\n delete_on_termination = true\n encrypted = true\n }\n\n tags = {\n Name = \"web-server-with-tls\"\n }\n\n lifecycle {\n create_before_destroy = true\n }\n}\n\n# outputs.tf\noutput \"instance_id\" {\n description = \"EC2 instance ID\"\n value = aws_instance.web_server.id\n}\n\noutput \"private_ip\" {\n description = \"Private IP address\"\n value = aws_instance.web_server.private_ip\n}\n\noutput \"public_ip\" {\n description = \"Public IP address\"\n value = aws_instance.web_server.public_ip\n}\n\noutput \"public_dns\" {\n description = \"Public DNS name\"\n value = aws_instance.web_server.public_dns\n}\n\noutput \"security_group_id\" {\n description = \"Security group ID\"\n value = aws_security_group.web_server.id\n}\n\noutput \"certificate_location\" {\n description = \"Location of the generated certificate\"\n value = \"/etc/ssl/private/ec2.crt\"\n}\n\noutput \"private_key_location\" {\n description = \"Location of the generated private key\"\n value = \"/etc/ssl/private/ec2.key\"\n}\n```\n\n**terraform.tfvars example:**\n\n```hcl\nvpc_id = \"vpc-xxxxx\"\nsubnet_id = \"subnet-xxxxx\"\ninstance_type = \"t3.small\"\nkey_name = \"my-key-pair\" # Optional\nallowed_cidr_blocks = [\"10.0.0.0/16\"] # Your VPC CIDR or ALB security group\n```\n\n**Usage:**\n\n```bash\n# Initialize Terraform\nterraform init\n\n# Plan the deployment\nterraform plan\n\n# Apply the configuration\nterraform apply\n\n# Get outputs\nterraform output\n```\n\n**To verify the certificate was generated:**\n\n```bash\n# SSH into the instance\nssh -i your-key.pem ec2-user@<instance-public-ip>\n\n# Check certificate\nsudo ls -la /etc/ssl/private/\nsudo openssl x509 -in /etc/ssl/private/ec2.crt -text -noout\n\n# Check cloud-init logs\nsudo cat /var/log/cloud-init-output.log\nsudo cat /var/log/ssl-cert-generation.log\n```\n\n**Key features:**\n\n- Uses IMDSv2 for enhanced security\n- Includes IAM role for SSM access (optional SSH-less access)\n- Encrypted root volume\n- Outputs all necessary information\n- Security group configured for ALB communication\n- Automatic AMI selection (latest Amazon Linux 2023)\n\n**Next steps:** Configure your ALB target group to point to this instance on port 443 (HTTPS)."
|