---
# System prepended metadata

title: Sign and verify an artifact with HashiCorp Vault KMS

---

# Sign and verify an artifact with HashiCorp Vault KMS


>**Note** Certificate in this guide is generated using OpenSSL for development and testing purposes. You need to use a certificate registered from a trusted CA in production.

## Outline

- Install and Configure Vault Development Server
- Generate Key and Certificate and Import them to Vault
- Add the Key to Notation and Sign the Artifact

## Install Notation-HC-Vault plugin and key import utility

1. Download this repo

```bash
git clone https://github.com/OliverShang/notation-hc-vault.git
```
2. Build the plugin

```bash
cd notation-hc-vault/cmd/notation-hc-vault
go build .
```
3. Install the plugin to the notation path specified by [notation plugin spec](https://github.com/notaryproject/notaryproject/blob/main/specs/plugin-extensibility.md#installation).

The folder structure should be like `$XDG_CONFIG_HOME/notation/plugins/hc-vault/notation-hc-vault`

4. Build the key import utility

```bash
cd notation-hc-vault/key-helper
go build .
```

## Install and Configure Vault Server

1. [Install Hashi Corp Vault](https://developer.hashicorp.com/vault/downloads)

2. Start the Vault development server or production server
    2.1 Start Vault development server (skip to step 2.2 if you want to use the production server)
   ```bash
   vault server -dev
   ```
   - In your browser, open `127.0.0.1:8200` to see the webpage of your vault server.
    
    2.2 Start Vault production server (skip to step 3 if you are using the dev server)
   - Create a vault config file udner your work directory. A minimal working example is shown below, more details about config can be found [here](https://developer.hashicorp.com/vault/tutorials/operations/configure-vault#configuration-files)):

    ```bash
    disable_mlock = true
    ui            = true

    listener "tcp" {
      address     = "127.0.0.1:8200"
      tls_disable = "true"
    }

    storage "file" {
      path = "/tmp/vault-data"
    }
    ```
    - In your browser, open `127.0.0.1:8200` to see the webpage of your vault server.
    - Initiate vault on webpage
    Setup the root keys. In this example, the root key is split into 3 key shares, and any two keys of the three will be sufficient to unseal the Vault, [see details](https://developer.hashicorp.com/vault/docs/concepts/seal).
    ![](https://hackmd.io/_uploads/HJZnBfwV2.png)
    Be aware and distribute the keys/root token conscientiously. For testing purposes, just use the root token as `VAULT_TOKEN`.
    ![](https://hackmd.io/_uploads/ByNidMDNh.png)
    
    ! IMPORTANT !: Remember to hit the `Download Keys` button before going forward. Both keys and the initial root token are downloaded. They are used in the next step.
    - Unseal the Vault
    Enter two of the three keys generated previously to unseal the vault.
    ![](https://hackmd.io/_uploads/SyqhtGv4h.png)
    
    By now the Vault production server is ready for testing.

3. Set environment variables

   - Launch a new terminal session.

   - Copy and run the `export VAULT_ADDR ...` command from the terminal output. This will configure the Vault client to talk to your server (dev or prod).
      ```bash
      export VAULT_ADDR='http://127.0.0.1:8200'
      ```

      Vault CLI determines which Vault servers to send requests using the `VAULT_ADDR` environment variable.

   - Set the `VAULT_TOKEN` environment variable value to the generated **Root Token** value displayed in the terminal output.
      ```bash
      export VAULT_TOKEN="hvs.**************"
      ```

4. Enable Transit Secrets Engine and KV Secrets Engine
   ```bash
   vault secrets enable transit
   vault secrets enable -path=secret kv-v2
   ```

## Generate Key and Certificate and Import them to Vault

1. Generate CA root certificate
   ```bash
   openssl genrsa -out ca.key 2048
   openssl req -new -x509 -days 365 -key ca.key -subj "/O=Notation/CN=Notation Root CA" -out ca.crt -addext "keyUsage=critical,keyCertSign"
   ```

2. Generate private key and leaf certificate
   ```bash
   openssl genrsa -out leaf.key 2048
   openssl req -newkey rsa:2048 -nodes -keyout leaf.key -subj "/CN=Notation.leaf" -out leaf.csr
   openssl x509 -req -extfile <(printf "basicConstraints=critical,CA:FALSE\nkeyUsage=critical,digitalSignature") -days 365 -in leaf.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out leaf.crt
   ```

3. Combine the CA certificate and leaf certificate in a pem file (CA certificate after leaf certificate)
   ```bash
   cat leaf.crt ca.crt > certificate_chain.pem
   ```

4. Import certificate and private key using the key import utility

```bash
cd notation-hc-vault/key-helper
key-helper import  --cert_path "{path-to-cert}/combined_cert.pem" --key_name "openssl" --key_path "{path-to-key}/leaf.key"
```

## Add the Key to Notation and Sign the Artifact

1. Add the key to Notation and associate it with hc-vault plugin
   ```bash
   notation key add "openssl-key" --id "openssl-key" --plugin "hc-vault"
   ```

2. Sign the artifact
   ```bash
   notation sign --oci-layout "{path-to-artifact}/oci-layout:v2" --key openssl-key
   ```

   You should expect an output similar to this:

   ```bash
   Warning: Always sign the artifact using digest(@sha256:...) rather than a tag(:v2) because tags are mutable and a tag reference can point to a different artifact than the one signed.
   Successfully signed C:\xxx\oci-layout@sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0
   ```

3. List the signature

    ```bash
    notation list --oci-layout "{path-to-artifact}/oci-layout:v2"
    ```

	You should expect an output similar to this:

    ```bash
    {path-to-artifact}\oci-layout@sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0
    └── application/vnd.cncf.notary.signature
        └── sha256:22a1636b458eecd06cda488099b301e89a155df2460e447ea9ce6d4fcc6d59da
    ```

4. Add the CA certificate to the trust store

   ```bash
   notation cert add -t ca -s alpine "{path-to-ca-cert}/ca.crt"
   ```

5. Verify the signature
   ```bash
   notation verify --oci-layout "{path-to-artifact}/oci-layout:v2" --scope local/oci-layout2 
   ```

   For successful verification, you should expect an output similar to this:

   ```bash
   Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:v2) because resolved digest may not point to the same signed artifact, as tags are mutable.
   Successfully verified signature for C:\Users\creep\Desktop\oci-layout@sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0
   ```

   