Skip to main content

Mejorar la cobertura de los recursos en la nube para reducir la desviación de infraestructura

Escrito por
Headshot of Stephane Jourdan

Stephane Jourdan

feature iac drift purple

23 de marzo de 2022

0 minutos de lectura

Aviso de obsolescencia: detección de desviaciones en recursos administrados

La detección de desviaciones en recursos administrados, incluidos snyk iac describe --only-managed and snyk iac describe --drift, dejó de estar disponible. La fecha de fin de vida útil de la detección de desviaciones en recursos administrados es el 30 de septiembre de 2023.

Como desarrolladores, necesitamos tener la máxima visibilidad de lo que realmente se ejecuta en nuestros entornos en la nube para mantenerlos seguros. La infraestructura como código (IaC) ayuda a automatizar las infraestructuras en la nube, de modo que lo que se implementa en la nube esté bajo control y pueda auditarse fácilmente. Pero lograr y mantener una cobertura de IaC del 100 % de tu infraestructura plantea muchos desafíos.

Nuestra seguridad depende de lo que realmente está implementado y en ejecución en nuestros entornos en la nube. Y, con frecuencia, nosotros, otros equipos o algunos servicios autenticados seguimos realizando muchas acciones manuales de forma habitual. Esos cambios quedan fuera de la IaC y de las auditorías, lo que genera problemas como configuraciones incorrectas y riesgos de seguridad. Ahí es cuando la gestión de desviaciones se vuelve importante: queremos informes de los recursos que aún no están bajo control de IaC o que cambiaron por algún motivo.

En este artículo, mostraremos cómo Snyk IaC ayuda a los desarrolladores a encontrar recursos en la nube que no están bajo control de infraestructura como código (IaC) (recursos no administrados) o que se desviaron del estado esperado (recursos administrados).

Configurar el entorno

Snyk IaC te ayuda a enumerar los recursos que encuentra como recursos de Terraform, para que puedas identificar fácilmente qué parte del servicio en la nube se detectó. Por ejemplo, un único servicio de Amazon API Gateway v2 consta de al menos 12 recursos de Terraform. Con la información de detección que proporciona Snyk, podrás decidir rápidamente si revertir la modificación, importar un recurso nuevo o simplemente eliminar ese cambio.

Para seguir los pasos, puedes usar el archivo de Terraform que aparece a continuación para crear dos recursos de AWS que usaremos en el tutorial. Crea un usuario de IAM llamado "user1" con un sufijo aleatorio, una clave de acceso y una política adjunta de acceso de solo lectura.

Al momento de escribir este artículo, usamos Terraform v1.1.7 con el proveedor de AWS v3.74.2

Vuelve a usar la siguiente configuración HCL:

main.tf

resource "random_string" "prefix" {
  length  = 6
  upper   = false
  special = false
}

resource "aws_iam_user" "user1" {
  name = "user1-${random_string.prefix.result}"

  tags = {
    Name = "user1-${random_string.prefix.result}"
    manual = "true"
  }
}

resource "aws_iam_access_key" "user1" {
  user = aws_iam_user.user1.name
}

