Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tekton Chains + Spire for validating results and taskrun status #462

Closed
wants to merge 5 commits into from
Closed
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
6 changes: 6 additions & 0 deletions config/100-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ spec:
mountPath: /etc/signing-secrets
- name: oidc-info
mountPath: /var/run/sigstore/cosign
- name: spiffe-workload-api
mountPath: /spiffe-workload-api
readOnly: true
env:
- name: SYSTEM_NAMESPACE
valueFrom:
Expand Down Expand Up @@ -120,3 +123,6 @@ spec:
path: oidc-token
expirationSeconds: 600 # Use as short-lived as possible.
audience: sigstore
- name: spiffe-workload-api
csi:
driver: "csi.spiffe.io"
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.17

replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c

replace github.com/tektoncd/pipeline v0.38.1 => ../pipeline

require (
cloud.google.com/go/compute v1.7.0
cloud.google.com/go/storage v1.24.0
Expand Down Expand Up @@ -44,7 +46,7 @@ require (
github.com/sigstore/rekor v0.5.0
github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5
github.com/spiffe/go-spiffe/v2 v2.1.1
github.com/tektoncd/pipeline v0.37.2
github.com/tektoncd/pipeline v0.38.1
github.com/tektoncd/plumbing v0.0.0-20220329085922-d765a5cba75f
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
go.uber.org/atomic v1.9.0
Expand Down Expand Up @@ -137,7 +139,7 @@ require (
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 // indirect
github.com/cloudevents/sdk-go/v2 v2.5.0 // indirect
github.com/cloudevents/sdk-go/v2 v2.10.1 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
Expand Down Expand Up @@ -347,6 +349,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.12.0 // indirect
github.com/spiffe/spire-api-sdk v1.3.2 // indirect
github.com/src-d/gcfg v1.4.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
Expand Down
16 changes: 9 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.8.24/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
Expand Down Expand Up @@ -561,8 +562,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudevents/sdk-go/v2 v2.5.0 h1:Ts6aLHbBUJfcNcZ4ouAfJ4+Np7SE1Yf2w4ADKRCd7Fo=
github.com/cloudevents/sdk-go/v2 v2.5.0/go.mod h1:nlXhgFkf0uTopxmRXalyMwS2LG70cRGPrxzmjJgSG0U=
github.com/cloudevents/sdk-go/v2 v2.10.1 h1:qNFovJ18fWOd8Q9ydWJPk1oiFudXyv1GxJIP7MwPjuM=
github.com/cloudevents/sdk-go/v2 v2.10.1/go.mod h1:GpCBmUj7DIRiDhVvsK5d6WCbgTWs8DxAWTRtAwQmIXs=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
Expand Down Expand Up @@ -604,6 +605,7 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
Expand All @@ -625,8 +627,8 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ=
github.com/containerd/containerd v1.5.10 h1:3cQ2uRVCkJVcx5VombsE7105Gl9Wrl7ORAO3+4+ogf4=
github.com/containerd/containerd v1.5.10/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ=
github.com/containerd/containerd v1.5.13 h1:XqvKw9i4P7/mFrC3TSM7yV5cwFZ9avXe6M3YANKnzEE=
github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
Expand Down Expand Up @@ -1672,7 +1674,7 @@ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJk
github.com/jedisct1/go-minisign v0.0.0-20210703085342-c1f07ee84431/go.mod h1:3VIJLjlf5Iako82IX/5KOoCzDmogK5mO+bl+DRItnR8=
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b h1:ZGiXF8sz7PDk6RgkP+A/SFfUD0ZR/AgG6SpRNEDKZy8=
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b/go.mod h1:hQmNrgofl+IY/8L+n20H6E6PWBBTokdsv+q49j0QhsU=
github.com/jenkins-x/go-scm v1.10.10/go.mod h1:z7xTO9/VzqW3xEbEMH2z5cpOGrZ8+nOHOWfU1ngFGxs=
github.com/jenkins-x/go-scm v1.11.19/go.mod h1:eIcty4+tf6E7ycGOg0cUqnaLP+1LH1Z8zncQFQqRa3E=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM=
Expand Down Expand Up @@ -2424,6 +2426,8 @@ github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiu
github.com/spiffe/go-spiffe/v2 v2.1.0/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
github.com/spiffe/go-spiffe/v2 v2.1.1 h1:RT9kM8MZLZIsPTH+HKQEP5yaAk3yd/VBzlINaRjXs8k=
github.com/spiffe/go-spiffe/v2 v2.1.1/go.mod h1:5qg6rpqlwIub0JAiF1UK9IMD6BpPTmvG6yfSgDBs5lg=
github.com/spiffe/spire-api-sdk v1.3.2 h1:8F5HQGm3jDL6amuxxeQcH8Rqs6/WOwaLt6h0LTU6uYA=
github.com/spiffe/spire-api-sdk v1.3.2/go.mod h1:73BC0cOGkqRQrqoB1Djk7etxN+bE1ypmzZMkhCQs6kY=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
Expand Down Expand Up @@ -2474,8 +2478,6 @@ github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A=
github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
github.com/tektoncd/pipeline v0.37.2 h1:JIp410ktvJPkprPqK0sgUGpRlZosy2B0C1jbUTwWd9c=
github.com/tektoncd/pipeline v0.37.2/go.mod h1:ZZOSGj1vCeK/xONQGcxBs+m17NzCXNNOqglCDhOPwjY=
github.com/tektoncd/plumbing v0.0.0-20220304154415-13228ac1f4a4/go.mod h1:b9esRuV1absBvaPzKkjYdKXjC5Tgs8/vh1sz++RiTdc=
github.com/tektoncd/plumbing v0.0.0-20220329085922-d765a5cba75f h1:74OqGOB+R3aobu2j9fxKnsgupS9c7KH1bZaR5LSXICw=
github.com/tektoncd/plumbing v0.0.0-20220329085922-d765a5cba75f/go.mod h1:b9esRuV1absBvaPzKkjYdKXjC5Tgs8/vh1sz++RiTdc=
Expand Down
26 changes: 25 additions & 1 deletion pkg/chains/formats/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ limitations under the License.

package formats

import (
"context"

"github.com/pkg/errors"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/spire"
"go.uber.org/zap"
)

// Payloader is an interface to generate a chains Payload from a TaskRun
type Payloader interface {
CreatePayload(obj interface{}) (interface{}, error)
CreatePayload(ctx context.Context, obj interface{}) (interface{}, error)
Type() PayloadType
Wrap() bool
}
Expand All @@ -30,3 +39,18 @@ const (
)

var AllFormatters = []PayloadType{PayloadTypeTekton, PayloadTypeSimpleSigning, PayloadTypeInTotoIte6}

func VerifySpire(ctx context.Context, tr *v1beta1.TaskRun, spireControllerAPI spire.ControllerAPIClient, logger *zap.SugaredLogger) error {

if !tr.IsTaskRunResultVerified() {
return errors.New("taskrun status condition not verified. Spire taskrun results verification failure")
}
logger.Info("spire taskrun status condition verified")

if err := spireControllerAPI.VerifyStatusInternalAnnotation(ctx, tr, logger); err != nil {
return errors.Wrap(err, "verifying SPIRE")
}
logger.Info("internal status annotation verified by spire")

return nil
}
238 changes: 238 additions & 0 deletions pkg/chains/formats/format_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/*
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.
*/

package formats

import (
"context"
"testing"
"time"

"github.com/tektoncd/pipeline/pkg/apis/config"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/spire"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
logtesting "knative.dev/pkg/logging/testing"
)

func TestVerifySpire(t *testing.T) {
spireMockClient := &spire.MockClient{}
var (
cc spire.ControllerAPIClient = spireMockClient
)

ctx := context.Background()

testCases := []struct {
// description of test
desc string
// function to tamper
tamperCondition apis.Condition
// annotations to set
setAnnotations map[string]string
// whether sign/verify procedure should succeed
success bool
}{
{
desc: "non-intrusive tamper with status annotation",
tamperCondition: apis.Condition{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionTrue,
},
setAnnotations: map[string]string{
"unrelated-hash": "change",
},
success: true,
},
{
desc: "tamper status hash annotation",
tamperCondition: apis.Condition{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionTrue,
},
setAnnotations: map[string]string{
spire.TaskRunStatusHashAnnotation: "change-hash",
},
success: false,
},
{
desc: "tamper condition fail",
tamperCondition: apis.Condition{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionFalse,
},
success: false,
},
{
desc: "Spire not verified",
tamperCondition: apis.Condition{
Type: apis.ConditionType(v1beta1.TaskRunConditionResultsVerified.String()),
Status: corev1.ConditionTrue,
},
setAnnotations: map[string]string{
spire.NotVerifiedAnnotation: "yes",
},
success: false,
},
}

for _, tt := range testCases {
for _, tr := range testTaskRuns() {

success := func() bool {
err := cc.AppendStatusInternalAnnotation(ctx, tr)
if err != nil {
return false
}

if tr.Status.Status.Annotations == nil {
tr.Status.Status.Annotations = map[string]string{}
}

if tt.setAnnotations != nil {
for k, v := range tt.setAnnotations {
tr.Status.Status.Annotations[k] = v
}
}

tr.Status.Status.Conditions = append(tr.Status.Status.Conditions, tt.tamperCondition)

err = VerifySpire(ctx, tr, cc, logtesting.TestLogger(t))
return err == nil
}()

if success != tt.success {
t.Fatalf("test %v expected verify %v, got %v", tt.desc, tt.success, success)
}
}
}
}

func objectMeta(name, ns string) metav1.ObjectMeta {
return metav1.ObjectMeta{
Name: name,
Namespace: ns,
Labels: map[string]string{},
Annotations: map[string]string{},
}
}

func testTaskRuns() []*v1beta1.TaskRun {
return []*v1beta1.TaskRun{
// taskRun 1
{
ObjectMeta: objectMeta("taskrun-example", "foo"),
Spec: v1beta1.TaskRunSpec{
TaskRef: &v1beta1.TaskRef{
Name: "taskname",
APIVersion: "a1",
},
ServiceAccountName: "test-sa",
},
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: duckv1beta1.Conditions{
apis.Condition{
Type: apis.ConditionSucceeded,
},
},
},
},
},
// taskRun 2
{
ObjectMeta: objectMeta("taskrun-example-populated", "foo"),
Spec: v1beta1.TaskRunSpec{
TaskRef: &v1beta1.TaskRef{Name: "unit-test-task"},
ServiceAccountName: "test-sa",
Resources: &v1beta1.TaskRunResources{},
Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
},
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: duckv1beta1.Conditions{
apis.Condition{
Type: apis.ConditionSucceeded,
},
},
},
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{ExitCode: int32(0)},
},
}},
},
},
},
// taskRun 3
{
ObjectMeta: objectMeta("taskrun-example-with-objmeta", "foo"),
Spec: v1beta1.TaskRunSpec{
TaskRef: &v1beta1.TaskRef{Name: "unit-test-task"},
ServiceAccountName: "test-sa",
Resources: &v1beta1.TaskRunResources{},
Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
},
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: duckv1beta1.Conditions{
apis.Condition{
Type: apis.ConditionSucceeded,
},
},
},
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{ExitCode: int32(0)},
},
}},
},
},
},
// taskRun 4
{
ObjectMeta: objectMeta("taskrun-example-with-objmeta-annotations", "foo"),
Spec: v1beta1.TaskRunSpec{
TaskRef: &v1beta1.TaskRef{Name: "unit-test-task"},
ServiceAccountName: "test-sa",
Resources: &v1beta1.TaskRunResources{},
Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
},
Status: v1beta1.TaskRunStatus{
Status: duckv1beta1.Status{
Conditions: duckv1beta1.Conditions{
apis.Condition{
Type: apis.ConditionSucceeded,
},
},
Annotations: map[string]string{
"annotation1": "a1value",
"annotation2": "a2value",
},
},
TaskRunStatusFields: v1beta1.TaskRunStatusFields{
Steps: []v1beta1.StepState{{
ContainerState: corev1.ContainerState{
Terminated: &corev1.ContainerStateTerminated{ExitCode: int32(0)},
},
}},
},
},
},
}
}
Loading