AWS básico: Región, IAM y servicios principales

1. Descripción general

Este artículo te ayuda a comprender rápidamente los tres pilares más importantes cuando comienzas con AWS: región (dónde ubicar tu infraestructura), IAM (quién puede hacer qué) y los servicios principales (EC2, S3, RDS, Lambda, VPC…). Cuando termines, entenderás cómo organizar tu cuenta AWS de forma segura, cómo crear roles de IAM para tus aplicaciones, y podrás escribir código Java que llame a S3 usando AWS SDK v2.

2. Región y Zona de disponibilidad

AWS divide su infraestructura en regiones (áreas geográficas, por ejemplo ap-southeast-1 en Singapur) y cada región contiene múltiples Zonas de disponibilidad (AZ) — data centers independientes en términos de energía y red, ubicados cerca entre sí para baja latencia pero con aislamiento de fallos (fault isolation).

aws ec2 describe-availability-zones --region ap-southeast-1

El comando anterior lista las AZ en la región de Singapur. El resultado típicamente se ve así:

ZoneName: ap-southeast-1a
ZoneName: ap-southeast-1b
ZoneName: ap-southeast-1c

Al diseñar tu sistema, debes desplegar en al menos 2 AZ para tolerancia a fallos (alta disponibilidad). Por ejemplo, un Auto Scaling Group o una instancia RDS Multi-AZ se basan en este principio.

Nota: Algunos servicios son globales (no están vinculados a una región específica) como IAM, Route 53, CloudFront. La mayoría de los servicios restantes (EC2, S3, RDS…) son regionales, los datos no se replican automáticamente a otras regiones a menos que lo configures.

2.1. Cómo elegir una región

Tres criterios principales: latencia (cercanía a los usuarios), cumplimiento (requisitos de residencia de datos), y costo (los precios varían entre regiones). Para usuarios en Vietnam, ap-southeast-1 (Singapur) suele ser la opción predeterminada debido a la baja latencia y disponibilidad completa de servicios.

3. IAM: Usuario, Grupo, Role, Política