resource "aws_iam_user_policy_attachment" "user1" {
  user       = aws_iam_user.user1.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

Aplica esa configuración de Terraform:

$ terraform init
[...]
$ terraform apply
[...]

Confirma que tienes un archivo terraform.tfstate en la raíz del directorio:

$ ls -al terraform.tfstate
-rw-r--r--  1 sjourdan  staff  5049 Mar 16 18:31 terraform.tfstate

Confirma también que el usuario de IAM se haya creado correctamente en AWS.

Empezar desde cero

Empecemos por enumerar todos los recursos en la nube que no están bajo el control de Terraform:

$ snyk iac describe --only-unmanaged

Es probable que obtengas una lista enorme de recursos que no están bajo el control de Terraform. Es información muy útil, pero no muy práctica para nuestro caso. Snyk IaC incluye una forma de ignorar recursos en bloque: agrega todos los recursos encontrados al archivo de políticas .snyk.

Ignoremos todos esos recursos no administrados existentes para poder trabajar con mayor precisión en un entorno controlado, solo con los dos recursos que creamos antes:

$ snyk iac describe --only-unmanaged --json  | snyk iac update-exclude-policy

Vuelve a ejecutar el análisis para confirmar que tu entorno ahora ignora las desviaciones detectadas (más adelante tendrás tiempo de programar su importación).

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

Ahora estamos listos para empezar desde un estado limpio.

¡Generemos una desviación con IAM!

Ahora crearemos tres tipos de desviación para simular situaciones reales:

  1. Una modificación del usuario de IAM existente (que querremos revertir)

  2. La asociación manual de una nueva política de IAM (que querremos eliminar)

  3. Un usuario de IAM nuevo (que querremos incorporar)

Para hacerlo, ve a la consola de AWS para IAM.

Modifica el usuario de IAM existente agregando una etiqueta

  1. En la página de usuarios de IAM, haz clic en "user1"

  2. Haz clic en la pestaña Tags

  3. Haz clic en el botón Edit Tags

  4. Agrega una clave nueva ("environment") y un valor nuevo ("production")

  5. Haz clic en Save

Asocia una política con privilegios elevados al usuario de IAM existente

  1. En la página de usuarios de IAM, haz clic en "user1"

  2. Haz clic en la pestaña Permissions

  3. Haz clic en el botón Add permissions

  4. Haz clic en Attach existing policies directly

  5. Selecciona Administrator Access

  6. Haz clic en Next: Review

  7. Confirma haciendo clic en Add permissions

Crea otro usuario de IAM de forma manual

  1. En la página de usuarios de IAM, haz clic en el botón Add Users

  2. Escribe "user2" en el campo User name:

  3. Selecciona Access key

  4. Haz clic en el botón Next: Permissions

  5. No configures permisos ni etiquetas

  6. Haz clic en Create user (no nos interesan las credenciales que se muestran, así que puedes descartarlas).

Ahora estamos listos para abordar estos tipos de cambios manuales con la detección de desviaciones de Snyk IaC.

Desviaciones de infraestructura administrada y no administrada

Veamos ahora cómo detecta Snyk IaC esos cambios. Empecemos por los recursos que Terraform no administra en absoluto.

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Este análisis informó lo siguiente, usando la terminología de los recursos de Terraform:

  • El usuario de IAM "user2" creado manualmente, con su clave de acceso de IAM

  • La política de IAM asociada manualmente al usuario de IAM "user1", administrado por Terraform.

Ahora busquemos cambios únicamente en los recursos administrados por Terraform que se encuentran en los distintos estados de Terraform:

$ snyk iac describe –only-managed
Scanned states (1)
Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"
Found 5 resource(s)
 - 100% coverage
 - 5 resource(s) managed by Terraform
     - 1/5 resource(s) out of sync with Terraform state
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Este análisis generó un resultado muy distinto y tardó bastante más (36 s frente a 9 s del modo de análisis de recursos "no administrados").

Con este resultado, vemos que el usuario de IAM llamado "user1-84i30k", que podemos encontrar en HCL (como recurso) con el nombre "user1", tiene una etiqueta llamada "environment" cuyo valor es "production".

Plan de acción

La herramienta de detección de desviaciones de Snyk nos ayudó a encontrar cuatro diferencias inesperadas entre lo que esperábamos y la realidad. Para este artículo, supongamos que el equipo decide lo siguiente:

  • El usuario de IAM "user2" se usa en producción y debe importarse a Terraform.

  • La clave de acceso de IAM de "user2" debe rotarse por motivos de seguridad.

  • "user1" no debe ser administrador bajo ninguna circunstancia.

  • La nueva etiqueta de "user1" es necesaria para cumplir un requisito y debe importarse a Terraform.

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Un usuario de IAM

aws_iam_user

user2

No administrado

IMPORTAR

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

ROTAR

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

ELIMINAR

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

IMPORTAR

Los pipelines de implementación no son una solución

Tenemos un excelente pipeline de implementación de Terraform y, cuando se active terraform apply la próxima vez, podríamos esperar que todo vuelva a la normalidad.

En este caso, ¿qué hará Terraform? Un trabajo de implementación:

$ terraform apply
Terraform will perform the following actions:

  # aws_iam_user.user1 will be updated in-place
  ~ resource "aws_iam_user" "user1" {
        id            = "user1-84i30k"
        name          = "user1-84i30k"
      ~ tags          = {
          - "environment" = "production" -> null
            # (1 unchanged element hidden)
        }
[...]

Plan: 0 to add, 1 to change, 0 to destroy.

Terraform nunca se diseñó para detectar recursos creados o asociados manualmente, y simplemente revertirá los que se modificaron al estado original (que no es lo que queremos en esta situación).

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Un usuario de IAM

aws_iam_user

user2

No administrado

NINGUNA

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

NINGUNA

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

NINGUNA

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

REVERTIR

En ninguno de los casos obtenemos la ayuda que esperamos:

  • El usuario de IAM creado manualmente y su clave de acceso no se informan (no es útil)

  • La política Administrator asociada manualmente a un usuario administrado no se informa (no es útil)

  • La etiqueta importante que se agregó manualmente a un usuario administrado se revertirá (es perjudicial)

Para este tipo de detección y trabajo se necesita otro tipo de herramienta.

Mejorar nuestra cobertura

Empezamos con una cobertura del 50 % de los recursos no administrados:

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Mejoremos esto según el plan del equipo.

Eliminar la política de IAM de 'user1'

Empecemos por lo más urgente y sencillo: quitar la política "Administrator" del usuario de IAM administrado "user1":

  • Ve a IAM > Users > "user1"

  • Haz clic en Permissions > elimina "AdministratorAccess"

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_user:
    - user2
Found 5 resource(s)
 - 60% coverage
 - 3 resource(s) managed by Terraform
 - 2 resource(s) not managed by Terraform

Ahora cubrimos el 60 % de nuestros recursos de AWS, frente al 50 % inicial.

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Estado

Un usuario de IAM

aws_iam_user

user2

No administrado

IMPORTAR

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

ROTAR

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

ELIMINAR

*

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

AGREGAR

Sigamos.

Desbloquear el pipeline de implementación de Terraform

El pipeline está bloqueado actualmente por este cambio manual en las etiquetas de aws_iam_user.user1. Si se realiza una implementación, las etiquetas volverán a los valores de HCL. Entonces, ¿cuál es la solución? Usar el resultado de detección de desviaciones de Snyk IaC para adaptar nuestra configuración de Terraform.

Tenemos la siguiente información:

Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"

Con este resultado, sabemos que:

  • Buscamos un recurso llamado "user1" de tipo aws_iam_user

  • Ese recurso se encuentra en terraform.tfstate (muy práctico cuando tienes decenas o cientos de estados)

  • Hay una nueva clave de etiqueta llamada environment con el valor "production".

Actualicemos nuestro recurso de usuario de IAM simplemente agregando environment = "production", para que ahora se vea así:

resource "aws_iam_user" "user1" {
 name = "user1-${random_string.prefix.result}"

 tags = {
   Name = "user1-${random_string.prefix.result}"
   environment = "production"
 }
}

Ahora podemos desbloquear de forma segura nuestro pipeline de implementación de Terraform:

$ terraform apply
No changes. Your infrastructure matches the configuration.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Por ahora, corregimos nuestras desviaciones "administradas":

$ snyk iac describe --only-managed
Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Estado

Un usuario de IAM

aws_iam_user

user2

No administrado

IMPORTAR

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

ROTAR

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

ELIMINAR

*

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

AGREGAR

*

Importar y rotar user2 de IAM

Ahora abordemos el caso de "user2". Queremos:

  • Importarlo a Terraform

  • Rotar la clave

Empecemos por importar el usuario de IAM a Terraform. Esta es una forma sencilla de hacerlo.

Primero, recopila la información de Snyk IaC:

Tipo de recurso

Nombre

aws_iam_user

user2

¿Cómo importamos un aws_iam_user resource? Según la documentación oficial de Terraform: Los usuarios de IAM se pueden importar usando elnombre, por ejemplo, $ terraform import aws_iam_user.lb loadbalancer.

También podemos leer que el único argumento obligatorio es name. Así que agreguemos esta estructura básica a nuestro archivo HCL:

resource "aws_iam_user" "user2" {
 name = "user2" # required
}

Ahora importemos este usuario a Terraform:

$ terraform import aws_iam_user.user2 user2
aws_iam_user.user2: Importing from ID "user2"...
aws_iam_user.user2: Import prepared!
  Prepared aws_iam_user for import
aws_iam_user.user2: Refreshing state... [id=user2]

Import successful!

¿Cómo evolucionó nuestra cobertura? Veámoslo:

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
Found 5 resource(s)
 - 80% coverage
 - 4 resource(s) managed by Terraform
 - 1 resource(s) not managed by Terraform

Ahora tenemos una cobertura del 80 % (frente al 60 %) y solo queda un recurso.

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Estado

Un usuario de IAM

aws_iam_user

user2

No administrado

IMPORTAR

*

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

ROTAR

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

ELIMINAR

*

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

AGREGAR

*

Rotar la clave

Abordemos esto ahora. Sabemos que queremos rotar la clave y agregarla a Terraform. Empecemos por agregar la clave nueva a HCL para crearla (por ejemplo, para compartirla con el equipo correspondiente) y, por último, simplemente eliminaremos la anterior de AWS.

La documentación de Terraform para aws_iam_access_key es muy clara, así que podemos crear simplemente un recurso que tome como argumento el nombre de user2:

resource "aws_iam_access_key" "user2" {
 user = aws_iam_user.user2.name
}

Como el pipeline de implementación ya está desbloqueado, podemos aplicar esto de forma segura con Terraform para crear una clave nueva:

$ terraform apply 
[...]
Terraform will perform the following actions:

  # aws_iam_access_key.user2 will be created
  + resource "aws_iam_access_key" "user2" {
      + create_date          = (known after apply)
      + encrypted_secret     = (known after apply)
      + id                   = (known after apply)
      + key_fingerprint      = (known after apply)
      + secret               = (sensitive value)
      + ses_smtp_password_v4 = (sensitive value)
      + status               = "Active"
      + user                 = "user2"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

aws_iam_access_key.user2: Creating...
aws_iam_access_key.user2: Creation complete after 1s [id=AKIASBXWQ3AY4KPUNIHZ]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Aún tenemos que eliminar la clave anterior. Según la información del resultado de Snyk IaC, el nombre de la clave es AKIASBXWQ3AYQETE6OFR.

La forma más sencilla de quitar esta clave es:

  • Ve a IAM > Users > user2 > Security Credentials

  • Quita la clave llamada AKIASBXWQ3AYQETE6OFR, que Snyk IaC informó, desactivándola y luego eliminándola.

¿Cómo está nuestra cobertura ahora?

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found 5 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

¡Felicitaciones! Todo volvió a estar bajo control gracias a la detección de desviaciones de Snyk IaC.

Qué

Tipo de recurso

Nombre

Tipo de desviación

Acción

Estado

Un usuario de IAM

aws_iam_user

user2

No administrado

IMPORTAR

*

Una clave de acceso de IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

No administrado

ROTAR

*

Una política de IAM asociada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

No administrado

ELIMINAR

*

Una etiqueta en un usuario de IAM

aws_iam_user

tags.environment

Administrado

AGREGAR

*

Conclusión

En este artículo, mostramos cómo la detección de desviaciones de Snyk IaC puede ayudar a encontrar recursos de AWS creados manualmente y cómo informa todo en términos de Terraform, con la información adecuada para que los desarrolladores importen esos recursos a su código HCL de Terraform. También vimos brevemente que revertir los cambios de forma automática quizá no siempre sea lo más conveniente y que se necesita un sistema ligero de alertas de detección de desviaciones junto con el pipeline de implementación.

Creemos firmemente que toda la infraestructura debe estar definida en código para que los ingenieros puedan obtener comentarios de seguridad y visibilidad de los problemas lo antes posible.

Por eso, Snyk IaC puede ayudar a los equipos a volver a integrar rápidamente en el código de Terraform todos los recursos que realmente se están ejecutando en su cuenta de AWS, para aumentar la cobertura general de IaC y reducir los problemas de seguridad. Snyk IaC permite corregir problemas más rápido al cerrar el ciclo de retroalimentación entre los equipos de seguridad en la nube y de ingeniería, y comunicar a los ingenieros soluciones prácticas en términos que les resulten familiares.

Protege la infraestructura desde el origen

Snyk automatiza la seguridad y el cumplimiento de IaC en los flujos de trabajo, y detecta recursos con desviaciones de configuración y recursos faltantes.