Skip to main content

Automatiser l’intégration Kubernetes de Snyk Container avec Pulumi

Écrit par

Pas Apicella

feature snyk container purple

9 février 2022

0 minutes de lecture

Nous avons tous entendu parler de l’infrastructure as code (IaC). Cependant, le code ne désigne pas vraiment ici du code au sens d’un langage de programmation. L’IaC fait généralement référence à la configuration de l’infrastructure à l’aide d’outils comme Terraform, CloudFormation, Kubernetes YAML ou les modèles Azure Resource Manager. Il s’agit en réalité de définir la manière dont l’infrastructure sera créée. Ces configurations n’offrent pas la flexibilité ni la puissance d’un langage de programmation moderne. L’IaC est donc du code, mais pas généralement ce type de code.

Dans cet article, nous allons vous expliquer comment utiliser Pulumi, un nouvel outil open source qui permet aux développeurs d’écrire du code dans plusieurs langages, comme JavaScript, TypeScript, Python et Go, afin de créer tous les éléments nécessaires à la configuration de l’intégration Kubernetes dans Snyk Container.

Présentation de l’intégration Kubernetes de Snyk

Snyk s’intègre à Kubernetes pour vous permettre d’importer et de tester vos workloads en cours d’exécution, et de détecter les vulnérabilités dans les images et les configurations associées qui pourraient compromettre leur sécurité. Une fois ces workloads importés, Snyk continue de les surveiller et détecte les nouveaux problèmes de sécurité à mesure que de nouvelles images sont déployées et que leur configuration évolue.

Qu’est-ce que Pulumi ?

Pulumi est un outil IaC open source qui s’appuie sur les langages de programmation les plus populaires pour simplifier le provisionnement et la gestion des ressources cloud.

Fondée en 2017, Pulumi a profondément transformé la manière dont les équipes DevOps abordent l’infrastructure as code. Au lieu de s’appuyer sur des langages spécifiques à un domaine, Pulumi permet aux organisations d’utiliser de véritables langages de programmation pour provisionner et décommissionner une infrastructure cloud native.

