Skip to content
English
On this page

Ejercicio: CDN y Sitio Web Estático con CloudFormation

Parte 1: Infraestructura Base y S3

Escenario

Implementaremos una arquitectura que incluye:

  • Infraestructura como código con CloudFormation
  • CDN con CloudFront
  • Almacenamiento con S3
  • Certificados SSL con ACM
  • Monitoreo con CloudWatch

Estructura del Proyecto

static-website-cdn/
├── cloudformation/
│   ├── templates/
│   │   ├── main.yaml
│   │   ├── s3.yaml
│   │   ├── cloudfront.yaml
│   │   └── monitoring.yaml
│   │
│   ├── parameters/
│   │   ├── dev.json
│   │   ├── staging.json
│   │   └── prod.json
│   │
│   └── scripts/
│       ├── deploy.sh
│       └── validate.sh

├── website/
│   ├── src/
│   │   ├── index.html
│   │   ├── css/
│   │   ├── js/
│   │   └── images/
│   │
│   └── scripts/
│       └── upload.sh

├── config/
│   ├── s3-policy.json
│   └── cloudfront-config.json

└── scripts/
    ├── build.sh
    └── deploy-all.sh

1. Plantilla Principal de CloudFormation

1.1 Template Principal

yaml
# cloudformation/templates/main.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Static Website with CloudFront Distribution'

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod
    Description: Environment name

  DomainName:
    Type: String
    Description: Domain name for the website

Resources:
  WebsiteStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub 'https://${TemplateBucket}.s3.amazonaws.com/s3.yaml'
      Parameters:
        Environment: !Ref Environment
        BucketName: !Sub '${DomainName}-${Environment}-content'

  MonitoringStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub 'https://${TemplateBucket}.s3.amazonaws.com/monitoring.yaml'
      Parameters:
        Environment: !Ref Environment
        BucketName: !GetAtt WebsiteStack.Outputs.BucketName

Outputs:
  WebsiteBucket:
    Description: Website content bucket
    Value: !GetAtt WebsiteStack.Outputs.BucketName
    Export:
      Name: !Sub '${AWS::StackName}-WebsiteBucket'

1.2 Template S3

yaml
# cloudformation/templates/s3.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'S3 Configuration for Static Website'

Parameters:
  BucketName:
    Type: String
    Description: Name for the S3 bucket

  Environment:
    Type: String
    Description: Environment name

