Integrating Anchore Security into an Azure DevOps Pipeline

Anchore and Azure DevOps

As I’m sure you have read throughout the previous blogs, Anchore is a very versatile tool that brings security to your containerized workflow. It can be integrated into any CI/CD platform for quick and easy security scans. Today I will show you how to integrate it into Azure DevOps, a useful tool offered by Microsoft.

Starter Azure Pipeline

Go ahead and take a look at this simple Azure DevOps pipeline:

trigger:
- master
 
resources:
- repo: self
 
stages:
- stage: Build
  displayName: Build and push stage
  jobs: 
  - job: Build
    displayName: Build
    pool:
      vmImage: ‘ubuntu-latest’
    steps:
    - task: [email protected]
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: jpetersenames/simpleserver
        dockerfile: Dockerfile
        containerRegistry: production
        tags: |
          $(Build.BuildId)

Whenever the code is pushed to this repository, it will kick off this pipeline to build a docker image and push it to our final registry. This is great, but we want to add a security scan for our containers before we push them to the final registry. What better tool to use for this than Anchore!

Adding Security

So what do we need to do to add Anchore to our pipeline? There are a few ways that you can use Anchore when it comes to integrating it into a pipeline. I am going to show you how to use the cli tool to access a running instance of Anchore Engine from inside your Azure DevOps pipeline.

You will need to make sure you have a few things before you start using Anchore:

  1. A running instance of Anchore Engine or Anchore Enterprise
  2. A staging registry for pre-scanned images

To set up an instance of Anchore Engine or Anchore Enterprise, please refer to our quick start documentation. I am going to use an Azure Container Registry as my staging registry. To create the registry go ahead and use your favorite method of creating Azure Resources. I used terraform:

provider "azurerm" {
  version = "=2.0.0"
  features {}
}
 
resource "azurerm_resource_group" "blog" {
  name     = "blog"
  location = "West US"
}
 
resource "azurerm_container_registry" "blog" {
  name                = "anchoreStaging"
  resource_group_name = azurerm_resource_group.blog.name
  location            = azurerm_resource_group.blog.location
  sku                 = "Standard"
  admin_enabled       = true
}

Once you have your registry you need to set up a service connection so you can access it easily from inside your pipeline. Go ahead and set up a service connection with a Docker Registry, once in the next blade select Azure Container Registry. Authenticate your Azure account and then select the anchoreStaging registry you just created.

Alright, now that you have your staging registry you must give Anchore the proper permissions to pull from it. Follow the steps in our documentation if you’re using an Azure Container Registry like I am. These instructions will allow Anchore to pull images from registries that aren’t publicly accessible.

Now that all the configuration has been done for your running instance of Anchore, we can add the tooling to our pipeline. We will need our usual information to access our Anchore instance (URL, username, and password); however, we don’t want to expose our password. To keep our password secret, use a variable group in Azure DevOps and make sure to lock the password variable.

Now we are all set to add Anchore to our Azure DevOps pipeline. Take a look at the pipeline code below. We must import the variable group that we created which contains our secret password, as well as our username and the URL for our Anchore instance.

Note: The Build and Production stages have been left out for brevity.

trigger:
- master

resources:
- repo: self

variables:
- name: stagedImage
  value: 'anchorestaging.azurecr.io/simpleserver:$(Build.BuildId)'
- name: productionImage
  value: 'production/simpleserver:$(Build.BuildId)'

  # Use a variable group to store the Anchore credentials
- group: anchoreCredentials


stages:
- stage: Build
  # Same build stage as previously shown


- stage: Security
  displayName: Security scan stage
  dependsOn: Build
  jobs:
  - job: Security
    displayName: Security
    pool:
      vmImage: 'ubuntu-latest'
    steps:
    - script: python -m pip install --upgrade setuptools wheel anchorecli
      displayName: Install Anchore CLI

      # Use the variables from the anchoreCredentials variable group
    - script: |
        export PATH=$PATH:/home/vsts/.local/bin
        export ANCHORE_CLI_USER=$(anchore_user)
        export ANCHORE_CLI_PASS=$(anchore_pass)
        export ANCHORE_CLI_URL=$(anchore_url)
        anchore-cli image add $(stagedImage) --dockerfile=Dockerfile
        anchore-cli image wait $(stagedImage)
        anchore-cli image vuln $(stagedImage) all
        anchore-cli evaluate check $(stagedImage)
      displayName: Anchore Security Scan

- stage: Production
  # Push the image to your production registry and deploy it however you want

You can see here that we have added a Security stage to our pipeline. Inside this stage, we install the anchore-cli tool using the python pip module. Since we are using the Ubuntu agent offered by Azure DevOps, the anchore-cli tool will install in the .local directory. This directory isn’t in our path by default so we must add it to our path along with configuring the credentials to access our Anchore instance. Once anchore-cli has been configured, you can use it however you like. I have chosen to simply add an image and wait for it to scan. Once it has been scanned, I print out all the vulnerabilities and get the policy evaluation result. The evaluate check command will fail the pipeline if the policy evaluation returns a ‘fail’ result.

Summing Up

To sum it all up, it is very easy to integrate strict security into a new or existing Azure DevOps pipeline. As you can see, it only took a few lines of yaml to add a security scan that will keep insecure or non-compliant containers from reaching our production environment. Anchore is a very versatile tool, and this is just one of the ways it can be deployed into a pipeline. This method uses a running instance of Anchore Engine or Anchore Enterprise to scan the staged images. This provides a stateful scan which means users can grab the results after the fact to create reports and provide justifications for passed or failed scans. Security is a requirement when developing modern production-grade software. Using Anchore and Azure DevOps, software developers can quickly and easily integrate security into their daily workflow to ensure only high-quality and secure software ever makes it to production.