Skip to content
Go back

Reduciendo el Riesgo de Credenciales Sin Romper la DX

Durante mucho tiempo, los servicios han dependido del modelo tradicional de autenticación username/password para conectarse a bases de datos. La mayoría de los frameworks de desarrollo funcionan muy bien con este patrón, proporcionando mecanismos integrados para leer credenciales desde variables de entorno, archivos de configuración o configuraciones a nivel de clase. Esto crea una experiencia de desarrollador simple y fluida — pero hay un trade-off: el verdadero desafío no es usar las credenciales, sino distribuirlas y protegerlas.

En nuestro caso, seguimos un enfoque común:

Esta configuración funcionaba “bien”… hasta que encontramos un error mientras operábamos a baja escala. Fue un incidente aislado:

SQLException. Message: Connect failed to authenticate: reached max connection retries

Solo con el mensaje de error no teníamos mucho contexto. Para entender qué pasó, correlacionamos eventos de CloudTrail, registros de aplicaciones y el historial de tareas de ECS para reconstruir la secuencia de eventos:

sequenceDiagram
    participant ECS as ECS Cluster
    participant Pod as Service Pod
    participant Secrets as AWS Secrets Manager
    participant RDS as Amazon RDS

    ECS->>Pod: El servicio escala por carga elevada
    
    activate Secrets
    Note over Secrets: Inicia rotación de contraseña

    loop Reintenta hasta alcanzar el máximo de intentos
        Pod->>Secrets: Obtiene credenciales
        Secrets-->>Pod: Devuelve credenciales obsoletas

        Pod->>RDS: Intenta conectar
        RDS-->>Pod: Autenticación fallida
    end
    
    Pod-->>ECS: Error en startup:<br/>máximo de reintentos alcanzado

    Note over Secrets: Finaliza la rotación:<br/>DB y secreto sincronizados
    deactivate Secrets

    ECS->>Pod: Recreación del Pod

Después de revisar la línea de tiempo, destacaron varias observaciones clave:

Dadas estas observaciones, el equipo decidió revisar el flujo de autenticación. Algunas opciones propuestas incluyeron:

Ambas eran soluciones razonables, pero se sentían como parches. Extender los intervalos de rotación debilita la postura de seguridad, mientras que reintentos más agresivos dificultan distinguir problemas de rotación de problemas reales de configuración o conectividad — especialmente a medida que crece el número de bases de datos y usuarios de aplicaciones.

Las credenciales son simples, pero nunca gratuitas

La autenticación tradicional de bases de datos tiene algunos problemas bien conocidos:

Incluso con servicios gestionados como Secrets Manager, las credenciales siguen siendo artefactos estáticos que debemos obtener, almacenar en caché y proteger.

La complejidad en nuestros sistemas es inevitable, pero dependiendo del contexto (el equipo, la arquitectura, las herramientas, etc.) podemos moverla para fortalecer algunas partes de nuestros sistemas.

La pregunta que quería responder era simple:

¿Podemos eliminar las contraseñas estáticas de base de datos con fricción mínima?

De credenciales a roles

El Control de Acceso Basado en Roles (RBAC) no es nuevo, empuja la complejidad de las credenciales a una capa inferior que las herramientas manejan de forma transparente. Es un patrón común en infraestructura, pero no ampliamente usado en desarrollo (creo que esto se debe a que en general aún hay una barrera entre equipos de infra y desarrollo, pero quizás eso sea para otro post).

En nuestro caso, la autenticación de base de datos IAM reemplaza contraseñas estáticas con tokens de autenticación de corta duración, generados bajo demanda. La complejidad se mueve de la distribución y rotación de contraseñas a la capa de IAM.

sequenceDiagram
    participant Pod as Service Pod
    participant RDS as Amazon RDS
    participant IAM

    Pod-->>Pod: Genera token IAM (SigV4)
    Pod->>RDS: Conecta usando usuario + token
    RDS->>IAM: Valida token y permisos
    IAM-->>RDS: Firma válida
    RDS-->>Pod: Conexión exitosa

Sobre el papel, ofrece:

Pero siempre hay un pero.

La preocupación común que escucho es:

Suena bien, pero ¿no es más lento o complejo?

La configuración del experimento

Construí una pequeña aplicación en Java que se conecta a RDS de dos maneras:

  1. Enfoque tradicional
  1. Autenticación IAM

El objetivo no era optimizar el rendimiento al extremo — solo observar comportamiento de conexión realista.

Midiendo el costo

Autenticación basada en secretos

Secret fetch time: 1260 ms
Connection time: 780 ms
SecretsManagerClient closed.

El overhead total se divide entre:

Autenticación basada en IAM

Token generation time: 877 ms
Connection time (JDBC connect): 760 ms
Connection closed.

Aquí, el costo se desplaza ligeramente:

Qué cambió

Desde un punto de vista de seguridad y operativo, esto fue una clara victoria para nuestro caso de uso.

Qué no cambió mucho

Esto fue importante: adoptar autenticación IAM no requirió un cambio en el modelo mental para los equipos de aplicaciones.

El impacto en el código (menor de lo esperado)

Otra preocupación es:

Esto requerirá un gran refactor.

En realidad, el cambio fue localizado:

getPropertyFromSecret(prop) {
    SecretsManagerClient smClient = SecretsManagerClient.builder().region("ap-northeast-1").credentialsProvider(DefaultCredentialsProvider.create()).build();
    GetSecretValueRequest req = GetSecretValueRequest.builder().secretId(DB_SECRET_NAME).build();
    GetSecretValueResponse resp = smClient.getSecretValue(req);
    JSONObject json = new JSONObject(resp.secretString());

    return json.getString(prop);
}

generateAuthToken() {
    RdsUtilities utilities = RdsUtilities.builder().region("ap-northeast-1").credentialsProvider(DefaultCredentialsProvider.create()).build();
    GenerateAuthenticationTokenRequest tokenRequest = GenerateAuthenticationTokenRequest.builder().hostname(DB_HOST).port(DB_PORT).username(DB_USER).build();
    
    return utilities.generateAuthenticationToken(tokenRequest);
}

// String password = getPropertyFromSecret("password");
String password = generateAuthToken();

Connection conn = DriverManager.getConnection(jdbcUrl, DB_USER, password);

La diferencia principal es de dónde viene la contraseña, no cómo funciona la conexión.

La adopción importa más que la elegancia

Desde una perspectiva puramente técnica, la autenticación IAM no es revolucionaria.

Lo que la hace valiosa es esta combinación:

Las mejoras de seguridad que son difíciles de adoptar suelen fallar.

Esta no necesita heroísmos.

Cuándo tiene sentido la autenticación IAM

Es una buena opción si:

Consejo: Para cargas de trabajo con altas conexiones o serverless, combínalo con RDS Proxy — maneja la generación y renovación de tokens de forma transparente, sin código extra.

Podría no ser ideal si:

El contexto importa.

Pensamientos finales

Este experimento no aceleró mágicamente las conexiones a la base de datos.

Ese no era el objetivo.

Lo que hizo fue eliminar toda una clase de riesgo sin hacer el sistema más difícil de operar.

Para mí, ese es el tipo de trade-off que vale la pena hacer: cambios pequeños, impacto medible y menos cosas que pueden fallar a las 3 a.m.


Share this post on:

Previous Post
DevOps comenzó cuando producción falló