Pulumi prend en charge les langages de programmation suivants :

  • Python

  • JavaScript

  • Go

  • TypeScript

  • Langages .NET (C#, F# et VB)

Installer l’intégration Kubernetes de Snyk avec Pulumi

Passons à la partie pratique ! Nous allons vous guider pas à pas dans la configuration de Pulumi et le lancement de nos automatisations. Voici les étapes à suivre :

  1. Configurer un ID d’intégration Kubernetes dans l’application Snyk

  2. Cloner le dépôt d’exemple

  3. Vous authentifier auprès de Google Cloud

  4. Créer une nouvelle stack Pulumi

  5. Définir les variables de configuration Pulumi requises

  6. Tout déployer avec pulumi up

  7. Récupérer la configuration Kubernetes

  8. Détruire toute la configuration

Prérequis

  1. Pour utiliser l’intégration Kubernetes, vous devez disposer d’un compte Snyk Business ou Enterprise. Si vous n’en avez pas, vous pouvez souscrire un essai gratuit de 14 jours de Business.

  2. Nous allons effectuer le déploiement sur Google Cloud ; vous aurez donc besoin d’un compte. Si vous n’en avez pas, inscrivez-vous gratuitement ici. Dans les deux cas, suivez les instructions ici pour connecter Pulumi à votre compte Google Cloud.

  3. Cet exemple suppose que la CLI gcloud est accessible depuis votre chemin d’accès. Elle est installée avec le Google Cloud SDK.

  4. Assurez-vous de disposer de Python 3, d’un compte Pulumi et de la CLI Pulumi.

  5. Notez que Pulumi nécessite que Python 3 soit la version par défaut dans votre environnement. Si Python 2 et Python 3 sont tous deux installés, vous devrez peut-être créer un alias. Pour le vérifier, exécutez la commande suivante et assurez-vous d’utiliser la dernière version 3.x :

❯ python --version
Python 3.9.9

Étape 1 : configurer un ID d’intégration Kubernetes dans l’application Snyk

Connectez-vous à Snyk et sélectionnez l’organisation dans laquelle vous souhaitez configurer automatiquement l’intégration Kubernetes. Il peut s’agir d’une organisation vide ou d’une organisation existante contenant des projets. Pour cet exemple, vérifiez que l’intégration Kubernetes n’est pas déjà configurée dans l’organisation choisie.

Cliquez ensuite sur Intégrations > Kubernetes > Connecter. Si vous n’avez pas de compte Snyk Business ou Enterprise, vous ne pourrez pas effectuer cette étape.

Notez bien l’ID d’intégration : nous en aurons besoin dans un instant.

Paramètres du projet Snyk affichant l’intégration Kubernetes comme non connectée, avec le bouton Connecter mis en évidence.

Et voilà ! Vous pouvez maintenant configurer notre démonstration de l’intégration Kubernetes de Snyk à l’aide de l’infrastructure as code de Pulumi. Pulumi va effectuer les opérations suivantes :

  • Créer un cluster GKE

  • Déployer le contrôleur Snyk dans le cluster0

  • Configurer l’intégration Kubernetes de Snyk pour importer automatiquement les workloads K8s dans Snyk

  • Déployer un exemple de workload dans l’espace de noms apples, conformément à notre fichier de règles Rego

Étape 2 : cloner le dépôt d’exemple

Clonez le dépôt GitHub de démonstration ci-dessous :

$ 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.

Après avoir cloné ce dépôt, accédez-y avec cd, puis exécutez les commandes suivantes…

Étape 3 : vous authentifier auprès de Google Cloud

Authentifiez-vous auprès de Google Cloud à l’aide de l’authentification locale pour déployer cette démonstration. Il existe d’autres façons de configurer Pulumi avec Google Cloud, mais c’est la plus simple pour cet exemple :

$ gcloud auth login

Étape 4 : créer une nouvelle stack Pulumi

Créez une nouvelle stack, qui constitue une cible de déploiement isolée pour cet exemple. Utilisez dev comme nom d’exemple :

$ pulumi stack init dev

Étape 5 : définir les variables de configuration Pulumi requises

Souvent, les différentes stacks d’un même projet nécessitent des valeurs différentes. Vous souhaiterez par exemple peut-être utiliser une taille différente pour votre instance Google Cloud Compute, ou un nombre de serveurs différent pour votre cluster Kubernetes entre les stacks de développement et de production.

Les paires clé-valeur de chaque stack sont stockées dans le fichier de paramètres de stack de votre projet, automatiquement nommé Pulumi.<stack-name>.yaml. En général, vous pouvez ignorer ce fichier, mais vous pouvez aussi l’intégrer au contrôle de version avec le code source de votre projet.

Ajoutez les variables de configuration suivantes à notre stack, comme indiqué ci-dessous :

$ 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

Par défaut, votre cluster comporte 3 nœuds de type n1-standard-1. Cette valeur est configurable. Pour choisir 5 nœuds de type n1-standard-2, vous pouvez exécuter les commandes suivantes :

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

Enfin, nous devons configurer les paramètres requis pour l’intégration Kubernetes de Snyk, qui permettent de l’ajouter automatiquement à notre cluster. Nous avons besoin de l’ID de l’intégration Kubernetes et de l’ID de notre organisation Snyk. Dans cet exemple, ils sont identiques :

$ 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

Les stacks peuvent ainsi être configurées de manière pratique. Vous pouvez même modifier ces paramètres après le provisionnement.

Une fois cette étape terminée, vous disposerez d’un fichier Pulumi.dev.yaml contenant les éléments suivants :

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

Étape 6 : tout déployer avec pulumi up

La commande pulumi up provisionne toutes les ressources Google Cloud nécessaires à l’intégration Kubernetes avec Snyk, notamment votre cluster GKE et le chart Helm du contrôleur Snyk. Elle déploie ensuite un déploiement Kubernetes exécutant une application Spring Boot :

$ pulumi up

Une prévisualisation s’affichera. Après confirmation, le provisionnement de la démonstration de l’intégration Kubernetes de Snyk commencera :

$ 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

Au bout d’environ cinq minutes, votre cluster sera prêt. Le contrôleur Snyk sera installé et un exemple de workload sera automatiquement importé dans votre organisation 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

Voici quelques captures d’écran qui vous permettront de vérifier que tout a été créé comme prévu.

Le cluster GKE créé sur Google Cloud :

Console Google Kubernetes Engine affichant les détails du cluster pulumi-gke-cluster-008049b.

L’intégration Kubernetes de Snyk configurée automatiquement :

Page Paramètres de Snyk montrant l’intégration Kubernetes connectée, avec une option pour ajouter des charges de travail Kubernetes et les détails de l’intégration.

L’exemple de workload importé automatiquement depuis l’espace de noms apples :

Tableau de bord des projets Snyk affichant des projets Kubernetes, le nombre de problèmes de sécurité par niveau de gravité et une option pour ajouter un autre projet
Tableau de bord Snyk montrant un déploiement Kubernetes avec 52 vulnérabilités et des vérifications de configuration sécurisée échouées

Explorer la configuration

Examinons de plus près le fichier Python __main__.py et voyons comment l’intégration Kubernetes de Snyk a été installée et configurée.

Le fichier de règles Rego utilisé par le contrôleur Snyk est actuellement codé en dur pour n’importer que les workloads de l’espace de noms apples, à condition qu’ils ne soient pas de type CronJob ou Service. Vous pouvez modifier ce paramètre dans __main__.py et utiliser un fichier externe au lieu de coder les règles en dur dans le code 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)

