Skip to content

Commit

Permalink
[TEP-0089] Apis to handle SPIRE signing and verification.
Browse files Browse the repository at this point in the history
This is the first PR to breakdown PR tektoncd#4759
proposed by @pxp928
according @lumjjb suggestions.
Plan for breaking down PR is
PR 1.1: api
PR 1.2: entrypointer (+cmd line + test/entrypointer)
Entrypoint takes results and signs the results (termination message).
PR 1.3: reconciler + pod + cmd/controller + integration tests
Controller will verify the signed result.
  • Loading branch information
florianl authored and tekton-robot committed Oct 20, 2022
1 parent b648a5b commit 07bf470
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 0 deletions.
8 changes: 8 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ const (
DefaultSendCloudEventsForRuns = false
// DefaultEmbeddedStatus is the default value for "embedded-status".
DefaultEmbeddedStatus = FullEmbeddedStatus
// DefaultEnableSpire is the default value for "enable-spire".
DefaultEnableSpire = false

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
Expand All @@ -73,6 +75,7 @@ const (
enableAPIFields = "enable-api-fields"
sendCloudEventsForRuns = "send-cloudevents-for-runs"
embeddedStatus = "embedded-status"
enableSpire = "enable-spire"
)

// FeatureFlags holds the features configurations
Expand All @@ -89,6 +92,7 @@ type FeatureFlags struct {
SendCloudEventsForRuns bool
AwaitSidecarReadiness bool
EmbeddedStatus string
EnableSpire bool
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -150,13 +154,17 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if tc.EnableAPIFields == AlphaAPIFields {
tc.EnableTektonOCIBundles = true
tc.EnableCustomTasks = true
tc.EnableSpire = true
} else {
if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil {
return nil, err
}
if err := setFeature(enableCustomTasks, DefaultEnableCustomTasks, &tc.EnableCustomTasks); err != nil {
return nil, err
}
if err := setFeature(enableSpire, DefaultEnableSpire, &tc.EnableSpire); err != nil {
return nil, err
}
}
return &tc, nil
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableAPIFields: "alpha",
SendCloudEventsForRuns: true,
EmbeddedStatus: "both",
EnableSpire: true,
},
fileName: "feature-flags-all-flags-set",
},
Expand All @@ -69,6 +70,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
// if the submitted text value is "false".
EnableTektonOCIBundles: true,
EnableCustomTasks: true,
EnableSpire: true,

DisableAffinityAssistant: config.DefaultDisableAffinityAssistant,
DisableCredsInit: config.DefaultDisableCredsInit,
Expand Down Expand Up @@ -112,6 +114,17 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
},
fileName: "feature-flags-beta-api-fields",
},
{
expectedConfig: &config.FeatureFlags{
EnableAPIFields: "stable",
EmbeddedStatus: "full",
EnableSpire: true,

RunningInEnvWithInjectedSidecars: config.DefaultRunningInEnvWithInjectedSidecars,
AwaitSidecarReadiness: config.DefaultAwaitSidecarReadiness,
},
fileName: "feature-flags-enable-spire",
},
}

for _, tc := range testCases {
Expand All @@ -136,6 +149,7 @@ func TestNewFeatureFlagsFromEmptyConfigMap(t *testing.T) {
EnableAPIFields: config.DefaultEnableAPIFields,
SendCloudEventsForRuns: config.DefaultSendCloudEventsForRuns,
EmbeddedStatus: config.DefaultEmbeddedStatus,
EnableSpire: config.DefaultEnableSpire,
}
verifyConfigFileWithExpectedFeatureFlagsConfig(t, FeatureFlagsConfigEmptyName, expectedConfig)
}
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 @@ -27,3 +27,4 @@ data:
enable-api-fields: "alpha"
send-cloudevents-for-runs: "true"
embedded-status: "both"
enable-spire: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ metadata:
data:
enable-tekton-oci-bundles: "false"
enable-custom-tasks: "false"
enable-spire: "false"
enable-api-fields: "alpha"
7 changes: 7 additions & 0 deletions pkg/apis/config/testdata/feature-flags-enable-spire.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags
namespace: tekton-pipelines
data:
enable-spire: "true"
29 changes: 29 additions & 0 deletions pkg/apis/pipeline/v1beta1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@ type TaskRunStatus struct {
TaskRunStatusFields `json:",inline"`
}

// TaskRunConditionType is an enum used to store TaskRun custom conditions
// conditions such as one used in spire results verification
type TaskRunConditionType string

