Terraform, mono repositorios y cumplimiento como código

Hola a todos. OTUS abrió el reclutamiento para un nuevo grupo en el curso "Plataforma de infraestructura basada en Kubernetes" , en relación con esto preparamos una traducción de material interesante sobre el tema.




Puede ser uno de los que usan Terraform para Infraestructura como Código, y se pregunta cómo usarlo de manera más productiva y segura. En general, recientemente, esto ha molestado a muchos. Todos escribimos la configuración y el código utilizando diferentes herramientas, idiomas y pasamos una cantidad considerable de tiempo haciéndolo más legible, extensible y escalable.


Tal vez el problema está en nosotros mismos?

El código escrito debería crear valor o resolver un problema, así como ser reutilizable para la deduplicación. Por lo general, este tipo de discusión termina con "Usemos módulos" . Todos usamos módulos de terraform, ¿verdad? Podría escribir muchas historias con problemas debido a la excesiva modularidad, pero esta es una historia completamente diferente, y no lo haré.


No, no lo haré. No insistas, no ... Bien, tal vez más tarde.

Existe una práctica bien conocida: etiquetar el código cuando se usan módulos para bloquear el módulo raíz, a fin de garantizar su funcionamiento incluso cuando se cambia el código del módulo. Este enfoque debería convertirse en un principio de equipo en el que los módulos apropiados se etiquetan y utilizan de manera adecuada.

... pero ¿qué pasa con las dependencias? ¿Qué pasa si tengo 120 módulos en 120 repositorios diferentes, y cambiar un módulo afecta a otros 20 módulos? ¿Significa esto que necesitamos hacer 20 + 1 solicitudes de extracción? Si el número mínimo de revisores es 2, entonces esto significa 21 x 2 = 44revisión. ¡Seriamente! Simplemente paralizamos el comando al "cambiar un módulo" y todos comenzarán a enviar memes o gifs del Señor de los Anillos, y el resto del día se perderá.


Un RP para notificar a todos, un RP para unir a todos, encadenarse y sumergirse en la oscuridad

¿Vale la pena trabajar? ¿Deberíamos reducir el número de revisores? O, tal vez, haga una excepción para los módulos y no requiera relaciones públicas si el cambio tiene un gran impacto. De Verdad? ¿Quieres caminar a ciegas en un bosque oscuro y profundo? ¿O reunirlos a todos, aburrirse y sumergirse en la oscuridad ?

No, no cambie el orden de la revisión. Si crees que trabajar con relaciones públicas es correcto, entonces cúmplelo. Si tiene tuberías inteligentes o presiona para dominar, entonces siga con este enfoque.

En este caso, el problema no es "cómo trabaja" , sino "cuál es la estructura de sus repositorios git" .



Esto es similar a lo que sentí cuando apliqué la sugerencia a continuación.

Volvamos a lo básico. ¿Cuáles son los requisitos generales para un repositorio con módulos de terraformación?

  1. Debe estar etiquetado para que no haya cambios importantes.
  2. Cualquier cambio debe poder probar.
  3. Los cambios deben pasar por una revisión mutua.

Luego sugiero lo siguiente: NO use microrepositorios para módulos de terraformación. Use un repositorio mono .

  • Puede etiquetar todo el repositorio cuando hay un cambio / requisito
  • Cualquier cambio, PR o push puede ser probado.
  • Cualquier cambio puede pasar por la revisión.


Tengo fuerza!

Ok, pero ¿cuál será la estructura de este repositorio? En los últimos cuatro años he tenido muchas fallas relacionadas con esto, y llegué a la conclusión de que un directorio separado para el módulo sería la mejor solución.


Ejemplo de estructura de directorios para un repositorio mono. ¿Ves el cambio tags_override?

Por lo tanto, un cambio de módulo que afecta a otros 20 módulos es solo 1 PR . Incluso si agrega 5 revisores a este RP, la revisión será muy rápida en comparación con los micro repositorios. Si usa Github, ¡esto es aún mejor! Puede usar CODEOWNERS para módulos que tienen mantenedores / propietarios, y cualquier cambio en estos módulos DEBE ser aprobado por este propietario.

Genial, pero ¿cómo usar dicho módulo, que se encuentra en el directorio del repositorio mono?

Fácil:

module "from_mono_repo" {
 source = "git::ssh://.../<org>/<repo>.git//<my_module_dir>"
 ...
}
module "from_mono_repo_with_tags" {
  source = "git::ssh://..../<org>/<repo>.git//<mod_dir>?ref=1.2.4"
  ...
}
module "from_micro_repo" {
  source = "git::ssh://.../<org>/<mod_repo>.git"
  ...
}
module "from_micro_repo_with_tags" {
  source = "git::ssh://.../<org>/<mod_repo>.git?ref=1.2.4"
  ...
}

¿Cuáles son las desventajas de este tipo de estructura? Bueno, si intenta probar "cada módulo" con PR / change, puede obtener 1,5 horas de canalizaciones de CI. Necesita encontrar los módulos modificados en PR. Lo hago así:

changed_modules=$(git diff --name-only $(git rev-parse origin/master) HEAD | cut -d "/" -f1 | grep ^aws- | uniq)

Hay otro inconveniente: cada vez que ejecuta "terraform init", carga todo el repositorio en el directorio .terraform. Pero nunca he tenido un problema con esto, ya que ejecuto mis tuberías en contenedores escalables de AWS CodeBuild. Si usa Jenkins y los esclavos persistentes de Jenkins, entonces puede tener este problema.


No nos hagas llorar.

Con un mono-repositorio, aún tiene todas las ventajas de los micro-repositorios, pero como beneficio adicional, reduce el costo de mantenimiento de sus módulos.

