github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/internal/builders/docker/README.md (about)

     1  # Generation of SLSA3+ provenance for artifacts created in a Docker container
     2  
     3  This document explains how to generate SLSA provenance for artifacts created by
     4  running a command inside a user-supplied container.
     5  
     6  The container-based workflow uses a GitHub Actions [reusable
     7  workflow](https://docs.github.com/en/actions/using-workflows/reusing-workflows)
     8  to build the artifacts and generate the SLSA provenance. We'll call this
     9  workflow the "container-based workflow" from now on.
    10  
    11  This workflow differs from the [generic container
    12  workflow](../container/README.md) which attests to a container image, not
    13  artifacts that are built from a process within a Docker image. This also differs
    14  from the [generic artifact workflow](../generic/README.md) as it performs the
    15  build as well as generates the provenance. This workflow uses a distinct build
    16  type that provides the full details on the build process.
    17  
    18  **NOTE**: This workflow is currently in
    19  [beta testing](https://github.com/yogeshkumararora/slsa-github-generator/milestone/4).
    20  
    21  ---
    22  
    23  <!-- markdown-toc --bullets="-" -i README.md -->
    24  
    25  <!-- toc -->
    26  
    27  - [Benefits of Provenance](#benefits-of-provenance)
    28  - [Generating Provenance](#generating-provenance)
    29    - [Getting Started](#getting-started)
    30    - [Referencing the SLSA builder](#referencing-the-slsa-builder)
    31    - [Private Repositories](#private-repositories)
    32    - [Registry Authentication](#registry-authentication)
    33    - [Supported Triggers](#supported-triggers)
    34    - [Configuration File](#configuration-file)
    35    - [Workflow Inputs](#workflow-inputs)
    36    - [Workflow Example](#workflow-example)
    37    - [Workflow Outputs](#workflow-outputs)
    38    - [Provenance Format](#provenance-format)
    39    - [Provenance Example](#provenance-example)
    40  - [Command line tool](#command-line-tool)
    41    - [The `dry-run` subcommand](#the-dry-run-subcommand)
    42    - [The `build` subcommand](#the-build-subcommand)
    43    - [The `verify` command](#the-verify-command)
    44  - [Users](#users)
    45  - [Known Issues](#known-issues)
    46    - [Compatibility with `actions/download-artifact`](#compatibility-with-actionsdownload-artifact)
    47  
    48  <!-- tocstop -->
    49  
    50  ---
    51  
    52  ## Benefits of Provenance
    53  
    54  Using this workflow to build artifacts will generate a non-forgeable attestation
    55  to specified artifacts using the identity of the GitHub workflow. This can be
    56  used to create a positive attestation to artifacts built inside a container
    57  image coming from your repository.
    58  
    59  In addition, the provenance contains detailed information about the build
    60  process: the base image, the command that was run to generate the artifact, the
    61  produced artifacts, and the environment where the execution was preformed.
    62  
    63  That means that once your users verify the artifacts they have downloaded they
    64  can be sure that the artifacts was created by your repository's workflow and
    65  hasn't been tampered with. The details in the provenance allow users to create
    66  policy on or verify properties of the build and even provide enough information
    67  to reproduce the artifact.
    68  
    69  ## Generating Provenance
    70  
    71  The container-based workflow uses a Github Actions reusable workflow to generate
    72  the provenance.
    73  
    74  ### Getting Started
    75  
    76  ### Referencing the SLSA builder
    77  
    78  At present, the generator **MUST** be referenced by a tag of the form `@vX.Y.Z`,
    79  because the build will fail if you reference it via a shorter tag like `@vX.Y`
    80  or `@vX` or if you reference it by a hash.
    81  
    82  For more information about this design decision and how to configure
    83  renovatebot, see the main repository [README.md](../../../README.md).
    84  
    85  ### Private Repositories
    86  
    87  Private repositories are supported with some caveats. Currently all builds
    88  generate and post a new entry in the public
    89  [Rekor](https://github.com/sigstore/rekor) API server instance at
    90  <https://rekor.sigstore.dev/>. This entry includes the repository name. This
    91  will cause the private repository name to leak and be discoverable via the
    92  public Rekor API server.
    93  
    94  If this is ok with you, you can set the `rekor-log-public` flag in order to opt
    95  in to publishing to the public Rekor instance from a private repository.
    96  
    97  ```yaml
    98  with:
    99    rekor-log-public: true
   100  ```
   101  
   102  If you do not set this flag then private repositories will generate an error in
   103  order to prevent leaking repository name information.
   104  
   105  Support for private transparency log instances that would not leak repository
   106  name information is tracked on [issue #372](https://github.com/yogeshkumararora/slsa-github-generator/issues/372).
   107  
   108  ### Registry Authentication
   109  
   110  This workflow support authentication against a Docker registry for private base images
   111  through an input `registry-username` and `registry-password` secret. Authentication is
   112  not required for public base images.
   113  See [Workflow Inputs](#workflow-inputs) for more.
   114  
   115  Authentication to GCR using GCP workflow identity federation is also supported using
   116  `gcp-workload-identity-provider` and `gcp-service-account`.
   117  
   118  ### Supported Triggers
   119  
   120  The following [GitHub trigger
   121  events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows)
   122  are fully supported and tested:
   123  
   124  - `schedule`
   125  - Manual run via `workflow_dispatch`
   126  - `push` (including new tags)
   127  - `release`
   128  
   129  In practice, most triggers should work. For events that do not have access to
   130  the `id-token: write` permission, like `pull_request`, the workflow will run the
   131  container-based build and produce an _unsigned_ DSSE attestation for the
   132  purposes of testing.
   133  
   134  If you have an issue with any other triggers please submit a [new
   135  issue](https://github.com/yogeshkumararora/slsa-github-generator/issues/new/choose).
   136  
   137  ### Configuration File
   138  
   139  The user must supply a configuration file location in their source repository
   140  that contains the details of the build.
   141  
   142  ```toml
   143  # (Required) Docker run command.
   144  command = ["cp", "internal/builders/docker/testdata/config.toml", "config.toml"]
   145  
   146  # Path to the file generated by the command above.
   147  artifact_path = "**.toml"
   148  ```
   149  
   150  The output artifact path supports wildcard characters. All matching files will
   151  be measured and recorded as attestation subjects. The subject names will be the
   152  basenames of the matching files.
   153  
   154  ### Workflow Inputs
   155  
   156  The [container-based
   157  workflow](https://github.com/yogeshkumararora/slsa-github-generator/blob/main/.github/workflows/builder_container-based_slsa3.yml)
   158  accepts the following inputs:
   159  
   160  Inputs:
   161  
   162  | Name                             | Description                                                                                                                                                                                                                                                                                                   |
   163  | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   164  | `builder-image`                  | **(Required)** The OCI image name of the builder image in which the build execution will be run. This must not include a tag or digest.                                                                                                                                                                       |
   165  | `builder-digest`                 | **(Required)** The OCI image digest of the builder-image. The image digest of the form '<algorithm>:<digest>' (e.g. 'sha256:abcdef...')                                                                                                                                                                       |
   166  | `config-path`                    | **(Required)** Path to a configuration file relative to the root of the repository containing the command that the builder image should be invoked with and the path to the output artifacts. See [Configuration File](#configuration-file).                                                                  |
   167  | `compile-builder`                | Whether to build the builder from source. This increases build time by ~2m.<br>Default: `false`.                                                                                                                                                                                                              |
   168  | `provenance-name`                | The artifact name of the signed provenance. The file must have the `.intoto` extension.<br>Defaults to `<filename>.intoto` for single artifact or `multiple.intoto.jsonl` for multiple artifacts.                                                                                                             |
   169  | `rekor-log-public`               | Set to true to opt-in to posting to the public transparency log. Will generate an error if false for private repositories. This input has no effect for public repositories. See [Private Repositories](#private-repositories).<br>Default: `false`                                                           |
   170  | `registry-username`              | Username to log in the container registry.                                                                                                                                                                                                                                                                    |
   171  | `gcp-workload-identity-provider` | The full identifier of the Workload Identity Provider, including the project number, pool name, and provider name. If provided, this must be the full identifier which includes all parts:<br>`projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider`                       |
   172  | `gcp-service-account`            | Email address or unique identifier of the Google Cloud service account for which to generate credentials. For example:<br>`my-service-account@my-project.iam.gserviceaccount.com`                                                                                                                             |
   173  | `upload-assets`                  | Uploads the artifact and provenance to a GitHub release.<br>If the `upload-tag-name` was provided, then the assets are uploaded to the provided input tag. This can be used for workflow_dispatch events. Otherwise, if a new tag triggered the workflow, then the assets are uploaded to the triggering tag. |
   174  | `upload-tag-name`                | If non-empty and `upload-assets` is set to true, the provenance is uploaded to the GitHub release identified by the tag name. If a workflow is run on a new tag and `upload-tag-name` is non-empty, the new tag is ignored and the value of `upload-tag-name` is used instead to upload the assets.           |
   175  | `prerelease`                     | If true, GitHub Release is created as a pre-release.                                                                                                                                                                                                                                                          |
   176  | `draft-release`                  | If true, the release is created as a draft. Defaults to false.                                                                                                                                                                                                                                                |
   177  
   178  Secrets:
   179  
   180  | Name                | Description                                                                                                                                                                                                                                                                                                                                                                                                        |
   181  | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   182  | `registry-username` | Username to log in the container registry. This should only be used for high entropy values such as AWS Access Key as described [here](https://github.com/docker/login-action#aws-elastic-container-registry-ecr). Normal username values could match other input values and cause them to be ignored by GitHub Actions and causing your build to fail. In those cases, use the `registry-username` input instead. |
   183  | `registry-password` | Password to log in the container registry. Required if a `registry-username` is provided                                                                                                                                                                                                                                                                                                                           |
   184  
   185  ### Workflow Example
   186  
   187  Create a new workflow, e.g., `.github/workflows/slsa-build.yml`.
   188  
   189  ```yaml
   190  name: SLSA container-based releaser
   191  on:
   192    workflow_dispatch:
   193    push:
   194      tags:
   195        - "*"
   196  
   197  permissions: read-all
   198  
   199  jobs:
   200    # Trusted builder.
   201    build:
   202      permissions:
   203        id-token: write # To sign the provenance.
   204        contents: write # To upload assets to release.
   205        actions: read # To read the workflow path.
   206      needs: args
   207      uses: yogeshkumararora/slsa-github-generator/.github/workflows/builder_container-based_slsa3.yml@v2.0.0
   208      with:
   209        builder-image: "bash"
   210        builder-digest: "sha256:9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9"
   211        config-path: ".github/configs-docker/config.toml"
   212  ```
   213  
   214  ### Workflow Outputs
   215  
   216  The [container-based
   217  workflow](https://github.com/yogeshkumararora/slsa-github-generator/blob/main/.github/workflows/builder_container-based_slsa3.yml) produces the following outputs:
   218  
   219  | Name                         | Description                                                                                                                                                                                                                                             |
   220  | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   221  | `build-outputs-name`         | The name of the artifact where the generated artifacts are uploaded to the artifact registry.                                                                                                                                                           |
   222  | `attestations-download-name` | Name of the artifact to download all the attestations. When run on a `pull_request` trigger, attestations are not signed and have an `.intoto` extension. When run on other triggers, attestations are signed and have an `.intoto.sigstore` extension. |
   223  
   224  ### Provenance Format
   225  
   226  The `buildDefinition` contains the following fields:
   227  
   228  | Name                                          | Value                                                 | Description                                                                                                                                                                                                        |
   229  | --------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   230  | `buildType`                                   | `"https://slsa.dev/container-based-build/v0.1?draft"` | Identifies the container-based build type.                                                                                                                                                                         |
   231  | `externalParameters.source`                   | `slsa.ResourceDescriptor`                             | An artifact reference specifying the location of the source repository.                                                                                                                                            |
   232  | `externalParameters.builderImage`             | `slsa.ResourceDescriptor`                             | An artifact reference specifying the container base image used to build the artifacts.                                                                                                                             |
   233  | `externalParameters.configPath`               | `".github/configs-docker/config.toml"`                | The location of the configuration file, relative to the root of the source repository.                                                                                                                             |
   234  | `externalParameters.buildConfig`              | JSON object                                           | An object describing the build configuration.                                                                                                                                                                      |
   235  | `externalParameters.buildConfig.ArtifactPath` | `"dist/**"`                                           | The path describing the output artifacts to attest to and upload.                                                                                                                                                  |
   236  | `externalParameters.buildConfig.Command`      | `"["npm", "run", "all"]"`                             | The build command invoked in the container image to produce the output artifacts.                                                                                                                                  |
   237  | `externalParameters.resolvedDependencies`     | `slsa.ResourceDescriptor`                             | Contains the artifact reference specifying the resolved source and the binary used by the reusable workflow to build the artifact and generate the build definition. See the [CLI tool](#command-line-tool) below. |
   238  
   239  The [CLI tool](#command-line-tool) described in `externalParameters.resolvedDependencies` contains the `uri` of the source that was used to build the artifact (from this GitHub repository). The `digest` referes to the cryptographic digest of the built binary. Using this information, a verifier may download the source artifact from the GitHub releases inferred by the URI and verify its digest.
   240  
   241  ### Provenance Example
   242  
   243  The following is an example of the generated provenance. Provenance is generated
   244  as an [in-toto](https://in-toto.io/) statement with a SLSA predicate.
   245  
   246  ```json
   247  {
   248    "_type": "https://in-toto.io/Statement/v0.1",
   249    "subject": [
   250      {
   251        "name": "example.js",
   252        "digest": {
   253          "sha256": "5d672b0dbb696a3289632bf241cc4bb08dbb32c3e9559ea7e9f96b0490209891"
   254        }
   255      }
   256    ],
   257    "predicateType": "https://slsa.dev/provenance/v1.0",
   258    "predicate": {
   259      "buildDefinition": {
   260        "buildType": "https://slsa.dev/container-based-build/v0.1?draft",
   261        "externalParameters": {
   262          "source": {
   263            "uri": "git+https://github.com/slsa-framework/example-package@refs/heads/main",
   264            "digest": {
   265              "sha1": "ca220e54c07b6fcdd758184a12c132ee3ae531f1"
   266            }
   267          },
   268          "builderImage": {
   269            "uri": "bash@sha256:9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9",
   270            "digest": {
   271              "sha256": "9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9"
   272            }
   273          },
   274          "configPath": ".github/configs-docker/config.toml",
   275          "buildConfig": {
   276            "ArtifactPath": "bin/**",
   277            "Command": ["npm", "run", "all"]
   278          }
   279        },
   280        "resolvedDependencies": [
   281          {
   282            "uri": "git+https://github.com/asraa/slsa-on-github-test@refs/heads/main",
   283            "digest": {
   284              "sha1": "c35e20e93ad5465899c12ce71cd6253d6e28fb15"
   285            }
   286          },
   287          {
   288            "uri": "git+https://github.com/asraa/slsa-github-generator@refs/tags/v1.6.0",
   289            "digest": {
   290              "sha256": "6ea80f1d7ca237eb390b2ce10a383cee229be8d084cee2af9bd1f55f87e28541"
   291            }
   292          }
   293        ],
   294        "internalParameters": {
   295          "GITHUB_ACTOR_ID": "5194569",
   296          "GITHUB_EVENT_NAME": "workflow_dispatch",
   297          "GITHUB_REF": "refs/heads/main",
   298          "GITHUB_REF_TYPE": "branch",
   299          "GITHUB_REPOSITORY": "asraa/slsa-on-github-test",
   300          "GITHUB_REPOSITORY_ID": "501395242",
   301          "GITHUB_REPOSITORY_OWNER_ID": "5194569",
   302          "GITHUB_RUN_ATTEMPT": "1",
   303          "GITHUB_RUN_ID": 5125704193,
   304          "GITHUB_RUN_NUMBER": 6,
   305          "GITHUB_SHA": "c35e20e93ad5465899c12ce71cd6253d6e28fb15",
   306          "GITHUB_TRIGGERING_ACTOR_ID": "5194569",
   307          "GITHUB_WORKFLOW": ".github/workflows/go-builder.yml",
   308          "GITHUB_WORKFLOW_REF": "asraa/slsa-on-github-test/.github/workflows/go-builder.yml@refs/heads/main",
   309          "GITHUB_WORKFLOW_SHA": "c35e20e93ad5465899c12ce71cd6253d6e28fb15",
   310          "GITHUB_BASE_REF": "",
   311          "GITHUB_EVENT_PAYLOAD": {}
   312        }
   313      },
   314      "runDetails": {
   315        "builder": {
   316          "id": "https://github.com/yogeshkumararora/slsa-github-generator/.github/workflows/builder_container-based_slsa3.yml@refs/tags/v1.5.0"
   317        },
   318        "metadata": {
   319          "invocationId": "https://github.com/slsa-framework/example-package/actions/runs/4310284899/attempts/1"
   320        }
   321      }
   322    }
   323  }
   324  ```
   325  
   326  See
   327  [hello-transparent-release](https://github.com/project-oak/hello-transparent-release)
   328  for a more detailed description of how to use this workflow.
   329  
   330  ## Command line tool
   331  
   332  This folder contains a command line tool for building artifacts using a Docker
   333  image.
   334  
   335  It is meant to be used as part of a GitHub Actions reusable workflow for
   336  generating SLSA provenances. However, users can also run the command locally to
   337  test their builds. When a build is intended to be reproducible, consumers may
   338  also use the `verify` sub-command to reproduce the build from the SLSA
   339  provenance.
   340  
   341  The command line tool provides three sub-commands, namely `dry-run`, `build`, and
   342  `verify`.
   343  
   344  ### The `dry-run` subcommand
   345  
   346  The `dry-run` subcommand can be used to validate the inputs. If the inputs are
   347  valid, then the tool creates a `BuildDefinition` and stores that as a JSON
   348  document in the output path that must be provided as one of the flags to the
   349  command. The following is an example, which assumes you are running the code in
   350  `internal/builders/docker`:
   351  
   352  ```bash
   353  go run *.go  dry-run \
   354    --build-config-path internal/builders/docker/testdata/config.toml \
   355    --builder-image bash@sha256:9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9 \
   356    --git-commit-digest sha1:cf5804b5c6f1a4b2a0b03401a487dfdfbe3a5f00 \
   357    --source-repo git+https://github.com/yogeshkumararora/slsa-github-generator \
   358    --build-definition-path bd.json \
   359    --force-checkout
   360  ```
   361  
   362  The output of this is a JSON document stored in `bd.json`.
   363  
   364  ### The `build` subcommand
   365  
   366  The `build` subcommand takes more or less the same inputs as the `dry-run`
   367  subcommand, but actually builds the artifacts. To successfully run this
   368  command, you need to have [rootless Docker installed](https://docs.docker.com/engine/security/rootless/).
   369  
   370  The following is an example:
   371  
   372  ```bash
   373  go run *.go build \
   374    --build-config-path internal/builders/docker/testdata/config.toml \
   375    --builder-image bash@sha256:9e2ba52487d945504d250de186cb4fe2e3ba023ed2921dd6ac8b97ed43e76af9 \
   376    --git-commit-digest sha1:cf5804b5c6f1a4b2a0b03401a487dfdfbe3a5f00 \
   377    --source-repo git+https://github.com/yogeshkumararora/slsa-github-generator \
   378    --subjects-path subjects.json \
   379    --output-folder /tmp/build-outputs \
   380    --force-checkout
   381  ```
   382  
   383  If the build is successful, this command will generate `subjects.json`
   384  containing a JSON-encoded list of generated artifacts and their SHA256 digests.
   385  It also writes all artifacts to the `output-folder`.
   386  
   387  ### The `verify` command
   388  
   389  The `verify` subcommand takes the path to a SLSAv1.0 provenance and verifies it,
   390  by rebuilding the artifacts using the build definition in the provenance, and
   391  checking that the resulting artifacts have the same names and subjects as the
   392  ones in the provenance subject.
   393  
   394  Here is an example:
   395  
   396  ```bash
   397  go run *.go verify --provenance-path testdata/slsa1-provenance.json
   398  ```
   399  
   400  ## Users
   401  
   402  The following project currently use the container-based workflow:
   403  
   404  - [Oak](https://github.com/project-oak/oak); See [the workflow file](https://github.com/project-oak/oak/blob/main/.github/workflows/provenance.yaml)
   405  
   406  We welcome any success stories. Please create a PR to add your project to the
   407  list, if you are using the container-based workflow.
   408  
   409  ## Known Issues
   410  
   411  ### Compatibility with `actions/download-artifact`
   412  
   413  To download provenance (e.g., if you don't use `upload-assets`) you have to
   414  use [`actions/download-artifact@v3`](https://github.com/actions/download-artifact).
   415  The workflow uses [`actions/upload-artifact@3`](https://github.com/actions/upload-artifact)
   416  which is
   417  [not compatible](https://github.com/actions/download-artifact?tab=readme-ov-file#breaking-changes)
   418  with `actions/download-artifact@v4`.