Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Asume un rol de AWS desde Google Cloud sin claves IAM

By Avi KeinanSep 30, 20206 min read

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

A menudo necesito acceder a recursos de AWS como S3, SQS, etc. desde una aplicación que corre en Google Cloud. Usar las access keys y secret keys se considera, con razón, una mala práctica, así que terminé creando Janus: una pequeña herramienta que te permite asumir un rol de AWS desde una instancia de Google Cloud Compute Engine con una service account.

¿Por qué Janus? Porque en la mitología romana, Janus, un dios de dos caras, era el dios de las puertas y los portales. Me pareció una buena analogía para este caso ;-)

Entonces, ¿qué es Janus, exactamente? Es un pequeño fragmento de código que puedes ejecutar en tu propia instancia de Google Cloud Compute Engine y que te permite asumir un rol de AWS sin tener que usar las claves de AWS IAM.

¿Por qué deberías usar Janus?

Supongamos que necesitas obtener un archivo privado de un bucket de S3 desde una instancia o contenedor que corre en Google Cloud. Para descargarlo, tendrás que autenticarte con AWS IAM.

Hay varias opciones de autenticación. La más segura es asociar un rol de IAM a una instancia, pero eso solo es posible con instancias EC2 (las que corren sobre infraestructura de AWS).

Cuando trabajas con una instancia en Google Cloud, las opciones se reducen, así que la mayoría termina generando access keys de AWS IAM (muchas veces con permisos más amplios de los necesarios) y dejando la clave hardcodeada.

Esto representa un riesgo de seguridad importante: que tu clave se filtre. Una vez filtrada, cualquiera que la obtenga puede entrar a tu cuenta de AWS, lo que puede derivar en una fuga de datos o en pérdidas económicas para tu empresa. El escenario más "inocente" que me ha tocado ver es el de hackers levantando servidores de minería de criptomonedas, o cifrando los datos y backups de la cuenta para luego pedir un rescate por recuperarlos.

Entonces, ¿cómo se establece una conexión segura desde GCP hacia recursos de AWS sin claves hardcodeadas?

Janus ayuda a superar estas limitaciones al permitirte asumir un rol usando una Google Web Identity en una máquina de GCP Compute Engine, de forma muy parecida a usar un rol de IAM con EC2. Janus solicita a AWS una clave temporal con una vigencia de 1 hora.

Cómo implementar Janus

Como ejemplo, voy a mostrarte cómo otorgar acceso a un bucket de AWS S3 con permisos de solo lectura, que después usaré en mi instancia de Google Compute.

  1. Inicia sesión en tu consola de GCP y elige IAM & Admin en el menú de la izquierda. Luego, haz clic en Service Accounts y después en +CREATE SERVICE ACCOUNT.

2. Ponle un nombre a tu service account y agrégale una descripción detallada (siempre es buena práctica). Después, haz clic en el botón CREATE.

3. A continuación, haz clic en la casilla Role y selecciona Service Account → Service Account Token Creator.

Una forma más rápida es escribir Token en el buscador Type to filter.

4. Aparecerá una página "Grant users access to this service account (optional)". Cuando se muestre, haz clic en DONE.

5. Haz clic en el nombre de la service account y copia el Unique ID.

6. Inicia sesión en tu cuenta de AWS y entra a IAM console Roles → Create role.

7. Como trusted entity, selecciona Web identity Google como Identity provider y pega el Unique ID de la service account de GCP en la casilla Audience. Luego, haz clic en el botón Next: Permissions.

8. Asígnale permisos al rol. Para esta demostración, vamos a usar AmazonS3ReadOnlyAccess. Haz clic en el botón Next: Tags.

9. La etapa de tags es opcional y la vamos a omitir en esta demostración. Haz clic en el botón Next: Review.

10. Asígnale un nombre y una descripción detallada al rol y haz clic en Create role.

11. El rol ya está listo para usarse. Haz clic y copia el Role ARN; lo vamos a usar en un paso posterior.

12. Vuelve a la consola de GCP y crea una nueva instancia de VM en Compute Engine.

Baja un poco hasta la sección Identity and API access y reemplaza la Compute Engine default service account por la service account que creamos en el paso 5.

13. Ahora que AWS y GCP están configurados y podemos asumir un rol de AWS desde GCP, hace falta una herramienta o algo de código que ejecute el proceso con la web identity de Google. Esa fue la motivación para crear Janus.

Janus devuelve credenciales temporales de AWS a todos los SDK de AWS compatibles y a la AWS CLI.

Para implementar Janus, basta con ejecutar los siguientes comandos como usuario root:

$ apt install python3-pip awscli
$ pip3 install boto3 requests
$ wget https://raw.githubusercontent.com/doitintl/janus/master/janus.py -O /usr/local/bin/janus
$ chmod 555 /usr/local/bin/janus

Para ejecutar Janus con el rol de IAM deseado, tendrás que indicar el AWS Role ARN que copiamos en el paso 10.

/usr/local/bin/janus arn:aws:iam::123456789012:role/s3-ro-from-gcp

14. Crea un nuevo profile en tu archivo /.aws/credentials ( es un atajo al directorio home del usuario). El SDK de AWS usa los profiles (definidos en este archivo) para completar la autenticación con AWS.

Si el archivo no existe, créalo:

$ mkdir ~/.aws
$ touch ~/.aws/credentials

Edita el archivo credentials y agrega un profile (el nombre del profile por defecto es default). Puedes tener varios profiles y, para esta demostración, vamos a crear un nuevo profile default:

credential_process = /usr/local/bin/janus arn:aws:iam::123456789012:role/s3-ro-from-gcp

15. ¡Y eso es todo! Ya puedes empezar a usar AWS desde tu instancia de GCP.

Como ejemplo, voy a copiar un archivo llamado hello.txt desde mi bucket de AWS S3 usando la AWS CLI:

¿Cómo funciona?

  • Cada vez que el SDK de AWS o la AWS CLI necesitan acceder a AWS, buscan el profile default en:

/.aws/credentials en Mac, Linux y Unix. ( es un atajo al directorio home)

o

C:\Users\USERNAME\.aws\credentials en Windows.

  • Después, ejecutan Janus con el nombre del rol de AWS que queremos asumir.
  • Janus solicita un token JWT al servidor de metadata de Compute Engine y luego asume un rol en AWS con el nombre indicado.
  • AWS valida que el token JWT coincida con la configuración del rol y devuelve una access key temporal:

  • Con esa access key temporal ya podemos acceder a AWS y llamar a las APIs en nombre del rol de AWS.

¿Cómo puedo saber qué instancia accede a mi cuenta de AWS?

Con fines de trazabilidad, Janus asume el rol con un nombre de sesión personalizado. El nombre de sesión será project-id.instance-name.

Si tienes habilitado un trail de AWS CloudTrail en tu cuenta, puedes filtrar todos los eventos AssumeRoleWithWebIdentity y dar seguimiento a cada llamada a la API que se haya hecho.

El evento contendrá:

  1. La IP de origen de la máquina de GCP.
  2. username: el unique id de la service account de GCP.
  3. El "session name" del rol de la sesión: el project id y el nombre de la instancia.
  4. El nombre del rol asumido.

Con la Access Key podemos buscar todas las acciones que ejecutó la instancia.