Previously in the Part 1 Blog, I showed you how to use Anchore to perform a stateful scan in Azure DevOps using Anchore Engine or Anchore Enterprise. This method works great, but what if you don’t have a running instance of Anchore? What if you just want to run a scan, gather the results, and then move on? Anchore (being the versatile tool it is) has that capability too!
Azure Starter Pipeline
Remember our simple Azure DevOps pipeline from my previous post:
trigger:
- master
resources:
- repo: self
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: ‘ubuntu-latest’
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: jpetersenames/simpleserver
dockerfile: Dockerfile
containerRegistry: production
tags: |
$(Build.BuildId)
All this pipeline does is build an image and push it to our production registry every time code is pushed to our repository. We want to add security to our pipeline using Anchore, but we don’t have the resources to run a staging registry as well as an instance of Anchore. Perhaps you just want to try out Anchore in your pipeline to see how the compliance scanning works. This is where the inline scan offered by Anchore comes in. You can read more about the tool in the Anchore documentation, but I want to show you how you can seamlessly integrate Anchore into your pipeline with almost no dependencies.
Take a look at the pipeline below. You can see that we no longer need a staging registry. Instead, we just build a local image using BuildKit so we have all the nice features; suggested but not required for Anchore. Once we have our local image, we can grab the inline scan script that is publicly available through Anchore. Using the inline scan script and container, we can perform a compliance scan on a locally built image without any outside dependencies. Pretty cool!
trigger:
- master
resources:
- repo: self
variables:
- name: localImage
value: 'local/simpleserver:$(Build.BuildId)'
- name: productionImage
value: 'production/simpleserver:$(Build.BuildId)'
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: 'ubuntu-latest'
steps:
- script: |
DOCKER_BUILDKIT=1 docker build -t $(localImage) -f Dockerfile .
displayName: Build the local image
- script: |
curl -s https://ci-tools.anchore.io/inline_scan-latest | bash -s -- \
scan -b .anchore/policy.json -d Dockerfile -f -r $(localImage)
displayName: Anchore Security Scan
- script: |
docker tag $(localImage) $(productionImage)
displayName: Tag the image as production
- task: Docker@2
displayName: Push the image to the production registry
inputs:
command: push
repository: jpetersenames/simpleserver
dockerfile: Dockerfile
containerRegistry: production
tags: |
$(Build.BuildId)
You can see that this pipeline is shorter than our previous pipeline that used anchore-cli and an instance of Anchore. The scan is the exact same as using any other instance of Anchore and it will provide the same results. Inline scan can also be loaded with any policy bundle you want to audit your image as I have done here using the -b option. You can also provide the -f option which will fail the pipeline when the policy scan returns a ‘fail’ result. This will provide output similar to what you see below where you are provided with the ‘fail’ result as well as which gates in the policy bundle were violated.
You can also see at the top of the output in the terminal that some reports were generated. These are JSON files that contain the contents Anchore found inside the image as well as a list of the vulnerabilities that were detected.
Overall Anchore’s inline scan functionality is a powerful way to integrate security into your Azure DevOps pipeline. It allows you to run a full Anchore compliance scan with no dependencies. This is great for environments that are air-gapped or if it doesn’t make sense to keep a staging registry or a running Anchore instance.