Voici le code Python qui installe le contrôleur Snyk à l’aide de son chart Helm. Notez que nous avons indiqué le dépôt dans lequel récupérer le chart Helm, fourni l’ID de l’organisation Snyk ainsi que le fichier de règles personnalisé présenté précédemment. Ces éléments sont tous nécessaires pour installer le contrôleur Snyk dans le cluster GKE et l’intégrer à 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)
)

Le code Python a également déployé une application d’exemple Spring Boot dans notre espace de noms apples. C’est cette application qui a été importée automatiquement dans l’application Snyk par le contrôleur Snyk. Voici le code Python utilisé pour ce déploiement :

# 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)
)

Étape 7 : récupérer la configuration Kubernetes

Vous pouvez utiliser cette configuration dans votre fichier ~/.kube/config, ou l’enregistrer localement et l’indiquer dans la variable d’environnement KUBECONFIG. Bien entendu, toutes vos commandes Google Cloud habituelles fonctionneront également.

Par exemple :

$ 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

Le contrôleur Snyk installé dans l’espace de noms snyk-monitor, ainsi que la ConfigMap et le secret désormais gérés par Pulumi, affichés à l’aide de quelques commandes 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

Étape 8 : détruire toute la configuration

Une fois que vous avez terminé, vous pouvez détruire toutes les ressources ainsi que la stack :

$ pulumi destroy
$ pulumi stack rm

En résumé, vous avez appris comment utiliser Pulumi pour installer et configurer l’intégration Kubernetes de Snyk. Cette intégration vous permet d’importer et de tester vos workloads en cours d’exécution, et de détecter les vulnérabilités dans les images et les configurations associées qui pourraient compromettre leur sécurité.

Ressources complémentaires

Maintenant que vous savez à quel point il est facile de configurer l’intégration Kubernetes de Snyk avec Pulumi et le langage de programmation Python, voici quelques liens utiles pour vous lancer dans la sécurisation de vos conteneurs.

Sécurisez votre infrastructure dès la source

Snyk automatise la sécurité et la conformité de l’IaC dans vos workflows, et détecte les ressources dont la configuration a dérivé ou qui sont manquantes.