Skip to main content

Usar Pulumi para automatizar la integración de Snyk con Kubernetes para contenedores

Escrito por

Pas Apicella

feature snyk container purple

9 de febrero de 2022

0 minutos de lectura

Todos hemos escuchado el término infraestructura como código (IaC); sin embargo, en este contexto, código no significa realmente código en el sentido de un lenguaje de programación. IaC suele referirse a la configuración de infraestructura mediante herramientas como Terraform, CloudFormation, Kubernetes YAML o plantillas de Azure Resource Manager, que en realidad definen cómo se creará la infraestructura. Estas configuraciones no ofrecen la flexibilidad ni la potencia de un lenguaje de programación moderno, así que IaC es código, pero no suele ser ese tipo de código.

En esta publicación del blog, te guiaremos por el proceso de usar Pulumi, una nueva herramienta de código abierto que permite a los desarrolladores escribir código en varios lenguajes, como JavaScript, TypeScript, Python y Go, para crear todo lo necesario para configurar la integración de Kubernetes en Snyk Container.

Descripción general de la integración de Snyk con Kubernetes

Snyk se integra con Kubernetes para que puedas importar y probar tus cargas de trabajo en ejecución, e identificar vulnerabilidades en las imágenes y configuraciones asociadas que podrían reducir su seguridad. Una vez importadas, Snyk sigue monitoreando esas cargas de trabajo e identifica otros problemas de seguridad a medida que se implementan nuevas imágenes y cambia la configuración de las cargas de trabajo.

¿Qué es Pulumi?

Pulumi es una herramienta de IaC de código abierto que utiliza los lenguajes de programación más populares para simplificar el aprovisionamiento y la administración de recursos en la nube.

Fundada en 2017, Pulumi cambió radicalmente la forma en que los equipos de DevOps abordan el concepto de infraestructura como código. En lugar de depender de lenguajes específicos de dominio, Pulumi permite a las organizaciones usar lenguajes de programación reales para aprovisionar y retirar infraestructura nativa de la nube.

