AWS MODULO 2 : IAM Roles & DynamoDB

El 60% de los Hacks en AWS Vienen de Aquí

📚 Serie: AWS Zero to Architect – Módulo 2

⏱️ Tiempo de lectura: 18 minutos

💻 Tiempo de implementación: 90 minutos

En los módulos anteriores configuramos AWS de forma segura y creamos infraestructura con Terraform. Ahora viene la parte que separa a los juniors de los seniors: IAM (Identity and Access Management).

🔥 Por Qué Deberías Preocuparte por IAM

Estadística que te hará sudar

60% de los incidentes de seguridad en AWS son por permisos mal configurados.

No por hackeo sofisticado. No por zero-days. Por dar permisos de más.

Historia Real: $47,000 en 3 Días

“Creé un rol IAM con `dynamodb: en ` porque ‘era más rápido’. Alguien comprometió mi Lambda. En 3 días:

– Borraron 12 tablas de producción

– Crearon 200 tablas nuevas en 5 regiones

– Factura: $47,000

– Tiempo de recuperación: 2 semanas

– Clientes perdidos: 34″

— Dev anónimo, AWS re:Invent 2023

El costo de “era más rápido”.

🎯 Lo Que Vas a Aprender

  • ✅ IAM Users vs Roles (y por qué confundirlos es peligroso)
  • ✅ Cómo leer y escribir Policies sin morir en el intento
  • Least Privilege: El principio de seguridad más importante
  • ✅ Trust Relationships (el paso que todos olvidan)
  • ✅ DynamoDB sin-erver (serverless) configurado profesionalmente
  • ✅ Todo con Terraform (Infrastructure as Code)

🏢 IAM Explicado: La Analogía del Edificio

Imagina AWS como un edificio de oficinas:

👤 IAM Users = Empleados con Credenciales

Juan el Admin:
- Username: juan-admin
- Password: ••••••••
- Access Keys: AKIAIOSFODNN7EXAMPLE

Tiene credenciales PERMANENTES.
Entra todos los días con su tarjeta.

Uso: Personas que acceden a AWS (tú, tu equipo).

👔 IAM Roles = Uniformes con Permisos

Rol: "lambda-db-writer"
- NO tiene credenciales permanentes
- Lambda se lo "pone" temporalmente
- Credenciales válidas por 15 minutos
- Luego expiran automáticamente

Es como un chaleco que dice:
"Quien use esto puede escribir en la tabla 'users'"

Uso: Servicios de AWS (Lambda, EC2, ECS).

📜 IAM Policies = Las Reglas Escritas

{
  "Effect": "Allow",
  "Action": "dynamodb:PutItem",
  "Resource": "arn:aws:dynamodb:*:*:table/users"
}

Traducción: “Permite escribir en la tabla ‘users'”

🔍 Anatomía de una Policy (Sin Marearte)

La Policy Más Simple del Mundo

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

En español: “Permite leer objetos del bucket ‘my-bucket'”

Desglose Línea por Línea

1. Version

"Version": "2012-10-17"
  • Siempre usa esta versión (sí, dice 2012 pero es la actual)
  • No es la versión de TU policy, es del formato

2. Effect

"Effect": "Allow"  // o "Deny"
  • Allow: Permitir
  • Deny: Denegar (SIEMPRE gana sobre Allow)

Regla de oro: Sin Allow explícito = denegado.

3. Action

"Action": "dynamodb:PutItem"
  • Formato: servicio:operación
  • Ejemplos:
    • dynamodb:GetItem → Leer item
    • s3:PutObject → Subir archivo
    • logs:PutLogEvents → Escribir logs
    • dynamodb:* → Todas las operaciones (⚠️ peligroso)

4. Resource

"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/users"
  • ARN (Amazon Resource Name) = Dirección única del recurso
  • Puede usar wildcards: *

🛡️ Least Privilege: La Regla de Oro

“Da solo los permisos que necesitas, NADA más.”

El Desastre: Permisos Excesivos

{
  "Effect": "Allow",
  "Action": "dynamodb:*",
  "Resource": "*"
}

Traducción: “Lambda puede hacer CUALQUIER COSA en CUALQUIER tabla”

¿Qué puede salir mal?

Si hackean tu Lambda:
✓ Borrar TODAS las tablas
✓ Crear 1000 tablas nuevas → $$$
✓ Leer datos de pagos, usuarios, admin
✓ Modificar datos críticos
✓ Exportar TODO a un bucket externo

Tiempo para detectarlo: 2-7 días
Daño: Irreversible en muchos casos

La Salvación: Least Privilege