IAM (Identity and Access Management) controla quién puede acceder a qué recursos. Cuatro conceptos clave:

  • Usuario: una identidad específica (persona o servicio) con credenciales propias.
  • Grupo: un conjunto de usuarios, con políticas comunes asignadas para facilitar la gestión.
  • Role: un conjunto de permisos temporales, sin credenciales fijas — se usa para EC2, Lambda, o acceso entre cuentas.
  • Política: un documento JSON que describe permisos (permitir/denegar) sobre acciones y recursos.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::order-invoices-bucket/*"
    }
  ]
}

Esta política permite leer/escribir objetos en el bucket order-invoices-bucket. Asigna la política a un role y luego adjunta ese role a una instancia EC2 o función Lambda que ejecute el servicio InvoiceStorageService — la aplicación tendrá automáticamente los permisos sin necesidad de hard-codear access key/secret key.

aws iam create-role \
  --role-name InvoiceServiceRole \
  --assume-role-policy-document file://trust-policy.json

aws iam attach-role-policy \
  --role-name InvoiceServiceRole \
  --policy-arn arn:aws:iam::123456789012:policy/InvoiceBucketAccess

El primer comando crea un role con trust-policy.json que define quién puede “asumir” este role (por ejemplo, el servicio EC2). El segundo comando adjunta una política de permisos específicos al role.

Nota: Nunca incrustes access key/secret key directamente en el código o los commits a Git. Usa IAM Role (para recursos ejecutándose en AWS) o IAM Identity Center/SSO (para usuarios).

3.1. Principio de mínimo privilegio

Concede solo los permisos necesarios, no uses la política AdministratorAccess para cuentas de servicio. Por ejemplo, si una Lambda solo necesita leer un bucket, no deberías otorgar s3:* en toda la cuenta.

{
  "Effect": "Deny",
  "Action": "s3:DeleteBucket",
  "Resource": "*"
}

La declaración Deny siempre tiene prioridad sobre Allow en caso de conflicto — esta es la forma de añadir una “red de seguridad” contra borrados accidentales de buckets importantes.

4. Servicios principales

4.1. Computación

  • EC2: máquinas virtuales por horas/segundos, tú gestionas el SO.
  • Lambda: ejecuta código basado en eventos (event-driven), sin gestión de servidores, facturación por invocaciones y tiempo de ejecución.
  • ECS/EKS: ejecuta contenedores (Docker) con orquestación.
aws lambda invoke \
  --function-name CalculateOrderTotal \
  --payload '{"orderId":"ORD-1001"}' \
  response.json

Este comando invoca la función CalculateOrderTotal con un payload JSON, el resultado se escribe en response.json.

4.2. Almacenamiento

  • S3: almacenamiento de objetos, almacena cualquier archivo (imágenes, logs, backups), con durabilidad del 99.999999999%.
  • EBS: volúmenes de bloque adjuntos a EC2.
  • EFS: sistema de archivos compartido que múltiples EC2 pueden montar.

4.3. Base de datos

  • RDS: base de datos relacional gestionada (MySQL, PostgreSQL…), respaldo y parches automáticos.
  • DynamoDB: NoSQL, escalado horizontal automático, latencia de un dígito en milisegundos.

4.4. Red

  • VPC: red privada virtual, defines subnets, tablas de rutas, grupos de seguridad.
  • Security Group: firewall con estado a nivel de instancia.
Resources:
  OrderServiceSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTPS inbound
      VpcId: vpc-0123456789abcdef0
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

Este fragmento de CloudFormation crea un Security Group llamado OrderServiceSG, que solo abre el puerto 443 (HTTPS) a todas las IPs — el resto de reglas de entrada se niegan por defecto.

5. Llamar a S3 desde una aplicación Java

Esta sección ilustra cómo un servicio Spring Boot carga un archivo a S3 usando AWS SDK for Java v2.

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.16</version>
</dependency>
public class InvoiceStorageService {

    private final S3Client s3Client;
    private final String bucketName;

    public InvoiceStorageService(S3Client s3Client, String bucketName) {
        this.s3Client = s3Client;
        this.bucketName = bucketName;
    }

    public void uploadInvoice(String orderId, byte[] content) {
        PutObjectRequest request = PutObjectRequest.builder()
                .bucket(bucketName)
                .key("invoices/" + orderId + ".pdf")
                .build();

        s3Client.putObject(request, RequestBody.fromBytes(content));
    }
}

S3Client se inyecta a través del constructor (obtiene credenciales automáticamente del IAM Role si se ejecuta en EC2/Lambda, sin necesidad de hard-code). El método uploadInvoice crea PutObjectRequest con key como la ruta del objeto en el bucket, luego llama a putObject para subir el contenido a S3.

Configuración del bean S3Client:

@Bean
public S3Client s3Client() {
    return S3Client.builder()
            .region(Region.AP_SOUTHEAST_1)
            .build();
}

No necesitas pasar credentialsProvider explícitamente — el SDK usa automáticamente la Cadena de Proveedores de Credenciales Predeterminada: busca en orden en variables de entorno, archivo ~/.aws/credentials, luego el IAM Role asociado con EC2/ECS/Lambda.

5.1. Test con mock S3Client

@Test
void shouldCallPutObjectWithCorrectKey() {
    S3Client mockS3 = mock(S3Client.class);
    InvoiceStorageService service = new InvoiceStorageService(mockS3, "order-invoices-bucket");

    service.uploadInvoice("ORD-1001", "contenido de factura".getBytes());

    ArgumentCaptor<PutObjectRequest> captor = ArgumentCaptor.forClass(PutObjectRequest.class);
    verify(mockS3).putObject(captor.capture(), any(RequestBody.class));

    assertThat(captor.getValue().bucket()).isEqualTo("order-invoices-bucket");
    assertThat(captor.getValue().key()).isEqualTo("invoices/ORD-1001.pdf");
}

Test mock S3Client (usando Mockito) para no llamar a AWS real durante CI. ArgumentCaptor captura PutObjectRequest real que se envía, luego AssertJ verifica que bucket y key sean correctos como se espera — asegura que la lógica de construcción de solicitudes sea correcta sin gastar costo de red.

Nota: Si quieres hacer pruebas de integración reales con S3, usa la librería LocalStack o Testcontainers en lugar de llamar al bucket real en producción — evita gastos innecesarios y riesgos de datos.

6. Errores comunes

  • Dejar un bucket S3 público sin intención: siempre habilita “Block Public Access” a nivel de cuenta a menos que realmente necesites un bucket público (por ejemplo, sitio web estático).
  • Adjuntar políticas muy amplias ("Action": "*", "Resource": "*") a un role de prueba y luego olvidar quitarlas en producción.
  • No habilitar MFA en la cuenta raíz: la cuenta raíz tiene permisos completos, perder acceso raíz es el riesgo más crítico.
  • Hard-codear access key en el código: deberías usar IAM Role, Secrets Manager, o variables de entorno a través de secretos de CI/CD.
  • Elegir la región incorrecta resultando en alta latencia para usuarios finales, o incumplimiento de requisitos de residencia de datos.

7. Conclusión

La región te ayuda a elegir la ubicación correcta de la infraestructura equilibrando latencia, costo y cumplimiento. IAM es la primera y más importante capa de protección — siempre aplica mínimo privilegio y prefiere Roles sobre access keys estáticas. Dominar los servicios principales (EC2, S3, RDS, Lambda, VPC) y cómo integrarlos a través de AWS SDK es suficiente para que comiences a desplegar un sistema real en AWS.

awscloudiamdevopsjava