Skip to content

Commit

Permalink
[TEP-0089] Enable SPIRE for signing taskrun results in alpha.
Browse files Browse the repository at this point in the history
Breaking down PR tektoncd#4759 originally proposed by @pxp928 to address TEP-0089 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. This commit corresponds to 1.3 above.
  • Loading branch information
jagathprakash committed Nov 3, 2022
1 parent 2d38f5f commit ef3d769
Show file tree
Hide file tree
Showing 31 changed files with 2,538 additions and 77 deletions.
8 changes: 8 additions & 0 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,20 @@ func main() {
flag.StringVar(&opts.Images.ImageDigestExporterImage, "imagedigest-exporter-image", "", "The container image containing our image digest exporter binary.")
flag.StringVar(&opts.Images.WorkingDirInitImage, "workingdirinit-image", "", "The container image containing our working dir init binary.")

flag.StringVar(&opts.SpireConfig.TrustDomain, "spire-trust-domain", "example.org", "Experimental: The SPIRE Trust domain to use.")
flag.StringVar(&opts.SpireConfig.SocketPath, "spire-socket-path", "unix:///spiffe-workload-api/spire-agent.sock", "Experimental: The SPIRE agent socket for SPIFFE workload API.")
flag.StringVar(&opts.SpireConfig.ServerAddr, "spire-server-addr", "spire-server.spire.svc.cluster.local:8081", "Experimental: The SPIRE server address for workload/node registration.")
flag.StringVar(&opts.SpireConfig.NodeAliasPrefix, "spire-node-alias-prefix", "/tekton-node/", "Experimental: The SPIRE node alias prefix to use.")

// This parses flags.
cfg := injection.ParseAndGetRESTConfigOrDie()

if err := opts.Images.Validate(); err != nil {
log.Fatal(err)
}
if err := opts.SpireConfig.Validate(); err != nil {
log.Fatal(err)
}
if cfg.QPS == 0 {
cfg.QPS = 2 * rest.DefaultQPS
}
Expand Down
20 changes: 20 additions & 0 deletions cmd/imagedigestexporter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ limitations under the License.
package main

import (
"context"
"encoding/json"
"flag"

"github.com/tektoncd/pipeline/pkg/spire"
"github.com/tektoncd/pipeline/pkg/spire/config"
"github.com/tektoncd/pipeline/pkg/termination"
"knative.dev/pkg/logging"

Expand All @@ -31,6 +34,8 @@ import (
var (
images = flag.String("images", "", "List of images resources built by task in json format")
terminationMessagePath = flag.String("terminationMessagePath", "/tekton/termination", "Location of file containing termination message")
enableSpire = flag.Bool("enable_spire", false, "If specified by configmap, this enables spire signing and verification")
socketPath = flag.String("spire_socket_path", "unix:///spiffe-workload-api/spire-agent.sock", "Experimental: The SPIRE agent socket for SPIFFE workload API.")
)

/* The input of this go program will be a JSON string with all the output PipelineResources of type
Expand Down Expand Up @@ -76,6 +81,21 @@ func main() {

}

if enableSpire != nil && *enableSpire && socketPath != nil && *socketPath != "" {
ctx := context.Background()
spireConfig := config.SpireConfig{
SocketPath: *socketPath,
}

spireWorkloadAPI := spire.NewEntrypointerAPIClient(&spireConfig)
signed, err := spireWorkloadAPI.Sign(ctx, output)
if err != nil {
logger.Fatal(err)
}

output = append(output, signed...)
}

if err := termination.WriteMessage(*terminationMessagePath, output); err != nil {
logger.Fatalf("Unexpected error writing message %s to %s", *terminationMessagePath, err)
}
Expand Down
4 changes: 4 additions & 0 deletions config/config-feature-flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ data:
# will fail the taskrun/pipelinerun. "warn" will only log the err message and "skip"
# will skip the whole verification
resource-verification-mode: "skip"
# Setting this flag to "true" enables spire integration with pipeline.
# This is an experimental feature and thus should still be considered
# an alpha feature.
enable-spire: "false"
285 changes: 285 additions & 0 deletions docs/spire.md

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion pkg/apis/pipeline/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ limitations under the License.

package pipeline

import (
spireconfig "github.com/tektoncd/pipeline/pkg/spire/config"
)

// Options holds options passed to the Tekton Pipeline controllers
// typically via command-line flags.
type Options struct {
Images Images
Images Images
SpireConfig spireconfig.SpireConfig
}
39 changes: 37 additions & 2 deletions pkg/pod/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"github.com/tektoncd/pipeline/pkg/internal/computeresources/tasklevel"
"github.com/tektoncd/pipeline/pkg/names"
"github.com/tektoncd/pipeline/pkg/spire"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -120,6 +121,12 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1beta1.TaskRun, taskSpec
featureFlags := config.FromContextOrDefaults(ctx).FeatureFlags
alphaAPIEnabled := featureFlags.EnableAPIFields == config.AlphaAPIFields

// Entrypoint arg to enable or disable spire
var commonExtraEntrypointArgs []string
if config.FromContextOrDefaults(ctx).FeatureFlags.EnableSpire {
commonExtraEntrypointArgs = append(commonExtraEntrypointArgs, "-enable_spire")
}

// Add our implicit volumes first, so they can be overridden by the user if they prefer.
volumes = append(volumes, implicitVolumes...)
volumeMounts = append(volumeMounts, implicitVolumeMounts...)
Expand Down Expand Up @@ -190,11 +197,13 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1beta1.TaskRun, taskSpec
}

readyImmediately := isPodReadyImmediately(*featureFlags, taskSpec.Sidecars)
// append credEntrypointArgs with entrypoint arg that contains if spire is enabled by configmap
commonExtraEntrypointArgs = append(commonExtraEntrypointArgs, credEntrypointArgs...)

if alphaAPIEnabled {
stepContainers, err = orderContainers(credEntrypointArgs, stepContainers, &taskSpec, taskRun.Spec.Debug, !readyImmediately)
stepContainers, err = orderContainers(commonExtraEntrypointArgs, stepContainers, &taskSpec, taskRun.Spec.Debug, !readyImmediately)
} else {
stepContainers, err = orderContainers(credEntrypointArgs, stepContainers, &taskSpec, nil, !readyImmediately)
stepContainers, err = orderContainers(commonExtraEntrypointArgs, stepContainers, &taskSpec, nil, !readyImmediately)
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -275,6 +284,32 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1beta1.TaskRun, taskSpec
return nil, err
}

if config.FromContextOrDefaults(ctx).FeatureFlags.EnableSpire {
volumes = append(volumes, corev1.Volume{
Name: spire.WorkloadAPI,
VolumeSource: corev1.VolumeSource{
CSI: &corev1.CSIVolumeSource{
Driver: "csi.spiffe.io",
},
},
})

for i := range stepContainers {
c := &stepContainers[i]
c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{
Name: spire.WorkloadAPI,
MountPath: spire.VolumeMountPath,
})
}
for i := range initContainers {
c := &initContainers[i]
c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{
Name: spire.WorkloadAPI,
MountPath: spire.VolumeMountPath,
})
}
}

mergedPodContainers := stepContainers

// Merge sidecar containers with step containers.
Expand Down
Loading

0 comments on commit ef3d769

Please sign in to comment.