---
# System prepended metadata

title: Offline Content Signing Proposal

---

# Offline Content Signing Proposal


1. The content is fully offline before the signature can be produced. 
2. The signature may be done using notation plugins or other configuration as need for local keys or using a remote signing service.
 

Here we use an example dockerfile below to build an offline archive that can be signed before pushing to the registry.

```dockerfile
FROM alpine:latest

RUN apk update && \
    apk add --update curl && \
    rm -rf /var/cache/apk/*
ENTRYPOINT ["/usr/bin/curl"]
```

## Proposal

The proposal is to recommend using `buildx` to create the offline archive and use the contents from that to generate the signature. 

:::warning
Proposal uses buildx which can be replaced with any builder that is able to produce a local OCI archive.
:::


###  Setup buildx and build the image offline 

This should generate a metadata file which as the image manifest descriptor 

```bash
$ docker buildx create --use --driver=docker-container

$ docker buildx build  --metadata-file metadata.json \
     --output=type=docker,dest=offline_alpine.tar \
     -f Dockerfile .
 ```

### Sign using notation from stdin or file path. 


- Option 1: Have notation use the archive. 

```bash

# generate the signature from the OCI layout.
$ notation sign offline_alpine.tar
Content manifest digest: sha256:aabbccddee
Signature manifest digest: sha256:aabbccddee

# View signatures locally
$notation ls
```

- Option 2: Support descriptor signing in notation if the full archive is not available and produce a file for consumption.

```bash
# extract the descriptor and sign 
cat metadata.json | jq '."containerimage.descriptor"' | \
    notation sign --output image.signature --descriptor --
```

### Push the signature and image

Use the image digest to push the signature. 

```bash
## Use the digest from the previous step. 
# and see if we can get the signature from the notation cache
notation attach \
    myregistry.io/wabbit-networks/net-monitor \
    -d $SIGNATURE_MANIFEST_DIGEST

# Push the image to the registry 
# This can be any client that can push an OCI layout. 
oras push -t myregistry.io/wabbit-networks/net-monitor:v1 --archive offline_netmonitor.tar
```

:::info
See below for more details about the files produced by buildx
:::

---
#### Details 

Docker buildx produces the following metadata. 


```json
➜ cat metadata.json | jq
{
  "containerimage.buildinfo": {
    "frontend": "dockerfile.v0",
    "attrs": {
      "filename": "Dockerfile"
    },
    "sources": [
      {
        "type": "docker-image",
        "ref": "docker.io/library/alpine:latest",
        "pin": "sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad"
      }
    ]
  },
  "containerimage.config.digest": "sha256:29088db788c0c622191aa050f719d11936ece2fc3bf8bae6e3a048f4efb51c26",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4",
    "size": 739,
    "annotations": {
      "org.opencontainers.image.created": "2022-10-14T20:37:40Z"
    }
  },
  "containerimage.digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4"
}
```

The manifest can be viewed in the tar file that has the oci layout 

```bash
➜ tar -t -f offline_alpine.tar
blobs/
blobs/sha256/
blobs/sha256/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49
blobs/sha256/29088db788c0c622191aa050f719d11936ece2fc3bf8bae6e3a048f4efb51c26
blobs/sha256/400d6aa32c694f8ce9342269ed26d085505b1a02bf9e976378e7bec2ccdb5898
blobs/sha256/bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4
index.json
manifest.json
oci-layout
```

You can see the manifest here - 

```json 
➜ tar -axf offline_alpine.tar index.json -O | jq
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4",
      "size": 739,
      "annotations": {
        "org.opencontainers.image.created": "2022-10-14T20:37:40Z"
      }
    }
  ]
}
```

- Notation only needs the descriptor for signing and maybe we can pass in more info into notation. 


    
## Cleanup 

```bash
docker buildx rm docker-container 
```