Asegurar el acceso de Jenkins a AWS (part I)

 In aws, DevOps, Security

Jenkins es un servidor de automatización de código abierto para acelerar el proceso de entrega de software y se ha convertido de facto en el motor DevOps, especialmente por sus canales de Jenkinsfile con secuencias de comandos comprometidos con el control del código fuente. Para cumplir su función, Jenkins necesita interactuar con algunos sistemas externos, como GitHub o, la razón de este artículo, Amazon Web Services (AWS).

Una forma de otorgar acceso a Jenkins a AWS es ejecutarlo en una instancia EC2 con una función de IAM adjunta. Este enfoque tiene algunas ventajas:

  • Es muy fácil de configurar (incluso puedes encontrarlo en AWS Marketplace)
  • No se utilizan claves de acceso, por lo que nunca se expondrán esas claves.

Pero también algunas desventajas:

  • No se puede ejecutar Jenkins fuera de AWS
  • El rol IAM adjunto debe tener todos los permisos que los jobs puedan necesitar (¿cuántos servidores Jenkins terminan con PowerUserAccess?)
  • Todas las acciones / eventos realizados desde Jenkins tendrán el mismo nombre de usuario en CloudTrail, independientemente de quién ejecutó el job.

Si, en tu caso, las desventajas superan las ventajas puedes optar por adoptar otra estrategia.

Paso 1: Crear usuarios y roles de IAM

Crea un usuario de IAM para cada usuario de Jenkins que necesite ejecutar jobs relacionados con AWS. El nombre de usuario de IAM debe ser similar al nombre de usuario de Jenkins (si puede ser el mismo, mejor) y solo debe adjuntarse a la siguiente política (más sobre esto más adelante):

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Effect": "Allow",
   "Action": "sts:AssumeRole",
   "Resource": "*"
  }
 ]
}

Crea roles de IAM (el número y los permisos adjuntos dependerán de sus necesidades: administrador, desarrollador, sre, solo lectura, …) y edita la relación de confianza para permitir que los usuarios generados previamente asuman estos roles.

Paso 2: generar claves de acceso

Creeaclaves de acceso de AWS para cada usuario y guárdalas en el servidor de Jenkins con el complemento de credenciales de AWS. Asegúrate de establecer una ID para estas credenciales que puedan vincularse fácilmente a partir del nombre de usuario (como antes, si puede ser el mismo, mejor).

Jenkins “Add Credentials” screen

Desde este punto, ya hemos resuelto todos los inconvenientes mencionados anteriormente:

  • El servidor Jenkins puede ejecutarse en cualquier lugar.
  • El proceso de Jenkins asumirá el rol con solo los permisos necesarios para ejecutar el job
  • CloudTrail mostrará el nombre del usuario que ejecuta el job.

Pero, seamos sinceros, Jenkins está lejos de ser la herramienta más segura del mundo. Entonces:

  • Un ataque podría comprometer nuestras credenciales de AWS.
  • Un usuario legítimo podría escalar sus privilegios (usando las credenciales de un usuario administrador)

¿Cómo podemos solucionar esto?

Paso 3: MFA al rescate

AWS STS proporciona API que permiten a los usuarios pasar información MFA: GetSessionToken y, lo que necesitamos, AssumeRole.

Asigna un dispositivo MFA a cada usuario y adjunta la siguiente política a cada rol (los creados en el paso 1):

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "ForceMFA",
   "Effect": "Allow",
   "Principal": {"AWS": "arn:aws:iam:::root"},
   "Action": "sts:AssumeRole",
   "Condition": {
    "StringEquals": { "aws:username": [  ] },
    "Bool": { "aws:MultiFactorAuthPresent": true }
   }
  }
 ]
}

Esta política obliga el uso de MFA al asumir el papel. De este modo, como las credenciales solo se pueden usar para asumir un rol (¿recuerdas la única política asociada a los usuarios?), Incluso si están comprometidas, un ataque podría hacer poco sin tener acceso al dispositivo MFA.

Explicaré cómo utilizar este enfoque en una pipeline de Jenkins en la próxima publicación.

Recent Posts

Leave a Comment

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.