Ctrl K
ComunidadGuías…

AWS_DEPLOYMENT.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# AWS Deployment Guide

This guide provides step-by-step instructions for deploying sup3rS3cretMes5age on AWS using various services. The application consists of two main components:
- The sup3rS3cretMes5age web application
- A HashiCorp Vault server for secure secret storage

## Table of Contents

1. [Prerequisites](#prerequisites)
2. [Option 1: ECS with Fargate (Recommended)](#option-1-ecs-with-fargate-recommended)
3. [Option 2: EKS (Kubernetes)](#option-2-eks-kubernetes)
4. [Option 3: EC2 with Docker](#option-3-ec2-with-docker)
5. [Security Considerations](#security-considerations)
6. [Cost Optimization](#cost-optimization)
7. [Troubleshooting](#troubleshooting)

## Prerequisites

Before starting, ensure you have:

1. **AWS CLI** installed and configured with appropriate permissions
2. **Docker** installed for building and testing images locally
3. **Domain name** (recommended for HTTPS with Let's Encrypt)
4. **AWS Account** with the following IAM permissions:
   - ECS full access
   - ECR full access
   - Application Load Balancer management
   - VPC management
   - IAM role creation
   - Route 53 (if using custom domain)

## Option 1: ECS with Fargate (Recommended)

This option uses AWS ECS with Fargate for a serverless container deployment, which is cost-effective and easy to manage.

### Step 1: Set up ECR Repository

First, create a private ECR repository to store your Docker images:

```bash
# Set your AWS region
export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# Create ECR repositories
aws ecr create-repository \
    --repository-name sup3rs3cretmes5age \
    --region $AWS_REGION

aws ecr create-repository \
    --repository-name vault \
    --region $AWS_REGION

# Get login token for ECR
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
```

### Step 2: Build and Push Docker Images

Build and push the application image to ECR:

```bash
# Clone and build the application
git clone https://github.com/algolia/sup3rS3cretMes5age.git
cd sup3rS3cretMes5age

# Build the application image (with network=host to handle certificate issues)
docker build --network=host -f deploy/Dockerfile -t sup3rs3cretmes5age .

# Tag for ECR
docker tag sup3rs3cretmes5age:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/sup3rs3cretmes5age:latest

# Push to ECR
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/sup3rs3cretmes5age:latest

# Pull and push Vault image to your ECR
docker pull hashicorp/vault:latest
docker tag hashicorp/vault:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/vault:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/vault:latest
```

### Step 3: Create VPC and Security Groups

Create a VPC with public and private subnets:

```bash
# Create VPC
export VPC_ID=$(aws ec2 create-vpc \
    --cidr-block 10.0.0.0/16 \
    --query 'Vpc.VpcId' \
    --output text)

aws ec2 create-tags \
    --resources $VPC_ID \
    --tags Key=Name,Value=sup3rs3cretmes5age-vpc

# Create Internet Gateway
export IGW_ID=$(aws ec2 create-internet-gateway \
    --query 'InternetGateway.InternetGatewayId' \
    --output text)

aws ec2 attach-internet-gateway \
    --vpc-id $VPC_ID \
    --internet-gateway-id $IGW_ID

# Create public subnets in two AZs
export PUBLIC_SUBNET_1=$(aws ec2 create-subnet \
    --vpc-id $VPC_ID \
    --cidr-block 10.0.1.0/24 \
    --availability-zone ${AWS_REGION}a \
    --query 'Subnet.SubnetId' \
    --output text)

export PUBLIC_SUBNET_2=$(aws ec2 create-subnet \
    --vpc-id $VPC_ID \
    --cidr-block 10.0.2.0/24 \
    --availability-zone ${AWS_REGION}b \
    --query 'Subnet.SubnetId' \
    --output text)

# Create private subnets
export PRIVATE_SUBNET_1=$(aws ec2 create-subnet \
    --vpc-id $VPC_ID \
    --cidr-block 10.0.3.0/24 \
    --availability-zone ${AWS_REGION}a \
    --query 'Subnet.SubnetId' \
    --output text)

export PRIVATE_SUBNET_2=$(aws ec2 create-subnet \
    --vpc-id $VPC_ID \
    --cidr-block 10.0.4.0/24 \
    --availability-zone ${AWS_REGION}b \
    --query 'Subnet.SubnetId' \
    --output text)

# Create route table for public subnets
export PUBLIC_RT=$(aws ec2 create-route-table \
    --vpc-id $VPC_ID \
    --query 'RouteTable.RouteTableId' \
    --output text)

aws ec2 create-route \
    --route-table-id $PUBLIC_RT \
    --destination-cidr-block 0.0.0.0/0 \
    --gateway-id $IGW_ID

# Associate public subnets with route table
aws ec2 associate-route-table --subnet-id $PUBLIC_SUBNET_1 --route-table-id $PUBLIC_RT
aws ec2 associate-route-table --subnet-id $PUBLIC_SUBNET_2 --route-table-id $PUBLIC_RT

# Enable auto-assign public IPs for public subnets
aws ec2 modify-subnet-attribute --subnet-id $PUBLIC_SUBNET_1 --map-public-ip-on-launch
aws ec2 modify-subnet-attribute --subnet-id $PUBLIC_SUBNET_2 --map-public-ip-on-launch
```

Create security groups:

```bash
# Security group for Application Load Balancer
export ALB_SG=$(aws ec2 create-security-group \
    --group-name sup3rs3cretmes5age-alb-sg \
    --description "Security group for sup3rs3cretmes5age ALB" \
    --vpc-id $VPC_ID \
    --query 'GroupId' \
    --output text)

# Allow HTTP and HTTPS traffic to ALB
aws ec2 authorize-security-group-ingress \
    --group-id $ALB_SG \
    --protocol tcp \
    --port 80 \
    --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress \
    --group-id $ALB_SG \
    --protocol tcp \
    --port 443 \
    --cidr 0.0.0.0/0

# Security group for ECS tasks
export ECS_SG=$(aws ec2 create-security-group \
    --group-name sup3rs3cretmes5age-ecs-sg \
    --description "Security group for sup3rs3cretmes5age ECS tasks" \
    --vpc-id $VPC_ID \
    --query 'GroupId' \
    --output text)

# Allow traffic from ALB to ECS tasks
aws ec2 authorize-security-group-ingress \
    --group-id $ECS_SG \
    --protocol tcp \
    --port 80 \
    --source-group $ALB_SG

# Allow Vault communication between tasks
aws ec2 authorize-security-group-ingress \
    --group-id $ECS_SG \
    --protocol tcp \
    --port 8200 \
    --source-group $ECS_SG
```

### Step 4: Create Application Load Balancer

```bash
# Create Application Load Balancer
export ALB_ARN=$(aws elbv2 create-load-balancer \
    --name sup3rs3cretmes5age-alb \
    --subnets $PUBLIC_SUBNET_1 $PUBLIC_SUBNET_2 \
    --security-groups $ALB_SG \
    --query 'LoadBalancers[0].LoadBalancerArn' \
    --output text)

# Get ALB DNS name
export ALB_DNS=$(aws elbv2 describe-load-balancers \
    --load-balancer-arns $ALB_ARN \
    --query 'LoadBalancers[0].DNSName' \
    --output text)

echo "ALB DNS Name: $ALB_DNS"

# Create target group
export TARGET_GROUP_ARN=$(aws elbv2 create-target-group \
    --name sup3rs3cretmes5age-tg \
    --protocol HTTP \
    --port 80 \
    --vpc-id $VPC_ID \
    --target-type ip \
    --health-check-path / \
    --health-check-interval-seconds 30 \
    --health-check-timeout-seconds 5 \
    --healthy-threshold-count 2 \
    --unhealthy-threshold-count 3 \
    --query 'TargetGroups[0].TargetGroupArn' \
    --output text)

# Create listener
aws elbv2 create-listener \
    --load-balancer-arn $ALB_ARN \
    --protocol HTTP \
    --port 80 \
    --default-actions Type=forward,TargetGroupArn=$TARGET_GROUP_ARN
```

### Step 5: Set up ECS Cluster and Task Definitions

Create ECS cluster:

```bash
# Create ECS cluster
aws ecs create-cluster --cluster-name sup3rs3cretmes5age-cluster
```

Create IAM roles for ECS:

```bash
# Create ECS task execution role
cat > ecs-task-execution-role-trust-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
    --role-name ecsTaskExecutionRole \
    --assume-role-policy-document file://ecs-task-execution-role-trust-policy.json

aws iam attach-role-policy \
    --role-name ecsTaskExecutionRole \
    --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

# Get the role ARN
export TASK_EXECUTION_ROLE_ARN=$(aws iam get-role \
    --role-name ecsTaskExecutionRole \
    --query 'Role.Arn' \
    --output text)
```

Create task definition:

```bash
cat > task-definition.json << EOF
{
  "family": "sup3rs3cretmes5age",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "$TASK_EXECUTION_ROLE_ARN",
  "containerDefinitions": [
    {
      "name": "vault",
      "image": "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/vault:latest",
      "essential": true,
      "environment": [
        {
          "name": "VAULT_DEV_ROOT_TOKEN_ID",
          "value": "supersecret"
        }
      ],
      "portMappings": [
        {
          "containerPort": 8200,
          "protocol": "tcp"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/sup3rs3cretmes5age",
          "awslogs-region": "$AWS_REGION",
          "awslogs-stream-prefix": "vault"
        }
      },
      "linuxParameters": {
        "capabilities": {
          "add": ["IPC_LOCK"]
        }
      }
    },
    {
      "name": "supersecret",
      "image": "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/sup3rs3cretmes5age:latest",
      "essential": true,
      "dependsOn": [
        {
          "containerName": "vault",
          "condition": "START"
        }
      ],
      "environment": [
        {
          "name": "VAULT_ADDR",
          "value": "http://localhost:8200"
        },
        {
          "name": "VAULT_TOKEN",
          "value": "supersecret"
        },
        {
          "name": "SUPERSECRETMESSAGE_HTTP_BINDING_ADDRESS",
          "value": ":80"
        }
      ],
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/sup3rs3cretmes5age",
          "awslogs-region": "$AWS_REGION",
          "awslogs-stream-prefix": "supersecret"
        }
      }
    }
  ]
}
EOF

# Create CloudWatch log group
aws logs create-log-group --log-group-name /ecs/sup3rs3cretmes5age

# Register task definition
aws ecs register-task-definition --cli-input-json file://task-definition.json
```

### Step 6: Create ECS Service

```bash
# Create ECS service
cat > service-definition.json << EOF
{
  "serviceName": "sup3rs3cretmes5age-service",
  "cluster": "sup3rs3cretmes5age-cluster",
  "taskDefinition": "sup3rs3cretmes5age",
  "desiredCount": 1,
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "subnets": ["$PRIVATE_SUBNET_1", "$PRIVATE_SUBNET_2"],
      "securityGroups": ["$ECS_SG"],
      "assignPublicIp": "DISABLED"
    }
  },
  "loadBalancers": [
    {
      "targetGroupArn": "$TARGET_GROUP_ARN",
      "containerName": "supersecret",
      "containerPort": 80
    }
  ]
}
EOF

aws ecs create-service --cli-input-json file://service-definition.json
```

### Step 7: Configure Domain and HTTPS (Optional but Recommended)

If you have a domain name, you can configure HTTPS:

```bash
# Request SSL certificate (replace with your domain)
export DOMAIN_NAME="secrets.yourdomain.com"

export CERT_ARN=$(aws acm request-certificate \
    --domain-name $DOMAIN_NAME \
    --validation-method DNS \
    --query 'CertificateArn' \
    --output text)

echo "Certificate ARN: $CERT_ARN"
echo "Complete DNS validation in ACM console, then continue..."

# After DNS validation is complete, create HTTPS listener
aws elbv2 create-listener \
    --load-balancer-arn $ALB_ARN \
    --protocol HTTPS \
    --port 443 \
    --certificates CertificateArn=$CERT_ARN \
    --default-actions Type=forward,TargetGroupArn=$TARGET_GROUP_ARN

# Create Route 53 record (if using Route 53)
# You'll need to create this manually or use your DNS provider
```

## Option 2: EKS (Kubernetes)

For teams already using Kubernetes, you can deploy using the provided Helm chart on Amazon EKS.

### Prerequisites for EKS Deployment

```bash
# Install required tools
# - kubectl
# - helm
# - eksctl (recommended for cluster creation)

# Create EKS cluster
eksctl create cluster \
    --name sup3rs3cretmes5age \
    --region $AWS_REGION \
    --nodegroup-name standard-workers \
    --node-type t3.medium \
    --nodes 2 \
    --nodes-min 1 \
    --nodes-max 4 \
    --managed
```

### Deploy with Helm

```bash
# Add Vault Helm repository
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update

# Install Vault
helm install vault hashicorp/vault \
    --set "server.dev.enabled=true" \
    --set "server.dev.devRootToken=supersecret"

# Deploy sup3rS3cretMes5age using the provided Helm chart
cd sup3rS3cretMes5age/deploy/charts/supersecretmessage

# Update values.yaml for your configuration
helm install sup3rs3cretmes5age . \
    --set image.repository=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/sup3rs3cretmes5age \
    --set image.tag=latest \
    --set vault.address=http://vault:8200 \
    --set vault.token=supersecret

# Create ingress for external access
kubectl apply -f - << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sup3rs3cretmes5age-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: sup3rs3cretmes5age
            port:
              number: 80
EOF
```

## Option 3: EC2 with Docker

For a simpler setup, you can deploy on EC2 instances using Docker Compose.

### Step 1: Launch EC2 Instance

```bash
# Create key pair
aws ec2 create-key-pair \
    --key-name sup3rs3cretmes5age-key \
    --query 'KeyMaterial' \
    --output text > sup3rs3cretmes5age-key.pem

chmod 400 sup3rs3cretmes5age-key.pem

# Launch EC2 instance
export INSTANCE_ID=$(aws ec2 run-instances \
    --image-id ami-0c55b159cbfafe1d0 \
    --count 1 \
    --instance-type t3.small \
    --key-name sup3rs3cretmes5age-key \
    --security-groups default \
    --query 'Instances[0].InstanceId' \
    --output text)

# Get public IP
export INSTANCE_IP=$(aws ec2 describe-instances \
    --instance-ids $INSTANCE_ID \
    --query 'Reservations[0].Instances[0].PublicIpAddress' \
    --output text)
```

### Step 2: Configure EC2 Instance

```bash
# SSH to instance and set up Docker
ssh -i sup3rs3cretmes5age-key.pem ec2-user@$INSTANCE_IP

# On the EC2 instance:
sudo yum update -y
sudo yum install -y docker
sudo service docker start
sudo usermod -a -G docker ec2-user

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# Clone repository
git clone https://github.com/algolia/sup3rS3cretMes5age.git
cd sup3rS3cretMes5age

# Start services
docker-compose -f deploy/docker-compose.yml up -d
```

## Security Considerations

### 1. Use AWS Secrets Manager for Vault Token

Instead of hardcoding the Vault token, use AWS Secrets Manager:

```bash
# Create secret
aws secretsmanager create-secret \
    --name sup3rs3cretmes5age/vault-token \
    --description "Vault root token for sup3rs3cretmes5age" \
    --secret-string "your-secure-vault-token"

# Update task definition to use secrets
# Add to containerDefinitions[].secrets:
{
  "name": "VAULT_TOKEN",
  "valueFrom": "arn:aws:secretsmanager:region:account:secret:sup3rs3cretmes5age/vault-token"
}
```

### 2. Enable VPC Flow Logs

```bash
aws ec2 create-flow-logs \
    --resource-type VPC \
    --resource-ids $VPC_ID \
    --traffic-type ALL \
    --log-destination-type cloud-watch-logs \
    --log-group-name VPCFlowLogs
```

### 3. Use HTTPS Only

Always configure HTTPS and redirect HTTP traffic:

```bash
# Modify task definition to enable HTTPS redirect
{
  "name": "SUPERSECRETMESSAGE_HTTPS_REDIRECT_ENABLED",
  "value": "true"
}
```

### 4. Implement Network ACLs

Create restrictive network ACLs for additional security:

```bash
# Create network ACL
export NACL_ID=$(aws ec2 create-network-acl \
    --vpc-id $VPC_ID \
    --query 'NetworkAcl.NetworkAclId' \
    --output text)

# Add rules as needed for your security requirements
```

## Cost Optimization

### 1. Use Fargate Spot for Development

For non-production environments, consider using Fargate Spot:

```bash
# Update service to use Fargate Spot
aws ecs put-cluster-capacity-providers \
    --cluster sup3rs3cretmes5age-cluster \
    --capacity-providers FARGATE FARGATE_SPOT
```

### 2. Auto Scaling

Configure auto scaling for production workloads:

```bash
# Register scalable target
aws application-autoscaling register-scalable-target \
    --service-namespace ecs \
    --scalable-dimension ecs:service:DesiredCount \
    --resource-id service/sup3rs3cretmes5age-cluster/sup3rs3cretmes5age-service \
    --min-capacity 1 \
    --max-capacity 10

# Create scaling policy
aws application-autoscaling put-scaling-policy \
    --policy-name sup3rs3cretmes5age-scaling-policy \
    --service-namespace ecs \
    --scalable-dimension ecs:service:DesiredCount \
    --resource-id service/sup3rs3cretmes5age-cluster/sup3rs3cretmes5age-service \
    --policy-type TargetTrackingScaling \
    --target-tracking-scaling-policy-configuration file://scaling-policy.json
```

### 3. Use Reserved Instances for EC2

For long-running deployments, consider Reserved Instances to reduce costs.

## Troubleshooting

### Common Issues

1. **Service won't start**: Check CloudWatch logs for container errors
2. **Can't access application**: Verify security group rules and target group health
3. **SSL certificate issues**: Ensure DNS validation is complete
4. **Vault connection errors**: Check network connectivity between containers

### Debugging Commands

```bash
# Check ECS service status
aws ecs describe-services \
    --cluster sup3rs3cretmes5age-cluster \
    --services sup3rs3cretmes5age-service

# View logs
aws logs tail /ecs/sup3rs3cretmes5age --follow

# Check target group health
aws elbv2 describe-target-health \
    --target-group-arn $TARGET_GROUP_ARN

# Test internal connectivity
aws ecs execute-command \
    --cluster sup3rs3cretmes5age-cluster \
    --task <task-id> \
    --container supersecret \
    --interactive \
    --command "/bin/sh"
```

### Support Resources

- [AWS ECS Documentation](https://docs.aws.amazon.com/ecs/)
- [HashiCorp Vault Documentation](https://www.vaultproject.io/docs)
- [Application Load Balancer Documentation](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/)

---

This guide provides multiple deployment options on AWS. Choose the option that best fits your team's expertise and requirements. For production deployments, we recommend Option 1 (ECS with Fargate) for its balance of simplicity, scalability, and cost-effectiveness.