# 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.