Skip to main content

Analyser les vulnérabilités AWS avec l’intégration Snyk

Écrit par
AWS vulnerability scanning

10 février 2021

0 minutes de lecture

Si vous utilisez la suite d’outils AWS liés à Kubernetes, vous serez ravi d’apprendre que vous pouvez intégrer Snyk à vos workflows pour y lancer des analyses, grâce aux intégrations avec Amazon Elastic Container Registry ( ECR ) et Amazon Elastic Kubernetes Service ( EKS ). Voici comment démarrer !

Dans cet article, je vais utiliser l’une de nos applications de test Snyk pour créer et déployer une application. Vous trouverez le code ici. Vous aurez également besoin d’installer quelques dépendances :

C’est parti

Maintenant que tout est prêt, commençons !

Commençons par configurer ECR afin que Snyk puisse accéder à nos dépôts. Pour cela, nous devons attribuer une stratégie et un rôle dans AWS Identity and Access Management, afin d’accorder au backend Snyk les autorisations nécessaires pour, par exemple, répertorier les images et les extraire de nos dépôts ECR.

Les étapes de configuration de l’intégration sont détaillées dans la documentation Snyk, mais nous pouvons accéder à tous les paramètres nécessaires directement depuis l’interface Snyk. Accédez à Settings/Integrations/ECR/Edit Settings. Commencez par créer une stratégie à l’aide du JSON affiché dans l’interface :

{
"Version": "2012-10-17",
"Statement": [
 {
  "Sid": "SnykAllowPull",
  "Effect": "Allow",
  "Action": [
   "ecr:GetLifecyclePolicyPreview",
   "ecr:GetDownloadUrlForLayer",
   "ecr:BatchGetImage",
   "ecr:DescribeImages",
   "ecr:GetAuthorizationToken",
   "ecr:DescribeRepositories",
   "ecr:ListTagsForResource",
   "ecr:ListImages",
   "ecr:BatchCheckLayerAvailability",
   "ecr:GetRepositoryPolicy",
   "ecr:GetLifecyclePolicy"
  ],
  "Resource": "*"
 }
]
}

- oriCela accordera à Snyk les autorisations définies dans la section Action du JSON pour tous les dépôts et toutes les images de notre compte ECR. Il s’agit du minimum d’autorisations nécessaire pour répertorier les dépôts et les images, et pour extraire les images des dépôts. Suivez les instructions pour ajouter ce JSON à la configuration de votre stratégie IAM dans AWS.

Nous devons ensuite ajouter un rôle et lui attribuer la stratégie, comme indiqué dans les instructions :

Instructions pour créer un rôle IAM AWS afin d’appliquer une politique, notamment en sélectionnant EC2, la politique ECR en lecture seule et en le nommant SnykServiceRole

Nous devons également définir la portée du rôle en précisant les ID d’organisation Snyk autorisés à l’utiliser. Pour cela, modifiez les relations de confiance du rôle nouvellement créé à l’aide du JSON fourni dans la documentation. La chaîne sts:ExternalId correspond à l’ID de votre organisation Snyk. Cet extrait JSON permet au principal AWS d’assumer le rôle si l’ExternalId fourni correspond à l’ID de notre organisation Snyk. 

{
"Version": "2012-10-17",
"Statement": [
 {
  "Effect": "Allow",
  "Principal": {
   "AWS": "arn:aws:iam::198361731867:user/ecr-integration-user"
  },
  "Action": "sts:AssumeRole",
  "Condition": {
   "StringEquals": {
    "sts:ExternalId": "11111111-1111-1111-1111-111111111111"
   }
  }
 }
]
}

Comme indiqué dans les instructions, si vous devez ajouter plusieurs organisations Snyk à cette stratégie, ajoutez-les sous forme de tableau JSON, entre crochets :

"sts:ExternalId": [
"11111111-1111-1111-1111-111111111111",
"22222222-2222-2222-2222-222222222222",
]

Pour trouver l’ID de votre organisation Snyk, accédez à Settings > General.

Page des paramètres affichant l’onglet Général avec les champs du nom de l’organisation, de la clé API et de l’identifiant de l’organisation.

La dernière étape consiste à configurer l’interface Snyk pour utiliser ce rôle afin de se connecter à ECR. De retour dans Settings/Integrations/ECR/Edit Settings, indiquez la région dans laquelle ECR est configuré ainsi que le rôle créé précédemment :

