Thursday, 13 October, 2022 UTC


Summary

GitOps is a popular framework for managing and securing the application development pipeline. For many who have embarked on a GitOps journey, a common question is: “how can I secure my pipeline when everything is automated?” 
The GitOps framework is a concept where any code commits or changes are done through Git, which then triggers an automated pipeline that builds and deploys applications on Kubernetes. Because there are few touch points for development and security teams in the pipeline, its security needs to be mandated to ensure the deployed applications have as few vulnerabilities as possible. 
This blog covers how Snyk can provide application security in GitOps, focusing on a popular tool, Argo CD. In this scenario, Snyk runs an IaC scan to ensure the to-be-deployed application is safe before deployment, and stops the build if it is not. Snyk also can monitor the deployed applications across different namespaces in Kubernetes in an automated fashion.
What is Argo CD?
Argo CD is a declarative, Kubernetes-native continuous delivery (CD) tool which tracks a repository and detects changes, or “drift”. It then applies the required changes to the Kubernetes cluster configuration.
Setting up Argo CD to work with Snyk
This is a demo for starting your GitOps process with Argo CD, using Snyk to provide security coverage on the application and monitoring of Kubernetes workloads. You’ll take the following steps:
  1. Clone your Git repository
  2. Configure Argo CD
  3. Deploy the application using Argo CD
  4. Create a Kubernetes secret object for your Snyk token
  5. Create an Argo CD PreSync resource hook
  6. Wait for Argo CD to detect the configuration drift
  7. Integrate with Kubernetes

Prerequisites

  1. A Snyk account with a Business or Enterprise plan is required to run Snyk tests on Argo CD, and to auto-import Kubernetes workloads into Snyk. If you don’t have a Snyk account, you can start a free trial of our Business plan.
  2. A running Argo CD instance in your Kubernetes cluster. Setup details are in the Argo CD documentation.
  3. A running Kubernetes cluster (for example, EKS, AKS, GKE, Red Hat OpenShift, or any supported flavor).

Step 1: Clone your Git repository

This demo uses a flask polling application where the source code is hosted at https://github.com/jiajunngjj/flask-polling-app. Clone the repository to your own environment.
➜  git clone https://github.com/jiajunngjj/flask-polling-app.git

Step 2: Configure Argo CD

Add your Kubernetes cluster into Argo CD:
➜ argocd cluster add CONTEXTNAME
In this demo, Argo CD resides inside this Kubernetes cluster, so it is automatically connected using the internal K8s hostname (kubernetes.default.svc):
Next, make sure the previously mentioned repository is also added to Argo CD:
When the repository is added successfully, you should see something like this:

Step 3: Deploy the application using Argo CD

Create a Kubernetes namespace to deploy the application. In this case, we’re creating the argocd-demo namespace to run the flask-polling-app:
➜ kubectl create ns argocd-demo
Use the Argo CD command line to create the application (or do it via the Argo CD UI after you have added the repository):
➜ argocd app create snyk-demo  \  --repo https://github.com/jiajunngjj/flask-polling-app.git \  --path argocd \  --dest-server https://kubernetes.default.svc \  --dest-namespace argocd-demo
Here’s a breakdown of the command:
  • repo — Source code management (SCM) repository
  • path — The directory that has the Kubernetes manifest 
  • dest-server — The Kubernetes cluster
  • dest-namespace — The namespace in Kubernetes to deploy the application
After the application is created on Argo CD, the created application on the UI shows an OutOfSync status:
Next, run the Argo CD sync command to deploy the application:
➜ argocd app sync snyk-demo
You should then see the application in the Argo CD UI:
You should also be able to see that the app has started deploying to the Kubernetes namespace, argocd-demo:
➜ kubectl get pods -n argocd-demo
NAME                           READY   STATUS      RESTARTS   AGEpolling-app-6f5978849c-pp8f4   1/1     Running     0          33spolling-app-6f5978849c-tqpd2   1/1     Running     0          33s

Step 4: Create a Kubernetes secret object for your Snyk token

After the application has been successfully added to Argo CD, it’s time to include the Snyk IaC test in the Argo CD pipeline. Retrieve your Snyk token from the Snyk App and create a secret object in the argocd-demo namespace:
➜ kubectl create secret generic snyk-token \  --from-literal=token=<XXXX-XXXXXX-XXXXXXXX> \  -n argocd-demo

