Skip to content

Commit

Permalink
split into app and builder image attestations
Browse files Browse the repository at this point in the history
There's actually 2 images that are completely generated by kpack (i.e.
not brought in by user). The builder image is stiched together from
existing layers, and the app image that is build via the builder image.

While the app image attestation is likely the most important one, we
should still attest that our builder images are not tempered with

Signed-off-by: Bohan Chen <[email protected]>
  • Loading branch information
chenbh committed Dec 15, 2023
1 parent e486d48 commit b20b1ea
Showing 1 changed file with 184 additions and 8 deletions.
192 changes: 184 additions & 8 deletions rfcs/0000-slsa-attestation.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,19 @@ look like, and how this provenance will be stored and surfaced to the user.

A new flag(`--generate-slsa-attestation`) and env var (`GENERATE_SLSA_ATTESTATION`) will be introduced in the controller
deployment. If this flag is set to `"true"`, all images built by kpack in the cluster will have an attestation attached
to it.
to it. This will apply to both the app images and the builder images generated by kpack.

### Attestation format

The proposed format for SLSA provenance generated by kpack is the [SLSA recommended suite][slsa-recommended-suite]:

#### Provenance schema

Build metadata and information is stored using the [SLSA provenance schema][slsa-schema]:
Build metadata and information is stored using the [SLSA provenance schema][slsa-schema]. There will be 2 provenance
schemas, one for the app images and one for the builder images generated by kpack.