Formulaire d’identifiants pour connecter Snyk à un compte Amazon ECR, avec les champs Région AWS, ARN du rôle et Enregistrer les modifications

L’intégration ECR devrait maintenant être entièrement configurée. Passons aux tests.

Commençons par créer un dépôt dans ECR à l’aide d’AWS CLI :

% aws ecr create-repository --repository-name goof
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:us-west-2:478468688580:repository/goof",
        "registryId": "478468688580",
        "repositoryName": "goof",
        "repositoryUri": "478468688580.dkr.ecr.us-west-2.amazonaws.com/goof",
        "createdAt": "2021-02-03T13:40:59+00:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

Maintenant que nous avons un dépôt dans ECR, configurons Docker pour pouvoir y envoyer des images :

% aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 478468688580.dkr.ecr.us-west-2.amazonaws.com

Cette commande affiche votre mot de passe de connexion, puis le transmet à Docker CLI pour authentifier votre accès au registre AWS ECR. Veillez à définir la bonne région AWS, celle dans laquelle ECR est activé.

Passons maintenant à notre application de test. Il s’agit d’une application Node.js simple qui comporte de nombreuses vulnérabilités, ainsi que la configuration nécessaire pour la créer avec Docker et la déployer sur Kubernetes.

% git clone https://github.com/mattj-io/goof.git goof
% cd goof

Nous allons d’abord créer l’application à l’aide de Docker.

% docker build -t goof .

Une fois l’image créée, elle devrait apparaître dans notre dépôt Docker local :

% docker images
REPOSITORY                                TAG      IMAGE ID       CREATED      SIZE
goof                                      latest    7934ddc2fec9   2 days ago   1.04GB

Avant de l’envoyer vers notre dépôt ECR en amont, nous devons lui attribuer une balise en remplaçant le nom du dépôt par celui que vous avez configuré précédemment dans ECR :

% docker tag goof:latest 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof:latest
% docker images
REPOSITORY                                          TAG       IMAGE ID       CREATED      SIZE
478468688580.dkr.ecr.us-west-2.amazonaws.com/goof   latest    7934ddc2fec9   2 days ago   1.04GB
goof                                      latest    7934ddc2fec9   2 days ago   1.04GB   

Nous pouvons maintenant l’envoyer vers ECR :

% docker push 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof:latest 

Une fois l’envoi terminé, vérifions dans notre dépôt ECR que l’image est bien présente :

% aws ecr list-images --repository-name goof
{
    "imageIds": [
        {
            "imageDigest": "sha256:ca6c19e25b4d7917769ee535f0b073e04e8ddc32ead83493c03abc65e82e5e6c",
            "imageTag": "latest"
        },
        {
            "imageDigest": "sha256:cd100d7c505ced1f5c4f4eb6fbd7ac83a623f9bb483db1e828fb4cd3b3c01bd9"
        }
    ]
}

Une fois l’image dans ECR, nous pouvons configurer Snyk pour l’analyser depuis cet emplacement. Dans l’interface Snyk, sélectionnez Add Project, puis accédez à l’icône ECR :

Menu de configuration de projet Snyk affichant les options d’intégration GitHub, Docker Hub, ECR, Kubernetes, CLI et Autre

Si notre configuration ECR est correcte, une vue présentant tous les dépôts et les images qu’ils contiennent devrait s’afficher :

Écran de sélection des dépôts Snyk avec un champ de nom d’image et des cases à cocher pour les dépôts aws-ecr, goof et latest

Nous voyons le dépôt goof créé précédemment, qui contient une seule balise d’image. Sélectionnez l’image, puis cliquez sur le bouton Add selected repositories. Snyk importera alors le dépôt depuis ECR et commencera à l’analyser et à le surveiller.

Une fois l’importation terminée, le projet importé devrait apparaître sur la page Projects de Snyk :

Tableau de bord du dépôt affichant le projet goof et le dernier fichier package.json, avec des badges d’état et les horodatages des tests récents

Snyk a détecté à la fois l’image elle-même et le fichier package.json utilisé par l’application Node et déployé dans l’image, puis a créé un projet pour chacun.

L’image utilise une ancienne image de base vulnérable. Snyk aura détecté de nombreuses vulnérabilités et proposé des images de base qui pourraient réduire le nombre total de vulnérabilités.

