Skip to content

Commit

Permalink
Slsa Branding of Chains Provenance Format
Browse files Browse the repository at this point in the history
This PR adds a new format `slsa/v1` which generates the same provenance as that generated when requesting `in-toto` format. The unit tests and documentation have been updated to use the new branding.
  • Loading branch information
chitrangpatel committed Jan 31, 2023
1 parent 49eaca0 commit 2f4551d
Show file tree
Hide file tree
Showing 20 changed files with 114 additions and 38 deletions.
7 changes: 5 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,22 @@ Supported keys include:

| Key | Description | Supported Values | Default |
| :--- | :--- | :--- | :--- |
| `artifacts.taskrun.format` | The format to store `TaskRun` payloads in. | `in-toto`| `in-toto` |
| `artifacts.taskrun.format` | The format to store `TaskRun` payloads in. | `in-toto`, `slsa/v1`| `in-toto` |
| `artifacts.taskrun.storage` | The storage backend to store `TaskRun` signatures in. Multiple backends can be specified with comma-separated list ("tekton,oci"). To disable the `TaskRun` artifact input an empty string (""). | `tekton`, `oci`, `gcs`, `docdb`, `grafeas` | `tekton` |
| `artifacts.taskrun.signer` | The signature backend to sign `TaskRun` payloads with. | `x509`, `kms` | `x509` |

> NOTE:, `slsa/v1` is an alias of `in-toto` for backwards compatibality.
### PipelineRun Configuration

| Key | Description | Supported Values | Default |
| :--- | :--- | :--- | :--- |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`| `in-toto` |
| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`| `in-toto` |
| `artifacts.pipelinerun.storage` | The storage backend to store `PipelineRun` signatures in. Multiple backends can be specified with comma-separated list ("tekton,oci"). To disable the `PipelineRun` artifact input an empty string (""). | `tekton`, `oci`, `gcs`, `docdb`, `grafeas` | `tekton` |
| `artifacts.pipelinerun.signer` | The signature backend to sign `PipelineRun` payloads with. | `x509`, `kms` | `x509` |

> NOTE: For grafeas storage backend, currently we only support Container Analysis. We will make grafeas server address configurabe within a short time.
> NOTE: `slsa/v1` is an alias of `in-toto` for backwards compatibality.
### OCI Configuration

Expand Down
5 changes: 3 additions & 2 deletions docs/intoto.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ The in-toto format can be enabled by running:

```
# For TaskRuns
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.format": "in-toto"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.format": "slsa/v1"}}'
# For PipelineRuns
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.pipelinerun.format": "in-toto"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.pipelinerun.format": "slsa/v1"}}'
```
**Note**, you can continue to use the older alias of `slsa/v1`: `in-toto`.

