Part 2 – Upload container vulnerability assessment result to Azure Storage Account

Previously I wrote an article to walk people through CI/CD Integration with Azure Security Center. I got a question about uploading vulnerability assessment result to an Azure Storage Account.

In this article, let’s see how to do that with Azure CLI GitHub Action.

Assume you have completed the workflow to scan your docker image using the Azure Container Scan GitHub action. The status has been reflected in Azure Security Center as well. Now you are asked to upload the vulnerability assessment result into an Azure Storage Account so you can download to read it offline or you want to integrate with Azure Logic App or Azure Function for notification or further action.

In this scenario, all you need to do is just log into Azure and run az storage blob upload

There are three steps to complete this action:

Step 1 – Create a Service Principal to authenticate with Azure

Use the following Azure CLI to create a new service principal and grant it Contributor role in your resource group scope:

RG_NAME='azsec-acr-rg'
SUB_ID=$(az account show --query id -o tsv)
SP_NAME='sp-for-storage'
az ad sp create-for-rbac -n "${SP_NAME}" \
                         --role Contributor \
                         --scopes /subscriptions/$SUB_ID/resourceGroups/$RG_NAME \
                         --sdk-auth

Copy the output and re-format it as follows:

{"clientId": "3ce96a3f-84e5-XXXX-ae93-2482a72f984b",
 "clientSecret": "XXXX~jkcuW-XXXXX.BehlMCJ",
 "subscriptionId": "67d6179d-XXXX-4ccd-XXXX-4d3ff2e13349",
 "tenantId": "03987603-0fc0-XXX-XXX-cdffbefb2226",
 "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
 "resourceManagerEndpointUrl": "https://management.azure.com/",
 "activeDirectoryGraphResourceId": "https://graph.windows.net/",
 "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
 "galleryEndpointUrl": "https://gallery.azure.com/",
 "managementEndpointUrl": "https://management.core.windows.net/"}

The following format won’t be accepted:

{
    "clientId": "3ce96a3f-84e5-XXXX-ae93-2482a72f984b",
    "clientSecret": "XXXX~jkcuW-XXXXX.BehlMCJ",
    "subscriptionId": "67d6179d-XXXX-4ccd-XXXX-4d3ff2e13349",
    "tenantId": "03987603-0fc0-XXX-XXX-cdffbefb2226",
    "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
    "resourceManagerEndpointUrl": "https://management.azure.com/",
    "activeDirectoryGraphResourceId": "https://graph.windows.net/",
    "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
    "galleryEndpointUrl": "https://gallery.azure.com/",
    "managementEndpointUrl": "https://management.core.windows.net/"
}

After service principal creation you also need a storage account and container to store the assessment result.

Step 2 – Create secrets to store storage account access key and credential

Use Github Secret to store service principal credentials and storage account key. In my demonstration I created the following secrets in GitHub:

  • AZ_CREDENTIAL
  • AZ_STORAGE_KEY

Step 3 – Update workflow to upload assessment result

After you have a service principal and a storage account with container ready now let’s update the workflow:

- name: Login to Azure
  uses: azure/login@v1
  with:
    creds: ${{ secrets.AZ_CREDENTIAL }}
    allow-no-subscriptions: true
- name: Upload to storage account
  run: |
    az account set -s ${{ env.AZ_SUBCRIPTION_ID }}
    az storage blob upload --account-name ${{ env.AZ_STORAGE_ACCOUNT_NAME }} \
                           --account-key ${{ secrets.AZ_STORAGE_KEY }} \
                           --container-name ${{ env.AZ_STORAGE_CONTAINER_NAME }} \
                           --file ${{ steps.container-scan.outputs.scan-report-path }} \
                           --name ${{ github.sha }}.json

Ensure to add environment variable for your storage account name and container name.

Go to storage account to download and verify the result. Below is the sample result of the testing docker image:

{
  "imageName": "ascacr0731.azurecr.io/azsec-firefox:7f83011c0596de71dc61c4f47b9e7033213b60da",
  "vulnerabilities": [
    {
      "vulnerabilityId": "CVE-2021-33910",
      "packageName": "libsystemd0",
      "severity": "HIGH",
      "description": "basic/unit-name.c in systemd prior to 246.15, 247.8, 248.5, and 249.1 has a Memory Allocation with an Excessive Size Value (involving strdupa and alloca for a pathname controlled by a local attacker) that results in an operating system crash.",
      "target": "ascacr0731.azurecr.io/azsec-firefox:7f83011c0596de71dc61c4f47b9e7033213b60da (ubuntu 18.04)"
    },
    {
      "vulnerabilityId": "CVE-2021-33910",
      "packageName": "libudev1",
      "severity": "HIGH",
      "description": "basic/unit-name.c in systemd prior to 246.15, 247.8, 248.5, and 249.1 has a Memory Allocation with an Excessive Size Value (involving strdupa and alloca for a pathname controlled by a local attacker) that results in an operating system crash.",
      "target": "ascacr0731.azurecr.io/azsec-firefox:7f83011c0596de71dc61c4f47b9e7033213b60da (ubuntu 18.04)"
    }
  ],
  "bestPracticeViolations": [
    {
      "code": "DKL-DI-0005",
      "title": "Clear apt-get caches",
      "level": "FATAL",
      "alerts": "Use 'rm -rf /var/lib/apt/lists' after 'apt-get install' : |1 firefox_version=88.0.1 /bin/sh -c apt-get update     && apt-get install -y wget     && rm -rf /var/lob/apt/lists/*"
    },
    {
      "code": "CIS-DI-0001",
      "title": "Create a user for the container",
      "level": "WARN",
      "alerts": "Last user should not be root"
    },
    {
      "code": "CIS-DI-0005",
      "title": "Enable Content trust for Docker",
      "level": "INFO",
      "alerts": "export DOCKER_CONTENT_TRUST=1 before docker pull/build"
    },
    {
      "code": "CIS-DI-0006",
      "title": "Add HEALTHCHECK instruction to the container image",
      "level": "INFO",
      "alerts": "not found HEALTHCHECK statement"
    },
    {
      "code": "CIS-DI-0008",
      "title": "Confirm safety of setuid/setgid files",
      "level": "INFO",
      "alerts": "setuid file: urwxr-xr-x usr/bin/chfn"
    }
  ],
  "vulnerabilityScanTimestamp": "2021-07-31T22:55:03.609Z"
}

Now you have several options for further steps:

  • Notify your DevOps team and cc to InfoSec manager about the result.
  • Copy/import vulnerable image to another container registry for further review using az acr import CLI
  • Read the result and decide what to do next

Sample email notification after an image is scanned.


This entry was posted in Secure Development and tagged . Bookmark the permalink.

2 Responses to Part 2 – Upload container vulnerability assessment result to Azure Storage Account

  1. Pingback: Quick look at CICD Integration in Azure Security Center to scan your docker image -Microsoft Azure Security Randomness

  2. Pingback: Notify container image vulnerability assessment result to email using Azure Logic App -Microsoft Azure Security Randomness

Leave a Reply

Your email address will not be published. Required fields are marked *