Résultats d’une analyse des vulnérabilités AWS présentant des recommandations pour mettre à niveau l’image de base Docker la plus récente de Goof, avec le nombre de vulnérabilités et leur niveau de gravité.

Le fichier package.json répertorie les packages Node inclus directement dans l’application, ceux spécifiés dans le fichier package.json, ainsi que les dépendances indirectes. Snyk aura créé un arbre de dépendances pour tous ces packages et interrogé la base de données des vulnérabilités afin de détecter celles présentes dans les versions utilisées. Vous en verrez beaucoup, car cette application est conçue pour utiliser des versions vulnérables.

Rapport de vulnérabilité du package Goofys signalant une faille de gravité élevée permettant l’écriture arbitraire de fichiers lors de l’extraction d’archives, ainsi que les mesures correctives

Vous trouverez également des informations sur chaque vulnérabilité ainsi que des conseils de correction indiquant quels packages mettre à niveau. Prenez le temps d’explorer toutes les informations disponibles dans l’interface Snyk.

Configurer l’intégration Snyk avec EKS

Nous allons maintenant configurer l’intégration Snyk avec Elastic Kubernetes Service. Pour cela, vous aurez besoin d’un essai gratuit de l’une des formules Snyk standard, car l’intégration Kubernetes fait partie de notre offre payante.

Pour cela, créons un cluster Kubernetes avec EKS. Il existe plusieurs façons de procéder, mais l’une des plus simples consiste à utiliser l’outil eksctl.

Je commence par utiliser AWS CLI pour créer une paire de clés que je pourrai utiliser pour me connecter en SSH aux nœuds de mon cluster si nécessaire :

% aws ec2 create-key-pair --key-name demo --query "KeyMaterial" --output text > demo.pem

J’utilise ensuite eksctl pour créer un cluster, nommé ici mattjarvis-sko, dans la région us-west-2, avec un groupe de nœuds géré sous Linux et ma paire de clés.

% eksctl create cluster --name mattjarvis-sko --region us-west-2 --with-oidc --ssh-access --ssh-public-key SKO_demo --managed

Cette commande prendra un certain temps, mais une fois terminée, vous disposerez d’un cluster EKS entièrement opérationnel et kubectl sera configuré pour communiquer avec lui.

% kubectl get nodes
NAME                                           STATUS   ROLES    AGE    VERSION
ip-192-168-24-115.us-west-2.compute.internal   Ready    <none>   2d5h   v1.18.9-eks-d1db3c
ip-192-168-84-146.us-west-2.compute.internal   Ready    <none>   2d5h   v1.18.9-eks-d1db3c

Maintenant que notre cluster EKS est opérationnel, examinons la configuration Kubernetes permettant de déployer l’application. Dans le dépôt Git de l’application goof, vous trouverez un répertoire manifests contenant deux fichiers YAML Kubernetes.

% ls manifests
goof-deployment.yaml goof-service.yaml

Le fichier goof-deployment.yaml définit l’application goof ainsi qu’un pod mongodb dont elle dépend. Vous devrez modifier la section image pour utiliser le dépôt ECR configuré précédemment :

% cat manifests/goof-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goof
spec:
  replicas: 1
  selector:
    matchLabels:
      app: goof
      tier: frontend
  template:
    metadata:
      labels:
        app: goof
        tier: frontend
    spec:
      containers:
        - name: goof
          image: 478468688580.dkr.ecr.us-west-2.amazonaws.com/goof
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 3001
            - containerPort: 9229
          env:
            - name: DOCKER
              value: "1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goof-mongo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: goof
      tier: backend
  template:
    metadata:
      labels:
        app: goof
        tier: backend
    spec:
      containers:
        - name: goof-mongo
          image: mongo
          ports:
            - containerPort: 27017

Le fichier goof-service.yaml définit le service mongodb, qui fournit une connexion au pod mongodb sur le port 27017. C’est ainsi que notre application goof se connecte à la base de données. Il définit également un service LoadBalancer externe qui sera déployé afin de permettre l’accès externe à l’application en cours d’exécution. L’implémentation de LoadBalancer dépend de la plateforme sur laquelle le cluster est déployé. Dans AWS, elle provisionnera un Elastic Load Balancer, accessible de l’extérieur sur le port 80 et pointant vers le port 3001 de notre pod goof, où s’exécute notre application Node.js. 