Step 5: Create an Argo CD PreSync resource hook

Create a file called snyk-scan.yaml in the same directory as the deployment YAML files, (argocd), containing the following content:
apiVersion: batch/v1
kind: Job
metadata:
  name: snyk-iac-scan
  annotations:
    argocd.argoproj.io/hook: PreSync
spec:
  ttlSecondsAfterFinished: 600
  template:
    spec:
      containers:
      - name: snyk-cli
        image: snyk/snyk-cli:npm
        command: ["/bin/sh","-c"]
        args:
          - git clone https://github.com/jiajunngjj/flask-polling-app.git;
            snyk auth $SNYK_TOKEN;
            snyk iac test flask-polling-app/argocd/polling-app.yaml || true;
        env:
          - name: SNYK_TOKEN
            valueFrom:
              secretKeyRef:
                name: snyk-token
                key: token
      restartPolicy: Never
  backoffLimit: 0
Edit the polling-app.yaml to trigger configuration drift detection (in this example, the number of replicas is changed to “1”):
---
apiVersion: v1
kind: Service
metadata:
  name: polling-app
spec:
  ports:
  - name: 8080-tcp
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: polling-app
  type: LoadBalancer


---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: polling-app
spec:
  replicas: 1
  selector:
  matchLabels:
    app: polling-app
  template:
    metadata:
      labels:
        app: polling-app
    spec:
      containers:
      - image: jiajunngjj/polling-app
        name: polling-app
        ports:
        - containerPort: 8080
      restartPolicy: "Always"
Run Git commands to send the file to the repository:
➜ git add argocd/snyk-scan.yaml argocd/polling-app.yaml
➜ git commit -m "added snyk-scan.yaml and edited polling-app.yaml"
➜ git push

Step 6: Wait for Argo CD to detect the configuration drift

When Argo CD detects the configuration drift, it begins to sync to achieve the desired new state. You can see the Snyk IaC scan triggered before the application is deployed:
You can also see the snyk-iac-scan running as pod:
➜ kubectl get pods -n argocd-demo
NAME                           READY   STATUS      RESTARTS   AGE
polling-app-6f5978849c-pp8f4   1/1     Running     0          16m
snyk-iac-scan-9x8gz            0/1     Completed   0          2m32s
Finally, you can see from the Argo CD UI that there is a snyk-iac-scan job:

Step 7: Integrate with Kubernetes

Snyk integrates with Kubernetes, enabling you to import and test your running workloads to identify vulnerabilities in their associated images and to identify configurations that might make those workloads less secure. After being imported, Snyk will continually monitor those workloads, identifying and prioritizing security issues as new images are deployed and the workload configurations change.
An advantage here is that your deployment YAML files don’t need any updating, as it is all done automatically through the Snyk Controller if you set it to auto import (as explained in the Snyk documnentation). Snyk supports the following workloads:
  • Deployments
  • ReplicaSets
  • DaemonSets
  • StatefulSets
  • Jobs
  • CronJobs
  • ReplicationControllers
  • Pods
Other Snyk blog posts illustrate how you can install multiple Snyk Kubernetes clusters into a single cluster, and how to use Pulumi to automate Snyk Kubernetes integration. 
When Argo CD has deployed your application, Snyk’s Kubernetes integration imports that workload scan, all without manual intervention, into the platform:
Summary
This demo uses the resource hook from Argo CD to trigger a Snyk IaC scan whenever a change in the configuration is detected. As such, a GitOps workflow can be mandated with security, using Snyk to detect any vulnerabilities and stop the workflow whenever a detected vulnerability hits the defined severity threshold. This ensures that vulnerable code never reaches the production environment. 
Learn more
Now that you have learned how to set up a Snyk IaC test with Argo CD and monitor workloads on Kubernetes, check out these resources for information on how to further secure your software development life cycle:
  • Snyk CI/CD Integrations
  • Build your own custom rules
  • Detect drift and manually created resources
Snyk integrates with many CI/CD tools
Start deploying more secure applications on your GitOps journey today.
Try it for free