Skip to content

Commit

Permalink
Add a feature flag to disable inline spec
Browse files Browse the repository at this point in the history
By default the inline specs will be enabled. Only if flag is set to
true, inline spec would be disabled. This is to increase security
of pipelines.
  • Loading branch information
khrm authored and tekton-robot committed Apr 24, 2024
1 parent 356b30d commit b419b2c
Show file tree
Hide file tree
Showing 29 changed files with 503 additions and 17 deletions.
6 changes: 6 additions & 0 deletions config/config-feature-flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@ data:
enable-artifacts: "false"
# Setting this flag to "true" will enable the built-in param input validation via param enum.
enable-param-enum: "false"
# Setting this flag to "pipeline,pipelinerun,taskrun" will prevent users from creating
# embedded spec Taskruns or Pipelineruns for Pipeline, Pipelinerun and taskrun
# respectively. We can specify "pipeline" to disable for Pipeline resource only.
# "pipelinerun" for Pipelinerun and "taskrun" for Taskrun. Or a combination of
# these.
disable-inline-spec: ""
26 changes: 26 additions & 0 deletions docs/additional-configs.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ installation.
- [Verify Tekton Resources](#verify-tekton-resources)
- [Pipelinerun with Affinity Assistant](#pipelineruns-with-affinity-assistant)
- [TaskRuns with `imagePullBackOff` Timeout](#taskruns-with-imagepullbackoff-timeout)
- [Disabling Inline Spec in TaskRun and PipelineRun](#disabling-inline-spec-in-taskrun-and-pipelinerun)
- [Next steps](#next-steps)


Expand Down Expand Up @@ -694,6 +695,31 @@ data:
default-imagepullbackoff-timeout: "5m"
```
## Disabling Inline Spec in Pipeline, TaskRun and PipelineRun
Tekton users may embed the specification of a `Task` (via `taskSpec`) or a `Pipeline` (via `pipelineSpec`) as an alternative to referring to an external resource via `taskRef` and `pipelineRef` respectively. This behaviour can be selectively disabled for three Tekton resources: `TaskRun`, `PipelineRun` and `Pipeline`.
In certain clusters and scenarios, an admin might want to disable the customisation of `Tasks` and `Pipelines` and only allow users to run pre-defined resources. To achieve that the admin should disable embedded specification via the `disable-inline-spec` flag, and remote resolvers too.
To disable inline specification, set the `disable-inline-spec` flag to `"pipeline,pipelinerun,taskrun"`
in the `feature-flags` configmap.
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags
namespace: tekton-pipelines
labels:
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-pipelines
data:
disable-inline-spec: "pipeline,pipelinerun,taskrun"
```
Inline specifications can be disabled for specific resources only. To achieve that, set the disable-inline-spec flag to a comma-separated list of the desired resources. Valid values are pipeline, pipelinerun and taskrun.
The default value of disable-inline-spec is "", which means inline specification is enabled in all cases.
## Next steps
To get started with Tekton check the [Introductory tutorials][quickstarts],
Expand Down
32 changes: 28 additions & 4 deletions docs/pipeline-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,8 @@ PipelineSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -1155,6 +1157,8 @@ TaskSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -2349,6 +2353,8 @@ PipelineSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -2887,7 +2893,9 @@ EmbeddedTask
</td>
<td>
<em>(Optional)</em>
<p>TaskSpec is a specification of a task</p>
<p>TaskSpec is a specification of a task
Specifying TaskSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -3014,7 +3022,9 @@ PipelineSpec
<td>
<em>(Optional)</em>
<p>PipelineSpec is a specification of a pipeline
Note: PipelineSpec is in preview mode and not yet supported</p>
Note: PipelineSpec is in preview mode and not yet supported
Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -5530,6 +5540,8 @@ TaskSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -9026,6 +9038,8 @@ PipelineSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -9524,6 +9538,8 @@ TaskSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -11197,6 +11213,8 @@ PipelineSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -11828,7 +11846,9 @@ EmbeddedTask
</td>
<td>
<em>(Optional)</em>
<p>TaskSpec is a specification of a task</p>
<p>TaskSpec is a specification of a task
Specifying TaskSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -11969,7 +11989,9 @@ PipelineSpec
<td>
<em>(Optional)</em>
<p>PipelineSpec is a specification of a pipeline
Note: PipelineSpec is in preview mode and not yet supported</p>
Note: PipelineSpec is in preview mode and not yet supported
Specifying TaskSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -14997,6 +15019,8 @@ TaskSpec
</td>
<td>
<em>(Optional)</em>
<p>Specifying PipelineSpec can be disabled by setting
<code>disable-inline-spec</code> feature flag..</p>
</td>
</tr>
<tr>
Expand Down
20 changes: 20 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const (
DefaultRunningInEnvWithInjectedSidecars = true
// DefaultAwaitSidecarReadiness is the default value for "await-sidecar-readiness".
DefaultAwaitSidecarReadiness = true
// DefaultDisableInlineSpec is the default value of "disable-inline-spec"
DefaultDisableInlineSpec = ""
// DefaultRequireGitSSHSecretKnownHosts is the default value for "require-git-ssh-secret-known-hosts".
DefaultRequireGitSSHSecretKnownHosts = false
// DefaultEnableTektonOciBundles is the default value for "enable-tekton-oci-bundles".
Expand Down Expand Up @@ -107,6 +109,10 @@ const (
// EnableParamEnum is the flag to enabled enum in params
EnableParamEnum = "enable-param-enum"

// DisableInlineSpec is the flag to disable embedded spec
// in Taskrun or Pipelinerun
DisableInlineSpec = "disable-inline-spec"

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
runningInEnvWithInjectedSidecarsKey = "running-in-environment-with-injected-sidecars"
Expand Down Expand Up @@ -193,6 +199,7 @@ type FeatureFlags struct {
EnableStepActions bool
EnableParamEnum bool
EnableArtifacts bool
DisableInlineSpec string
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -291,6 +298,10 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if err := setPerFeatureFlag(EnableArtifacts, DefaultEnableArtifacts, &tc.EnableArtifacts); err != nil {
return nil, err
}
if err := setFeatureInlineSpec(cfgMap, DisableInlineSpec, DefaultDisableInlineSpec, &tc.DisableInlineSpec); err != nil {
return nil, err
}

// Given that they are alpha features, Tekton Bundles and Custom Tasks should be switched on if
// enable-api-fields is "alpha". If enable-api-fields is not "alpha" then fall back to the value of
// each feature's individual flag.
Expand Down Expand Up @@ -364,6 +375,15 @@ func setEnforceNonFalsifiability(cfgMap map[string]string, feature *string) erro
}
}

func setFeatureInlineSpec(cfgMap map[string]string, key string, defaultValue string, feature *string) error {
if cfg, ok := cfgMap[key]; ok {
*feature = cfg
return nil
}
*feature = strings.ReplaceAll(defaultValue, " ", "")
return nil
}

// setResultExtractionMethod sets the "results-from" flag based on the content of a given map.
// If the feature gate is invalid or missing then an error is returned.
func setResultExtractionMethod(cfgMap map[string]string, defaultValue string, feature *string) error {
Expand Down
12 changes: 11 additions & 1 deletion pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: config.GetFeatureFlagsConfigName(),
},
Expand All @@ -81,6 +82,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableStepActions: true,
EnableArtifacts: true,
EnableParamEnum: true,
DisableInlineSpec: "pipeline,pipelinerun,taskrun",
},
fileName: "feature-flags-all-flags-set",
},
Expand All @@ -107,6 +109,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: "feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks",
},
Expand All @@ -128,6 +131,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: "feature-flags-bundles-and-custom-tasks",
},
Expand All @@ -149,6 +153,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: "feature-flags-beta-api-fields",
},
Expand All @@ -169,6 +174,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: "feature-flags-enforce-nonfalsifiability-spire",
},
Expand All @@ -188,6 +194,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
},
fileName: "feature-flags-results-via-sidecar-logs",
},
Expand Down Expand Up @@ -224,6 +231,7 @@ func TestNewFeatureFlagsFromEmptyConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
DisableInlineSpec: config.DefaultDisableInlineSpec,
}
verifyConfigFileWithExpectedFeatureFlagsConfig(t, FeatureFlagsConfigEmptyName, expectedConfig)
}
Expand Down Expand Up @@ -311,7 +319,9 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) {
t.Run(tc.fileName, func(t *testing.T) {
cm := test.ConfigMapFromTestFile(t, tc.fileName)
_, err := config.NewFeatureFlagsFromConfigMap(cm)
if d := cmp.Diff(tc.want, err.Error()); d != "" {
if err == nil {
t.Error("failed to get:", tc.want)
} else if d := cmp.Diff(tc.want, err.Error()); d != "" {
t.Errorf("failed to get expected error; diff:\n%s", diff.PrintWantGot(d))
}
})
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/config/testdata/feature-flags-all-flags-set.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ data:
enable-step-actions: "true"
enable-param-enum: "true"
enable-artifacts: "true"
disable-inline-spec: "pipeline,pipelinerun,taskrun"
10 changes: 6 additions & 4 deletions pkg/apis/pipeline/v1/openapi_generated.go

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

4 changes: 4 additions & 0 deletions pkg/apis/pipeline/v1/pipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ type PipelineTask struct {
TaskRef *TaskRef `json:"taskRef,omitempty"`

// TaskSpec is a specification of a task
// Specifying TaskSpec can be disabled by setting
// `disable-inline-spec` feature flag..
// +optional
TaskSpec *EmbeddedTask `json:"taskSpec,omitempty"`

Expand Down Expand Up @@ -243,6 +245,8 @@ type PipelineTask struct {

// PipelineSpec is a specification of a pipeline
// Note: PipelineSpec is in preview mode and not yet supported
// Specifying PipelineSpec can be disabled by setting
// `disable-inline-spec` feature flag..
// +optional
PipelineSpec *PipelineSpec `json:"pipelineSpec,omitempty"`

Expand Down
21 changes: 21 additions & 0 deletions pkg/apis/pipeline/v1/pipeline_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1
import (
"context"
"fmt"
"slices"
"strings"

"github.com/tektoncd/pipeline/pkg/apis/config"
Expand Down Expand Up @@ -177,6 +178,8 @@ func (pt PipelineTask) ValidateName() *apis.FieldError {
func (pt PipelineTask) Validate(ctx context.Context) (errs *apis.FieldError) {
errs = errs.Also(pt.validateRefOrSpec(ctx))

errs = errs.Also(pt.validateEnabledInlineSpec(ctx))

errs = errs.Also(pt.validateEmbeddedOrType())
// taskKinds contains the kinds when the apiVersion is not set, they are not custom tasks,
// if apiVersion is set they are custom tasks.
Expand Down Expand Up @@ -271,6 +274,24 @@ func (pt *PipelineTask) validateWorkspaces(workspaceNames sets.String) (errs *ap
return errs
}

// validateEnabledInlineSpec validates that pipelineSpec or taskSpec is allowed by checking
// disable-inline-spec field
func (pt PipelineTask) validateEnabledInlineSpec(ctx context.Context) (errs *apis.FieldError) {
if pt.TaskSpec != nil {
if slices.Contains(strings.Split(
config.FromContextOrDefaults(ctx).FeatureFlags.DisableInlineSpec, ","), "pipeline") {
errs = errs.Also(apis.ErrDisallowedFields("taskSpec"))
}
}
if pt.PipelineSpec != nil {
if slices.Contains(strings.Split(
config.FromContextOrDefaults(ctx).FeatureFlags.DisableInlineSpec, ","), "pipeline") {
errs = errs.Also(apis.ErrDisallowedFields("pipelineSpec"))
}
}
return errs
}

// validateRefOrSpec validates at least one of taskRef or taskSpec or pipelineRef or pipelineSpec is specified
func (pt PipelineTask) validateRefOrSpec(ctx context.Context) (errs *apis.FieldError) {
// collect all the specified specifications
Expand Down
Loading

0 comments on commit b419b2c

Please sign in to comment.