{
  "Effect": "Allow",
  "Action": [
    "dynamodb:GetItem",
    "dynamodb:PutItem"
  ],
  "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/auth-sessions"
}

Traducción: “Lambda puede SOLO leer y escribir en la tabla ‘auth-sessions'”

Si hackean tu Lambda:

Daño limitado:
✓ Solo pueden leer/escribir en 1 tabla
✗ NO pueden borrar la tabla
✗ NO pueden acceder a otras tablas
✗ NO pueden crear recursos nuevos

Impacto: Contenido y reversible
Tiempo de recuperación: Horas, no semanas

Comparación Visual

❌ Permisos Excesivos = Dar llaves del edificio completo
✅ Least Privilege = Dar llave de UNA oficina específica

🔑 Trust Relationships: El Paso Olvidado

¿Qué es un Trust Relationship?

Define QUIÉN puede usar (asumir) un rol.

Analogía: El rol es un chaleco con permisos. El trust relationship dice quién puede ponerse ese chaleco.

Trust Policy

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Service": "lambda.amazonaws.com"
    },
    "Action": "sts:AssumeRole"
  }]
}

Traducción: “Solo Lambda puede ponerse este chaleco”

¿Qué Pasa Sin Trust Relationship?

Error: The role defined for the function 
cannot be assumed by Lambda.

Traducción: "Lambda no puede usar este rol"

Secuencia correcta:

1. Trust Relationship ✓
   ↓
2. ¿Lambda puede asumir el rol? → SÍ
   ↓
3. Permisos del rol se activan
   ↓
4. Lambda ejecuta con esos permisos

Sin trust relationship:

1. Intentas asignar rol a Lambda
   ↓
2. AWS rechaza: "Lambda no está en la lista de confianza"
   ↓
3. ERROR

💾 DynamoDB: Base de Datos Serverless

¿Por Qué DynamoDB?

Tradicional (RDS):

- Tienes que provisionar servidores
- Pagas 24/7 aunque no uses
- Escalado manual
- Backups manuales
Costo mínimo: ~$15/mes

DynamoDB:

- Sin servidores (serverless)
- Pagas SOLO por uso
- Escala automáticamente
- Backups automáticos
Costo mínimo: $0.00

Billing Modes

On-Demand (Recomendado para empezar)

billing_mode = "PAY_PER_REQUEST"
  • Pagas por operación (~$1.25 por millón)
  • Escalado automático infinito
  • Ideal para: Dev, tráfico variable

Ejemplo de costo:

10,000 lecturas/día × 30 días = 300,000 ops/mes
Costo: 300,000 ÷ 1,000,000 × $1.25 = $0.375/mes

Provisioned (Para producción estable)

billing_mode = "PROVISIONED"
read_capacity_units  = 5
write_capacity_units = 5
  • Pagas por capacidad reservada
  • Más económico si el tráfico es predecible
  • Requiere planificación

TTL: Auto-Limpieza Gratis

ttl {
  attribute_name = "expires_at"
  enabled        = true
}

Uso: Sesiones, cachés, datos temporales

Ejemplo:

{
  "session_id": "abc-123",
  "expires_at": 1735689600  // Unix timestamp
}

DynamoDB borra automáticamente este item después de esa fecha. Gratis.

💻 Implementación: El Código que Importa

Estructura

terraform/
├── variables.tf   (variables globales)
├── iam.tf         (roles y policies) ⭐
├── dynamodb.tf    (tabla)
└── outputs.tf     (outputs)

IAM Role + Policies

# Rol para Lambda
resource "aws_iam_role" "lambda_execution" {
  name = "go-hexagonal-auth-dev-lambda-role"

  # Trust Relationship: Solo Lambda
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
      Action = "sts:AssumeRole"
    }]
  })
}

# Policy para DynamoDB (Least Privilege)
resource "aws_iam_policy" "lambda_dynamodb" {
  name = "lambda-dynamodb-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem"
      ]
      # Solo esta tabla específica
      Resource = aws_dynamodb_table.auth_sessions.arn
    }]
  })
}

# Asociar policy al rol
resource "aws_iam_role_policy_attachment" "lambda_dynamodb" {
  role       = aws_iam_role.lambda_execution.name
  policy_arn = aws_iam_policy.lambda_dynamodb.arn
}

DynamoDB Table

resource "aws_dynamodb_table" "auth_sessions" {
  name         = "auth-sessions"
  billing_mode = "PAY_PER_REQUEST"  # Pay-per-use
  hash_key     = "session_id"

  attribute {
    name = "session_id"
    type = "S"  # String
  }

  # Auto-eliminar sesiones expiradas
  ttl {
    attribute_name = "expires_at"
    enabled        = true
  }

  # Encryption habilitada por defecto
  server_side_encryption {
    enabled = true
  }
}