Resources:
  WebsiteBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      AccessControl: Private
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: Environment
          Value: !Ref Environment

  WebsiteBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref WebsiteBucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudfront.amazonaws.com
            Action: s3:GetObject
            Resource: !Sub '${WebsiteBucket.Arn}/*'
            Condition:
              StringEquals:
                AWS:SourceArn: !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/*'

Outputs:
  BucketName:
    Description: Name of the website bucket
    Value: !Ref WebsiteBucket
    Export:
      Name: !Sub '${AWS::StackName}-BucketName'

  BucketArn:
    Description: ARN of the website bucket
    Value: !GetAtt WebsiteBucket.Arn
    Export:
      Name: !Sub '${AWS::StackName}-BucketArn'

2. Scripts de Despliegue

2.1 Script de Despliegue Principal

bash
#!/bin/bash
# scripts/deploy-all.sh

# Variables
STACK_NAME="static-website-cdn"
TEMPLATE_BUCKET="my-cloudformation-templates"
REGION="us-east-1"
ENVIRONMENT="dev"

# Validar templates
echo "Validando templates..."
aws cloudformation validate-template \
    --template-body file://cloudformation/templates/main.yaml

# Empaquetar templates
echo "Empaquetando templates..."
aws cloudformation package \
    --template-file cloudformation/templates/main.yaml \
    --s3-bucket $TEMPLATE_BUCKET \
    --output-template-file packaged.yaml

# Desplegar stack
echo "Desplegando stack..."
aws cloudformation deploy \
    --template-file packaged.yaml \
    --stack-name $STACK_NAME \
    --parameter-overrides \
        Environment=$ENVIRONMENT \
        DomainName=example.com \
    --capabilities CAPABILITY_IAM \
    --tags Environment=$ENVIRONMENT

2.2 Script de Validación

python
# cloudformation/scripts/validate.py
import boto3
import sys

def validate_stack(stack_name):
    cf = boto3.client('cloudformation')
    
    try:
        # Verificar estado del stack
        response = cf.describe_stacks(StackName=stack_name)
        stack = response['Stacks'][0]
        
        if stack['StackStatus'] != 'CREATE_COMPLETE':
            print(f"Stack status: {stack['StackStatus']}")
            return False
            
        # Verificar recursos
        resources = cf.list_stack_resources(StackName=stack_name)
        for resource in resources['StackResourceSummaries']:
            if resource['ResourceStatus'] != 'CREATE_COMPLETE':
                print(f"Resource {resource['LogicalResourceId']} status: {resource['ResourceStatus']}")
                return False
                
        return True
        
    except Exception as e:
        print(f"Error validating stack: {str(e)}")
        return False

if __name__ == "__main__":
    stack_name = sys.argv[1]
    if validate_stack(stack_name):
        print("Stack validation successful")
        sys.exit(0)
    else:
        print("Stack validation failed")
        sys.exit(1)

3. Contenido del Sitio Web

3.1 HTML Base

html
<!-- website/src/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Static Website with CDN</title>
    <link rel="stylesheet" href="/css/styles.css">
</head>
<body>
    <header>
        <h1>Welcome to Our Static Website</h1>
    </header>
    <main>
        <section>
            <h2>Features</h2>
            <ul>
                <li>CloudFront CDN</li>
                <li>S3 Storage</li>
                <li>SSL Certificate</li>
                <li>CloudFormation IaC</li>
            </ul>
        </section>
    </main>
    <script src="/js/main.js"></script>
</body>
</html>

3.2 Script de Carga

bash
#!/bin/bash
# website/scripts/upload.sh

# Variables
BUCKET_NAME=$(aws cloudformation describe-stacks \
    --stack-name static-website-cdn \
    --query 'Stacks[0].Outputs[?OutputKey==`WebsiteBucket`].OutputValue' \
    --output text)

# Sincronizar contenido
aws s3 sync \
    website/src/ \
    s3://$BUCKET_NAME/ \
    --delete \
    --cache-control "max-age=3600"

# Invalidar cache de CloudFront
DISTRIBUTION_ID=$(aws cloudformation describe-stacks \
    --stack-name static-website-cdn \
    --query 'Stacks[0].Outputs[?OutputKey==`DistributionId`].OutputValue' \
    --output text)

aws cloudfront create-invalidation \
    --distribution-id $DISTRIBUTION_ID \
    --paths "/*"

Verificación Parte 1

1. Verificar CloudFormation

  • [ ] Templates validados
  • [ ] Stack desplegado
  • [ ] Recursos creados
  • [ ] Outputs disponibles

2. Verificar S3

  • [ ] Bucket creado
  • [ ] Política aplicada
  • [ ] Versionamiento activo
  • [ ] Encriptación configurada

3. Verificar Contenido

  • [ ] Archivos cargados
  • [ ] Permisos correctos
  • [ ] Cache-Control configurado
  • [ ] Estructura correcta

Troubleshooting Común

Errores de CloudFormation

  1. Verificar sintaxis YAML
  2. Revisar permisos IAM
  3. Verificar dependencias

Errores de S3

  1. Verificar políticas
  2. Revisar permisos
  3. Verificar encriptación

Errores de Contenido

  1. Verificar rutas
  2. Revisar permisos
  3. Verificar sync

Parte 2: CloudFront y Certificados SSL

1. Configuración de CloudFront

1.1 Template de CloudFront

yaml
# cloudformation/templates/cloudfront.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFront Distribution Configuration'

Parameters:
  DomainName:
    Type: String
    Description: Domain name for the website

  CertificateArn:
    Type: String
    Description: ARN of the SSL certificate

  S3BucketName:
    Type: String
    Description: Name of the S3 bucket containing website content

Resources:
  CloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: !Sub 'OAI for ${DomainName}'

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        DefaultRootObject: index.html
        Aliases:
          - !Ref DomainName
          - !Sub 'www.${DomainName}'
        Origins:
          - DomainName: !Sub '${S3BucketName}.s3.amazonaws.com'
            Id: S3Origin
            S3OriginConfig:
              OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}'
        DefaultCacheBehavior:
          TargetOriginId: S3Origin
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
          CachedMethods:
            - GET
            - HEAD
            - OPTIONS
          Compress: true
          DefaultTTL: 3600
          MaxTTL: 86400
          MinTTL: 0
          ForwardedValues:
            QueryString: false
            Cookies:
              Forward: none
        ViewerCertificate:
          AcmCertificateArn: !Ref CertificateArn
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021
        CustomErrorResponses:
          - ErrorCode: 404
            ResponseCode: 200
            ResponsePagePath: /index.html
          - ErrorCode: 403
            ResponseCode: 200
            ResponsePagePath: /index.html
        PriceClass: PriceClass_100
        HttpVersion: http2
        IPV6Enabled: true

Outputs:
  DistributionId:
    Description: ID of the CloudFront distribution
    Value: !Ref CloudFrontDistribution
    Export:
      Name: !Sub '${AWS::StackName}-DistributionId'

  DistributionDomainName:
    Description: Domain name of the CloudFront distribution
    Value: !GetAtt CloudFrontDistribution.DomainName
    Export:
      Name: !Sub '${AWS::StackName}-DistributionDomain'

1.2 Configuración de Cache

json
// config/cloudfront-config.json
{
  "CacheBehaviors": {
    "static/*": {
      "DefaultTTL": 86400,
      "MaxTTL": 31536000,
      "MinTTL": 3600,
      "Compress": true
    },
    "images/*": {
      "DefaultTTL": 604800,
      "MaxTTL": 31536000,
      "MinTTL": 86400,
      "Compress": true
    },
    "api/*": {
      "DefaultTTL": 0,
      "MaxTTL": 0,
      "MinTTL": 0,
      "Compress": true,
      "ForwardQueryStrings": true
    }
  }
}

2. Certificados SSL con ACM

2.1 Template de ACM

yaml
# cloudformation/templates/acm.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'SSL Certificate Configuration'

Parameters:
  DomainName:
    Type: String
    Description: Domain name for the certificate

  Environment:
    Type: String
    Description: Environment name

Resources:
  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: !Ref DomainName
      SubjectAlternativeNames:
        - !Sub '*.${DomainName}'
      ValidationMethod: DNS
      Tags:
        - Key: Environment
          Value: !Ref Environment

  DNSValidationRecord:
    Type: AWS::Route53::RecordSet
    DependsOn: Certificate
    Properties:
      HostedZoneId: !Ref HostedZoneId
      Name: !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Name
      Type: !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Type
      TTL: '300'
      ResourceRecords:
        - !GetAtt Certificate.DomainValidationOptions.0.ResourceRecord.Value

Outputs:
  CertificateArn:
    Description: ARN of the SSL certificate
    Value: !Ref Certificate
    Export:
      Name: !Sub '${AWS::StackName}-CertificateArn'

2.2 Script de Validación de Certificado

python
# scripts/validate_certificate.py
import boto3
import time

def wait_for_certificate_validation(certificate_arn):
    acm = boto3.client('acm')
    
    print("Waiting for certificate validation...")
    while True:
        response = acm.describe_certificate(
            CertificateArn=certificate_arn
        )
        
        status = response['Certificate']['Status']
        if status == 'ISSUED':
            print("Certificate validated successfully!")
            return True
        elif status == 'FAILED':
            print("Certificate validation failed!")
            return False
            
        print(f"Current status: {status}")
        time.sleep(30)

def validate_certificate(stack_name):
    cf = boto3.client('cloudformation')
    
    try:
        response = cf.describe_stacks(
            StackName=stack_name
        )
        
        for output in response['Stacks'][0]['Outputs']:
            if output['OutputKey'] == 'CertificateArn':
                return wait_for_certificate_validation(output['OutputValue'])
                
    except Exception as e:
        print(f"Error validating certificate: {str(e)}")
        return False

if __name__ == "__main__":
    validate_certificate('static-website-cdn')

3. Configuración de DNS

3.1 Template de Route 53

yaml
# cloudformation/templates/route53.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'DNS Configuration'

Parameters:
  DomainName:
    Type: String
    Description: Domain name

  DistributionDomainName:
    Type: String
    Description: CloudFront distribution domain name

Resources:
  WebsiteDNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneName: !Sub '${DomainName}.'
      Name: !Ref DomainName
      Type: A
      AliasTarget:
        DNSName: !Ref DistributionDomainName
        HostedZoneId: Z2FDTNDATAQYW2  # CloudFront hosted zone ID
        EvaluateTargetHealth: false

  WwwDNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneName: !Sub '${DomainName}.'
      Name: !Sub 'www.${DomainName}'
      Type: A
      AliasTarget:
        DNSName: !Ref DistributionDomainName
        HostedZoneId: Z2FDTNDATAQYW2
        EvaluateTargetHealth: false

3.2 Script de Verificación DNS

python
# scripts/verify_dns.py
import dns.resolver
import time

def verify_dns_propagation(domain_name):
    resolvers = [
        '8.8.8.8',  # Google DNS
        '1.1.1.1',  # Cloudflare DNS
        '208.67.222.222'  # OpenDNS
    ]
    
    for resolver_ip in resolvers:
        resolver = dns.resolver.Resolver()
        resolver.nameservers = [resolver_ip]
        
        try:
            answers = resolver.resolve(domain_name, 'A')
            print(f"Resolution from {resolver_ip}: {answers[0]}")
        except Exception as e:
            print(f"Error resolving from {resolver_ip}: {str(e)}")
            return False
            
    return True

def wait_for_dns_propagation(domain_name, timeout=3600):
    print(f"Waiting for DNS propagation for {domain_name}...")
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        if verify_dns_propagation(domain_name):
            print("DNS propagation complete!")
            return True
            
        print("Still waiting for DNS propagation...")
        time.sleep(60)
        
    print("DNS propagation timeout!")
    return False

if __name__ == "__main__":
    wait_for_dns_propagation('example.com')

Verificación Parte 2

1. Verificar CloudFront

  • [ ] Distribución creada
  • [ ] Origen configurado
  • [ ] Comportamientos de caché
  • [ ] HTTPS habilitado

2. Verificar ACM

  • [ ] Certificado emitido
  • [ ] Validación DNS completada
  • [ ] Dominios alternativos
  • [ ] Integración con CloudFront

3. Verificar DNS

  • [ ] Registros creados
  • [ ] Propagación completa
  • [ ] Resolución correcta
  • [ ] SSL funcionando

Troubleshooting Común

Errores de CloudFront

  1. Verificar origen
  2. Revisar cache behaviors
  3. Verificar certificado

Errores de Certificado

  1. Verificar validación DNS
  2. Revisar dominios
  3. Verificar región

Errores de DNS

  1. Verificar registros
  2. Revisar propagación
  3. Verificar nameservers

Parte 3: Monitoreo, Rendimiento y Mejores Prácticas

1. Monitoreo con CloudWatch

1.1 Template de Monitoreo

yaml
# cloudformation/templates/monitoring.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Monitoring Configuration for CDN'

Parameters:
  DistributionId:
    Type: String
    Description: CloudFront distribution ID

  AlertEmail:
    Type: String
    Description: Email for alerts

Resources:
  MonitoringDashboard:
    Type: AWS::CloudWatch::Dashboard
    Properties:
      DashboardName: !Sub 'cdn-monitoring-${AWS::StackName}'
      DashboardBody: !Sub |
        {
          "widgets": [
            {
              "type": "metric",
              "properties": {
                "metrics": [
                  ["AWS/CloudFront", "Requests", "DistributionId", "${DistributionId}", "Region", "Global"],
                  [".", "BytesDownloaded", ".", ".", ".", "."],
                  [".", "4xxErrorRate", ".", ".", ".", "."],
                  [".", "5xxErrorRate", ".", ".", ".", "."]
                ],
                "period": 300,
                "region": "us-east-1",
                "title": "CloudFront Metrics"
              }
            },
            {
              "type": "metric",
              "properties": {
                "metrics": [
                  ["AWS/CloudFront", "TotalErrorRate", "DistributionId", "${DistributionId}"],
                  [".", "BytesUploaded", ".", "."]
                ],
                "period": 300,
                "region": "us-east-1",
                "title": "Error Rates"
              }
            }
          ]
        }

  HighErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-HighErrorRate'
      AlarmDescription: 'High error rate detected in CloudFront distribution'
      MetricName: 5xxErrorRate
      Namespace: AWS/CloudFront
      Dimensions:
        - Name: DistributionId
          Value: !Ref DistributionId
        - Name: Region
          Value: Global
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 5
      ComparisonOperator: GreaterThanThreshold
      AlarmActions:
        - !Ref AlertTopic

  AlertTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: 'CDN Alerts'
      Subscription:
        - Protocol: email
          Endpoint: !Ref AlertEmail

1.2 Script de Análisis de Métricas

python
# scripts/analyze_metrics.py
import boto3
from datetime import datetime, timedelta
import pandas as pd

class CDNMetricsAnalyzer:
    def __init__(self, distribution_id):
        self.cloudwatch = boto3.client('cloudwatch')
        self.distribution_id = distribution_id
        
    def get_metrics(self, days=7):
        end_time = datetime.utcnow()
        start_time = end_time - timedelta(days=days)
        
        metrics = {
            'requests': self._get_metric_data('Requests'),
            'bytes_downloaded': self._get_metric_data('BytesDownloaded'),
            'error_rates': self._get_error_rates(),
            'cache_hits': self._get_metric_data('CacheHitRate')
        }
        
        return self._analyze_metrics(metrics)
        
    def _get_metric_data(self, metric_name):
        response = self.cloudwatch.get_metric_data(
            MetricDataQueries=[
                {
                    'Id': 'data',
                    'MetricStat': {
                        'Metric': {
                            'Namespace': 'AWS/CloudFront',
                            'MetricName': metric_name,
                            'Dimensions': [
                                {
                                    'Name': 'DistributionId',
                                    'Value': self.distribution_id
                                },
                                {
                                    'Name': 'Region',
                                    'Value': 'Global'
                                }
                            ]
                        },
                        'Period': 3600,
                        'Stat': 'Sum'
                    }
                }
            ],
            StartTime=datetime.utcnow() - timedelta(days=7),
            EndTime=datetime.utcnow()
        )
        
        return response['MetricDataResults'][0]
        
    def _analyze_metrics(self, metrics):
        df = pd.DataFrame(metrics)
        
        analysis = {
            'summary': {
                'total_requests': df['requests'].sum(),
                'average_daily_requests': df['requests'].mean(),
                'error_rate_avg': df['error_rates'].mean(),
                'cache_hit_rate_avg': df['cache_hits'].mean()
            },
            'trends': {
                'requests_trend': self._calculate_trend(df['requests']),
                'errors_trend': self._calculate_trend(df['error_rates'])
            },
            'recommendations': self._generate_recommendations(df)
        }
        
        return analysis
        
    def _generate_recommendations(self, df):
        recommendations = []
        
        if df['cache_hits'].mean() < 0.8:
            recommendations.append({
                'type': 'cache_optimization',
                'message': 'Consider increasing cache TTL to improve hit rate'
            })
            
        if df['error_rates'].mean() > 0.02:
            recommendations.append({
                'type': 'error_investigation',
                'message': 'High error rate detected - investigate root cause'
            })
            
        return recommendations

2. Pruebas de Rendimiento

2.1 Script de Pruebas de Carga

python
# scripts/performance/load_test.py
import locust
from locust import HttpUser, task, between

class CDNLoadTest(HttpUser):
    wait_time = between(1, 3)
    
    @task(3)
    def get_index(self):
        self.client.get("/")
        
    @task(2)
    def get_images(self):
        self.client.get("/images/banner.jpg")
        self.client.get("/images/logo.png")
        
    @task(1)
    def get_static_assets(self):
        self.client.get("/css/styles.css")
        self.client.get("/js/main.js")

def run_load_test(host, users=100, spawn_rate=10, runtime='5m'):
    import subprocess
    
    cmd = f"""locust \
        --host={host} \
        --users={users} \
        --spawn-rate={spawn_rate} \
        --run-time={runtime} \
        --headless \
        --only-summary
    """
    
    subprocess.run(cmd, shell=True)

2.2 Optimización de Caché

python
# scripts/optimization/cache_analyzer.py
import boto3
import json

class CacheOptimizer:
    def __init__(self, distribution_id):
        self.cloudfront = boto3.client('cloudfront')
        self.distribution_id = distribution_id
        
    def analyze_and_optimize(self):
        # Obtener configuración actual
        config = self.get_distribution_config()
        
        # Analizar patrones de acceso
        patterns = self.analyze_access_patterns()
        
        # Generar recomendaciones
        recommendations = self.generate_recommendations(config, patterns)
        
        return recommendations
        
    def get_distribution_config(self):
        response = self.cloudfront.get_distribution_config(
            Id=self.distribution_id
        )
        return response['DistributionConfig']
        
    def analyze_access_patterns(self):
        # Analizar logs de CloudFront
        pass
        
    def generate_recommendations(self, config, patterns):
        recommendations = []
        
        # Analizar configuración de caché
        cache_behavior = config['DefaultCacheBehavior']
        ttl = cache_behavior.get('DefaultTTL', 0)
        
        if ttl < 3600:
            recommendations.append({
                'type': 'TTL_INCREASE',
                'current': ttl,
                'recommended': 3600,
                'reason': 'Low TTL may cause unnecessary origin requests'
            })
            
        # Verificar compresión
        if not cache_behavior.get('Compress', False):
            recommendations.append({
                'type': 'ENABLE_COMPRESSION',
                'reason': 'Compression can reduce transfer size'
            })
            
        return recommendations

3. Mejores Prácticas y Seguridad

3.1 Security Headers

yaml
# cloudformation/templates/security.yaml
Resources:
  SecurityHeadersFunction:
    Type: AWS::CloudFront::Function
    Properties:
      Name: !Sub '${AWS::StackName}-security-headers'
      AutoPublish: true
      FunctionConfig:
        Comment: 'Add security headers to responses'
        Runtime: cloudfront-js-1.0
      FunctionCode: |
        function handler(event) {
            var response = event.response;
            var headers = response.headers;
            
            headers['strict-transport-security'] = {
                value: 'max-age=31536000; includeSubdomains; preload'
            };
            
            headers['x-content-type-options'] = {
                value: 'nosniff'
            };
            
            headers['x-frame-options'] = {
                value: 'DENY'
            };
            
            headers['x-xss-protection'] = {
                value: '1; mode=block'
            };
            
            headers['content-security-policy'] = {
                value: "default-src 'self'; img-src 'self' data: https:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
            };
            
            return response;
        }

3.2 WAF Rules

yaml
# cloudformation/templates/waf.yaml
Resources:
  CDNWebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub '${AWS::StackName}-cdn-protection'
      Scope: CLOUDFRONT
      DefaultAction:
        Allow: {}
      Rules:
        - Name: RateLimit
          Priority: 1
          Statement:
            RateBasedStatement:
              Limit: 2000
              AggregateKeyType: IP
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: RateLimitRule
            
        - Name: BlockMaliciousRequests
          Priority: 2
          Statement:
            AndStatement:
              Statements:
                - XssMatchStatement:
                    FieldToMatch:
                      UriPath: {}
                    TextTransformations:
                      - Type: URL_DECODE
                        Priority: 1
                - SqliMatchStatement:
                    FieldToMatch:
                      QueryString: {}
                    TextTransformations:
                      - Type: URL_DECODE
                        Priority: 1
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: BlockMaliciousRequests

Verificación Final

1. Verificar Monitoreo

  • [ ] Dashboard creado
  • [ ] Alertas configuradas
  • [ ] Métricas recopiladas
  • [ ] Análisis funcionando

2. Verificar Rendimiento

  • [ ] Tests ejecutados
  • [ ] Cache optimizada
  • [ ] Compresión habilitada
  • [ ] Latencia aceptable

3. Verificar Seguridad

  • [ ] Headers implementados
  • [ ] WAF configurado
  • [ ] SSL funcionando
  • [ ] Logs habilitados

Troubleshooting Final

Problemas de Rendimiento

  1. Verificar configuración de caché
  2. Revisar compresión
  3. Verificar origen

Problemas de Seguridad

  1. Verificar headers
  2. Revisar reglas WAF
  3. Verificar certificados

Problemas de Monitoreo

  1. Verificar métricas
  2. Revisar alertas
  3. Verificar logs

Puntos Importantes

  1. Monitoreo continuo es esencial
  2. Optimización regular de caché
  3. Seguridad en múltiples capas
  4. Pruebas regulares de rendimiento

Este ejercicio completo proporciona:

  1. Monitoreo completo con CloudWatch
  2. Pruebas de rendimiento automatizadas
  3. Optimización de caché
  4. Mejores prácticas de seguridad

Puntos clave para recordar:

  • El monitoreo es crítico
  • La optimización debe ser continua
  • La seguridad es multicapa
  • Las pruebas deben ser regulares