Pulumi admite los siguientes lenguajes de programación:

  • Python

  • JavaScript

  • Go

  • TypeScript

  • Lenguajes de .NET (C#, F# y VB)

Cómo instalar la integración de Snyk con Kubernetes mediante Pulumi

¡Ahora viene lo divertido! Vamos a configurar Pulumi paso a paso y poner en marcha nuestras automatizaciones. Estos son los pasos que seguiremos:

  1. Configurar un ID de integración de Kubernetes desde la aplicación de Snyk

  2. Clonar el repositorio de ejemplo

  3. Autenticarse en Google Cloud

  4. Crear una nueva pila de Pulumi

  5. Configurar las variables de Pulumi requeridas

  6. Implementar todo con pulumi up

  7. Obtener la configuración de Kubernetes

  8. Destruir toda la configuración

Requisitos previos

  1. Necesitarás una cuenta Business o Enterprise de Snyk para usar la integración de Kubernetes. Si no tienes una, puedes registrarte para obtener una prueba gratuita de Business por 14 días.

  2. Implementaremos en Google Cloud, así que necesitarás una cuenta. Si no tienes una, regístrate gratis aquí. En cualquier caso, sigue estas instrucciones para conectar Pulumi con tu cuenta de Google Cloud.

  3. En este ejemplo se supone que tienes la CLI gcloud en tu ruta. Se instala como parte del Google Cloud SDK.

  4. Asegúrate de tener Python 3, una cuenta de Pulumi y la CLI de Pulumi.

  5. Ten en cuenta que Pulumi requiere que Python 3 sea la versión predeterminada en tu entorno. Si tienes Python 2 y Python 3 instalados, quizá debas crear un alias. Para verificarlo, ejecuta el siguiente comando y asegúrate de usar la versión más reciente de 3.x:

❯ python --version
Python 3.9.9

Paso 1: Configurar un ID de integración de Kubernetes desde la aplicación de Snyk

Inicia sesión en Snyk y selecciona la organización en la que quieres configurar automáticamente la integración de Kubernetes. Puede ser una organización vacía o una existente que ya tenga proyectos. Para este ejemplo, asegúrate de que la integración de Kubernetes aún no esté configurada en la organización que elijas.

Luego, haz clic en Integraciones > Kubernetes > Conectar. Si no tienes una cuenta Business o Enterprise de Snyk, no podrás realizar este paso.

Anota el ID de integración, porque lo necesitaremos en breve.

Configuración del proyecto de Snyk que muestra la integración de Kubernetes como desconectada y el botón Conectar resaltado.

¡Eso es todo! Ya estás listo para configurar nuestra demostración de integración de Snyk con Kubernetes mediante la infraestructura como código de Pulumi. Pulumi hará lo siguiente:

  • Crear un clúster de GKE

  • Implementar el controlador de Snyk en el clúster0

  • Configurar la integración de Snyk con Kubernetes para importar automáticamente cargas de trabajo de K8s a Snyk

  • Implementar una carga de trabajo de ejemplo en el espacio de nombres apples, según nuestro archivo de políticas Rego

Paso 2: Clonar el repositorio de ejemplo

Clona el siguiente repositorio de demostración de GitHub, como se muestra a continuación:

$ git clone https://github.com/papicella/snyk-kubernetes-integration
Cloning into 'snyk-kubernetes-integration'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 18 (delta 8), reused 14 (delta 4), pack-reused 0
Receiving objects: 100% (18/18), 8.76 KiB | 4.38 MiB/s, done.
Resolving deltas: 100% (8/8), done.

Después de clonar este repositorio, ejecuta cd para entrar en él y ejecuta los siguientes comandos…

Paso 3: Autenticarse en Google Cloud

Autentícate en Google Cloud mediante la autenticación local para implementar esta demostración. Hay otras formas de configurar Pulumi con Google Cloud, pero esta es la más sencilla para esta demostración:

$ gcloud auth login

Paso 4: Crear una nueva pila de Pulumi

Crea una pila nueva, que será un destino de implementación aislado para este ejemplo. Usa dev como nombre de ejemplo:

$ pulumi stack init dev

Paso 5: Configurar las variables de Pulumi requeridas

En muchos casos, las distintas pilas de un mismo proyecto necesitan valores diferentes. Por ejemplo, quizás quieras usar un tamaño diferente para tu instancia de Google Cloud Compute o una cantidad distinta de servidores para el clúster de Kubernetes entre las pilas de desarrollo y producción.

Los pares clave-valor de cada pila se almacenan en el archivo de configuración de la pila de tu proyecto, cuyo nombre se genera automáticamente como Pulumi.<stack-name>.yaml. Por lo general, puedes ignorar este archivo, aunque quizá quieras incluirlo en el control de versiones junto con el código fuente del proyecto.

Agrega las siguientes variables de configuración a nuestra pila, como se muestra a continuación:

$ pulumi config set gcp:project [your-gcp-project-here] # Eg: snyk-cx-se-demo
$ pulumi config set gcp:zone us-central1-c # any valid GCP zone here
$ pulumi config set password --secret [your-cluster-password-here] # password for the cluster
$ pulumi config set master_version 1.21.6-gke.1500 # any valid K8s master version on GKE

De forma predeterminada, el clúster tendrá 3 nodos de tipo n1-standard-1. Este valor se puede configurar, así que, si queremos elegir 5 nodos de tipo n1-standard-2, podemos ejecutar estos comandos:

$ pulumi config set node_count 5
$ pulumi config set node_machine_type n1-standard-2

Por último, debemos configurar los ajustes necesarios para la integración de Snyk con Kubernetes, que se usan para configurar automáticamente dicha integración en nuestro clúster. Necesitamos el ID de integración de Kubernetes y el ID de organización de Snyk. En este ejemplo, son iguales:

$ pulumi config set snyk_K8s_integration_id K8S_INTEGRATION_ID #same as ORG_ID at the moment
$ pulumi config set snyk_org_id ORG_ID # your Snyk ORG ID under settings

Esto muestra cómo se pueden configurar las pilas de forma práctica. Incluso puedes cambiar estos valores después del aprovisionamiento.

Una vez hecho esto, tendrás un archivo Pulumi.dev.yaml con lo siguiente:

config:
gcp-K8s-integration-demo:master_version: 1.21.5-gke.1302
gcp-K8s-integration-demo:node_count: "3"
gcp-K8s-integration-demo:node_machine_type: n1-standard-2
gcp-K8s-integration-demo:password:
    secure: AAABsomesecret+EnF1p4w==
gcp-K8s-integration-demo:snyk_K8s_integration_id: yyyy1234
gcp-K8s-integration-demo:snyk_org_id: yyyy1234
gcp:project: snyk-cx-se-demo
gcp:zone: us-central1-c

Paso 6: Implementar todo con pulumi up

La implementación de todo con el comando pulumi up aprovisiona todos los recursos de Google Cloud necesarios para la integración de Kubernetes con Snyk, incluido el clúster de GKE y el gráfico de Helm del controlador de Snyk. Luego, implementa una implementación de Kubernetes que ejecuta una aplicación de Spring Boot:

$ pulumi up

Esto te mostrará una vista previa, te pedirá confirmación e iniciará el proceso de aprovisionamiento de la demostración de integración de Snyk con Kubernetes:

$ pulumi up
Previewing update (dev)

View Live: https://app.pulumi.com/papicella/gcp-K8s-integration-demo/dev/previews/1db6492c-ae23-4e87-abf0-41e09fb62177

    Type                                                              Name                          Plan
+   pulumi:pulumi:Stack                                               gcp-K8s-integration-demo-dev  create
+   ├─ kubernetes:helm.sh/v3:Chart                                    snyk-monitor                  create
+   │  ├─ kubernetes:core/v1:ServiceAccount                           snyk-monitor/snyk-monitor     create
+   │  ├─ kubernetes:networking.k8s.io/v1:NetworkPolicy               snyk-monitor/snyk-monitor     create
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRole         snyk-monitor                  create
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRoleBinding  snyk-monitor                  create
+   │  └─ kubernetes:apps/v1:Deployment                               snyk-monitor/snyk-monitor     create
+   ├─ gcp:container:Cluster                                          pulumi-gke-cluster            create
+   ├─ pulumi:providers:kubernetes                                    gke_k8s                       create
+   ├─ kubernetes:core/v1:Namespace                                   snyk-monitor                  create
+   ├─ kubernetes:core/v1:Namespace                                   apples                        create
+   ├─ kubernetes:core/v1:ConfigMap                                   snyk-monitor-custom-policies  create
+   ├─ kubernetes:core/v1:Service                                     springboot-employee-api       create
+   ├─ kubernetes:core/v1:Secret                                      snyk-monitor                  create
+   └─ kubernetes:apps/v1:Deployment                                  springboot-employee-api       create

Resources:
    + 15 to create

Después de unos cinco minutos, el clúster estará listo, con el controlador de Snyk instalado y una implementación de carga de trabajo de ejemplo importada automáticamente a tu organización de Snyk:

Do you want to perform this update? yes
Updating (dev)

View Live: https://app.pulumi.com/papicella/gcp-K8s-integration-demo/dev/updates/1

    Type                                                              Name                          Status
+   pulumi:pulumi:Stack                                               gcp-K8s-integration-demo-dev  created
+   ├─ kubernetes:helm.sh/v3:Chart                                    snyk-monitor                  created
+   │  ├─ kubernetes:core/v1:ServiceAccount                           snyk-monitor/snyk-monitor     created
+   │  ├─ kubernetes:networking.k8s.io/v1:NetworkPolicy               snyk-monitor/snyk-monitor     created
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRole         snyk-monitor                  created
+   │  ├─ kubernetes:rbac.authorization.k8s.io/v1:ClusterRoleBinding  snyk-monitor                  created
+   │  └─ kubernetes:apps/v1:Deployment                               snyk-monitor/snyk-monitor     created
+   ├─ gcp:container:Cluster                                          pulumi-gke-cluster            created
+   ├─ pulumi:providers:kubernetes                                    gke_k8s                       created
+   ├─ kubernetes:core/v1:Namespace                                   snyk-monitor                  created
+   ├─ kubernetes:core/v1:Namespace                                   apples                        created
+   ├─ kubernetes:core/v1:Service                                     springboot-employee-api       created
+   ├─ kubernetes:core/v1:ConfigMap                                   snyk-monitor-custom-policies  created
+   ├─ kubernetes:core/v1:Secret                                      snyk-monitor                  created
+   └─ kubernetes:apps/v1:Deployment                                  springboot-employee-api       created

Outputs:
    kubeconfig: "[secret]"

Resources:
    + 15 created

Duration: 6m28s

A continuación, encontrarás algunas capturas de pantalla para verificar que todo se haya creado según lo previsto.

El clúster de GKE creado en Google Cloud:

Consola de Google Kubernetes Engine que muestra detalles del clúster pulumi-gke-cluster-008049b.

La integración de Snyk con Kubernetes configurada automáticamente:

Página de configuración de Snyk que muestra la integración de Kubernetes conectada, con una opción para agregar cargas de trabajo de Kubernetes y detalles de la integración.

La carga de trabajo de ejemplo importada automáticamente desde el espacio de nombres apples:

Panel de proyectos de Snyk que muestra proyectos de Kubernetes con la cantidad de problemas de seguridad por nivel de gravedad y una opción para agregar otro proyecto
Panel de Snyk que muestra una implementación de Kubernetes con 52 vulnerabilidades y verificaciones de configuración segura fallidas

Explorar la configuración

Veamos de cerca el archivo de Python __main__.py y entendamos cómo se instaló y configuró la integración de Snyk con Kubernetes.

El archivo de políticas Rego que usa el controlador de Snyk está codificado actualmente para importar solo las cargas de trabajo del espacio de nombres apples, siempre que no sean de tipo CronJob o Service. Puedes cambiarlo en __main__.py y usar un archivo externo en lugar de codificarlo directamente en el código de Python:

snyk_monitor_custom_policies_str = """package snyk
orgs := ["%s"]
default workload_events = false
workload_events {
input.metadata.namespace == "apples"
    input.kind != "CronJob"
    input.kind != "Service"
}""" % (SNYK_ORG_ID)

Este es el código de Python para instalar el controlador de Snyk mediante su gráfico de Helm. Observa que especificamos el repositorio del que se obtiene el gráfico de Helm, indicamos el ID de la organización de Snyk y agregamos el archivo de políticas personalizado anterior. Todo esto es necesario para instalar el controlador de Snyk en el clúster de GKE e integrarlo con Snyk.

# Deploy the snyk controller using it's helm chart
snyk_monitor_chart = Chart(
    "snyk-monitor",
    ChartOpts(
        chart="snyk-monitor",
        version="1.79.0",
        namespace="snyk-monitor",
        fetch_opts=FetchOpts(
            repo="https://snyk.github.io/kubernetes-monitor",
        ),
        values={
          "clusterName": "K8s-integration-demo-cluster",
          "policyOrgs": "{%s}" % (SNYK_ORG_ID),
          "workloadPoliciesMap": "snyk-monitor-custom-policies"
        }
    ),
    opts=ResourceOptions(provider=k8s_provider)
)

El código de Python también implementó una aplicación de ejemplo de Spring Boot en nuestro espacio de nombres apples, que el controlador de Snyk importó automáticamente a la aplicación de Snyk. El código de Python para realizar esa implementación es el siguiente:

# deploy spring boot employee app

"""springboot employee api container, replicated 1 time."""
app_name = "springboot-employee-api"
app_labels = { "app": app_name }

springboot_employee_api = k8s.apps.v1.Deployment(
            app_name,
            metadata={
              "namespace": "apples",
            },
            spec=k8s.apps.v1.DeploymentSpecArgs(
                replicas=1,
                selector=k8s.meta.v1.LabelSelectorArgs(match_labels=app_labels),
                template=k8s.core.v1.PodTemplateSpecArgs(
                    metadata=k8s.meta.v1.ObjectMetaArgs(labels=app_labels),
                    spec=k8s.core.v1.PodSpecArgs(
                        containers=[
                            k8s.core.v1.ContainerArgs(
                                name=app_name,
                                image="pasapples/springbootemployee:cnb",
                                ports=[k8s.core.v1.ContainerPortArgs(
                                  container_port=8080
                                )]
                            )
                        ]
                    ),
                ),
            ),
            opts=ResourceOptions(provider=k8s_provider)
)

Paso 7: Obtener la configuración de Kubernetes

Desde aquí, puedes usar esta configuración en tu archivo ~/.kube/config o guardarla localmente y asignarla a la variable de entorno KUBECONFIG. Por supuesto, también funcionarán todos tus comandos habituales de Google Cloud.

Por ejemplo:

$ pulumi stack output kubeconfig --show-secrets > kubeconfig.yaml
$ KUBECONFIG=./kubeconfig.yaml kubectl get po -n apples
NAME                                                READY   STATUS    RESTARTS   AGE
springboot-employee-api-fyrj9hr2-66d8456f5f-hqqhx   1/1     Running   0          17m

El controlador de Snyk instalado en el espacio de nombres snyk-monitor, junto con el mapa de configuración y el secreto que ahora administra Pulumi, como se muestra con algunos comandos de kubectl:

$ kubectl get all -n snyk-monitor
NAME                              READY   STATUS    RESTARTS   AGE
pod/snyk-monitor-db67744d-szl79   1/1     Running   0          8m52s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/snyk-monitor   1/1     1            1           8m53s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/snyk-monitor-db67744d   1         1         1       8m53s

$ kubectl get secret -n snyk-monitor -l app.kubernetes.io/managed-by=pulumi
NAME           TYPE     DATA   AGE
snyk-monitor   Opaque   2      42m

$ kubectl get configmap -n snyk-monitor -l app.kubernetes.io/managed-by=pulumi
NAME                           DATA   AGE
snyk-monitor-custom-policies   1      42m

Paso 8: Destruir toda la configuración

Cuando termines, puedes destruir todos los recursos y la pila:

$ pulumi destroy
$ pulumi stack rm

En resumen, aprendiste cómo usar Pulumi para instalar y configurar la integración de Snyk con Kubernetes. Esta integración te permite importar y probar tus cargas de trabajo en ejecución, e identificar vulnerabilidades en las imágenes y configuraciones asociadas que podrían reducir su seguridad.

Más recursos

Ahora que aprendiste lo fácil que es configurar la integración de Snyk con Kubernetes usando Pulumi y el lenguaje de programación Python, aquí tienes algunos enlaces útiles para comenzar tu recorrido por la seguridad de contenedores.

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.