Ejecución

# 1. Exportar variables
export TF_VAR_aws_account_id=$(aws sts get-caller-identity --query Account --output text)

# 2. Aplicar
cd terraform
terraform init
terraform apply

Recursos creados: 6

  • 1 IAM Role
  • 2 IAM Policies (DynamoDB + Logs)
  • 2 Policy Attachments
  • 1 DynamoDB Table

🧪 Testing: Verificar que Funciona

Test 1: Insertar Sesión

# Crear sesión
aws dynamodb put-item 
  --table-name auth-sessions 
  --item '{
    "session_id": {"S": "test-123"},
    "user_id": {"S": "user-456"},
    "expires_at": {"N": "1735689600"}
  }'

# Leer sesión
aws dynamodb get-item 
  --table-name auth-sessions 
  --key '{"session_id": {"S": "test-123"}}'

Test 2: Verificar Trust Relationship

aws iam get-role 
  --role-name go-hexagonal-auth-dev-lambda-role 
  --query 'Role.AssumeRolePolicyDocument'

Debe mostrar Lambda en “Principal”.

🆘 Troubleshooting: Problemas Comunes

“Tabla no aparece en Console”

Problema: Console en región incorrecta

Solución:

  1. AWS Console → Arriba derecha
  2. Cambiar región a US East (N. Virginia)
  3. Refrescar

“Put-Item no inserta datos”

Problema: JSON mal formateado en archivo

Solución: Usar sintaxis inline

aws dynamodb put-item 
  --table-name auth-sessions 
  --item '{"session_id": {"S": "test"}}'

💰 Costos Reales

Recurso Costo
IAM Role + Policies $0.00 (gratis)
DynamoDB (sin uso) $0.00
DynamoDB (1M ops/mes) ~$0.25

Total con uso ligero: < $0.50/mes

🎓 Lo Que Aprendiste

  • ✅ IAM Roles vs Users (y cuándo usar cada uno)
  • ✅ Policies con Least Privilege (no “todo para todos”)
  • ✅ Trust Relationships (prerequisito olvidado)
  • ✅ DynamoDB serverless (pay-per-use)
  • ✅ TTL para auto-limpieza (gratis)
  • ✅ Todo con Terraform (reproducible)

🚀 Próximos Pasos

Módulo 3: Lambda Functions con Go

Vamos a crear:

  • Lambda function en Go
  • Compilar para AWS (ARM64)
  • Deploy con Terraform
  • API Gateway
  • Testing end-to-end

📦 Código Completo

Todo el código está en GitHub:

GitHub logo

edgar-macias-se
/
aws_road

Learn aws in a secured way and with the best practices

🚀 AWS Engineering Repository

Author: Edgar Macías — Senior Software Engineer & AppSec Advocate

Este repositorio documenta y consolida mi proceso profesional de adopción, dominio y aplicación de Amazon Web Services (AWS) desde la perspectiva de un ingeniero de software sénior, con enfoque en:

  • Arquitectura moderna
  • Seguridad desde el diseño (Security by Design)
  • Infraestructura como código (Terraform)
  • Buenas prácticas de ingeniería en la nube
  • Desarrollo de servicios serverless (Go + AWS Lambda)
  • Gobernanza, control de costos y operación segura

El objetivo no es ser un “roadmap de aprendizaje”, sino construir un cuerpo de trabajo técnico verificable, con estándares profesionales y material que refleje la forma en que implemento, documento y despliego soluciones en AWS.

📘 Propósito del Repositorio

Este proyecto funciona como un laboratorio estructurado, donde desarrollo:

  • Componentes reales listos para producción
  • Arquitecturas modulares basadas en principios hexagonales
  • Configuración segura y reproducible de infraestructura
  • Adaptadores, servicios y…

Carpeta: terraform/

💬 Tu Turno

¿Has tenido un susto con permisos en AWS? Cuenta tu historia en los comentarios 👇

¿Preguntas sobre IAM? Pregunta, respondo todo.

🔗 Conecta

Serie: AWS Zero to Architect

Anterior: Módulo 1 – Terraform & Remote Backend

Siguiente: Módulo 3 – Lambda Functions con Go (próximamente)

💡 Tip: Si este tutorial te salvó de un error costoso, compártelo con tu equipo. El mejor seguro contra hackeos es el conocimiento.

Leave a Reply