Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ Supported keys include:
| Key | Description | Supported Values | Default |
| :--- | :--- | :--- | :--- |
| `artifacts.taskrun.format` | The format to store `TaskRun` payloads in. | `tekton`, `in-toto`| `tekton` |
| `artifacts.taskrun.storage` | The storage backend to store `TaskRun` signatures in. | `tekton`, `oci`, `gcs`, `docdb` | `tekton` |
| `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` | `tekton` |
| `artifacts.taskrun.signer` | The signature backend to sign `Taskrun` payloads with. | `x509`, `kms` | `x509` |

### OCI Configuration

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

### KMS Configuration
Expand Down
15 changes: 15 additions & 0 deletions docs/tutorials/getting-started-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ cosign generate-key-pair k8s://tekton-chains/signing-secrets

cosign will prompt you for a password, which will be stored in a Kubernetes secret named signing-secrets in the tekton-chains namespace.

## Configuring Tekton Chains

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

* `artifacts.oci.storage=""`

You can set these fields by running

```shell
kubectl patch configmap chains-config -n tekton-chains -p='{"data":{"artifacts.oci.storage": ""}}'
```

This tells Chains to use the default `tekton` artifact (enabled by default) and disable the `OCI` artifact.


To create a simple `TaskRun`, run:

```shell
Expand Down
18 changes: 14 additions & 4 deletions pkg/artifacts/signable.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import (
"github.com/tektoncd/chains/pkg/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/util/sets"
)

type Signable interface {
ExtractObjects(tr *v1beta1.TaskRun) []interface{}
StorageBackend(cfg config.Config) string
StorageBackend(cfg config.Config) sets.String
Signer(cfg config.Config) string
PayloadFormat(cfg config.Config) formats.PayloadType
Key(interface{}) string
Type() string
Enabled(cfg config.Config) bool
}

type TaskRunArtifact struct {
Expand All @@ -49,7 +51,7 @@ func (ta *TaskRunArtifact) Type() string {
return "tekton"
}

func (ta *TaskRunArtifact) StorageBackend(cfg config.Config) string {
func (ta *TaskRunArtifact) StorageBackend(cfg config.Config) sets.String {
return cfg.Artifacts.TaskRuns.StorageBackend
}

Expand All @@ -61,6 +63,10 @@ func (ta *TaskRunArtifact) Signer(cfg config.Config) string {
return cfg.Artifacts.TaskRuns.Signer
}

func (ta *TaskRunArtifact) Enabled(cfg config.Config) bool {
return cfg.Artifacts.TaskRuns.Enabled()
}

type OCIArtifact struct {
Logger *zap.SugaredLogger
}
Expand Down Expand Up @@ -172,7 +178,7 @@ func (oa *OCIArtifact) Type() string {
return "oci"
}

func (oa *OCIArtifact) StorageBackend(cfg config.Config) string {
func (oa *OCIArtifact) StorageBackend(cfg config.Config) sets.String {
return cfg.Artifacts.OCI.StorageBackend
}

Expand All @@ -184,7 +190,11 @@ func (oa *OCIArtifact) Signer(cfg config.Config) string {
return cfg.Artifacts.OCI.Signer
}

func (ta *OCIArtifact) Key(obj interface{}) string {
func (oa *OCIArtifact) Key(obj interface{}) string {
v := obj.(name.Digest)
return strings.TrimPrefix(v.DigestStr(), "sha256:")[:12]
}

func (oa *OCIArtifact) Enabled(cfg config.Config) bool {
return cfg.Artifacts.OCI.Enabled()
}
26 changes: 15 additions & 11 deletions pkg/chains/signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ func (ts *TaskRunSigner) SignTaskRun(ctx context.Context, tr *v1beta1.TaskRun) e
var merr *multierror.Error
extraAnnotations := map[string]string{}
for _, signableType := range enabledSignableTypes {

if !signableType.Enabled(cfg) {
continue
}
payloadFormat := signableType.PayloadFormat(cfg)
// Find the right payload format and format the object
payloader, ok := allFormats[payloadFormat]
Expand Down Expand Up @@ -196,16 +198,18 @@ func (ts *TaskRunSigner) SignTaskRun(ctx context.Context, tr *v1beta1.TaskRun) e
}

// Now store those!
b := allBackends[signableType.StorageBackend(cfg)]
storageOpts := config.StorageOpts{
Key: signableType.Key(obj),
Cert: signer.Cert(),
Chain: signer.Chain(),
PayloadFormat: payloadFormat,
}
if err := b.StorePayload(rawPayload, string(signature), storageOpts); err != nil {
logger.Error(err)
merr = multierror.Append(merr, err)
for _, backend := range signableType.StorageBackend(cfg).List() {
b := allBackends[backend]
storageOpts := config.StorageOpts{
Key: signableType.Key(obj),
Cert: signer.Cert(),
Chain: signer.Chain(),
PayloadFormat: payloadFormat,
}
if err := b.StorePayload(rawPayload, string(signature), storageOpts); err != nil {
logger.Error(err)
merr = multierror.Append(merr, err)
}
}

if shouldUploadTlog(cfg, tr) {
Expand Down
5 changes: 3 additions & 2 deletions pkg/chains/signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
fakepipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client/fake"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/kubernetes"
rtesting "knative.dev/pkg/reconciler/testing"
)
Expand Down Expand Up @@ -169,7 +170,7 @@ func TestTaskRunSigner_SignTaskRun(t *testing.T) {
Artifacts: config.ArtifactConfigs{
TaskRuns: config.Artifact{
Format: "tekton",
StorageBackend: tt.configuredBackend,
StorageBackend: sets.NewString(tt.configuredBackend),
Signer: "x509",
},
},
Expand Down Expand Up @@ -235,7 +236,7 @@ func TestTaskRunSigner_Transparency(t *testing.T) {
Artifacts: config.ArtifactConfigs{
TaskRuns: config.Artifact{
Format: format,
StorageBackend: "mock",
StorageBackend: sets.NewString("mock"),
Signer: "x509",
},
},
Expand Down
10 changes: 7 additions & 3 deletions pkg/chains/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ type Backend interface {
// InitializeBackends creates and initializes every configured storage backend.
func InitializeBackends(ps versioned.Interface, kc kubernetes.Interface, logger *zap.SugaredLogger, tr *v1beta1.TaskRun, cfg config.Config) (map[string]Backend, error) {
// Add an entry here for every configured backend
configuredBackends := []string{
cfg.Artifacts.TaskRuns.StorageBackend,
cfg.Artifacts.OCI.StorageBackend}
configuredBackends := []string{}
if cfg.Artifacts.TaskRuns.Enabled() {
configuredBackends = append(configuredBackends, cfg.Artifacts.TaskRuns.StorageBackend.List()...)
}
if cfg.Artifacts.OCI.Enabled() {
configuredBackends = append(configuredBackends, cfg.Artifacts.OCI.StorageBackend.List()...)
}

// Now only initialize and return the configured ones.
backends := map[string]Backend{}
Expand Down
7 changes: 6 additions & 1 deletion pkg/chains/storage/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/tektoncd/chains/pkg/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
fakepipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client/fake"
"k8s.io/apimachinery/pkg/util/sets"
fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake"
logtesting "knative.dev/pkg/logging/testing"
rtesting "knative.dev/pkg/reconciler/testing"
Expand All @@ -37,7 +38,11 @@ func TestInitializeBackends(t *testing.T) {
}, {
name: "tekton",
want: []string{"tekton"},
cfg: config.Config{Artifacts: config.ArtifactConfigs{TaskRuns: config.Artifact{StorageBackend: "tekton"}}},
cfg: config.Config{Artifacts: config.ArtifactConfigs{TaskRuns: config.Artifact{StorageBackend: sets.NewString("tekton")}}},
}, {
name: "multi",
want: []string{"tekton"},
cfg: config.Config{Artifacts: config.ArtifactConfigs{TaskRuns: config.Artifact{StorageBackend: sets.NewString("tekton", "mock")}}},
}}
logger := logtesting.TestLogger(t)
ctx, _ := rtesting.SetupFakeContext(t)
Expand Down
29 changes: 16 additions & 13 deletions pkg/chains/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,29 @@ func (tv *TaskRunVerifier) VerifyTaskRun(ctx context.Context, tr *v1beta1.TaskRu
signers := allSigners(tv.SecretPath, cfg, logger)

for _, signableType := range enabledSignableTypes {

if !signableType.Enabled(cfg) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @rgreinho just an fyi since you've been working on this code!

continue
}
// Verify the signature.
signerType := signableType.Signer(cfg)
signer, ok := signers[signerType]
if !ok {
logger.Warnf("No signer %s configured for %s", signerType, signableType.Type())
continue
}

backend := allBackends[signableType.StorageBackend(cfg)]
signature, err := backend.RetrieveSignature(config.StorageOpts{})
if err != nil {
return err
}
payload, err := backend.RetrievePayload(config.StorageOpts{})
if err != nil {
return err
}
if err := signer.VerifySignature(strings.NewReader(signature), strings.NewReader(payload)); err != nil {
return err
for _, backend := range signableType.StorageBackend(cfg).List() {
b := allBackends[backend]
signature, err := b.RetrieveSignature(config.StorageOpts{})
if err != nil {
return err
}
payload, err := b.RetrievePayload(config.StorageOpts{})
if err != nil {
return err
}
if err := signer.VerifySignature(strings.NewReader(signature), strings.NewReader(payload)); err != nil {
return err
}
}
}

Expand Down
38 changes: 33 additions & 5 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package config
import (
"fmt"
"strconv"
"strings"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
Expand All @@ -42,7 +43,7 @@ type ArtifactConfigs struct {
// Artifact contains the configuration for how to sign/store/format the signatures for a single artifact
type Artifact struct {
Format string
StorageBackend string
StorageBackend sets.String
Signer string
}

Expand Down Expand Up @@ -129,17 +130,21 @@ const (
ChainsConfig = "chains-config"
)

func (artifact *Artifact) Enabled() bool {
return !(artifact.StorageBackend.Len() == 1 && artifact.StorageBackend.Has(""))
}

func defaultConfig() *Config {
return &Config{
Artifacts: ArtifactConfigs{
TaskRuns: Artifact{
Format: "tekton",
StorageBackend: "tekton",
StorageBackend: sets.NewString("tekton"),
Signer: "x509",
},
OCI: Artifact{
Format: "simplesigning",
StorageBackend: "oci",
StorageBackend: sets.NewString("oci"),
Signer: "x509",
},
},
Expand All @@ -166,11 +171,11 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
// Artifact-specific configs
// TaskRuns
asString(taskrunFormatKey, &cfg.Artifacts.TaskRuns.Format, "tekton", "in-toto", "tekton-provenance"),
asString(taskrunStorageKey, &cfg.Artifacts.TaskRuns.StorageBackend, "tekton", "oci", "gcs", "docdb"),
asStringSet(taskrunStorageKey, &cfg.Artifacts.TaskRuns.StorageBackend, sets.NewString("tekton", "oci", "gcs", "docdb")),
asString(taskrunSignerKey, &cfg.Artifacts.TaskRuns.Signer, "x509", "kms"),
// OCI
asString(ociFormatKey, &cfg.Artifacts.OCI.Format, "tekton", "simplesigning"),
asString(ociStorageKey, &cfg.Artifacts.OCI.StorageBackend, "tekton", "oci", "gcs", "docdb"),
asStringSet(ociStorageKey, &cfg.Artifacts.OCI.StorageBackend, sets.NewString("tekton", "oci", "gcs", "docdb")),
asString(ociSignerKey, &cfg.Artifacts.OCI.Signer, "x509", "kms"),

// Storage level configs
Expand Down Expand Up @@ -257,3 +262,26 @@ func asString(key string, target *string, values ...string) cm.ParseFunc {
return nil
}
}

// asStringSet parses the value at key as a sets.String (split by ',') into the target, if it exists.
func asStringSet(key string, target *sets.String, allowed sets.String) cm.ParseFunc {
return func(data map[string]string) error {
if raw, ok := data[key]; ok {
if raw == "" {
*target = sets.NewString("")
return nil
}
splitted := strings.Split(raw, ",")
if allowed.Len() > 0 {
for i, v := range splitted {
splitted[i] = strings.TrimSpace(v)
if !allowed.Has(splitted[i]) {
return fmt.Errorf("invalid value %q wanted one of %v", splitted[i], allowed.List())
}
}
}
*target = sets.NewString(splitted...)
}
return nil
}
}
Loading