Honestamente, después de trabajar en este modo, la propuesta de usar micro repositorios para módulos de terraformación debe considerarse un delito.

Genial, ¿qué pasa con las pruebas unitarias? ¿Realmente necesitas esto? ... En general, ¿qué quiere decir exactamente con pruebas unitarias? ¿Realmente va a verificar si el recurso de AWS se creó correctamente? ¿De quién es la responsabilidad: terraform o una API que maneja la creación de recursos? Quizás deberíamos centrarnos más en las pruebas negativas y la idempotencia del código .

Para verificar la idempotencia del código, terraform proporciona un excelente parámetro llamado -detailed-exitcode. Solo corre:

> terraform plan -detailed-exitcode

Después de eso, corre terraform applyy eso es todo. Al menos, estará seguro de que su código es idempotente y no crea nuevos recursos debido a una cadena aleatoria u otra cosa.

¿Qué pasa con las pruebas negativas? ¿Qué es, en general, una prueba negativa? De hecho, esto no es muy diferente de las pruebas unitarias, pero presta atención a las situaciones negativas.

Por ejemplo, a nadie se le permite crear un depósito S3 público y sin cifrar .

Por lo tanto, en lugar de verificar si realmente se está creando un depósito S3, usted, de hecho, basándose en un conjunto de políticas, verifique si su código crea un recurso. ¿Cómo hacerlo? Terraform Enterprise proporciona una gran herramienta para esto, Sentinel .

... pero también hay alternativas de código abierto. Actualmente, hay muchas herramientas para el análisis estático del código HCL. Estas herramientas, basadas en las mejores prácticas comunes, no le permitirán hacer nada no deseado, pero qué pasa si no tiene la prueba que necesita ... o, lo que es peor, si su situación es ligeramente diferente. Por ejemplo, desea permitir que algunos cubos S3 se hagan públicos en función de ciertas condiciones, lo que, de hecho, será un error de seguridad para estas herramientas.

Aquí es donde aparece el cumplimiento de terraform. Esta herramienta no solo le permitirá escribir sus propias pruebas en las que puede determinar QUÉ quiere como política de su empresa, sino que también lo ayudará a separar la seguridad y el desarrollo moviendo la seguridad hacia la izquierda. Suena bastante controvertido, ¿verdad? No. ¿Mientras?


Logotipo de Terraform-Compliance En

primer lugar, Terraform-Compliance utiliza Behavior Driven Development (BDD).

Feature: Ensure that we have encryption everywhere.

    Scenario: Reject if an S3 bucket is not encrypted
        Given I have aws_s3_bucket defined
        Then it must contain server_side_encryption_configuration

Compruebe si el cifrado está habilitado.

Si esto no es suficiente para usted, puede escribir con más detalle:

Feature: Ensure that we have encryption everywhere.

    Scenario: Reject if an S3 bucket is not encrypted with KMS
        Given I have aws_s3_bucket defined
        Then it must contain server_side_encryption_configuration
        And it must contain rule
        And it must contain apply_server_side_encryption_by_default
        And it must contain sse_algorithm
        And its value must match the "aws:kms" regex

Profundizamos y verificamos que KMS se utiliza para el cifrado.

El código de terraforma para esta prueba:

resource "aws_kms_key" "mykey" {
 description             = "This key is used to encrypt bucket objects"
 deletion_window_in_days = 10
}

resource "aws_s3_bucket" "mybucket" {
 bucket = "mybucket"

 server_side_encryption_configuration {
   rule {
     apply_server_side_encryption_by_default {
       kms_master_key_id = "${aws_kms_key.mykey.arn}"
       sse_algorithm     = "aws:kms"
     }
   }
 }
}

Por lo tanto, las pruebas se entienden literalmente por TODO en su organización. Aquí puede delegar la redacción de estas pruebas a un servicio de seguridad oa desarrolladores con suficiente conocimiento de seguridad. Esta herramienta también le permite almacenar archivos BDD en otro repositorio. Esto ayudará a diferenciar la responsabilidad cuando los cambios en el código y los cambios en las políticas de seguridad asociadas con su código serán dos entidades diferentes. Estos pueden ser diferentes equipos con diferentes ciclos de vida. Increíble verdad? Bueno, al menos para mí lo fue.

Para obtener más información sobre el cumplimiento de terraform, consulte esta presentación .

Resolvimos muchos problemas con el cumplimiento de terraform, especialmente cuando los servicios de seguridad están bastante alejados de los equipos de desarrollo y es posible que no entiendan lo que están haciendo los desarrolladores. Ya adivinas lo que está sucediendo en tales organizaciones. Por lo general, el servicio de seguridad comienza a bloquear todo lo sospechoso para ellos y crea un sistema de seguridad basado en la seguridad del perímetro. Oh, Dios ...

En muchas situaciones, solo usar terraform y cumplimiento de terraform para equipos que diseñan (o acompañan) la infraestructura ayudó a poner a estos dos equipos diferentes en la misma mesa. Cuando su equipo de seguridad comienza a desarrollar algo con comentarios inmediatos de todos los canales de desarrollo, generalmente obtienen la motivación para hacer más y más. Bueno, por lo general ...

Por lo tanto, cuando usamos terraform, estructuramos los repositorios de git de la siguiente manera:



Por supuesto, esto es bastante arrogante. Pero tuve suerte (¿o no tuve suerte?) De trabajar con una estructura más detallada en varias organizaciones. Desafortunadamente, todo esto no terminó muy bien. El final feliz debería estar oculto en el número 3.

¡Avíseme si tiene alguna historia de éxito con micro repositorios, estoy realmente interesado!



Lo invitamos a una lección gratuita en la que consideraremos los componentes de una futura plataforma de infraestructura y veremos cómo entregar nuestra aplicación correctamente .

All Articles