% cat manifests/goof-service.yaml   
apiVersion: v1
kind: Service
metadata:
  name: goof
spec:
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3001
    name: "http"
  - protocol: TCP
    port: 9229
    targetPort: 9229
    name: "debug"
  selector:
    app: goof
    tier: frontend
---
apiVersion: v1
kind: Service
metadata:
  name: goof-mongo
spec:
  ports:
  - protocol: TCP
    port: 27017
    targetPort: 27017
    name: "mongo"
  selector:
    app: goof
    tier: backend

Déployons maintenant l’application dans notre cluster :

FIXME TO HERE

% kubectl create -f manifests/goof-deployment.yaml
% kubectl create -f manifests/goof-service.yaml

% kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
goof-5589f855f8-hzvjw        1/1     Running   0          2d13h
goof-mongo-775d5b7d8-w4658   1/1     Running   0          2d13h

% kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                               PORT(S)                       AGE
goof         LoadBalancer   10.100.94.189   adae6cf9abdb84b63919cc27c2ecafcb-1847540121.us-west-2.elb.amazonaws.com   80:32621/TCP,9229:31301/TCP   2d13h
goof-mongo   ClusterIP      10.100.97.98    <none>                                                                    27017/TCP                     2d13h
kubernetes   ClusterIP      10.100.0.1      <none>          

L’URL du champ EXTERNAL-IP est fournie par l’ELB provisionné dans le cadre du service LoadBalancer. Nous pouvons l’utiliser pour consulter notre application en cours d’exécution. Si nous ouvrons cette URL dans un navigateur, l’application goof devrait s’afficher :

Interface minimaliste d’une application TODO, avec le titre « Goof TODO » et un champ de saisie vide.

Notre application est donc déployée et fonctionne dans notre cluster EKS. La dernière étape consiste à configurer l’intégration entre Snyk et notre cluster EKS afin de pouvoir analyser les workloads en cours d’exécution en production. L’intégration Snyk avec Kubernetes repose sur un seul opérateur Kubernetes exécuté dans un pod. Il interroge l’API Kubernetes, analyse les images de conteneurs du cluster et communique avec le backend Snyk.

Si nous utilisions CloudFormation pour déployer le cluster EKS, nous pourrions utiliser les Quick Starts AWS que nous avons créés pour déployer l’intégration Snyk. Comme nous utilisons eksctl pour cette démonstration, procédons à l’installation manuelle.

Commençons par ajouter le dépôt Helm qui contient les charts permettant de déployer le moniteur Kubernetes Snyk :

helm repo add snyk-charts https://snyk.github.io/kubernetes-monitor/

Nous allons maintenant créer un espace de noms distinct pour le moniteur Snyk. En règle générale, il est recommandé de créer des espaces de noms distincts pour vos applications dans Kubernetes, car cela permet de contrôler plus finement les autorisations.

kubectl create namespace snyk-monitor

L’étape suivante consiste à créer un secret dans Kubernetes contenant notre integrationID Snyk. Le processus du moniteur Snyk l’utilisera pour communiquer avec l’API Snyk en amont et transmettre à Snyk des informations sur les pods en cours d’exécution dans le cluster. Si nous utilisions des registres privés nécessitant une authentification pour extraire les images, nous devrions également transmettre ces informations dans la section dockercfg.json. Pour en savoir plus, consultez la documentation du moniteur Snyk.

kubectl create secret generic snyk-monitor -n snyk-monitor --from-literal=dockercfg.json={} --from-literal=integrationId=11111111-1111-1111-1111-111111111111

Une fois le secret créé, nous pouvons utiliser Helm pour installer Snyk Monitor dans l’espace de noms snyk-monitor.

helm upgrade --install snyk-monitor snyk-charts/snyk-monitor --namespace snyk-monitor --set clusterName="Production"

Une fois le chart Helm installé, le pod snyk-monitor devrait être actif dans l’espace de noms snyk-monitor de notre cluster :

% kubectl get pods -n snyk-monitor
NAME                            READY   STATUS    RESTARTS   AGE
snyk-monitor-589cff67c7-kcj8j   1/1     Running   0          2d22h

Nous pouvons également consulter les journaux et vérifier que snyk-monitor envoie des données à Snyk :

