diff --git a/config/config-feature-flags.yaml b/config/config-feature-flags.yaml index 01ac93e7703..cb059014fe4 100644 --- a/config/config-feature-flags.yaml +++ b/config/config-feature-flags.yaml @@ -97,3 +97,8 @@ data: # Acceptable values are "v1beta1" and "v1alpha1". # The default is "v1alpha1". custom-task-version: "v1alpha1" + # Setting this flag will determine how Tekton pipelines will handle non-falsifiable provenance. + # If set to "spire", then SPIRE will be used to ensure non-falsifiable provenance. + # If set to "none", then Tekton will not have non-falsifiable provenance. + # This is an experimental feature and thus should still be considered an alpha feature. + enforce-nonfalsifiablity: "none" diff --git a/config/config-spire.yaml b/config/config-spire.yaml new file mode 100644 index 00000000000..726d5ade916 --- /dev/null +++ b/config/config-spire.yaml @@ -0,0 +1,49 @@ +# Copyright 2022 The Tekton Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-spire + namespace: tekton-pipelines + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipelines +data: + _example: | + ################################ + # # + # EXAMPLE CONFIGURATION # + # # + ################################ + # This block is not actually functional configuration, + # but serves to illustrate the available configuration + # options and document them in a way that is accessible + # to users that `kubectl edit` this config map. + # + # These sample configuration options may be copied out of + # this example block and unindented to be in the data block + # to actually change the configuration. + # + # spire-trust-domain specifies the SPIRE trust domain to use. + # spire-trust-domain: "example.org" + # + # spire-socket-path specifies the SPIRE agent socket for SPIFFE workload API. + # spire-socket-path: "unix:///spiffe-workload-api/spire-agent.sock" + # + # spire-server-addr specifies the SPIRE server address for workload/node registration. + # spire-server-addr: "spire-server.spire.svc.cluster.local:8081" + # + # spire-node-alias-prefix specifies the SPIRE node alias prefix to use. + # spire-node-alias-prefix: "/tekton-node/" diff --git a/config/controller.yaml b/config/controller.yaml index 832c7242633..83d561d6c60 100644 --- a/config/controller.yaml +++ b/config/controller.yaml @@ -117,6 +117,8 @@ spec: value: feature-flags - name: CONFIG_LEADERELECTION_NAME value: config-leader-election + - name: CONFIG_SPIRE + value: config-spire - name: CONFIG_TRUSTED_RESOURCES_NAME value: config-trusted-resources - name: SSL_CERT_FILE diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 52fd3bd8d81..5336a86826d 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -57,6 +57,11 @@ ${PREFIX}/deepcopy-gen \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ -i github.com/tektoncd/pipeline/pkg/apis/config +${PREFIX}/deepcopy-gen \ + -O zz_generated.deepcopy \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ + -i github.com/tektoncd/pipeline/pkg/spire/config + ${PREFIX}/deepcopy-gen \ -O zz_generated.deepcopy \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ diff --git a/pkg/apis/config/feature_flags.go b/pkg/apis/config/feature_flags.go index 71dee99f42a..ef8206ea692 100644 --- a/pkg/apis/config/feature_flags.go +++ b/pkg/apis/config/feature_flags.go @@ -80,8 +80,12 @@ const ( DefaultSendCloudEventsForRuns = false // DefaultEmbeddedStatus is the default value for "embedded-status". DefaultEmbeddedStatus = FullEmbeddedStatus - // DefaultEnableSpire is the default value for "enable-spire". - DefaultEnableSpire = false + // 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. + EnforceNonfalsifiabilityNone = "" + // DefaultEnforceNonfalsifiability is the default value for "enforce-nonfalsifiability". + DefaultEnforceNonfalsifiability = EnforceNonfalsifiabilityNone // DefaultResourceVerificationMode is the default value for "resource-verification-mode". DefaultResourceVerificationMode = SkipResourceVerificationMode // DefaultEnableProvenanceInStatus is the default value for "enable-provenance-status". @@ -103,7 +107,7 @@ const ( enableAPIFields = "enable-api-fields" sendCloudEventsForRuns = "send-cloudevents-for-runs" embeddedStatus = "embedded-status" - enableSpire = "enable-spire" + enforceNonfalsifiability = "enforce-nonfalsifiability" verificationMode = "resource-verification-mode" enableProvenanceInStatus = "enable-provenance-in-status" resultExtractionMethod = "results-from" @@ -125,7 +129,7 @@ type FeatureFlags struct { SendCloudEventsForRuns bool AwaitSidecarReadiness bool EmbeddedStatus string - EnableSpire bool + EnforceNonfalsifiability string ResourceVerificationMode string EnableProvenanceInStatus bool ResultExtractionMethod string @@ -142,6 +146,14 @@ func GetFeatureFlagsConfigName() string { return "feature-flags" } +func getEnforceNonfalsifiabilityValues() map[string]struct{} { + var value struct{} + return map[string]struct{}{ + EnforceNonfalsifiabilityNone: value, + EnforceNonfalsifiabilityWithSpire: value, + } +} + // NewFeatureFlagsFromMap returns a Config given a map corresponding to a ConfigMap func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { setFeature := func(key string, defaultValue bool, feature *bool) error { @@ -157,6 +169,19 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { return nil } + setStringFeature := func(key string, defaultValue string, acceptedValues map[string]struct{}, feature *string) error { + value := defaultValue + if cfg, ok := cfgMap[key]; ok { + value = strings.ToLower(cfg) + } + if _, ok := acceptedValues[value]; !ok { + *feature = defaultValue + return fmt.Errorf("invalid value for feature flag %q: %q", key, value) + } + *feature = value + return nil + } + tc := FeatureFlags{} if err := setFeature(disableAffinityAssistantKey, DefaultDisableAffinityAssistant, &tc.DisableAffinityAssistant); err != nil { return nil, err @@ -207,7 +232,7 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { if tc.EnableAPIFields == AlphaAPIFields { tc.EnableTektonOCIBundles = true tc.EnableCustomTasks = true - tc.EnableSpire = true + tc.EnforceNonfalsifiability = EnforceNonfalsifiabilityWithSpire } else { if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil { return nil, err @@ -215,7 +240,7 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { if err := setFeature(enableCustomTasks, DefaultEnableCustomTasks, &tc.EnableCustomTasks); err != nil { return nil, err } - if err := setFeature(enableSpire, DefaultEnableSpire, &tc.EnableSpire); err != nil { + if err := setStringFeature(enforceNonfalsifiability, DefaultEnforceNonfalsifiability, getEnforceNonfalsifiabilityValues(), &tc.EnforceNonfalsifiability); err != nil { return nil, err } } diff --git a/pkg/apis/config/feature_flags_test.go b/pkg/apis/config/feature_flags_test.go index 4d38cb266a6..003c0f2660c 100644 --- a/pkg/apis/config/feature_flags_test.go +++ b/pkg/apis/config/feature_flags_test.go @@ -64,7 +64,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) { EnableAPIFields: "alpha", SendCloudEventsForRuns: true, EmbeddedStatus: "both", - EnableSpire: true, + EnforceNonfalsifiability: "spire", ResourceVerificationMode: "enforce", EnableProvenanceInStatus: true, ResultExtractionMethod: "termination-message", @@ -78,10 +78,9 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) { EnableAPIFields: "alpha", // These are prescribed as true by enabling "alpha" API fields, even // if the submitted text value is "false". - EnableTektonOCIBundles: true, - EnableCustomTasks: true, - EnableSpire: true, - + EnableTektonOCIBundles: true, + EnableCustomTasks: true, + EnforceNonfalsifiability: "spire", DisableAffinityAssistant: config.DefaultDisableAffinityAssistant, DisableCredsInit: config.DefaultDisableCredsInit, RunningInEnvWithInjectedSidecars: config.DefaultRunningInEnvWithInjectedSidecars, @@ -141,7 +140,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) { EnableAPIFields: "stable", EmbeddedStatus: "full", EnableCustomTasks: config.DefaultEnableCustomTasks, - EnableSpire: true, + EnforceNonfalsifiability: "spire", ResourceVerificationMode: config.DefaultResourceVerificationMode, RunningInEnvWithInjectedSidecars: config.DefaultRunningInEnvWithInjectedSidecars, AwaitSidecarReadiness: config.DefaultAwaitSidecarReadiness, @@ -149,7 +148,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) { MaxResultSize: config.DefaultMaxResultSize, CustomTaskVersion: config.DefaultCustomTaskVersion, }, - fileName: "feature-flags-enable-spire", + fileName: "feature-flags-enforce-nonfalsifiability-spire", }, { expectedConfig: &config.FeatureFlags{ @@ -189,7 +188,7 @@ func TestNewFeatureFlagsFromEmptyConfigMap(t *testing.T) { EnableAPIFields: config.DefaultEnableAPIFields, SendCloudEventsForRuns: config.DefaultSendCloudEventsForRuns, EmbeddedStatus: config.DefaultEmbeddedStatus, - EnableSpire: config.DefaultEnableSpire, + EnforceNonfalsifiability: config.DefaultEnforceNonfalsifiability, ResourceVerificationMode: config.DefaultResourceVerificationMode, EnableProvenanceInStatus: config.DefaultEnableProvenanceInStatus, ResultExtractionMethod: config.DefaultResultExtractionMethod, @@ -245,6 +244,8 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) { fileName: "feature-flags-invalid-max-result-size-bad-value", }, { fileName: "feature-flags-invalid-custom-task-version", + }, { + fileName: "feature-flags-enforce-nonfalsifiability-bad-flag", }} { t.Run(tc.fileName, func(t *testing.T) { cm := test.ConfigMapFromTestFile(t, tc.fileName) diff --git a/pkg/apis/config/spire_config.go b/pkg/apis/config/spire_config.go new file mode 100644 index 00000000000..7ad507f2020 --- /dev/null +++ b/pkg/apis/config/spire_config.go @@ -0,0 +1,83 @@ +/* +Copyright 2022 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config + +import ( + "fmt" + "os" + + sc "github.com/tektoncd/pipeline/pkg/spire/config" + corev1 "k8s.io/api/core/v1" +) + +const ( + // SpireConfigMapName is the name of the trusted resources configmap + SpireConfigMapName = "config-spire" + + // SpireTrustDomain is the key to extract out the SPIRE trust domain to use + SpireTrustDomain = "spire-trust-domain" + // SpireSocketPath is the key to extract out the SPIRE agent socket for SPIFFE workload API + SpireSocketPath = "spire-socket-path" + // SpireServerAddr is the key to extract out the SPIRE server address for workload/node registration + SpireServerAddr = "spire-server-addr" + // SpireNodeAliasPrefix is the key to extract out the SPIRE node alias prefix to use + SpireNodeAliasPrefix = "spire-node-alias-prefix" + + // SpireTrustDomainDefault is the default value for the SpireTrustDomain + SpireTrustDomainDefault = "example.org" + // SpireSocketPathDefault is the default value for the SpireSocketPath + SpireSocketPathDefault = "unix:///spiffe-workload-api/spire-agent.sock" + // SpireServerAddrDefault is the default value for the SpireServerAddr + SpireServerAddrDefault = "spire-server.spire.svc.cluster.local:8081" + // SpireNodeAliasPrefixDefault is the default value for the SpireNodeAliasPrefix + SpireNodeAliasPrefixDefault = "/tekton-node/" +) + +// NewSpireConfigFromMap creates a Config from the supplied map +func NewSpireConfigFromMap(data map[string]string) (*sc.SpireConfig, error) { + cfg := &sc.SpireConfig{} + var ok bool + if cfg.TrustDomain, ok = data[SpireTrustDomain]; !ok { + cfg.TrustDomain = SpireTrustDomainDefault + } + if cfg.SocketPath, ok = data[SpireSocketPath]; !ok { + cfg.SocketPath = SpireSocketPathDefault + } + if cfg.ServerAddr, ok = data[SpireServerAddr]; !ok { + cfg.ServerAddr = SpireServerAddrDefault + } + if cfg.NodeAliasPrefix, ok = data[SpireNodeAliasPrefix]; !ok { + cfg.NodeAliasPrefix = SpireNodeAliasPrefixDefault + } + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("failed to parse SPIRE configmap: %w", err) + } + return cfg, nil +} + +// NewSpireConfigFromConfigMap creates a Config from the supplied ConfigMap +func NewSpireConfigFromConfigMap(configMap *corev1.ConfigMap) (*sc.SpireConfig, error) { + return NewSpireConfigFromMap(configMap.Data) +} + +// GetSpireConfigName returns the name of Spire ConfigMap +func GetSpireConfigName() string { + if e := os.Getenv("CONFIG_SPIRE"); e != "" { + return e + } + return SpireConfigMapName +} diff --git a/pkg/apis/config/spire_config_test.go b/pkg/apis/config/spire_config_test.go new file mode 100644 index 00000000000..19b89c0bb43 --- /dev/null +++ b/pkg/apis/config/spire_config_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package config_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/config" + test "github.com/tektoncd/pipeline/pkg/reconciler/testing" + sc "github.com/tektoncd/pipeline/pkg/spire/config" + "github.com/tektoncd/pipeline/test/diff" +) + +func TestNewSpireConfigFromConfigMap(t *testing.T) { + type testCase struct { + want *sc.SpireConfig + fileName string + } + + testCases := []testCase{ + { + want: &sc.SpireConfig{ + TrustDomain: "test.com", + SocketPath: "unix:///test-spire-api/test-spire-agent.sock", + ServerAddr: "test-spire-server.spire.svc.cluster.local:8081", + NodeAliasPrefix: "/test-tekton-node/", + }, + fileName: config.GetSpireConfigName(), + }, + { + want: &sc.SpireConfig{ + TrustDomain: "example.org", + SocketPath: "unix:///spiffe-workload-api/spire-agent.sock", + ServerAddr: "spire-server.spire.svc.cluster.local:8081", + NodeAliasPrefix: "/tekton-node/", + }, + fileName: "config-spire-empty", + }, + } + + for _, tc := range testCases { + verifyConfigFileWithExpectedSpireConfig(t, tc.fileName, tc.want) + } +} + +func verifyConfigFileWithExpectedSpireConfig(t *testing.T, fileName string, want *sc.SpireConfig) { + t.Helper() + cm := test.ConfigMapFromTestFile(t, fileName) + if got, err := config.NewSpireConfigFromConfigMap(cm); err == nil { + if d := cmp.Diff(got, want); d != "" { + t.Errorf("Diff:\n%s", diff.PrintWantGot(d)) + } + } else { + t.Errorf("NewSpireConfigFromConfigMap(actual) = %v", err) + } +} diff --git a/pkg/apis/config/store.go b/pkg/apis/config/store.go index 338a05c2ff9..5143d3e0b79 100644 --- a/pkg/apis/config/store.go +++ b/pkg/apis/config/store.go @@ -19,6 +19,7 @@ package config import ( "context" + sc "github.com/tektoncd/pipeline/pkg/spire/config" "knative.dev/pkg/configmap" ) @@ -33,6 +34,7 @@ type Config struct { ArtifactPVC *ArtifactPVC Metrics *Metrics TrustedResources *TrustedResources + SpireConfig *sc.SpireConfig } // FromContext extracts a Config from the provided context. @@ -56,6 +58,8 @@ func FromContextOrDefaults(ctx context.Context) *Config { artifactPVC, _ := NewArtifactPVCFromMap(map[string]string{}) metrics, _ := newMetricsFromMap(map[string]string{}) trustedresources, _ := NewTrustedResourcesConfigFromMap(map[string]string{}) + spireconfig, _ := NewSpireConfigFromMap(map[string]string{}) + return &Config{ Defaults: defaults, FeatureFlags: featureFlags, @@ -63,6 +67,7 @@ func FromContextOrDefaults(ctx context.Context) *Config { ArtifactPVC: artifactPVC, Metrics: metrics, TrustedResources: trustedresources, + SpireConfig: spireconfig, } } @@ -91,6 +96,7 @@ func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value i GetArtifactPVCConfigName(): NewArtifactPVCFromConfigMap, GetMetricsConfigName(): NewMetricsFromConfigMap, GetTrustedResourcesConfigName(): NewTrustedResourcesConfigFromConfigMap, + GetSpireConfigName(): NewSpireConfigFromConfigMap, }, onAfterStore..., ), @@ -131,6 +137,10 @@ func (s *Store) Load() *Config { if trustedresources == nil { trustedresources, _ = NewTrustedResourcesConfigFromMap(map[string]string{}) } + spireconfig := s.UntypedLoad(GetSpireConfigName()) + if spireconfig == nil { + spireconfig, _ = NewSpireConfigFromMap(map[string]string{}) + } return &Config{ Defaults: defaults.(*Defaults).DeepCopy(), @@ -139,5 +149,6 @@ func (s *Store) Load() *Config { ArtifactPVC: artifactPVC.(*ArtifactPVC).DeepCopy(), Metrics: metrics.(*Metrics).DeepCopy(), TrustedResources: trustedresources.(*TrustedResources).DeepCopy(), + SpireConfig: spireconfig.(*sc.SpireConfig).DeepCopy(), } } diff --git a/pkg/apis/config/store_test.go b/pkg/apis/config/store_test.go index 3e04f19d1fe..fcb42a44d66 100644 --- a/pkg/apis/config/store_test.go +++ b/pkg/apis/config/store_test.go @@ -35,6 +35,7 @@ func TestStoreLoadWithContext(t *testing.T) { artifactPVCConfig := test.ConfigMapFromTestFile(t, "config-artifact-pvc") metricsConfig := test.ConfigMapFromTestFile(t, "config-observability") trustedresourcesConfig := test.ConfigMapFromTestFile(t, "config-trusted-resources") + spireConfig := test.ConfigMapFromTestFile(t, "config-spire") expectedDefaults, _ := config.NewDefaultsFromConfigMap(defaultConfig) expectedFeatures, _ := config.NewFeatureFlagsFromConfigMap(featuresConfig) @@ -42,6 +43,7 @@ func TestStoreLoadWithContext(t *testing.T) { expectedArtifactPVC, _ := config.NewArtifactPVCFromConfigMap(artifactPVCConfig) metrics, _ := config.NewMetricsFromConfigMap(metricsConfig) expectedTrustedResources, _ := config.NewTrustedResourcesConfigFromConfigMap(trustedresourcesConfig) + expectedSpireConfig, _ := config.NewSpireConfigFromConfigMap(spireConfig) expected := &config.Config{ Defaults: expectedDefaults, @@ -50,6 +52,7 @@ func TestStoreLoadWithContext(t *testing.T) { ArtifactPVC: expectedArtifactPVC, Metrics: metrics, TrustedResources: expectedTrustedResources, + SpireConfig: expectedSpireConfig, } store := config.NewStore(logtesting.TestLogger(t)) @@ -59,6 +62,7 @@ func TestStoreLoadWithContext(t *testing.T) { store.OnConfigChanged(artifactPVCConfig) store.OnConfigChanged(metricsConfig) store.OnConfigChanged(trustedresourcesConfig) + store.OnConfigChanged(spireConfig) cfg := config.FromContext(store.ToContext(context.Background())) @@ -74,21 +78,23 @@ func TestStoreLoadWithContext_Empty(t *testing.T) { artifactPVC, _ := config.NewArtifactPVCFromMap(map[string]string{}) metrics, _ := config.NewMetricsFromConfigMap(&corev1.ConfigMap{Data: map[string]string{}}) trustedresources, _ := config.NewTrustedResourcesConfigFromMap(map[string]string{}) + spireConfig, _ := config.NewSpireConfigFromMap(map[string]string{}) - expected := &config.Config{ + want := &config.Config{ Defaults: defaults, FeatureFlags: featureFlags, ArtifactBucket: artifactBucket, ArtifactPVC: artifactPVC, Metrics: metrics, TrustedResources: trustedresources, + SpireConfig: spireConfig, } store := config.NewStore(logtesting.TestLogger(t)) - cfg := config.FromContext(store.ToContext(context.Background())) + got := config.FromContext(store.ToContext(context.Background())) - if d := cmp.Diff(cfg, expected); d != "" { + if d := cmp.Diff(want, got); d != "" { t.Errorf("Unexpected config %s", diff.PrintWantGot(d)) } } diff --git a/pkg/apis/config/testdata/config-spire-empty.yaml b/pkg/apis/config/testdata/config-spire-empty.yaml new file mode 100644 index 00000000000..834f88ee409 --- /dev/null +++ b/pkg/apis/config/testdata/config-spire-empty.yaml @@ -0,0 +1,29 @@ +# Copyright 2022 The Tekton Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-spire + namespace: tekton-pipelines + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipelines +data: + _example: | + ################################ + # # + # EXAMPLE CONFIGURATION # + # # + ################################ diff --git a/pkg/apis/config/testdata/config-spire.yaml b/pkg/apis/config/testdata/config-spire.yaml new file mode 100644 index 00000000000..85c328242c3 --- /dev/null +++ b/pkg/apis/config/testdata/config-spire.yaml @@ -0,0 +1,31 @@ +# Copyright 2022 The Tekton Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-spire + namespace: tekton-pipelines + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipelines +data: + # spire-trust-domain specifies the SPIRE trust domain to use. + spire-trust-domain: "test.com" + # spire-socket-path specifies the SPIRE agent socket for SPIFFE workload API. + spire-socket-path: "unix:///test-spire-api/test-spire-agent.sock" + # spire-server-addr specifies the SPIRE server address for workload/node registration. + spire-server-addr: "test-spire-server.spire.svc.cluster.local:8081" + # spire-node-alias-prefix specifies the SPIRE node alias prefix to use. + spire-node-alias-prefix: "/test-tekton-node/" diff --git a/pkg/apis/config/testdata/feature-flags-all-flags-set.yaml b/pkg/apis/config/testdata/feature-flags-all-flags-set.yaml index 6b0aff680a0..909594069d7 100644 --- a/pkg/apis/config/testdata/feature-flags-all-flags-set.yaml +++ b/pkg/apis/config/testdata/feature-flags-all-flags-set.yaml @@ -27,7 +27,7 @@ data: enable-api-fields: "alpha" send-cloudevents-for-runs: "true" embedded-status: "both" - enable-spire: "true" + enforce-nonfalsifiability: "spire" resource-verification-mode: "enforce" enable-provenance-in-status: "true" custom-task-version: "v1beta1" diff --git a/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml b/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml index cea578c238d..8fe445f1f00 100644 --- a/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml +++ b/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml @@ -6,5 +6,5 @@ metadata: data: enable-tekton-oci-bundles: "false" enable-custom-tasks: "false" - enable-spire: "false" + enforce-nonfalsifiability: "" enable-api-fields: "alpha" diff --git a/pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-bad-flag.yaml b/pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-bad-flag.yaml new file mode 100644 index 00000000000..856694bd46f --- /dev/null +++ b/pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-bad-flag.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: feature-flags + namespace: tekton-pipelines +data: + enforce-nonfalsifiability: "bad-value" diff --git a/pkg/apis/config/testdata/feature-flags-enable-spire.yaml b/pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-spire.yaml similarity index 72% rename from pkg/apis/config/testdata/feature-flags-enable-spire.yaml rename to pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-spire.yaml index ae4e99a93c6..79c69d40d93 100644 --- a/pkg/apis/config/testdata/feature-flags-enable-spire.yaml +++ b/pkg/apis/config/testdata/feature-flags-enforce-nonfalsifiability-spire.yaml @@ -4,4 +4,4 @@ metadata: name: feature-flags namespace: tekton-pipelines data: - enable-spire: "true" + enforce-nonfalsifiability: "spire" diff --git a/pkg/spire/config/config.go b/pkg/spire/config/config.go index 5398e234f24..f8fed32dafc 100644 --- a/pkg/spire/config/config.go +++ b/pkg/spire/config/config.go @@ -24,6 +24,7 @@ import ( // SpireConfig holds the images reference for a number of container images used // across tektoncd pipelines. +// +k8s:deepcopy-gen=true type SpireConfig struct { // The trust domain corresponds to the trust root of a SPIFFE identity provider. TrustDomain string diff --git a/pkg/spire/config/zz_generated.deepcopy.go b/pkg/spire/config/zz_generated.deepcopy.go new file mode 100644 index 00000000000..56590eee535 --- /dev/null +++ b/pkg/spire/config/zz_generated.deepcopy.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SpireConfig) DeepCopyInto(out *SpireConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpireConfig. +func (in *SpireConfig) DeepCopy() *SpireConfig { + if in == nil { + return nil + } + out := new(SpireConfig) + in.DeepCopyInto(out) + return out +} diff --git a/test/controller.go b/test/controller.go index ee18bc53345..74b713ed17e 100644 --- a/test/controller.go +++ b/test/controller.go @@ -340,7 +340,7 @@ func PrependResourceVersionReactor(f *ktesting.Fake) { // EnsureConfigurationConfigMapsExist makes sure all the configmaps exists. func EnsureConfigurationConfigMapsExist(d *Data) { - var defaultsExists, featureFlagsExists, artifactBucketExists, artifactPVCExists, metricsExists, trustedresourcesExists bool + var defaultsExists, featureFlagsExists, artifactBucketExists, artifactPVCExists, metricsExists, trustedresourcesExists, spireconfigExists bool for _, cm := range d.ConfigMaps { if cm.Name == config.GetDefaultsConfigName() { defaultsExists = true @@ -360,6 +360,9 @@ func EnsureConfigurationConfigMapsExist(d *Data) { if cm.Name == config.GetTrustedResourcesConfigName() { trustedresourcesExists = true } + if cm.Name == config.GetSpireConfigName() { + spireconfigExists = true + } } if !defaultsExists { d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{ @@ -397,4 +400,10 @@ func EnsureConfigurationConfigMapsExist(d *Data) { Data: map[string]string{}, }) } + if !spireconfigExists { + d.ConfigMaps = append(d.ConfigMaps, &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: config.GetSpireConfigName(), Namespace: system.Namespace()}, + Data: map[string]string{}, + }) + } } diff --git a/test/controller_test.go b/test/controller_test.go index 65bd444626e..fba6e94cb7f 100644 --- a/test/controller_test.go +++ b/test/controller_test.go @@ -158,6 +158,10 @@ func TestEnsureConfigurationConfigMapsExist(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: config.GetTrustedResourcesConfigName(), Namespace: system.Namespace()}, Data: map[string]string{}, }) + expected.ConfigMaps = append(expected.ConfigMaps, &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: config.GetSpireConfigName(), Namespace: system.Namespace()}, + Data: map[string]string{}, + }) EnsureConfigurationConfigMapsExist(&d) if d := cmp.Diff(expected, d); d != "" {