Skip to content

Commit

Permalink
Merge branch 'main' into spire-config-map
Browse files Browse the repository at this point in the history
  • Loading branch information
jagathprakash committed Jan 26, 2023
2 parents 21618b6 + 3c075d8 commit c2dfbe8
Show file tree
Hide file tree
Showing 16 changed files with 316 additions and 245 deletions.
2 changes: 1 addition & 1 deletion config/resolvers/resolvers-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ spec:
memory: 100Mi
limits:
cpu: 1000m
memory: 1000Mi
memory: 4Gi
ports:
- name: metrics
containerPort: 9090
Expand Down
2 changes: 1 addition & 1 deletion docs/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ being deprecated.
| [`v1alpha1.Run` is deprecated](https://github.com/tektoncd/community/blob/main/teps/0114-custom-tasks-beta.md) | v0.43.0 | Alpha | April 10, 2023 or v0.47.0 |
| [ClusterTask is deprecated](https://github.com/tektoncd/pipeline/issues/4476) | v0.41.0 | Beta | July 13, 2023 |
| [`pipelineRef.bundle` and `taskRef.bundle` are deprecated](https://github.com/tektoncd/pipeline/issues/5514) | v0.41.0 | Alpha | July 13, 2023 |
| [`taskrun.status.cloudEvents` are deprecated](https://github.com/tektoncd/community/blob/main/teps/0074-deprecate-pipelineresources.md) | v0.44.0 | Alpha | Oct 11, 2023 |
| [`taskrun.status.cloudEvents` are deprecated](https://github.com/tektoncd/community/blob/main/teps/0074-deprecate-pipelineresources.md) | v0.44.0 | Alpha | Oct 11, 2023 |
156 changes: 0 additions & 156 deletions docs/spire.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,57 +13,6 @@ This being a large feature, this will be implemented in the following phases. Th
2. Add a configMap which initializes SPIRE (in progress).
3. Modify TaskRun to sign and verify TaskRun Results using SPIRE.
4. Modify Tekton Chains to verify the TaskRun Results.
# TaskRun Result Attestations

TaskRun result attestations is currently an alpha experimental feature.

The TaskRun result attestations feature provides the first part of non-falsifiable provenance to the build processes that run in the pipeline. They ensure that the results of the tekton pipeline executions originate from the build workloads themselves and that they have not been tampered with. The second part of non-falsifiable provenance is to ensure that no third party interfered with the build process. Using SPIRE, the TaskRun status is monitored for any activity or change not performed by the Tekton Pipeline Controller. If an unauthorized change is detected, it will invalidate the TaskRun.

When the TaskRun result attestations feature is enabled, all TaskRuns will produce a signature alongside its results, which can then be used to validate its provenance. For example, a TaskRun result that creates user-specified results `commit` and `url` would look like the following. `SVID`, `RESULT_MANIFEST`, `RESULT_MANIFEST.sig`, `commit.sig` and `url.sig` are generated attestations by the integration of SPIRE and Tekton Controller.

Parsed, the fields would be:
```
...
<truncated>
...
📝 Results
NAME VALUE
∙ RESULT_MANIFEST commit,url,SVID,commit.sig,url.sig
∙ RESULT_MANIFEST.sig MEUCIQD55MMII9SEk/esQvwNLGC43y7efNGZ+7fsTdq+9vXYFAIgNoRW7cV9WKriZkcHETIaAKqfcZVJfsKbEmaDyohDSm4=
∙ SVID -----BEGIN CERTIFICATE-----
MIICGzCCAcGgAwIBAgIQH9VkLxKkYMidPIsofckRQTAKBggqhkjOPQQDAjAeMQsw
CQYDVQQGEwJVUzEPMA0GA1UEChMGU1BJRkZFMB4XDTIyMDIxMTE2MzM1MFoXDTIy
MDIxMTE3MzQwMFowHTELMAkGA1UEBhMCVVMxDjAMBgNVBAoTBVNQSVJFMFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAEBRdg3LdxVAELeH+lq8wzdEJd4Gnt+m9G0Qhy
NyWoPmFUaj9vPpvOyRgzxChYnW0xpcDWihJBkq/EbusPvQB8CKOB4TCB3jAOBgNV
HQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
EwEB/wQCMAAwHQYDVR0OBBYEFID7ARM5+vwzvnLPMO7Icfnj7l7hMB8GA1UdIwQY
MBaAFES3IzpGDqgV3QcQNgX8b/MBwyAtMF8GA1UdEQRYMFaGVHNwaWZmZTovL2V4
YW1wbGUub3JnL25zL2RlZmF1bHQvdGFza3J1bi9jYWNoZS1pbWFnZS1waXBlbGlu
ZXJ1bi04ZHE5Yy1mZXRjaC1mcm9tLWdpdDAKBggqhkjOPQQDAgNIADBFAiEAi+LR
JkrZn93PZPslaFmcrQw3rVcEa4xKmPleSvQaBoACIF1QB+q1uwH6cNvWdbLK9g+W
T9Np18bK0xc6p5SuTM2C
-----END CERTIFICATE-----
∙ commit aa79de59c4bae24e32f15fda467d02ae9cd94b01
∙ commit.sig MEQCIEJHk+8B+mCFozp0F52TQ1AadlhEo1lZNOiOnb/ht71aAiBCE0otKB1R0BktlPvweFPldfZfjG0F+NUSc2gPzhErzg==
∙ url https://github.com/buildpacks/samples
∙ url.sig MEUCIF0Fuxr6lv1MmkreqDKcPH3m+eXp+gY++VcxWgGCx7T1AiEA9U/tROrKuCGfKApLq2A9EModbdoGXyQXFOpAa0aMpOg=
```

However, the verification materials are removed from the final results as part of the TaskRun status. It is stored in the termination messages (more details below):

```
$ tkn tr describe cache-image-pipelinerun-8dq9c-fetch-from-git
...
<truncated>
...
📝 Results
NAME VALUE
∙ commit aa79de59c4bae24e32f15fda467d02ae9cd94b01
∙ url https://github.com/buildpacks/samples
```

## Architecture Overview

This feature relies on a SPIRE installation. This is how it integrates into the architecture of Tekton:
Expand Down Expand Up @@ -177,108 +126,3 @@ To enable TaskRun attestations:
# spire-node-alias-prefix specifies the SPIRE node alias prefix to use.
spire-node-alias-prefix: "/tekton-node/"
```
## Sample TaskRun attestation
The following example shows how this feature works:
```yaml
kind: TaskRun
apiVersion: tekton.dev/v1beta1
metadata:
name: non-falsifiable-provenance
spec:
timeout: 60s
taskSpec:
steps:
- name: non-falsifiable
image: ubuntu
script: |
#!/usr/bin/env bash
printf "%s" "hello" > "$(results.foo.path)"
printf "%s" "world" > "$(results.bar.path)"
results:
- name: foo
- name: bar
```


The termination message is:
```
message: '[{"key":"RESULT_MANIFEST","value":"foo,bar","type":1},{"key":"RESULT_MANIFEST.sig","value":"MEQCIB4grfqBkcsGuVyoQd9KUVzNZaFGN6jQOKK90p5HWHqeAiB7yZerDA+YE3Af/ALG43DQzygiBpKhTt8gzWGmpvXJFw==","type":1},{"key":"SVID","value":"-----BEGIN
CERTIFICATE-----\nMIICCjCCAbCgAwIBAgIRALH94zAZZXdtPg97O5vG5M0wCgYIKoZIzj0EAwIwHjEL\nMAkGA1UEBhMCVVMxDzANBgNVBAoTBlNQSUZGRTAeFw0yMjAzMTQxNTUzNTlaFw0y\nMjAzMTQxNjU0MDlaMB0xCzAJBgNVBAYTAlVTMQ4wDAYDVQQKEwVTUElSRTBZMBMG\nByqGSM49AgEGCCqGSM49AwEHA0IABPLzFTDY0RDpjKb+eZCIWgUw9DViu8/pM8q7\nHMTKCzlyGqhaU80sASZfpkZvmi72w+gLszzwVI1ZNU5e7aCzbtSjgc8wgcwwDgYD\nVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBSsUvspy+/Dl24pA1f+JuNVJrjgmTAfBgNVHSME\nGDAWgBSOMyOHnyLLGxPSD9RRFL+Yhm/6qzBNBgNVHREERjBEhkJzcGlmZmU6Ly9l\neGFtcGxlLm9yZy9ucy9kZWZhdWx0L3Rhc2tydW4vbm9uLWZhbHNpZmlhYmxlLXBy\nb3ZlbmFuY2UwCgYIKoZIzj0EAwIDSAAwRQIhAM4/bPAH9dyhBEj3DbwtJKMyEI56\n4DVrP97ps9QYQb23AiBiXWrQkvRYl0h4CX0lveND2yfqLrGdVL405O5NzCcUrA==\n-----END
CERTIFICATE-----\n","type":1},{"key":"bar","value":"world","type":1},{"key":"bar.sig","value":"MEUCIQDOtg+aEP1FCr6/FsHX+bY1d5abSQn2kTiUMg4Uic2lVQIgTVF5bbT/O77VxESSMtQlpBreMyw2GmKX2hYJlaOEH1M=","type":1},{"key":"foo","value":"hello","type":1},{"key":"foo.sig","value":"MEQCIBr+k0i7SRSyb4h96vQE9hhxBZiZb/2PXQqReOKJDl/rAiBrjgSsalwOvN0zgQay0xQ7PRbm5YSmI8tvKseLR8Ryww==","type":1}]'
```

Parsed, the fields are:
- `RESULT_MANIFEST`: List of results that should be present, to prevent pick and choose attacks
- `RESULT_MANIFEST.sig`: The signature of the result manifest
- `SVID`: The x509 certificate that will be used to verify the signature trust chain to the authority
- `*.sig`: The signature of each individual result output
```
∙ RESULT_MANIFEST foo,bar
∙ RESULT_MANIFEST.sig MEQCIB4grfqBkcsGuVyoQd9KUVzNZaFGN6jQOKK90p5HWHqeAiB7yZerDA+YE3Af/ALG43DQzygiBpKhTt8gzWGmpvXJFw==
∙ SVID -----BEGIN CERTIFICATE-----
MIICCjCCAbCgAwIBAgIRALH94zAZZXdtPg97O5vG5M0wCgYIKoZIzj0EAwIwHjEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBlNQSUZGRTAeFw0yMjAzMTQxNTUzNTlaFw0y
MjAzMTQxNjU0MDlaMB0xCzAJBgNVBAYTAlVTMQ4wDAYDVQQKEwVTUElSRTBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABPLzFTDY0RDpjKb+eZCIWgUw9DViu8/pM8q7
HMTKCzlyGqhaU80sASZfpkZvmi72w+gLszzwVI1ZNU5e7aCzbtSjgc8wgcwwDgYD
VR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
HRMBAf8EAjAAMB0GA1UdDgQWBBSsUvspy+/Dl24pA1f+JuNVJrjgmTAfBgNVHSME
GDAWgBSOMyOHnyLLGxPSD9RRFL+Yhm/6qzBNBgNVHREERjBEhkJzcGlmZmU6Ly9l
eGFtcGxlLm9yZy9ucy9kZWZhdWx0L3Rhc2tydW4vbm9uLWZhbHNpZmlhYmxlLXBy
b3ZlbmFuY2UwCgYIKoZIzj0EAwIDSAAwRQIhAM4/bPAH9dyhBEj3DbwtJKMyEI56
4DVrP97ps9QYQb23AiBiXWrQkvRYl0h4CX0lveND2yfqLrGdVL405O5NzCcUrA==
-----END CERTIFICATE-----
∙ bar world
∙ bar.sig MEUCIQDOtg+aEP1FCr6/FsHX+bY1d5abSQn2kTiUMg4Uic2lVQIgTVF5bbT/O77VxESSMtQlpBreMyw2GmKX2hYJlaOEH1M=
∙ foo hello
∙ foo.sig MEQCIBr+k0i7SRSyb4h96vQE9hhxBZiZb/2PXQqReOKJDl/rAiBrjgSsalwOvN0zgQay0xQ7PRbm5YSmI8tvKseLR8Ryww==
```


However, the verification materials are removed from the results as part of the TaskRun status:
```console
$ tkn tr describe non-falsifiable-provenance
Name: non-falsifiable-provenance
Namespace: default
Service Account: default
Timeout: 1m0s
Labels:
app.kubernetes.io/managed-by=tekton-pipelines

🌡️ Status

STARTED DURATION STATUS
38 seconds ago 36 seconds Succeeded

📝 Results

NAME VALUE
∙ bar world
∙ foo hello

🦶 Steps

NAME STATUS
∙ non-falsifiable Completed
```

## How is the result being verified

The signatures are being verified by the Tekton controller, the process of verification is as follows:

- Verifying the SVID
- Obtain the trust bundle from the SPIRE server
- Verify the SVID with the trust bundle
- Verify that the SVID spiffe ID is for the correct TaskRun
- Verifying the result manifest
- Verify the content of `RESULT_MANIFEST` with the field `RESULT_MANIFEST.sig` with the SVID public key
- Verify that there is a corresponding field for all items listed in `RESULT_MANIFEST` (besides SVID and `*.sig` fields)
- Verify individual result fields
- For each of the items in the results, verify its content against its associated `.sig` field


## Further Details

To learn more about SPIRE TaskRun attestations, check out the [TEP](https://github.com/tektoncd/community/blob/main/teps/0089-nonfalsifiable-provenance-support.md).
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/sigstore/sigstore v1.5.1
github.com/spiffe/go-spiffe/v2 v2.1.2
github.com/spiffe/spire-api-sdk v1.5.2
github.com/spiffe/spire-api-sdk v1.5.4
github.com/tektoncd/plumbing v0.0.0-20220817140952-3da8ce01aeeb
go.opencensus.io v0.24.0
go.uber.org/zap v1.24.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 8 additions & 9 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const (
// DefaultSendCloudEventsForRuns is the default value for "send-cloudevents-for-runs".
DefaultSendCloudEventsForRuns = false
// DefaultEmbeddedStatus is the default value for "embedded-status".
DefaultEmbeddedStatus = FullEmbeddedStatus
DefaultEmbeddedStatus = MinimalEmbeddedStatus
// EnforceNonfalsifiabilityWithSpire is the value used for "enable-nonfalsifiability" when SPIRE is used to enable non-falsifiability.
EnforceNonfalsifiabilityWithSpire = "spire"
// EnforceNonfalsifiabilityNone is the value used for "enable-nonfalsifiability" when non-falsifiability is not enabled.
Expand Down Expand Up @@ -142,7 +142,7 @@ func GetFeatureFlagsConfigName() string {
return "feature-flags"
}

func getEnforceNonfalsifiabilityFeature(cfgMap map[string]string, feature *string) error {
func getEnforceNonfalsifiabilityFeature(cfgMap map[string]string) (string, error) {
var mapValue struct{}
var acceptedValues = map[string]struct{}{
EnforceNonfalsifiabilityNone: mapValue,
Expand All @@ -153,11 +153,9 @@ func getEnforceNonfalsifiabilityFeature(cfgMap map[string]string, feature *strin
value = strings.ToLower(cfg)
}
if _, ok := acceptedValues[value]; !ok {
*feature = DefaultEnforceNonfalsifiability
return fmt.Errorf("invalid value for feature flag %q: %q", enforceNonfalsifiability, value)
return DefaultEnforceNonfalsifiability, fmt.Errorf("invalid value for feature flag %q: %q", enforceNonfalsifiability, value)
}
*feature = value
return nil
return value, nil
}

// NewFeatureFlagsFromMap returns a Config given a map corresponding to a ConfigMap
Expand Down Expand Up @@ -225,17 +223,18 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if tc.EnableAPIFields == AlphaAPIFields {
tc.EnableTektonOCIBundles = true
// Only consider SPIRE if alpha is on.
if err := getEnforceNonfalsifiabilityFeature(cfgMap, &tc.EnforceNonfalsifiability); err != nil {
enforceNonfalsifiabilityValue, err := getEnforceNonfalsifiabilityFeature(cfgMap)
if err != nil {
return nil, err
}
tc.EnforceNonfalsifiability = enforceNonfalsifiabilityValue
} else {
if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil {
return nil, err
}
// Do not enable any form of non-falsifiability enforcement in non-alpha mode.
tc.EnforceNonfalsifiability = EnforceNonfalsifiabilityNone
var enforceNonfalsifiabilityValue = DefaultEnforceNonfalsifiability
if err := getEnforceNonfalsifiabilityFeature(cfgMap, &enforceNonfalsifiabilityValue); err != nil || enforceNonfalsifiabilityValue != DefaultEnforceNonfalsifiability {
if enforceNonfalsifiabilityValue, err := getEnforceNonfalsifiabilityFeature(cfgMap); err != nil || enforceNonfalsifiabilityValue != DefaultEnforceNonfalsifiability {
return nil, fmt.Errorf("%q can be set to non-default values (%q) only in alpha", enforceNonfalsifiability, enforceNonfalsifiabilityValue)
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
{
expectedConfig: &config.FeatureFlags{
EnableAPIFields: "alpha",
EmbeddedStatus: "full",
EmbeddedStatus: "minimal",
EnforceNonfalsifiability: "spire",
EnableTektonOCIBundles: true,
ResourceVerificationMode: config.DefaultResourceVerificationMode,
Expand Down
36 changes: 7 additions & 29 deletions pkg/apis/config/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

sc "github.com/tektoncd/pipeline/pkg/spire/config"
"knative.dev/pkg/configmap"
"knative.dev/pkg/logging"
)

type cfgKey struct{}
Expand Down Expand Up @@ -53,34 +52,13 @@ func FromContextOrDefaults(ctx context.Context) *Config {
if cfg := FromContext(ctx); cfg != nil {
return cfg
}
defaults, errDefaults := NewDefaultsFromMap(map[string]string{})
if errDefaults != nil {
logging.FromContext(ctx).Info(errDefaults)
}
featureFlags, errFeatureFlags := NewFeatureFlagsFromMap(map[string]string{})
if errFeatureFlags != nil {
logging.FromContext(ctx).Info(errFeatureFlags)
}
artifactBucket, errArtifactBucket := NewArtifactBucketFromMap(map[string]string{})
if errArtifactBucket != nil {
logging.FromContext(ctx).Info(errArtifactBucket)
}
artifactPVC, errArifactPVC := NewArtifactPVCFromMap(map[string]string{})
if errArifactPVC != nil {
logging.FromContext(ctx).Info(errArifactPVC)
}
metrics, errMetrics := newMetricsFromMap(map[string]string{})
if errMetrics != nil {
logging.FromContext(ctx).Info(errMetrics)
}
trustedresources, errTrustedresources := NewTrustedResourcesConfigFromMap(map[string]string{})
if errTrustedresources != nil {
logging.FromContext(ctx).Info(errTrustedresources)
}
spireconfig, errSpireconfig := NewSpireConfigFromMap(map[string]string{})
if errSpireconfig != nil {
logging.FromContext(ctx).Info(errSpireconfig)
}
defaults, _ := NewDefaultsFromMap(map[string]string{})
featureFlags, _ := NewFeatureFlagsFromMap(map[string]string{})
artifactBucket, _ := NewArtifactBucketFromMap(map[string]string{})
artifactPVC, _ := NewArtifactPVCFromMap(map[string]string{})
metrics, _ := newMetricsFromMap(map[string]string{})
trustedresources, _ := NewTrustedResourcesConfigFromMap(map[string]string{})
spireconfig, _ := NewSpireConfigFromMap(map[string]string{})

return &Config{
Defaults: defaults,
Expand Down
Loading

0 comments on commit c2dfbe8

Please sign in to comment.