---
# System prepended metadata

title: Sign an OCI artifact with Notation in GitHub Actions

---

# Sign an OCI artifact with Notation in GitHub Actions

This document walks you through how to create a GitHub Actions workflow to achieve following goals:

1. Generate an OCI artifact and push it to Azure Container Registry (ACR)
2. Sign the OCI artifact with Notation and Notation Azure Key Vault (AKV) plugin. The generated signature is automatically pushed to Azure Container Registry

## Prerequisites

- You have created a Key Vault in Azure Key Vault and created a self-signed signing key and certificate. You can follow this [doc](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-tutorial-sign-build-push#create-a-self-signed-certificate-azure-cli) to create self-signed key and certificate for testing purposes
- You have created a registry in Azure Container Registry
- You have a GitHub repository to store the sample workflow and GitHub Secrets

## Create necessary GitHub Secrets

Enter your GitHub repository, add two Repository secrets  `ACR_PASSWORD` and `AZURE_CREDENTIALS` for authenticating with ACR and AKV.

See [GitHub Doc](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) for how to add Repository secrets in a GitHub repository.

### `ACR_PASSWORD`
The password to log in to the ACR where your OCI artifact will be stored.

### `AZURE_CREDENTIALS`
The credential to AKV where your signing key pair is stored.

Follow the steps below to get the value of `AZURE_CREDENTIALS`.

- Execute the following commands to create a new service principal on Azure.

```
# login using your own account
az login

# Create a service principal
# Output of this command is in JSON format
spn=notationtest
az ad sp create-for-rbac -n $spn --sdk-auth
```

> [!IMPORTANT]
> 1. Paste the entire JSON output from the `az ad sp` command execution result into `AZURE_CREDENTIALS`'s secret value field.
>
> 2. Save the `clientId` from the JSON output into an environment variable (without double quotes) as it will be needed in the next step:
>```
>  clientId=<clientId_from_JSON_output_of_last_step>
>```

- Grant AKV access permissions to the service principal that we created in the previous step.

```
# set policy for your AKV
akv=<your_akv_name>
az keyvault set-policy --name $akv --spn $clientId --certificate-permissions get --key-permissions sign --secret-permissions get
```

See [az keyvault set-policy](https://learn.microsoft.com/en-us/cli/azure/keyvault?view=azure-cli-latest#az-keyvault-set-policy) for details.

## Create the GitHub Actions Workflow

- `git clone` your Git repository.

- Create `<your_git_repo>/.github/workflows/<your_workflow>.yml` as your repository's CI/CD pipeline. As a start, you can copy the [signing workflow template](https://github.com/notation-playground/notation-integration-with-ACR-and-AKV/blob/template/sign-template.yml) from the collapsed section below to your own `<your_workflow>.yml` file. 

- Update the environmental variables based on your environment by following the comments in the template. `git add` and `git commit` to the repository.

<details>

<summary>See the signing workflow template (Click here).</summary>

```yaml
# build and push an OCI artifact to ACR, setup notation and sign the artifact
name: notation-github-actions-sign-template

on:
  push:

env:
  ACR_REGISTRY_NAME: <registry_name_of_your_ACR>        # example: myRegistry.azurecr.io
  ACR_REPO_NAME: <repository_name_of_your_ACR>          # example: myRepo
  ACR_USERNAME: <user_name_of_your_ACR>                 # example: myRegistry
  AKV_NAME: <your_Azure_Key_Vault_Name>                 # example: myAzureKeyVault
  KEY_ID: <key_id_of_your_private_key_to_sign_in_AKV>   # example: https://mynotationakv.vault.azure.net/keys/notationLeafCert/c585b8ad8fc542b28e41e555d9b3a1fd
  NOTATION_EXPERIMENTAL: 1                              # [Optional] when set, can use Referrers API in the workflow

jobs:
  notation-sign:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: prepare
        id: prepare
        # using `v1` as an example tag, user can pick their own
        run: |
          echo "target_artifact_reference=${{ env.ACR_REGISTRY_NAME }}/${{ env.ACR_REPO_NAME }}:v1" >> "$GITHUB_ENV"
      # Log into your ACR
      - name: docker login
        uses: azure/docker-login@v1
        with:
          login-server: ${{ env.ACR_REGISTRY_NAME }}
          username: ${{ env.ACR_USERNAME }}
          password: ${{ secrets.ACR_PASSWORD }}
      # Build and Push an OCI artifact to ACR
      # Using `Dockerfile` as an example to build an OCI artifact
      - name: Build and push
        id: push
        uses: docker/build-push-action@v4
        with:
          push: true
          tags: ${{ env.target_artifact_reference }}
      # Get the manifest digest of the OCI artifact
      - name: Retrieve digest
        run: |
          echo "target_artifact_reference=${{ env.ACR_REGISTRY_NAME }}/${{ env.ACR_REPO_NAME }}@${{ steps.push.outputs.digest }}" >> "$GITHUB_ENV"
      # Log into Azure in order to access AKV
      - name: Azure login
        uses: Azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
          allow-no-subscriptions: true
      
      # Install Notation CLI, the default version is "1.0.0"
      - name: setup notation
        uses: notaryproject/notation-action/setup@main
      
      # Sign your OCI artifact using private key stored in AKV
      - name: sign OCI artifact using key pair from AKV
        uses: notaryproject/notation-action/sign@main
        with:
          plugin_name: azure-kv
          plugin_url: https://github.com/Azure/notation-azure-kv/releases/download/v1.0.0/notation-azure-kv_1.0.0_linux_amd64.tar.gz
          plugin_checksum: 82d4fee34dfe5e9303e4340d8d7f651da0a89fa8ae03195558f83bb6fa8dd263
          key_id: ${{ env.KEY_ID }}
          target_artifact_reference: ${{ env.target_artifact_reference }}
          signature_format: cose
          plugin_config: |-
            ca_certs=.github/cert-bundle/cert-bundle.crt
            self_signed=false
          # if using self-signed certificate from AKV, then the plugin_config should be:
          # plugin_config: |-
          #   self_signed=true
          allow_referrers_api: 'true'
```

</details>

## Trigger the GitHub Actions Workflow

The workflow trigger logic has been set to `on: push` [event](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#using-events-to-trigger-workflows) so that the workflow will run when `git push` to your GitHub repository.

On success, you will be able to see the OCI artifact been pushed to your ACR with a COSE format signature attached to it.

Another use case is to trigger the workflow when a new tag is created in your GitHub repository. See [this doc](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#example-excluding-branches-and-tags) for details. This use case is typical in a software release process.

## Check the GitHub Actions Workflow running status

See the workflow logs under the GitHub `Actions` tab of your GitHub repository.