Lab práctico · Semana 7: Seguridad de datos: cifrado, secretos, identidad de aplicaciones y detección
Auditoría y detección: CloudTrail, AWS Config y GuardDuty
Qué vas a construir
El «kit mínimo» de auditoría y detección de una cuenta:
- Un trail multirregión de CloudTrail con validación de integridad que entrega los logs en un bucket S3 protegido por una política de recurso.
- AWS Config registrando solo buckets de S3, con una regla gestionada que comprueba el versionado, y verás cómo un recurso pasa de NON_COMPLIANT a COMPLIANT.
- Amazon GuardDuty activado, con hallazgos de ejemplo para ver qué detecta y cómo se consultan.
flowchart LR
API["Llamadas a la API (tú, servicios)"] --> CT["CloudTrail trail multirregión"]
CT -->|"logs + digest cada hora"| B["Bucket S3 de auditoría"]
CFG["AWS Config (recorder: AWS::S3::Bucket)"] -->|"historial y snapshots"| B
CFG --> R["Regla: s3-bucket-versioning-enabled"]
GD["GuardDuty"] -->|"lee CloudTrail, Flow Logs, DNS"| F["Hallazgos"]
Antes de empezar
- Usuario de IAM Identity Center o IAM con MFA y permisos de administrador del laboratorio; nunca root.
- Región: eu-south-2 (España), en CloudShell. CloudTrail, AWS Config y GuardDuty están disponibles en esa región (lo puedes comprobar en la lista de endpoints de cada servicio).
- Si tu cuenta está en el plan gratuito (Free account plan), algunos servicios de seguridad pueden no estar disponibles hasta pasar al plan de pago: revisa
docs/investigacion.md(sección 5). - Costes (30/09/2026): la primera copia de los eventos de gestión que CloudTrail entrega a S3 es gratis; Config cobra 0,003 USD por configuration item y 0,001 USD por evaluación de regla (aquí, unos pocos); GuardDuty tiene 30 días de prueba gratuita al activarlo por primera vez. El almacenamiento S3 son céntimos.
- Si tu cuenta pertenece a una organización con Control Tower, ya existe un organization trail y Config gestionado: haz el lab en una cuenta de pruebas propia para no interferir.
export AWS_REGION=eu-south-2
export CUENTA=$(aws sts get-caller-identity --query Account --output text)
export BUCKET=lab14-auditoria-$CUENTA-$AWS_REGION
export TRAIL=lab14-trail
mkdir -p ~/lab14 && cd ~/lab14
Paso 1: bucket de auditoría con su política de recurso
Crea el bucket (privado por defecto, con Block Public Access activado):
aws s3api create-bucket --bucket "$BUCKET" \
--create-bucket-configuration LocationConstraint="$AWS_REGION"
aws s3api put-public-access-block --bucket "$BUCKET" \
--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
CloudTrail y Config escriben en el bucket como principales de servicio, así que necesitan permiso en la bucket policy. Esta política combina lo que exige cada servicio, limitado a tu cuenta y a tu trail (condiciones aws:SourceArn y AWS:SourceAccount, para evitar el problema del confused deputy):
cat > politica-bucket.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudTrailAclCheck",
"Effect": "Allow",
"Principal": { "Service": "cloudtrail.amazonaws.com" },
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::$BUCKET",
"Condition": { "StringEquals": { "aws:SourceArn": "arn:aws:cloudtrail:$AWS_REGION:$CUENTA:trail/$TRAIL" } }
},
{
"Sid": "CloudTrailWrite",
"Effect": "Allow",
"Principal": { "Service": "cloudtrail.amazonaws.com" },
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::$BUCKET/AWSLogs/$CUENTA/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control",
"aws:SourceArn": "arn:aws:cloudtrail:$AWS_REGION:$CUENTA:trail/$TRAIL"
}
}
},
{
"Sid": "ConfigBucketPermissionsCheck",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::$BUCKET",
"Condition": { "StringEquals": { "AWS:SourceAccount": "$CUENTA" } }
},
{
"Sid": "ConfigBucketExistenceCheck",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::$BUCKET",
"Condition": { "StringEquals": { "AWS:SourceAccount": "$CUENTA" } }
},
{
"Sid": "ConfigBucketDelivery",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::$BUCKET/AWSLogs/$CUENTA/Config/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control",
"AWS:SourceAccount": "$CUENTA"
}
}
},
{
"Sid": "DenegarSinTLS",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::$BUCKET", "arn:aws:s3:::$BUCKET/*"],
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
}
]
}
EOF
aws s3api put-bucket-policy --bucket "$BUCKET" --policy file://politica-bucket.json
La última declaración obliga a usar HTTPS: cifrado en tránsito impuesto por política.
Paso 2: trail multirregión con validación de integridad
aws cloudtrail create-trail --name "$TRAIL" \
--s3-bucket-name "$BUCKET" \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name "$TRAIL"
aws cloudtrail get-trail-status --name "$TRAIL" --query '{Registrando:IsLogging,UltimaEntrega:LatestDeliveryTime}'
Genera algo de actividad para que haya eventos (crear y borrar un bucket de prueba, por ejemplo):
aws s3api create-bucket --bucket "lab14-prueba-$CUENTA" \
--create-bucket-configuration LocationConstraint="$AWS_REGION"
Los ficheros de log llegan al bucket en unos minutos, bajo AWSLogs/CUENTA/CloudTrail/REGION/AAAA/MM/DD/. Los ficheros digest de integridad llegan cada hora bajo AWSLogs/CUENTA/CloudTrail-Digest/.
aws s3 ls "s3://$BUCKET/AWSLogs/$CUENTA/" --recursive | head
Mientras tanto, consulta el event history (90 días, gratis, no depende del trail):
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=CreateBucket \
--max-results 5 --query 'Events[].[EventTime,Username,EventName]' --output table
Paso 3: AWS Config registrando solo buckets de S3
Config usa un rol vinculado al servicio. Créalo (si ya existe, el comando da error y puedes seguir):
aws iam create-service-linked-role --aws-service-name config.amazonaws.com || true
Crea el configuration recorder limitado a AWS::S3::Bucket (así el coste es mínimo) y el delivery channel hacia tu bucket:
cat > grabacion.json <<'EOF'
{
"allSupported": false,
"includeGlobalResourceTypes": false,
"resourceTypes": ["AWS::S3::Bucket"],
"recordingStrategy": { "useOnly": "INCLUSION_BY_RESOURCE_TYPES" }
}
EOF
aws configservice put-configuration-recorder \
--configuration-recorder name=default,roleARN=arn:aws:iam::$CUENTA:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig \
--recording-group file://grabacion.json
aws configservice put-delivery-channel \
--delivery-channel name=default,s3BucketName=$BUCKET
aws configservice start-configuration-recorder --configuration-recorder-name default
aws configservice describe-configuration-recorder-status
Añade la regla gestionada que comprueba si los buckets tienen versionado:
cat > regla.json <<'EOF'
{
"ConfigRuleName": "lab14-s3-versionado",
"Description": "Comprueba que los buckets de S3 tienen el versionado activado",
"Scope": { "ComplianceResourceTypes": ["AWS::S3::Bucket"] },
"Source": { "Owner": "AWS", "SourceIdentifier": "S3_BUCKET_VERSIONING_ENABLED" }
}
EOF
aws configservice put-config-rule --config-rule file://regla.json
Espera 2-5 minutos a que Config descubra los buckets y evalúe:
aws configservice start-config-rules-evaluation --config-rule-names lab14-s3-versionado
aws configservice get-compliance-details-by-config-rule \
--config-rule-name lab14-s3-versionado \
--query 'EvaluationResults[].[EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType]' \
--output table
Los buckets lab14-prueba-… y el de auditoría aparecerán como NON_COMPLIANT.
Paso 4: corregir y volver a evaluar
Activa el versionado en el bucket de prueba (en un entorno real, esto lo haría una remediación automática con el documento de SSM Automation AWS-ConfigureS3BucketVersioning asociado a la regla):
aws s3api put-bucket-versioning --bucket "lab14-prueba-$CUENTA" \
--versioning-configuration Status=Enabled
sleep 60
aws configservice start-config-rules-evaluation --config-rule-names lab14-s3-versionado
sleep 60
aws configservice get-compliance-details-by-config-rule \
--config-rule-name lab14-s3-versionado \
--query 'EvaluationResults[].[EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType]' \
--output table
El bucket de prueba pasa a COMPLIANT. En la consola de Config abre el recurso y pulsa Resource timeline: verás el cambio de configuración y, enlazado, el evento de CloudTrail PutBucketVersioning con tu usuario. «Cómo estaba y cómo está» (Config) + «quién lo cambió» (CloudTrail).
Paso 5: GuardDuty y hallazgos de ejemplo
DETECTOR_ID=$(aws guardduty create-detector --enable \
--finding-publishing-frequency FIFTEEN_MINUTES \
--query DetectorId --output text)
echo "DETECTOR_ID=$DETECTOR_ID"
GuardDuty empieza a analizar solo, sin agentes: eventos de gestión de CloudTrail, VPC Flow Logs y logs DNS (no hace falta activarlos tú). Como en una cuenta de pruebas no habrá amenazas reales, genera hallazgos de ejemplo:
aws guardduty create-sample-findings --detector-id "$DETECTOR_ID" \
--finding-types "CryptoCurrency:EC2/BitcoinTool.B!DNS" "UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom" "Recon:EC2/PortProbeUnprotectedPort"
sleep 20
aws guardduty list-findings --detector-id "$DETECTOR_ID" --query 'FindingIds' --output text > hallazgos.txt
aws guardduty get-findings --detector-id "$DETECTOR_ID" \
--finding-ids $(head -c 2000 hallazgos.txt) \
--query 'Findings[].[Type,Severity,Resource.ResourceType]' --output table
Revisa también la consola de GuardDuty: cada hallazgo indica el recurso afectado, la severidad y la acción recomendada. Observa el panel Protection plans: S3 Protection, EKS, Runtime Monitoring, Malware Protection, RDS y Lambda Protection.
Comprueba que funciona
aws cloudtrail get-trail-status --name lab14-traildevuelveIsLogging: truey una fecha de última entrega.- En el bucket hay objetos bajo
AWSLogs/CUENTA/CloudTrail/yAWSLogs/CUENTA/Config/. - La regla de Config muestra un bucket
COMPLIANTy otroNON_COMPLIANT. - GuardDuty lista los hallazgos de ejemplo (marcados como sample).
- Opcional (si ha pasado al menos una hora desde el paso 2): valida la integridad de los logs.
aws cloudtrail validate-logs \
--trail-arn "arn:aws:cloudtrail:$AWS_REGION:$CUENTA:trail/$TRAIL" \
--start-time "$(date -u -d '-2 hours' +%Y-%m-%dT%H:%M:%SZ)"
Limpieza
En orden de dependencias:
# 1) GuardDuty (borrar el detector detiene el servicio y la prueba gratuita en esta región)
aws guardduty delete-detector --detector-id "$DETECTOR_ID"
# 2) AWS Config: regla, grabación y canal de entrega
aws configservice delete-config-rule --config-rule-name lab14-s3-versionado
aws configservice stop-configuration-recorder --configuration-recorder-name default
aws configservice delete-delivery-channel --delivery-channel-name default
aws configservice delete-configuration-recorder --configuration-recorder-name default
# 3) CloudTrail
aws cloudtrail stop-logging --name "$TRAIL"
aws cloudtrail delete-trail --name "$TRAIL"
# 4) Buckets (el de prueba tiene versionado: hay que borrar también las versiones)
aws s3api delete-objects --bucket "lab14-prueba-$CUENTA" \
--delete "$(aws s3api list-object-versions --bucket "lab14-prueba-$CUENTA" \
--query '{Objects: Versions[].{Key:Key,VersionId:VersionId}}' --output json)" 2>/dev/null || true
aws s3api delete-bucket --bucket "lab14-prueba-$CUENTA"
aws s3 rm "s3://$BUCKET" --recursive
aws s3api delete-bucket --bucket "$BUCKET"
# 5) Ficheros locales
cd ~ && rm -rf ~/lab14
El rol vinculado a Config puede quedarse (no cuesta nada) o borrarse con aws iam delete-service-linked-role --role-name AWSServiceRoleForConfig. Revisa al día siguiente en Billing → Bills que no queda nada de Config ni de GuardDuty.
Preguntas para pensar como arquitecto
- Tu empresa tiene 40 cuentas en AWS Organizations y el auditor exige que toda la actividad de la API quede registrada de forma centralizada y que ninguna cuenta pueda desactivarlo. ¿Cómo lo diseñas?
Respuesta
Un organization trail multirregión creado desde la cuenta de administración (o un administrador delegado) que entrega en un bucket de una cuenta dedicada de log archive. Las cuentas miembro ven el trail pero no pueden modificarlo ni pararlo. El bucket con Object Lock, cifrado SSE-KMS, acceso muy restringido y validación de integridad activada. Una SCP puede además impedir cloudtrail:StopLogging y DeleteTrail. AWS Control Tower configura este patrón automáticamente.
- ¿Qué diferencia hay entre lo que te dio la regla de Config y lo que habría hecho una SCP que denegara crear buckets sin versionado?
Respuesta
Config es detectivo (y correctivo con remediación): el bucket se crea, Config lo marca como no conforme y, si configuras remediación, lo arregla después. Una SCP o una política IAM es preventiva: la acción no llega a ocurrir. En la práctica se combinan: guardarraíles preventivos donde se pueda expresar la condición y reglas de Config para todo lo demás y para demostrar cumplimiento continuo.
- GuardDuty genera un hallazgo de minería de criptomonedas en una instancia. ¿Cómo automatizarías la respuesta?
Respuesta
GuardDuty publica sus hallazgos en EventBridge. Una regla que filtre por tipo y severidad dispara una Lambda o un documento de SSM Automation que aísla la instancia (cambia su security group por uno sin reglas, toma una instantánea de EBS para análisis forense) y avisa por SNS. Para investigar el alcance, Amazon Detective; para verlo priorizado junto a otros hallazgos, Security Hub.
- ¿Por qué no basta con el event history de CloudTrail para una auditoría de dos años?
Respuesta
Porque el event history solo guarda 90 días de eventos de gestión y por región. Para retención larga hace falta un trail que entregue a S3 (con lifecycle hacia clases más baratas como Glacier y Object Lock para inmutabilidad). Tampoco incluye data events (lecturas de objetos S3, invocaciones de Lambda), que hay que activar explícitamente en el trail.
- Te piden descubrir si hay números de tarjeta o DNI en los buckets de la empresa. ¿GuardDuty, Inspector o Macie?
Respuesta
Amazon Macie: analiza objetos de S3 con identificadores gestionados (PII, datos financieros, credenciales) y personalizados (expresiones regulares, por ejemplo para el formato del DNI). GuardDuty detecta amenazas y comportamiento malicioso; Inspector, vulnerabilidades de software en EC2, ECR y Lambda.