const (
// TaskRunConditionResultsVerified is a Condition Type that indicates that the results were verified by spire
TaskRunConditionResultsVerified TaskRunConditionType = "SignedResultsVerified"
)

func (t TaskRunConditionType) String() string {
return string(t)
}

// TaskRunReason is an enum used to store all TaskRun reason for
// the Succeeded condition that are controlled by the TaskRun itself. Failure
// reasons that emerge from underlying resources are not included here
Expand All @@ -162,6 +175,12 @@ const (
TaskRunReasonResolvingTaskRef = "ResolvingTaskRef"
// TaskRunReasonImagePullFailed is the reason set when the step of a task fails due to image not being pulled
TaskRunReasonImagePullFailed TaskRunReason = "TaskRunImagePullFailed"
// TaskRunReasonResultsVerified is the reason set when the TaskRun results are verified by spire
TaskRunReasonResultsVerified TaskRunReason = "TaskRunResultsVerified"
// TaskRunReasonsResultsVerificationFailed is the reason set when the TaskRun results are failed to verify by spire
TaskRunReasonsResultsVerificationFailed TaskRunReason = "TaskRunResultsVerificationFailed"
// AwaitingTaskRunResults is the reason set when waiting upon `TaskRun` results and signatures to verify
AwaitingTaskRunResults TaskRunReason = "AwaitingTaskRunResults"
)

func (t TaskRunReason) String() string {
Expand Down Expand Up @@ -442,6 +461,16 @@ func (tr *TaskRun) IsCancelled() bool {
return tr.Spec.Status == TaskRunSpecStatusCancelled
}

// IsTaskRunResultVerified returns true if the TaskRun's results have been validated by spire.
func (tr *TaskRun) IsTaskRunResultVerified() bool {
return tr.Status.GetCondition(apis.ConditionType(TaskRunConditionResultsVerified.String())).IsTrue()
}

// IsTaskRunResultDone returns true if the TaskRun's results are available for verification
func (tr *TaskRun) IsTaskRunResultDone() bool {
return !tr.Status.GetCondition(apis.ConditionType(TaskRunConditionResultsVerified.String())).IsUnknown()
}

// HasTimedOut returns true if the TaskRun runtime is beyond the allowed timeout
func (tr *TaskRun) HasTimedOut(ctx context.Context, c clock.PassiveClock) bool {
if tr.Status.StartTime.IsZero() {
Expand Down
64 changes: 64 additions & 0 deletions pkg/apis/pipeline/v1beta1/taskrun_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,70 @@ func TestTaskRunIsCancelledWithMessage(t *testing.T) {
}
}

func TestTaskRunIsTaskRunResultVerified(t *testing.T) {
tr := &v1beta1.TaskRun{
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: []apis.Condition{{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionTrue,
Reason: v1beta1.TaskRunReasonResultsVerified.String(),
Message: "Successfully verified all spire signed taskrun results",
}},
},
},
}
if !tr.IsTaskRunResultVerified() {
t.Fatal("Expected pipelinerun status to be results verified")
}
if tr.Status.GetCondition(apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String())).Reason != v1beta1.TaskRunReasonResultsVerified.String() {
t.Fatal("Expected pipelinerun status reason to be TaskRunResultsVerified")
}
}

func TestTaskRunEmptyIsTaskRunResultVerified(t *testing.T) {
tr := &v1beta1.TaskRun{
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{},
},
}
if tr.IsTaskRunResultVerified() {
t.Fatal("Expected false as no condition exists for SignedResultsVerified")
}
}

func TestTaskRunIsTaskRunResultDone(t *testing.T) {
tr := &v1beta1.TaskRun{
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: []apis.Condition{{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionUnknown,
Reason: v1beta1.AwaitingTaskRunResults.String(),
Message: "Waiting upon TaskRun results and signatures to verify",
}},
},
},
}
if tr.IsTaskRunResultDone() {
t.Fatal("Expected pipelinerun status to be unknown and waiting")
}
if tr.Status.GetCondition(apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String())).Reason != v1beta1.AwaitingTaskRunResults.String() {
t.Fatal("Expected pipelinerun status reason to be AwaitingTaskRunResults")
}
}

func TestTaskRunEmptyIsTaskRunResultDone(t *testing.T) {
tr := &v1beta1.TaskRun{
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{},
},
}
if tr.IsTaskRunResultDone() {
t.Fatal("Expected false as no condition exists for SignedResultsVerified")
}
}

func TestTaskRunHasVolumeClaimTemplate(t *testing.T) {
tr := &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Expand Down

0 comments on commit 07bf470

Please sign in to comment.