To provide a git URL/commit as material, add a parameter named
`CHAINS-GIT_COMMIT` and `CHAINS-GIT_URL`. The value of these
Expand Down
6 changes: 4 additions & 2 deletions docs/tutorials/signed-provenance-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,20 @@ kubectl create secret generic [DOCKERCONFIG_SECRET_NAME] --from-file [PATH TO CO

You'll need to make these changes to the Tekton Chains Config:

* `artifacts.taskrun.format=in-toto`
* `artifacts.taskrun.format=slsa/v1`
* `artifacts.taskrun.storage=oci`
* `transparency.enabled=true`

You can set these fields by running

```shell
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.format": "in-toto"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.format": "slsa/v1"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.taskrun.storage": "oci"}}'
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"transparency.enabled": "true"}}'
```

**Note**, you can continue to use the older alias of `slsa/v1`: `in-toto` above.

This tells Chains to generate an in-toto attestation and store it in the specified OCI registry.
Attestations will also be stored in [rekor](https://github.com/sigstore/rekor) since transparency is enabled.

Expand Down
4 changes: 3 additions & 1 deletion pkg/chains/formats/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ const (
PayloadTypeTekton config.PayloadType = "tekton"
PayloadTypeSimpleSigning config.PayloadType = "simplesigning"
PayloadTypeInTotoIte6 config.PayloadType = "in-toto"
PayloadTypeSlsav1 config.PayloadType = "slsa/v1"
)

var (
payloaderMap = map[config.PayloadType]PayloaderInit{}
IntotoAttestationSet = map[config.PayloadType]struct{}{PayloadTypeInTotoIte6: {}, PayloadTypeSlsav1: {}}
payloaderMap = map[config.PayloadType]PayloaderInit{}
)

// PayloaderInit initializes a new Payloader instance for the given config.
Expand Down
14 changes: 14 additions & 0 deletions pkg/chains/formats/slsa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SLSA Branding of Tekton Chains Provenance Format

`Tekton Chains` is migrating the naming of provenance formats from `intotoite6` to `slsa`.
As different versions of provenance formats are rolled out in the future, they will take
the form `slsa/v1, slsa/v2` and the `package names` will be `v1`, `v2` and so on, respectively.

**Note**: the `slsa` branding in `Tekton Chains` does not map directly to the slsa predicate release.
Tekton chains `slsa/v1` is not the same as `slsav1.0`.

Shown below is the mapping between Tekton chains proveance and SLSA predicate.

|Tekton Chains Provenance Format version | SLSA predicate | Notes |
|:------------------------------------------|---------------:|------:|
|**slsa/v1**| **slsa v0.2** | same as currently supported `in-toto` format|
4 changes: 3 additions & 1 deletion pkg/chains/formats/slsa/v1/intotoite6.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import (

const (
PayloadTypeInTotoIte6 = formats.PayloadTypeInTotoIte6
PayloadTypeSlsav1 = formats.PayloadTypeSlsav1
)

func init() {
formats.RegisterPayloader(PayloadTypeInTotoIte6, NewFormatter)
formats.RegisterPayloader(PayloadTypeSlsav1, NewFormatter)
}

type InTotoIte6 struct {
Expand Down Expand Up @@ -63,5 +65,5 @@ func (i *InTotoIte6) CreatePayload(ctx context.Context, obj interface{}) (interf
}

func (i *InTotoIte6) Type() config.PayloadType {
return formats.PayloadTypeInTotoIte6
return formats.PayloadTypeSlsav1
}
2 changes: 1 addition & 1 deletion pkg/chains/formats/slsa/v1/intotoite6_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ func TestCreatePayloadError(t *testing.T) {

func TestCorrectPayloadType(t *testing.T) {
var i InTotoIte6
if i.Type() != formats.PayloadTypeInTotoIte6 {
if i.Type() != formats.PayloadTypeSlsav1 {
t.Errorf("Invalid type returned: %s", i.Type())
}
}
3 changes: 2 additions & 1 deletion pkg/chains/rekor.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/tektoncd/chains/pkg/chains/formats"
"github.com/tektoncd/chains/pkg/chains/objects"
"github.com/tektoncd/chains/pkg/chains/signing"
"github.com/tektoncd/chains/pkg/config"
Expand All @@ -46,7 +47,7 @@ func (r *rekor) UploadTlog(ctx context.Context, signer signing.Signer, signature
if err != nil {
return nil, errors.Wrap(err, "public key or cert")
}
if payloadFormat == "in-toto" {
if _, ok := formats.IntotoAttestationSet[config.PayloadType(payloadFormat)]; ok {
return cosign.TLogUploadInTotoAttestation(ctx, r.c, signature, pkoc)
}
return cosign.TLogUpload(ctx, r.c, signature, rawPayload, pkoc)
Expand Down
4 changes: 2 additions & 2 deletions pkg/chains/signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func TestSigner_Transparency(t *testing.T) {
cfg: &config.Config{
Artifacts: config.ArtifactConfigs{
TaskRuns: config.Artifact{
Format: "in-toto",
Format: "slsa/v1",
StorageBackend: sets.NewString("mock"),
Signer: "x509",
},
Expand All @@ -245,7 +245,7 @@ func TestSigner_Transparency(t *testing.T) {
cfg: &config.Config{
Artifacts: config.ArtifactConfigs{
PipelineRuns: config.Artifact{
Format: "in-toto",
Format: "slsa/v1",
StorageBackend: sets.NewString("mock"),
Signer: "x509",
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/chains/storage/gcs/gcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestBackend_StorePayload(t *testing.T) {
},
signed: []byte("signed"),
signature: "signature",
opts: config.StorageOpts{ShortKey: "foo.uuid", PayloadFormat: formats.PayloadTypeInTotoIte6},
opts: config.StorageOpts{ShortKey: "foo.uuid", PayloadFormat: formats.PayloadTypeSlsav1},
},
},
{
Expand Down
4 changes: 2 additions & 2 deletions pkg/chains/storage/grafeas/grafeas.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func NewStorageBackend(ctx context.Context, logger *zap.SugaredLogger, cfg confi
// StorePayload implements the storage.Backend interface.
func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, rawPayload []byte, signature string, opts config.StorageOpts) error {
// We only support simplesigning for OCI images, and in-toto for taskrun & pipelinerun.
if opts.PayloadFormat != formats.PayloadTypeInTotoIte6 && opts.PayloadFormat != formats.PayloadTypeSimpleSigning {
if _, ok := formats.IntotoAttestationSet[opts.PayloadFormat]; !ok && opts.PayloadFormat != formats.PayloadTypeSimpleSigning {
return errors.New("Grafeas storage backend only supports simplesigning and intoto payload format.")
}

Expand Down Expand Up @@ -386,7 +386,7 @@ func (b *Backend) getAllOccurrences(ctx context.Context, obj objects.TektonObjec
uriFilters := extract.RetrieveAllArtifactURIs(obj, b.logger)

// step 2: find all build occurrences
if opts.PayloadFormat == formats.PayloadTypeInTotoIte6 {
if _, ok := formats.IntotoAttestationSet[opts.PayloadFormat]; ok {
occs, err := b.findOccurrencesForCriteria(ctx, b.getBuildNotePath(obj), uriFilters)
if err != nil {
return nil, err
Expand Down
10 changes: 5 additions & 5 deletions pkg/chains/storage/grafeas/grafeas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) {
},
payload: getRawPayload(t, cloneTaskRunProvenance),
signature: "clone taskrun signatures",
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6},
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeSlsav1},
},
wantOccurrences: nil,
wantErr: false,
Expand All @@ -277,7 +277,7 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) {
},
payload: getRawPayload(t, buildTaskRunProvenance),
signature: "build taskrun signature",
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6},
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeSlsav1},
},
wantOccurrences: []*pb.Occurrence{getTaskRunBuildOcc(t, artifactIdentifier1), getTaskRunBuildOcc(t, artifactIdentifier2)},
wantErr: false,
Expand All @@ -303,7 +303,7 @@ func TestGrafeasBackend_StoreAndRetrieve(t *testing.T) {
},
payload: getRawPayload(t, ciPipelineRunProvenance),
signature: "ci pipelinerun signature",
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeInTotoIte6},
opts: config.StorageOpts{PayloadFormat: formats.PayloadTypeSlsav1},
},
wantOccurrences: []*pb.Occurrence{getPipelineRunBuildOcc(t, artifactIdentifier1), getPipelineRunBuildOcc(t, artifactIdentifier2)},
wantErr: false,
Expand Down Expand Up @@ -397,7 +397,7 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf
if test.args.opts.PayloadFormat == formats.PayloadTypeSimpleSigning {
expectSignature[test.args.opts.FullKey] = []string{test.args.signature}
}
if test.args.opts.PayloadFormat == formats.PayloadTypeInTotoIte6 {
if _, ok := formats.IntotoAttestationSet[test.args.opts.PayloadFormat]; ok {
allURIs := extract.RetrieveAllArtifactURIs(test.args.runObject, backend.logger)
for _, u := range allURIs {
expectSignature[u] = []string{test.args.signature}
Expand All @@ -419,7 +419,7 @@ func testStoreAndRetrieveHelper(ctx context.Context, t *testing.T, test testConf
if test.args.opts.PayloadFormat == formats.PayloadTypeSimpleSigning {
expectPayload[test.args.opts.FullKey] = string(test.args.payload)
}
if test.args.opts.PayloadFormat == formats.PayloadTypeInTotoIte6 {
if _, ok := formats.IntotoAttestationSet[test.args.opts.PayloadFormat]; ok {
allURIs := extract.RetrieveAllArtifactURIs(test.args.runObject, backend.logger)
for _, u := range allURIs {
expectPayload[u] = string(test.args.payload)
Expand Down
2 changes: 1 addition & 1 deletion pkg/chains/storage/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (b *Backend) StorePayload(ctx context.Context, obj objects.TektonObject, ra
return b.uploadSignature(format, rawPayload, signature, storageOpts, auth)
}

if storageOpts.PayloadFormat == formats.PayloadTypeInTotoIte6 {
if _, ok := formats.IntotoAttestationSet[storageOpts.PayloadFormat]; ok {
attestation := in_toto.Statement{}
if err := json.Unmarshal(rawPayload, &attestation); err != nil {
return errors.Wrap(err, "unmarshal attestation")
Expand Down
10 changes: 5 additions & 5 deletions pkg/chains/storage/oci/oci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func TestBackend_StorePayload(t *testing.T) {
payload: intotoStatement,
signature: "into-to",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand All @@ -149,7 +149,7 @@ func TestBackend_StorePayload(t *testing.T) {
payload: in_toto.Statement{},
signature: "",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand All @@ -175,7 +175,7 @@ func TestBackend_StorePayload(t *testing.T) {
payload: intotoStatement,
signature: "into-to",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand All @@ -188,7 +188,7 @@ func TestBackend_StorePayload(t *testing.T) {
payload: simple,
signature: "",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand All @@ -214,7 +214,7 @@ func TestBackend_StorePayload(t *testing.T) {
payload: in_toto.Statement{},
signature: "",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand Down
3 changes: 2 additions & 1 deletion pkg/chains/storage/pubsub/pubsub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"

"github.com/in-toto/in-toto-golang/in_toto"
"github.com/tektoncd/chains/pkg/chains/formats"
"github.com/tektoncd/chains/pkg/chains/objects"
"github.com/tektoncd/chains/pkg/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
Expand Down Expand Up @@ -71,7 +72,7 @@ func TestBackend_StorePayload(t *testing.T) {
rawPayload: sampleIntotoStatementBytes,
signature: "signature",
storageOpts: config.StorageOpts{
PayloadFormat: "in-toto",
PayloadFormat: formats.PayloadTypeSlsav1,
},
},
wantErr: false,
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,12 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
if err := cm.Parse(data,
// Artifact-specific configs
// TaskRuns
asString(taskrunFormatKey, &cfg.Artifacts.TaskRuns.Format, "in-toto"),
asString(taskrunFormatKey, &cfg.Artifacts.TaskRuns.Format, "in-toto", "slsa/v1"),
asStringSet(taskrunStorageKey, &cfg.Artifacts.TaskRuns.StorageBackend, sets.NewString("tekton", "oci", "gcs", "docdb", "grafeas", "kafka")),
asString(taskrunSignerKey, &cfg.Artifacts.TaskRuns.Signer, "x509", "kms"),

// PipelineRuns
asString(pipelinerunFormatKey, &cfg.Artifacts.PipelineRuns.Format, "in-toto"),
asString(pipelinerunFormatKey, &cfg.Artifacts.PipelineRuns.Format, "in-toto", "slsa/v1"),
asStringSet(pipelinerunStorageKey, &cfg.Artifacts.PipelineRuns.StorageBackend, sets.NewString("tekton", "oci", "grafeas")),
asString(pipelinerunSignerKey, &cfg.Artifacts.PipelineRuns.Signer, "x509", "kms"),

Expand Down
14 changes: 7 additions & 7 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func TestFulcio(t *testing.T) {
resetConfig := setConfigMap(ctx, t, c, map[string]string{
"artifacts.taskrun.storage": "tekton",
"artifacts.taskrun.signer": "x509",
"artifacts.taskrun.format": "in-toto",
"artifacts.taskrun.format": "slsa/v1",
"artifacts.oci.signer": "x509",
"signers.x509.fulcio.enabled": "true",
"transparency.enabled": "false",
Expand Down Expand Up @@ -404,7 +404,7 @@ func TestOCIStorage(t *testing.T) {
"artifacts.oci.format": "simplesigning",
"artifacts.oci.storage": "oci",
"artifacts.oci.signer": "x509",
"artifacts.taskrun.format": "in-toto",
"artifacts.taskrun.format": "slsa/v1",
"artifacts.taskrun.signer": "x509",
"artifacts.taskrun.storage": "oci",
"storage.oci.repository.insecure": "true",
Expand Down Expand Up @@ -459,7 +459,7 @@ func TestMultiBackendStorage(t *testing.T) {
"artifacts.oci.format": "simplesigning",
"artifacts.oci.storage": "tekton,oci",
"artifacts.oci.signer": "x509",
"artifacts.taskrun.format": "in-toto",
"artifacts.taskrun.format": "slsa/v1",
"artifacts.taskrun.signer": "x509",
"artifacts.taskrun.storage": "tekton,oci",
"storage.oci.repository.insecure": "true",
Expand All @@ -469,7 +469,7 @@ func TestMultiBackendStorage(t *testing.T) {
{
name: "pipelinerun",
cm: map[string]string{
"artifacts.pipelinerun.format": "in-toto",
"artifacts.pipelinerun.format": "slsa/v1",
"artifacts.pipelinerun.signer": "x509",
"artifacts.pipelinerun.storage": "tekton,oci",
"storage.oci.repository.insecure": "true",
Expand Down Expand Up @@ -546,7 +546,7 @@ func TestRetryFailed(t *testing.T) {
"transparency.url": "doesnotexist",
"transparency.enabled": "true",
"artifacts.pipelinerun.storage": "tekton",
"artifacts.pipelinerun.format": "in-toto",
"artifacts.pipelinerun.format": "slsa/v1",
},
opts: setupOpts{
registry: true,
Expand Down Expand Up @@ -693,7 +693,7 @@ func TestProvenanceMaterials(t *testing.T) {
{
name: "taskrun",
cm: map[string]string{
"artifacts.taskrun.format": "in-toto",
"artifacts.taskrun.format": "slsa/v1",
"artifacts.taskrun.signer": "x509",
"artifacts.taskrun.storage": "tekton",
},
Expand All @@ -703,7 +703,7 @@ func TestProvenanceMaterials(t *testing.T) {
{
name: "pipelinerun",
cm: map[string]string{
"artifacts.pipelinerun.format": "in-toto",
"artifacts.pipelinerun.format": "slsa/v1",
"artifacts.pipelinerun.signer": "x509",
"artifacts.pipelinerun.storage": "tekton",
},
Expand Down
4 changes: 2 additions & 2 deletions test/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestExamples(t *testing.T) {
{
name: "taskrun-examples",
cm: map[string]string{
"artifacts.taskrun.format": "in-toto",
"artifacts.taskrun.format": "slsa/v1",
"artifacts.oci.storage": "tekton",
},
getExampleObjects: getTaskRunExamples,
Expand All @@ -77,7 +77,7 @@ func TestExamples(t *testing.T) {
{
name: "pipelinerun-examples",
cm: map[string]string{
"artifacts.pipelinerun.format": "in-toto",
"artifacts.pipelinerun.format": "slsa/v1",
"artifacts.pipelinerun.storage": "tekton",
},
getExampleObjects: getPipelineRunExamples,
Expand Down
Loading

0 comments on commit 2f4551d

Please sign in to comment.