Cómo mejorar la cobertura de los recursos en la nube para reducir las desviaciones de infraestructura

Stephane Jourdan
23 de marzo de 2022
0 minutos de lecturaAviso de obsolescencia: detección de desviaciones de recursos gestionados
La detección de desviaciones de recursos gestionados, que incluye snyk iac describe --only-managed and snyk iac describe --drift
, es obsoleta. La fecha de obsolescencia para la detección de desviaciones de recursos gestionados es el 30 de septiembre de 2023.
Como desarrolladores, necesitamos máxima visibilidad sobre lo que realmente se está ejecutando en los entornos de nube para poder protegerlos. La infraestructura como código (IaC) permite a los desarrolladores automatizar las infraestructuras en la nube; de este modo, lo que se implementa en la nube está bajo control y puede auditarse fácilmente. Sin embargo, alcanzar el 100 % de cobertura de IaC de la infraestructura y mantenerla es un gran desafío.
Por un lado, la seguridad que tengamos dependerá de lo que realmente se implementa y ejecuta en los entornos de nube; además, con mucha frecuencia, nosotros, otros equipos y algunos servicios autenticados siguen realizando muchas acciones manuales. Estos cambios no son visibles desde IaC ni desde las auditorías, lo que acarrea problemas, como configuraciones incorrectas y preocupaciones de seguridad. En este momento es cuando la gestión de desviaciones se vuelve importante: necesitamos informes de los recursos que aún no están bajo el control de IaC o que, por algún motivo, se modificaron.
En este artículo, veremos cómo Snyk IaC ayuda a los desarrolladores a detectar cuáles son los recursos de nube por fuera del control de la infraestructura como código (IaC), es decir, recursos no gestionados, o que se desviaron del estado esperado (recursos gestionados).
Configura el entorno
Con Snyk IaC, puedes enumerar los recursos encontrados como recursos de Terraform; de este modo, puedes saber con facilidad hacia qué parte del servicio de nube se dirige la detección. Por ejemplo, un único servicio Amazon API Gateway v2 está conformado por al menos 12 recursos de Terraform. Con la información de la detección que brinda Snyk, podrás decidir rápidamente si revertir los cambios, importar un recurso nuevo o eliminar la nueva modificación.
Para continuar, puedes usar el archivo de Terraform siguiente para crear dos recursos de AWS que usaremos en la práctica guiada. Este archivo crea un usuario de IAM denominado “user1” con un sufijo aleatorio, una clave de acceso y una política adjunta de acceso de solo lectura.
Cuando se redactó este artículo, se utilizó Terraform versión 1.1.7 con AWS versión 3.74.2
Reutiliza la siguiente configuración de HCL:
main.tf
1resource "random_string" "prefix" {
2 length = 6
3 upper = false
4 special = false
5}
6
7resource "aws_iam_user" "user1" {
8 name = "user1-${random_string.prefix.result}"
9
10 tags = {
11 Name = "user1-${random_string.prefix.result}"
12 manual = "true"
13 }
14}
15
16resource "aws_iam_access_key" "user1" {
17 user = aws_iam_user.user1.name
18}
19
20resource "aws_iam_user_policy_attachment" "user1" {
21 user = aws_iam_user.user1.name
22 policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
23}
Aplica la configuración de Terraform:
1$ terraform init
2[...]
3$ terraform apply
4[...]
Verifica que terraform.tfstate
esté en la raíz del directorio:
1$ ls -al terraform.tfstate
2-rw-r--r-- 1 sjourdan staff 5049 Mar 16 18:31 terraform.tfstate
Además, verifica que el usuario de IAM se haya creado correctamente en AWS.
Cómo empezar desde cero
En primer lugar, enumera todos los recursos de nube que no se controlan con Terraform:
1$ snyk iac describe --only-unmanaged
Es muy probable que recibas una lista enorme de recursos que no están bajo el control de Terraform. Esta información es muy útil, pero no nos sirve demasiado para nuestro caso. Snyk IaC tiene una función integrada a fin de ignorar recursos en bloque; para ello deben agregarse todos los recursos encontrados al archivo de política .snyk
.
Por ahora, ignoremos todos los recursos existentes no gestionados para poder trabajar con más precisión en un entorno controlado con los dos recursos creados más arriba:
1$ snyk iac describe --only-unmanaged --json | snyk iac update-exclude-policy
Vuelve a hacer un escaneo para confirmar que el entorno ignore, de forma activa, las desviaciones halladas; luego podrás programar su importación.
1$ snyk iac describe --only-unmanaged
2
3Scanned states (1)
4Found 3 resource(s)
5 - 100% coverage
6Congrats! Your infrastructure is fully in sync.
Ahora podemos comenzar desde cero.
Es el momento de tener desviaciones con IAM
Para simular situaciones del mundo real, crearemos tres tipos de desviaciones:
Una modificación del usuario de IAM existente (que buscaremos revertir).
La agregación manual de una nueva política de IAM (que buscaremos eliminar).
Un nuevo usuario de IAM (que buscaremos mejorar).
Para ello, ve a la Consola de AWS para IAM.
Modifica el usuario de IAM existente con una etiqueta
En la página de usuarios de IAM, haz clic en “user1”.
Haz clic en la pestaña Tags (Etiquetas).
Haz clic en el botón Edit Tags (Editar etiquetas).
Agrega una nueva clave (“environment”) y un nuevo valor (“production”).
Haz clic en Save (Guardar).
Adjunta una política importante al usuario de IAM existente
En la página de usuarios de IAM, haz clic en “user1”.
Haz clic en la pestaña Permissions (Permisos).
Haz clic en el botón Add permissions (Agregar permisos).
Haz clic en Attach existing policies directly (Adjuntar políticas existentes directamente).
Selecciona Administrator Access (Acceso de administrador).
Haz clic en Next: Review (Siguiente: revisar).
Haz clic en Add permissions (Agregar permisos) para validar la acción.
Crea otro usuario de IAM de forma manual
En la página de usuarios de IAM, haz clic en el botón Add Users (Agregar usuarios).
En el campo User name: (Nombre de usuario), escribe “user2”.
Selecciona Access key (Clave de acceso).
Haz clic en el botón Next: Permissions (Siguiente: permisos).
No configures ningún permiso o etiqueta.
Haz clic en Create user (Crear usuario). En este momento, no nos preocuparemos por las credenciales que se muestran; puedes desestimarlas.
Ahora podemos abordar estos cambios manuales con la detección de desviaciones de Snyk IaC.
Desviaciones de infraestructura gestionada y no gestionada
Es hora de buscar cómo Snyk IaC detecta los cambios. En primer lugar, veremos los recursos que no gestiona Terraform.
1$ snyk iac describe --only-unmanaged
2
3Scanned states (1)
4Found resources not covered by IaC:
5 aws_iam_access_key:
6 - AKIASBXWQ3AYQETE6OFR
7 User: user2
8 aws_iam_policy_attachment:
9 - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
10 aws_iam_user:
11 - user2
12Found 6 resource(s)
13 - 50% coverage
14 - 3 resource(s) managed by Terraform
15 - 3 resource(s) not managed by Terraform
16 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Luego del escaneo, recibimos la siguiente información (en términos de recursos de Terraform):
El usuario de IAM “user2” creado manualmente, con su clave de acceso de IAM.
La política de IAM adjuntada manualmente al usuario de IAM “user1” gestionado en Terraform.
Ahora veamos los cambios hallados solo en recursos gestionados en Terraform, en los diversos estados de Terraform.
1$ snyk iac describe –only-managed
2Scanned states (1)
3Found changed resources:
4 From tfstate://terraform.tfstate
5 - user1-84i30k (aws_iam_user.user1):
6 + tags.environment: <nil> => "production"
7Found 5 resource(s)
8 - 100% coverage
9 - 5 resource(s) managed by Terraform
10 - 1/5 resource(s) out of sync with Terraform state
11 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Con este escaneo, el resultado es completamente diferente y llevó mucho más tiempo (36 segundos en lugar de 9 segundos para el modo de escaneo sobre recursos no gestionados).
Con este resultado, vemos que el usuario de IAM “user1-84i30k”, que podemos encontrar en HCL (como recurso) con el nombre “user1”, tiene una etiqueta “environment” con el valor “production”.
Plan de acción
La herramienta de detección de desviaciones de Snyk nos permitió encontrar cuatro diferencias inesperadas entre las expectativas que teníamos y lo que sucede en realidad. Solo a modo de ejemplo para este artículo, consideremos que el equipo decide lo siguiente:
El usuario de IAM “user2” se usa en producción y debería importarse en Terraform.
La clave de acceso de IAM de “user2” debería rotarse por cuestiones de seguridad.
El usuario “user1” no puede ser administrador.
La etiqueta nueva de “user1” es necesaria según un requisito y debería importarse en Terraform.
Qué | Tipo de recurso | Nombre | Tipo de desviación | Acción |
---|---|---|---|---|
Un usuario de IAM |
|
| No gestionada | IMPORTAR |
Una clave de acceso de IAM |
|
| No gestionada | ROTAR |
Una política de IAM adjunta |
|
| No gestionada | ELIMINAR |
Una etiqueta en un usuario de IAM |
|
| Gestionada | IMPORTAR |
Los pipelines de implementación no son un remedio
El pipeline de implementación en Terraform es perfecto y, la próxima vez que se aplique terraform apply
, esperamos que todo vuelva a la normalidad.
En este caso, ¿qué es lo que hará Terraform? Una tarea de implementación:
1$ terraform apply
2Terraform will perform the following actions:
3
4 # aws_iam_user.user1 will be updated in-place
5 ~ resource "aws_iam_user" "user1" {
6 id = "user1-84i30k"
7 name = "user1-84i30k"
8 ~ tags = {
9 - "environment" = "production" -> null
10 # (1 unchanged element hidden)
11 }
12[...]
13
14Plan: 0 to add, 1 to change, 0 to destroy.
Terraform no se creó para descubrir recursos adjuntados o creados manualmente, y simplemente revertirá los modificados a su estado original (que, en este caso, no es lo que buscamos).
Qué | Tipo de recurso | Nombre | Tipo de desviación | Acción |
---|---|---|---|---|
Un usuario de IAM |
|
| No gestionada | NINGUNA |
Una clave de acceso de IAM |
|
| No gestionada | NINGUNA |
Una política de IAM adjunta |
|
| No gestionada | NINGUNA |
Una etiqueta en un usuario de IAM |
|
| Gestionada | REVERTIR |
En ninguno de estos casos recibimos la ayuda que esperamos:
El usuario de IAM creado manualmente y la clave de acceso no se informan. Esto no sirve.
La política de administrador adjuntada manualmente a un usuario gestionado no se informa. Esto no sirve.
La etiqueta importante agregada manualmente a un usuario gestionado se revertirá. Esto es peligroso.
Para este trabajo y esta tarea de detección, se necesita otra clase de herramienta.
Cómo mejorar la cobertura
Comenzamos con una cobertura del 50 % sobre los recursos no gestionados:
1$ snyk iac describe --only-unmanaged
2
3Scanned states (1)
4Found resources not covered by IaC:
5 aws_iam_access_key:
6 - AKIASBXWQ3AYQETE6OFR
7 User: user2
8 aws_iam_policy_attachment:
9 - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
10 aws_iam_user:
11 - user2
12Found 6 resource(s)
13 - 50% coverage
14 - 3 resource(s) managed by Terraform
15 - 3 resource(s) not managed by Terraform
16 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Mejoremos esto según la planificación del equipo.
Eliminar la política de IAM de “user1”
Empecemos por la tarea más urgente y sencilla: eliminar la política “Administrator” para el usuario de IAM gestionado “user1”:
Ve a IAM > Users (Usuarios) > “user1”.
Haz clic en Permissions (Permisos) y elimina “AdministratorAccess”.
1$ snyk iac describe --only-unmanaged
2Scanned states (1)
3Found resources not covered by IaC:
4 aws_iam_access_key:
5 - AKIASBXWQ3AYQETE6OFR
6 User: user2
7 aws_iam_user:
8 - user2
9Found 5 resource(s)
10 - 60% coverage
11 - 3 resource(s) managed by Terraform
12 - 2 resource(s) not managed by Terraform
Ahora la cobertura de los recursos de AWS es del 60 %, habiendo partido del 50 %.
Qué | Tipo de recurso | Nombre | Tipo de desviación | Acción | Estado |
---|---|---|---|---|---|
Un usuario de IAM |
|
| No gestionada | IMPORTAR | |
Una clave de acceso de IAM |
|
| No gestionada | ROTAR | |
Una política de IAM adjunta |
|
| No gestionada | ELIMINAR | * |
Una etiqueta en un usuario de IAM |
|
| Gestionada | AGREGAR |
Continuemos.
Desbloquear el pipeline de implementación de Terraform
Actualmente, el pipeline está bloqueado con el cambio manual de las etiquetas para aws_iam_user.user1. Si ocurriera una implementación, las etiquetas se revertirían a lo que hay en HCL. Entonces, ¿cuál es la solución? Usa los resultados de las desviaciones de Snyk IaC para adaptar la configuración de Terraform.
Tenemos la siguiente información:
1Found changed resources:
2 From tfstate://terraform.tfstate
3 - user1-84i30k (aws_iam_user.user1):
4 + tags.environment: <nil> => "production"
A partir de este resultado, sabemos lo siguiente:
Estamos buscando un recurso
aws_iam_user
llamado “user1”.El recurso aparece en terraform.tfstate; esto es muy útil cuando tienes cientos de estados.
Hay una clave de etiqueta nueva
environment
con el valor “production”.
Actualicemos el recurso de usuario de IAM agregando environment = "production"
; de este modo, el recurso lucirá así:
1resource "aws_iam_user" "user1" {
2 name = "user1-${random_string.prefix.result}"
3
4 tags = {
5 Name = "user1-${random_string.prefix.result}"
6 environment = "production"
7 }
8}
Ahora podemos desbloquear de forma segura el pipeline de implementación en Terraform:
1$ terraform apply
2No changes. Your infrastructure matches the configuration.
3Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Ya corregimos las desviaciones “gestionadas”:
1$ snyk iac describe --only-managed
2Scanned states (1)
3Found 3 resource(s)
4 - 100% coverage
5Congrats! Your infrastructure is fully in sync.
Qué | Tipo de recurso | Nombre | Tipo de desviación | Acción | Estado |
---|---|---|---|---|---|
Un usuario de IAM |
|
| No gestionada | IMPORTAR | |
Una clave de acceso de IAM |
|
| No gestionada | ROTAR | |
Una política de IAM adjunta |
|
| No gestionada | ELIMINAR | * |
Una etiqueta en un usuario de IAM |
|
| Gestionada | AGREGAR | * |
Importar y rotar el usuario de IAM user2
Ahora analicemos el caso de “user2”. Necesitamos hacer lo siguiente:
Importarlo en Terraform
Rotar la clave
Para comenzar, importemos el usuario de IAM a Terraform; a continuación, detallamos una forma sencilla de hacerlo.
En primer lugar, debemos recopilar la información de Snyk IaC:
Tipo de recurso | Nombre |
---|---|
|
|
¿Cómo importamos aws_iam_user resource
? Según la documentación oficial de Terraform, “los usuarios de IAM pueden importarse con el nombre, por ejemplo,$ terraform import aws_iam_user.lb loadbalancer”
.
También podemos leer que el único argumento necesario es name
. Entonces, agreguemos esta estructura básica al archivo HCL:
1resource "aws_iam_user" "user2" {
2 name = "user2" # required
3}
Ahora debemos importar el usuario a Terraform:
1$ terraform import aws_iam_user.user2 user2
2aws_iam_user.user2: Importing from ID "user2"...
3aws_iam_user.user2: Import prepared!
4 Prepared aws_iam_user for import
5aws_iam_user.user2: Refreshing state... [id=user2]
6
7Import successful!
¿Se modificó la cobertura? Averigüémoslo:
1$ snyk iac describe --only-unmanaged
2Scanned states (1)
3Found resources not covered by IaC:
4 aws_iam_access_key:
5 - AKIASBXWQ3AYQETE6OFR
6 User: user2
7Found 5 resource(s)
8 - 80% coverage
9 - 4 resource(s) managed by Terraform
10 - 1 resource(s) not managed by Terraform
Ahora, la cobertura es del 80 % (de un 60 % anterior) y solo falta un recurso.
Qué | Tipo de recurso | Nombre | Tipo de desviación | Acción | Estado |
---|---|---|---|---|---|
Un usuario de IAM |
|
| No gestionada | IMPORTAR | * |
Una clave de acceso de IAM |
|
| No gestionada | ROTAR | |
Una política de IAM adjunta |
|
| No gestionada | ELIMINAR | * |
Una etiqueta en un usuario de IAM |
|
| Gestionada | AGREGAR | * |
Rotar la clave
Ahora, abordemos esta tarea. Sabemos que debemos rotar la clave y agregarla a Terraform. En primer lugar, debemos agregar la nueva clave al HCL para crear una clave nueva (de modo que, por ejemplo, podamos asignársela al equipo correspondiente) y, finalmente, eliminaremos de AWS la anterior.
La documentación de Terraform para aws_iam_access_key es bastante clara: podemos crear un único recurso que toma el nombre user2 como argumento:
1resource "aws_iam_access_key" "user2" {
2 user = aws_iam_user.user2.name
3}
Como habíamos desbloqueado el pipeline de implementación, podemos hacer esta acción de forma segura con Terraform para crear una clave nueva:
1$ terraform apply
2[...]
3Terraform will perform the following actions:
4
5 # aws_iam_access_key.user2 will be created
6 + resource "aws_iam_access_key" "user2" {
7 + create_date = (known after apply)
8 + encrypted_secret = (known after apply)
9 + id = (known after apply)
10 + key_fingerprint = (known after apply)
11 + secret = (sensitive value)
12 + ses_smtp_password_v4 = (sensitive value)
13 + status = "Active"
14 + user = "user2"
15 }
16
17Plan: 1 to add, 0 to change, 0 to destroy.
18
19aws_iam_access_key.user2: Creating...
20aws_iam_access_key.user2: Creation complete after 1s [id=AKIASBXWQ3AY4KPUNIHZ]
21
22Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Aún debemos eliminar la clave anterior. Con la información del resultado de Snyk IaC, sabemos que el nombre de la clave es AKIASBXWQ3AYQETE6OFR
.
Esta es la forma más sencilla de eliminar la clave:
Ve a IAM > Users (Usuarios) > user2 > Security Credentials (Credenciales de seguridad).
Elimina la clave
AKIASBXWQ3AYQETE6OFR
que informó Snyk IaC; para ello, primero desactívala y luego bórrala.
¿Y ahora de cuánto es la cobertura?
1$ snyk iac describe --only-unmanaged
2Scanned states (1)
3Found 5 resource(s)
4 - 100% coverage
5Congrats! Your infrastructure is fully in sync.
¡Felicitaciones! Ahora todo está de nuevo 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 |
|
| No gestionada | IMPORTAR | * |
Una clave de acceso de IAM |
|
| No gestionada | ROTAR | * |
Una política de IAM adjunta |
|
| No gestionada | ELIMINAR | * |
Una etiqueta en un usuario de IAM |
|
| Gestionada | AGREGAR | * |
Conclusión
En el artículo, mostramos cómo la detección de desviaciones de Snyk IaC puede ayudar a descubrir recursos de AWS creados de forma manual, cómo se informa todo en términos de Terraform con la información adecuada para ayudar a los desarrolladores a importar esos recursos en el código de HCL en Terraform. También vimos brevemente que revertir los cambios automáticamente no siempre podría generar el resultado esperado y que se necesita un sistema de alertas liviano de detección de desviaciones con el pipeline de implementación.
Creemos firmemente que toda la infraestructura debe estar en el código para que el equipo de ingeniería pueda recibir comentarios de seguridad y pueda tener visibilidad de los problemas tan pronto como sea posible.
Es por esto que Snyk IaC puede ayudar a los equipos a volver a integrar rápidamente todos los recursos que se están ejecutando en la cuenta de AWS al código de Terraform para aumentar la cobertura general de IaC y reducir los problemas de seguridad. Con Snyk IaC, las correcciones son más veloces porque se cierran los bucles de comentarios entre los equipos de ingeniería y seguridad en la nube, y las correcciones prácticas se informan directamente al equipo de ingeniería, en su idioma.
Protege la infraestructura desde la fuente
Snyk automatiza la seguridad y el cumplimiento de IaC desde los flujos de trabajo, y detecta recursos faltantes y desviados.