Skip to content

Commit 1b02a19

Browse files
authored
Merge pull request #694 from stormqueen1990/cosign-integration
RFC for sigstore/cosign integration with kpack.
2 parents 4e56473 + 2f836b4 commit 1b02a19

1 file changed

Lines changed: 168 additions & 0 deletions

File tree

rfcs/0000-cosign-integration.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Integrate `cosign` with `kpack`
2+
3+
## Problem
4+
5+
The signing solution currently supported by `kpack` is
6+
[Notary v1](https://github.com/theupdateframework/notary). However, Notary
7+
presents itself with several different challenges, including:
8+
- It is unable to sign container image digests. The user must always specify a
9+
tag to be signed.
10+
- It is unable to verify container image signature by digests.
11+
- Signature relocation is not possible with this tool.
12+
- It is a project that currently has low activity and community involvement,
13+
since the community is currently focused on the development of Notary v2.
14+
15+
[`cosign`](https://github.com/sigstore/cosign) presents itself as a solution to
16+
some of those aforementioned challenges. With `cosign`, the user is able to:
17+
- Relocate container images across registries along with its signatures, using
18+
either:
19+
- `crane cp` to copy images and signatures separately.
20+
- `cosign copy` to copy images along with their signatures from one registry
21+
to another.
22+
- Sign container images by tag or by digest.
23+
- Verify container image signatures by specifying either a tag or a digest.
24+
- Verify container image signatures after relocation.
25+
26+
Moreover, `cosign` is a project that has had a lot of activity and community
27+
involvement recently.
28+
29+
## Outcome
30+
31+
`kpack` integrates with `cosign` to sign images it builds and push the
32+
signatures to a registry so that users can ensure the chain of custody of a
33+
generated artifact.
34+
35+
This proposal aims to cover specifically the flow of signing an image produced
36+
by the `kpack` `Image`, `Build`, `Builder` and `ClusterBuilder` resources, without
37+
verification of any container images pulled in the process.
38+
39+
## Actions to take
40+
41+
### Enable image signing using `cosign`
42+
43+
- Implement a flow that generates the signature payload for the image, then
44+
calculates its signature and pushes it either to the registry where the image
45+
is located, using the same credentials that were used to push the image, or
46+
[to the registry specified in the `COSIGN_REPOSITORY` environment variable](#key-generation-and-storage).
47+
`kpack` should sign images produced by `kpack` builds and images produced by
48+
the `Builder` and `ClusterBuilder` resources, using their respective service
49+
accounts to find credentials. This flow must happen after each of the images
50+
have been pushed to the registry.
51+
52+
- If `cosign` fails to sign an image, the build should fail and output an error
53+
message in the build log, so the operator can troubleshoot the issue. The
54+
error messages should also be added in any other places where error messages
55+
are presented.
56+
- If `cosign` fails to sign an image produced by a `Builder` resource, the
57+
`Builder` should not enter a Ready status.
58+
- Whenever `kpack` signs an image produced within a `kpack` build using `cosign`,
59+
it should add these annotations:
60+
- Build number.
61+
- Build time.
62+
63+
- Signing with `cosign` should not affect any configurations that enable signing
64+
using the Notary v1 mechanism. These two signing mechanisms should be able to
65+
coexist.
66+
67+
### Key generation and storage
68+
69+
`cosign` can use file-based keys, key management systems or hardware keys to
70+
ingest private keys, as well as a keyless flow that requires integration with
71+
[Rekor](https://github.com/sigstore/rekor).
72+
73+
`kpack` should not generate the keys used for signing and verification. The user
74+
should pass them in using one of the mechanisms supported by `cosign`.
75+
In this RFC, we suggest that the first mechanism implemented be the use of
76+
Kubernetes `Secret`s for sending the relevant data into the build pod, by means
77+
of attaching secrets to the service account used by `kpack`.
78+
These secrets must follow the format generated by
79+
[`cosign generate-key-pair -k8s <namespace>/<name>`](https://github.com/sigstore/cosign/pull/345).
80+
Any build that has a service account with `cosign` secrets attached to it will
81+
have signatures generated.
82+
83+
The service account can have more than one `cosign` secret attached to it. For
84+
each `cosign` secret attached, a separate signature should be generated and
85+
stored.
86+
87+
`kpack` will be able to determine that the user wants to sign images using
88+
`cosign` by scanning the existing keys in each of the secrets. Secrets to be
89+
used by `cosign` signing must contain at least the `cosign.key` and
90+
`cosign.password` keys on the `data` section. Optionally, the user can also
91+
annotate the secrets with the following information:
92+
- `kpack.io/cosign.repository`: a separate registry URL to upload the generated
93+
signatures, instead of pushing the signatures collocated with the images. Adding
94+
this annotation should have the same effect as setting the `COSIGN_REPOSITORY`
95+
variable. The user must provide credentials for `kpack` to authenticate with the
96+
specified registry. In the case where this repository is inaccessible, the build
97+
should fail and output an error message to allow the operator to troubleshoot.
98+
- `kpack.io/cosign.docker-media-types`: a flag indicating whether legacy media
99+
types should be used instead of OCI media types. Adding this annotation should
100+
have the same effect as setting the `COSIGN_DOCKER_MEDIA_TYPES` variable.
101+
102+
Secret format example:
103+
```yaml
104+
---
105+
apiVersion: v1
106+
kind: Secret
107+
metadata:
108+
name: cosign-key
109+
annotations:
110+
# Optional
111+
kpack.io/cosign.repository: "<repository-url>"
112+
# Optional
113+
kpack.io/cosign.docker-media-types: "1"
114+
type: Opaque
115+
data:
116+
cosign.key: <cosign-private-key>
117+
cosign.pub: <cosign-public-key>
118+
cosign.password: <cosign-private-key-passphrase>
119+
```
120+
121+
### Configure custom static annotations
122+
123+
Create a new optional configuration in the `Image` resource that allow users to
124+
parameterize optional annotations to add to the generated signatures. These
125+
annotations will be static and configured as a list of key-value pairs:
126+
```yaml
127+
cosign:
128+
annotations:
129+
- name: "key1"
130+
value: "value1"
131+
- name: "key2"
132+
value: "value2"
133+
```
134+
135+
### Authentication to a container registry
136+
137+
`cosign` uses the `DefaultKeychain` from
138+
[`go-containerregistry`](https://github.com/google/go-containerregistry/blob/main/pkg/authn/README.md#tldr-for-consumers-of-this-package)
139+
to authenticate the command-line interface using the machine's Docker CLI
140+
credentials. For `kpack`, it may be possible to use the same authentication
141+
mechanism that is in-place for uploading an image.
142+
143+
## Complexity
144+
145+
Integration with `cosign` is estimated to be of medium complexity. Since
146+
`cosign` is also written in Go, it is possible to import code from the tool
147+
directly within `kpack`, which can help make the integration easier.
148+
149+
## Prior art
150+
151+
- [Issue](https://github.com/pivotal/kpack/issues/684) filed on May 4th.
152+
- [Use of `cosign` in Kubernetes](https://github.com/kubernetes/release/pull/2016)
153+
for validation of distroless images.
154+
- [Use of `cosign` in Connaisseur](https://github.com/sse-secure-systems/connaisseur/pull/107)
155+
for policy enforcement in container images.
156+
- [Notary v1 implementation pull request](https://github.com/pivotal/kpack/pull/541).
157+
158+
## Alternatives
159+
160+
- Use a CI/CD step to sign images using `cosign` instead of implementing it as
161+
a part of `kpack`.
162+
- Configure `cosign` integration on a per-`Image` resource basis.
163+
164+
## Risks
165+
166+
- Notary v2 support might be a requirement in the future.
167+
- `cosign` is at an early stage of development and may have breaking changes in
168+
the future.

0 commit comments

Comments
 (0)