##### App image (Build resource)
For the app image:
- `buildDefinition`:
- `buildType`: Must be `https://github.com/buildpacks-community/kpack/blob/${KPACK_VERSION}/docs/slsa.md`. According
to SLSA, this should resolve to a human readable spec that documents the build definition and run details. The link
Expand All @@ -61,8 +64,8 @@ Build metadata and information is stored using the [SLSA provenance schema][slsa
- The builder image as uri, its digest as digest set, and all of its image labels as annotations
- `runDetails`:
- `builder`:
- `id`: Either `https://kpack.io/signed-build` or `https://kpack.io/unsigned-build` depending on if a signing secret
is found.
- `id`: Either `https://kpack.io/slsa/signed-app-build` or `https://kpack.io/slsa/unsigned-app-build` depending on
if a signing secret is found.
- `version`: This should contain versions of kpack and its components
- `kpack`: version of the controller as compiled into `cmd/version.go`
- `lifecycle`: version of the lifecycle as read from the lifecycle image metadata
Expand All @@ -72,7 +75,7 @@ Build metadata and information is stored using the [SLSA provenance schema][slsa
- ServiceAccount (name and resource version only) associated with the Build.
- Secrets (name and resource version only) used by the Build.
- `metadata`
- `invocationID`: Follows the format `https://kpack.io/<namespace>/<build_name>/<build_pod_name>@<build_pod_node_name>`
- `invocationID`: Follows the format `https://kpack.io/build/<namespace>/<build_name>/<build_pod_name>@<build_pod_node_name>`
- `startedOn`: Time the build pod was created in RFC3339 format.
- `finishedOn`: Time the build pod (or completion container) finished in RFC3339 format.
- `byproducts`: Empty array for now, but may contain things like link to SBoMs in the future.
Expand Down Expand Up @@ -129,12 +132,14 @@ Example:
},
"resolvedDependencies": [
{
"name": "source",
"uri": "git+https://github.com/buildpacks-community/kpack@refs/heads/main",
"digest": {
"sha1": "759bd290a5310bef5069385b649883e586024dae"
}
},
{
"name": "builder",
"uri": "paketobuildpacks/builder-jammy-tiny",
"digest": {
"sha256": "78d74bd1c27f633341045f1c5f7f33209f6af0a5dc5700fdfd71200b5b5a0b9a"
Expand Down Expand Up @@ -162,7 +167,7 @@ Example:
},
"runDetails": {
"builder": {
"id": "https://kpack.io/signed-build",
"id": "https://kpack.io/signed-app-build",
"version": {
"kpack": "0.12.2"
"lifecycle": "0.17.0"
Expand Down Expand Up @@ -196,6 +201,175 @@ Example:
}
```

##### Builder image (Builder and ClusterBuilder resource)

For the builder image:
- `buildDefinition`:
- `buildType`: Must be `https://github.com/buildpacks-community/kpack/blob/${KPACK_VERSION}/docs/slsa.md`. According
to SLSA, this should resolve to a human readable spec that documents the build definition and run details. The link
should point to the version of the doc that has been compiled into the controller via `cmd/version.go`.
- `externalParameters`: This should be the JSON serialized contents of the `.spec` field from the [Cluster]Builder
resource.
- `internalParameters`:
- All the image values: `buildInitImage`, `buildInitWindowsImage`, `buildWaiterImage`, `completionImage`,
`completionWindowsImage`, `lifecycleImage`, and `rebaseImage`
- All the controller flags: `enablePriorityClasses`, `maximumPlatformApiVersion`, `injectedSidecarSupport`,
and `insecureSshTrustUnknownHosts`
- `resolvedDependencies`:
- The build image as uri, digest as digest set, and all of its image labels as annotation
- The run image as content (note: this is different from the build image because we don't actuall resolve it)
- The group/order buildpacks with the name@version as uri, layer diff id as digest set, and metadata as annotation
- `runDetails`:
- `builder`:
- `id`: Either `https://kpack.io/slsa/signed-builder-build` or `https://kpack.io/slsa/unsigned-builder-build`
depending on if a signing secret is found.
- `version`: This should contain versions of kpack and its components
- `kpack`: version of the controller as compiled into `cmd/version.go`
- `lifecycle`: version of the lifecycle as read from the lifecycle image metadata
- `builderDependencies`:
- Namespace where the Build occured in (ommitted for ClusterBuilder)
- Builder/ClusterBuilder (name and resource version only) resource that generated the image
- ServiceAccount (name and resource version only) associated with the [Cluster]Builder
- Secrets (name and resource version only) used by the [Cluster]Builder
- ClusterStore (name and resource version only) resource used by the [Cluster]Builder
- Buildpack (name and resource version only) resources used by the [Cluster]Builder
- ClusterBuildpack (name and resource version only) resources used by the [Cluster]Builder
- `metadata`
- `invocationID`: Follows the format `https://kpack.io/builder/<namespace>/<builder_name>@<generation>`, or
`https://kpack.io/clusterbuilder/<builder_name>@<generation>`
- `startedOn`: Time the reconciler started creating the builder in RFC3339 format.
- `finishedOn`: Time the reconciler finished pushing the builder in RFC3339 format.
- `byproducts`: Empty array for now, but may contain things like link to SBoMs in the future.

Example:
```json
{
"buildDefinition": {
"buildType": "https://github.com/buildpacks-community/kpack/blob/v0.12.2/docs/slsa.md",
"externalParameters": {
"tag": "gcr.io/sample/builder",
"serviceAccountName": "default",
"stack": {
"name": "bionic-stack",
"kind": "ClusterStack",
},
"store": {
"name": "sample-cluster-store",
"kind": "ClusterStore",
"order": [
{
"group": [
{"id": "paketo-buildpacks/java"}
]
},
{
"group": [
{"id": "kpack/my-custom-buildpack", "version": "1.2.3"},
{"id": "kpack/my-optional-custom-buildpack", "optional": "true"}
]
},
{
"group": [
{"name": "sample-buildpack", "kind": "Buildpack"},
{"name": "sample-cluster-buildpack", "kind": "ClusterBuildpack", "id": "paketo-buildpacks/nodejs", "version": "1.2.3"}
]
},
]
},
"internalParameters": {
"builderImage": "my.registry.com/my/builder@sha256:de9964b5f501a77b8cf549659f81e29dbac4f8df7f1890ddc2b568dbed428b73",
"lifecycleImage": "gcr.io/cf-build-service-public/kpack/lifecycle@sha256:0b1cd35012f7152053c42e0d6835cbb5b7c9c24207a0627f556bd931e678f8d7",
"enablePriorityClasses": "false",
"maximumPlatformApiVersion": "",
"injectedSidecarSupport": "false",
"insecureSshTrustUnknownHosts": "true"
},
"resolvedDependencies": [
{
"name": "build image",
"uri": "paketobuildpacks/builder-jammy-tiny",
"digest": {
"sha256": "78d74bd1c27f633341045f1c5f7f33209f6af0a5dc5700fdfd71200b5b5a0b9a"
},
"annotations": {
"io.buildpacks.stack.description": "ubuntu:jammy with compilers and shell utilities",
"io.buildpacks.stack.distro.name": "ubuntu",
"io.buildpacks.stack.distro.version": "22.04",
"io.buildpacks.stack.homepage": "https://github.com/paketo-buildpacks/jammy-tiny-stack",
"io.buildpacks.stack.id": "io.buildpacks.stacks.jammy.tiny",
"io.buildpacks.stack.maintainer": "Paketo Buildpacks",
"io.buildpacks.stack.metadata": "{}",
"io.buildpacks.stack.released": "2023-12-11T14:37:26Z",
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "22.04"
}
},
{
"name": "run image",
"content": "paketobuildpacks/builder-jammy-tiny@sha256:78d74bd1c27f633341045f1c5f7f33209f6af0a5dc5700fdfd71200b5b5a0b9a",
},
{
"name": "paketo-buildpacks/[email protected]",
"digest": {
"sha256": "76b1619f81820ed875e544a5fe47eb25e515352c4f7804c7dbe8723966e528c6"
},
"annotations": {
"homepage": "https://github.com/paketo-buildpacks/go-build",
"name": "Paketo Buildpack for Go Build"
}
},
{
"uri": "paketo-buildpacks/[email protected]",
"digest": {
"sha256": "b4b8b2d4b5f8bd0d39648b52f8fc7c54d88d433cc846ea07d6e5082a2cbca62a"
},
"annotations": {
"homepage": "https://github.com/paketo-buildpacks/go-dist",
"name": "Paketo Buildpack for Go Distribution"
}
},
{
"name": "",
"content": "paketobuildpacks/builder-jammy-tiny@sha256:78d74bd1c27f633341045f1c5f7f33209f6af0a5dc5700fdfd71200b5b5a0b9a",
},
]
},
"runDetails": {
"builder": {
"id": "https://kpack.io/signed-builder-build",
"version": {
"kpack": "0.12.2"
"lifecycle": "0.17.0"
},
"builderDependencies": [
{
"name": "Namespace",
"content": "{\"name\":\"default\",\"resourceVersion\":\"195\"}"
},
{
"name": "Build",
"content": "{\"name\":\"test-build-1\",\"resourceVersion\":\"5\"}"
},
{
"name": "ServiceAccount",
"content": "{\"name\":\"default\",\"resourceVersion\":\"269\"}"
},
{
"name": "Secrets",
"content": "[{\"name\":\"my-registry-creds\",\"resourceVersion\":\"53\"},{\"name\":\"my-git-creds\",\"resourceVersion\":\"123\"}]"
},
]
},
"metadata": {
"invocationID": "https://kpack.io/builder/default/my-builder@1",
"startedOn": "2023-11-09T16:47:17.215551-05:00",
"finishedOn": "2023-11-09T16:54:17.215551-05:00"
},
"byproducts": []
}
}
```

#### Statement
The provenance is wrapped in an [in-toto statement][in-toto-statement] and formated as JSON. The `subject.name` and
`subject.digest` should be set to the built image and digest.
Expand Down Expand Up @@ -272,8 +446,8 @@ Once the provenance has been stamped out according to the template above, these
envelope. The signatures may be in any arbitrary order, each signature should have the `keyid` set to the
`<secret-name>` that was used.

Any attestation errors (signing errors, push errors, registry errors, etc) should be surfaced to the Build status via a
new condition.
Any attestation errors (signing errors, push errors, registry errors, etc) should be surfaced to the
Build/Builder/ClusterBuilder status via a new condition.

### Documentation needed

Expand Down Expand Up @@ -347,6 +521,8 @@ process and the system itself.
image using just the diffId (other than `pack sbom download`).
- The CNB spec splits the SBoM into component (buildpack) pieces, which doesn't create the best user experience.
Should we try to combine all of them into a single (or 3 since there's at most 3 formats) SBoM?
- Should we allow each signing secret to specify a different destination repo for the attestation like how the cosign
signing currently do?

[cluster-wide-cosign-rfc]: https://github.com/samj1912/kpack/blob/cluster-signing/rfcs/0000-cluster-signing.md#key-generation-and-storage
[slsa-verifier]: https://github.com/slsa-framework/slsa-verifier

0 comments on commit b20b1ea

Please sign in to comment.