% kubectl logs snyk-monitor-589cff67c7-kcj8j
----snipped for brevity-----
{"name":"kubernetes-monitor","hostname":"snyk-monitor-589cff67c7-kcj8j","pid":6,"level":30,"workloadLocator":{"userLocator":"eb30b15b-a0a5-47a4-ab75-7e50b853d6a9","cluster":"Production","namespace":"default","type":"Deployment","name":"goof"},"attempt":1,"msg":"workload metadata sent upstream successfully","time":"2021-02-04T10:43:42.789Z","v":0}
{"name":"kubernetes-monitor","hostname":"snyk-monitor-589cff67c7-kcj8j","pid":6,"level":30,"workloadLocator":{"userLocator":"eb30b15b-a0a5-47a4-ab75-7e50b853d6a9","cluster":"Production","namespace":"default","type":"Deployment","name":"goof-mongo"},"attempt":1,"msg":"workload metadata sent upstream successfully","time":"2021-02-04T10:43:42.821Z","v":0}

Les workloads peuvent mettre un peu de temps à apparaître dans l’interface Snyk, car le moniteur doit d’abord lui transmettre les données. Mais au bout d’une minute environ, vous devriez pouvoir consulter les workloads en cours d’exécution dans votre cluster en accédant à Add Project/Kubernetes :

Menu de création de projet affichant les options GitHub, Docker Hub, ECR, Kubernetes, CLI, dépôts GitHub publics et Autre

Les workloads en cours d’exécution devraient maintenant s’afficher. Pour les ajouter, il suffit de cocher la case afin que Snyk les importe et les teste.

Écran de sélection des workloads Kubernetes affichant l’environnement Production, les espaces de noms default et synke-monitor, ainsi que les options de déploiement.

Une fois le projet importé, accédons à la page Projects pour examiner le projet importé. Première constatation : Snyk a détecté la configuration en cours d’exécution du workload et vérifié si elle présentait des problèmes de sécurité. Ici, plusieurs tests de sécurité ont échoué, notamment parce que l’application s’exécute en tant que root et sans limites CPU :

Rapport de sécurité du déploiement Kubernetes pour default/deployment.apps/goof, présentant les vulnérabilités, les dépendances, les métadonnées et les vérifications de configuration sécurisée.

Si nous examinons maintenant le workload lui-même, nous voyons que Snyk a détecté l’image de base et toutes les vulnérabilités qu’elle contient, et a recommandé d’autres images de base moins exposées aux vulnérabilités.

Page de détails d’une image AWS ECR affichant les résultats de l’analyse des vulnérabilités et des recommandations de mise à niveau pour une image conteneur

Pour conclure

Cette démonstration montre comment intégrer les tests de sécurité tout au long du cycle de développement logiciel, une stratégie essentielle pour préserver la sécurité de nos workloads et de notre infrastructure dans les environnements cloud natifs.

Snyk s’intègre également à un large éventail d’environnements de développement intégrés, d’outils de gestion du code source et de systèmes CI/CD, afin de couvrir l’ensemble de votre pipeline de déploiement.

Si vous utilisez les services de conteneurs et Kubernetes d’Amazon, intégrer Snyk à ECR et EKS est très simple. Des Quick Starts AWS permettent de tout déployer à l’aide de modèles CloudFormation. Créez un compte Snyk gratuit et essayez !

Lancez-vous dans les compétitions Capture The Flag

Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.

Lire la suite

feature insights context
Blog

Les attaques autonomes sont déjà là. La défense doit suivre leur rythme.

Les attaquants autonomes réduisent la fenêtre de défense. Découvrez comment la découverte, la correction, la validation et la prévention continues peuvent aider les équipes de sécurité à suivre le rythme.

Blog

Pourquoi les agents de codage IA créent-ils sans cesse des failles de contrôle d’accès ?

Les agents de codage IA peuvent générer une logique d’autorisation qui compile et passe la revue, tout en exposant les données d’un tenant à un autre. Découvrez pourquoi les failles de contrôle d’accès sont difficiles à détecter et comment les prévenir.

Blog

Evo ADS : la gouvernance des comportements des agents est disponible : maîtrisez l’utilisation de MCP

La gouvernance des comportements des agents Evo ADS est désormais disponible, avec MCP Governance en première étape. Découvrez, approuvez, surveillez, consignez et bloquez l’utilisation des serveurs MCP par les principaux agents de programmation IA.