-
Notifications
You must be signed in to change notification settings - Fork 165
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
split into app and builder image attestations
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
Showing
1 changed file
with
184 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -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. | ||
|
@@ -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" | ||
|
@@ -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" | ||
|
@@ -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. | ||
|
@@ -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 | ||
|
||
|
@@ -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 |