github.com/containerd/nerdctl@v1.7.7/docs/cosign.md (about)

     1  # Container Image Sign and Verify with cosign tool
     2  
     3  | :zap: Requirement | nerdctl >= 0.15 |
     4  |-------------------|-----------------|
     5  
     6  [cosign](https://github.com/sigstore/cosign) is tool that allows you to sign and verify container images with the
     7  public/private key pairs or without them by providing
     8  a [Keyless support](https://github.com/sigstore/cosign/blob/main/KEYLESS.md).
     9  
    10  Keyless uses ephemeral keys and certificates, which are signed automatically by
    11  the [fulcio](https://github.com/sigstore/fulcio) root CA. Signatures are stored in
    12  the [rekor](https://github.com/sigstore/rekor) transparency log, which automatically provides an attestation as to when
    13  the signature was created.
    14  
    15  Cosign would use prompt to confirm the statement below during `sign`. Nerdctl added `--yes` to Cosign command, which says yes and prevents this prompt.
    16  Using Nerdctl push with signing by Cosign means that users agree the statement.
    17  
    18  
    19  ```
    20  Note that there may be personally identifiable information associated with this signed artifact.
    21  This may include the email address associated with the account with which you authenticate.
    22  This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
    23  
    24  By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.
    25  ```
    26  
    27  You can enable container signing and verifying features with `push` and `pull` commands of `nerdctl` by using `cosign`
    28  under the hood with make use of flags `--sign` while pushing the container image, and `--verify` while pulling the
    29  container image.
    30  
    31  > * Ensure cosign executable in your `$PATH`.
    32  > * You can install cosign by following this page: https://docs.sigstore.dev/cosign/installation
    33  
    34  Prepare your environment:
    35  
    36  ```shell
    37  # Create a sample Dockerfile
    38  $ cat <<EOF | tee Dockerfile.dummy
    39  FROM alpine:latest
    40  CMD [ "echo", "Hello World" ]
    41  EOF
    42  ```
    43  
    44  > Please do not forget, we won't be validating the base images, which is `alpine:latest` in this case, of the container image that was built on,
    45  > we'll only verify the container image itself once we sign it.
    46  
    47  ```shell
    48  
    49  # Build the image
    50  $ nerdctl build -t devopps/hello-world -f Dockerfile.dummy .
    51  
    52  # Generate a key-pair: cosign.key and cosign.pub
    53  $ cosign generate-key-pair
    54  
    55  # Export your COSIGN_PASSWORD to prevent CLI prompting
    56  $ export COSIGN_PASSWORD=$COSIGN_PASSWORD
    57  ```
    58  
    59  Sign the container image while pushing:
    60  
    61  ```
    62  # Sign the image with Keyless mode
    63  $ nerdctl push --sign=cosign devopps/hello-world
    64  
    65  # Sign the image and store the signature in the registry
    66  $ nerdctl push --sign=cosign --cosign-key cosign.key devopps/hello-world
    67  ```
    68  
    69  Verify the container image while pulling:
    70  
    71  > REMINDER: Image won't be pulled if there are no matching signatures in case you passed `--verify` flag.
    72  
    73  > REMINDER: For keyless flows to work, you need to set either --cosign-certificate-identity or --cosign-certificate-identity-regexp, and either --cosign-certificate-oidc-issuer or --cosign-certificate-oidc-issuer-regexp. The OIDC issuer expected in a valid Fulcio certificate for --verify=cosign, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth.
    74  
    75  ```shell
    76  # Verify the image with Keyless mode
    77  $ nerdctl pull --verify=cosign --certificate-identity=name@example.com --certificate-oidc-issuer=https://accounts.example.com devopps/hello-world
    78  INFO[0004] cosign:
    79  INFO[0004] cosign: [{"critical":{"identity":...}]
    80  docker.io/devopps/nginx-new:latest:                                               resolved       |++++++++++++++++++++++++++++++++++++++|
    81  manifest-sha256:0910d404e58dd320c3c0c7ea31bf5fbfe7544b26905c5eccaf87c3af7bcf9b88: done           |++++++++++++++++++++++++++++++++++++++|
    82  config-sha256:1de1c4fb5122ac8650e349e018fba189c51300cf8800d619e92e595d6ddda40e:   done           |++++++++++++++++++++++++++++++++++++++|
    83  elapsed: 1.4 s                                                                    total:  1.3 Ki (928.0 B/s)
    84  
    85  # You can not verify the image if it is not signed
    86  $ nerdctl pull --verify=cosign --cosign-key cosign.pub devopps/hello-world-bad
    87  INFO[0003] cosign: Error: no matching signatures:
    88  INFO[0003] cosign: failed to verify signature
    89  INFO[0003] cosign: main.go:46: error during command execution: no matching signatures:
    90  INFO[0003] cosign: failed to verify signature
    91  ```
    92  
    93  ## Cosign in Compose
    94  
    95  > Cosign support in Compose is also experimental and implemented based on Compose's [extension](https://github.com/compose-spec/compose-spec/blob/master/spec.md#extension) capibility.
    96  
    97  cosign is supported in `nerdctl compose up|run|push|pull`. You can use cosign in Compose by adding the following fields in your compose yaml. These fields are _per service_, and you can enable only `verify` or only `sign` (or both).
    98  
    99  ```yaml
   100  # only put cosign related fields under the service you want to sign/verify.
   101  services:
   102    svc0:
   103      build: .
   104      image: ${REGISTRY}/svc0_image # replace with your registry
   105      # `x-nerdctl-verify` and `x-nerdctl-cosign-public-key` are for verify
   106      # required for `nerdctl compose up|run|pull`
   107      x-nerdctl-verify: cosign
   108      x-nerdctl-cosign-public-key: /path/to/cosign.pub
   109      # `x-nerdctl-sign` and `x-nerdctl-cosign-private-key` are for sign
   110      # required for `nerdctl compose push`
   111      x-nerdctl-sign: cosign
   112      x-nerdctl-cosign-private-key: /path/to/cosign.key
   113      ports:
   114      - 8080:80
   115    svc1:
   116      build: .
   117      image: ${REGISTRY}/svc1_image # replace with your registry
   118      ports:
   119      - 8081:80
   120  ```
   121  
   122  Following the cosign tutorial above, first set up environment and prepare cosign key pair:
   123  
   124  ```shell
   125  # Generate a key-pair: cosign.key and cosign.pub
   126  $ cosign generate-key-pair
   127  
   128  # Export your COSIGN_PASSWORD to prevent CLI prompting
   129  $ export COSIGN_PASSWORD=$COSIGN_PASSWORD
   130  ```
   131  
   132  We'll use the following `Dockerfile` and `docker-compose.yaml`:
   133  
   134  ```shell
   135  $ cat Dockerfile
   136  FROM nginx:1.19-alpine
   137  RUN uname -m > /usr/share/nginx/html/index.html
   138  
   139  $ cat docker-compose.yml
   140  services:
   141    svc0:
   142      build: .
   143      image: ${REGISTRY}/svc1_image # replace with your registry
   144      x-nerdctl-verify: cosign
   145      x-nerdctl-cosign-public-key: ./cosign.pub
   146      x-nerdctl-sign: cosign
   147      x-nerdctl-cosign-private-key: ./cosign.key
   148      ports:
   149      - 8080:80
   150    svc1:
   151      build: .
   152      image: ${REGISTRY}/svc1_image # replace with your registry
   153      ports:
   154      - 8081:80
   155  ```
   156  
   157  For keyless mode, the `docker-compose.yaml` will be:
   158  ```
   159  $ cat docker-compose.yml
   160  services:
   161    svc0:
   162      build: .
   163      image: ${REGISTRY}/svc1_image # replace with your registry
   164      x-nerdctl-verify: cosign
   165      x-nerdctl-sign: cosign
   166      x-nerdctl-cosign-certificate-identity: name@example.com # or x-nerdctl-cosign-certificate-identity-regexp
   167      x-nerdctl-cosign-certificate-oidc-issuer: https://accounts.example.com # or x-nerdctl-cosign-certificate-oidc-issuer-regexp
   168      ports:
   169      - 8080:80
   170    svc1:
   171      build: .
   172      image: ${REGISTRY}/svc1_image # replace with your registry
   173      ports:
   174      - 8081:80
   175  ```
   176  
   177  > The `env "COSIGN_PASSWORD="$COSIGN_PASSWORD""` part in the below commands is a walkaround to use rootful nerdctl and make the env variable visible to root (in sudo). You don't need this part if (1) you're using rootless, or (2) your `COSIGN_PASSWORD` is visible in root.
   178  
   179  First let's `build` and `push` the two services:
   180  
   181  ```shell
   182  $ sudo nerdctl compose build
   183  INFO[0000] Building image xxxxx/svc0_image
   184  ...
   185  INFO[0000] Building image xxxxx/svc1_image
   186  [+] Building 0.2s (6/6) FINISHED
   187  
   188  $ sudo env "COSIGN_PASSWORD="$COSIGN_PASSWORD"" nerdctl compose --experimental=true push
   189  INFO[0000] Pushing image xxxxx/svc1_image
   190  ...
   191  INFO[0000] Pushing image xxxxx/svc0_image
   192  INFO[0000] pushing as a reduced-platform image (application/vnd.docker.distribution.manifest.v2+json, sha256:4329abc3143b1545835de17e1302c8313a9417798b836022f4c8c8dc8b10a3e9)
   193  INFO[0000] cosign: WARNING: Image reference xxxxx/svc0_image uses a tag, not a digest, to identify the image to sign.
   194  INFO[0000] cosign:
   195  INFO[0000] cosign: This can lead you to sign a different image than the intended one. Please use a
   196  INFO[0000] cosign: digest (example.com/ubuntu@sha256:abc123...) rather than tag
   197  INFO[0000] cosign: (example.com/ubuntu:latest) for the input to cosign. The ability to refer to
   198  INFO[0000] cosign: images by tag will be removed in a future release.
   199  INFO[0000] cosign: Pushing signature to: xxxxx/svc0_image
   200  ```
   201  
   202  Then we can `pull` and `up` services (`run` is similar to up):
   203  
   204  ```shell
   205  # ensure built images are removed and pull is performed.
   206  $ sudo nerdctl compose down
   207  $ sudo env "COSIGN_PASSWORD="$COSIGN_PASSWORD"" nerdctl compose --experimental=true pull
   208  $ sudo env "COSIGN_PASSWORD="$COSIGN_PASSWORD"" nerdctl compose --experimental=true up
   209  $ sudo env "COSIGN_PASSWORD="$COSIGN_PASSWORD"" nerdctl compose --experimental=true run svc0 -- echo "hello"
   210  # clean up compose resources.
   211  $ sudo nerdctl compose down
   212  ```
   213  
   214  Check your logs to confirm that svc0 is verified by cosign (have cosign logs) and svc1 is not. You can also change the public key in `docker-compose.yaml` to a random value to see verify failure will stop the container being `pull|up|run`.