diff --git a/cmd/entrypoint/main.go b/cmd/entrypoint/main.go index 44c8fe5de3a..0adef65e71b 100644 --- a/cmd/entrypoint/main.go +++ b/cmd/entrypoint/main.go @@ -30,15 +30,12 @@ import ( "github.com/containerd/containerd/platforms" "github.com/tektoncd/pipeline/cmd/entrypoint/subcommands" - featureFlags "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "github.com/tektoncd/pipeline/pkg/credentials" "github.com/tektoncd/pipeline/pkg/credentials/dockercreds" "github.com/tektoncd/pipeline/pkg/credentials/gitcreds" "github.com/tektoncd/pipeline/pkg/entrypoint" - "github.com/tektoncd/pipeline/pkg/spire" - "github.com/tektoncd/pipeline/pkg/spire/config" "github.com/tektoncd/pipeline/pkg/termination" ) @@ -59,9 +56,7 @@ var ( onError = flag.String("on_error", "", "Set to \"continue\" to ignore an error and continue when a container terminates with a non-zero exit code."+ " Set to \"stopAndFail\" to declare a failure with a step error and stop executing the rest of the steps.") stepMetadataDir = flag.String("step_metadata_dir", "", "If specified, create directory to store the step metadata e.g. /tekton/steps//") - 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.") - resultExtractionMethod = flag.String("result_from", featureFlags.ResultExtractionMethodTerminationMessage, "The method using which to extract results from tasks. Default is using the termination message.") + resultExtractionMethod = flag.String("result_from", entrypoint.ResultExtractionMethodTerminationMessage, "The method using which to extract results from tasks. Default is using the termination message.") ) const ( @@ -130,13 +125,7 @@ func main() { } } - var spireWorkloadAPI spire.EntrypointerAPIClient - if enableSpire != nil && *enableSpire && socketPath != nil && *socketPath != "" { - spireConfig := config.SpireConfig{ - SocketPath: *socketPath, - } - spireWorkloadAPI = spire.NewEntrypointerAPIClient(&spireConfig) - } + spireWorkloadAPI := initializeSpireAPI() e := entrypoint.Entrypointer{ Command: append(cmd, commandArgs...), diff --git a/cmd/entrypoint/spire.go b/cmd/entrypoint/spire.go new file mode 100644 index 00000000000..ad2086b257e --- /dev/null +++ b/cmd/entrypoint/spire.go @@ -0,0 +1,41 @@ +//go:build !disable_spire + +/* +Copyright 2025 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 main + +import ( + "flag" + + "github.com/tektoncd/pipeline/pkg/spire" + "github.com/tektoncd/pipeline/pkg/spire/config" +) + +var ( + 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.") +) + +func initializeSpireAPI() spire.EntrypointerAPIClient { + if enableSpire != nil && *enableSpire && socketPath != nil && *socketPath != "" { + spireConfig := config.SpireConfig{ + SocketPath: *socketPath, + } + return spire.NewEntrypointerAPIClient(&spireConfig) + } + return nil +} diff --git a/cmd/entrypoint/spire_disable.go b/cmd/entrypoint/spire_disable.go new file mode 100644 index 00000000000..7199d3a9868 --- /dev/null +++ b/cmd/entrypoint/spire_disable.go @@ -0,0 +1,36 @@ +//go:build disable_spire + +/* +Copyright 2025 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 main + +import ( + "context" + + "github.com/tektoncd/pipeline/pkg/result" +) + +// EntrypointerAPIClient interface maps to the spire entrypointer API to interact with spire +type EntrypointerAPIClient interface { + Close() error + // Sign returns the signature material to be put in the RunResult to append to the output results + Sign(ctx context.Context, results []result.RunResult) ([]result.RunResult, error) +} + +func initializeSpireAPI() EntrypointerAPIClient { + return nil +} diff --git a/docs/developers/fips.md b/docs/developers/fips.md new file mode 100644 index 00000000000..015260335fa --- /dev/null +++ b/docs/developers/fips.md @@ -0,0 +1,15 @@ +## Introduction +FIPS compliance requires compiling the project with a Go FIPS-compliant compiler (e.g., golang-fips) and using dynamic linking. + +This approach works for most binaries in tektoncd/pipeline, except for the entrypoint, which must be statically compiled to ensure it runs in any environment, regardless of library locations or versions. To mark a statically compiled binary as FIPS compliant, we must eliminate cryptographic symbols (crypto/*, golang.org/x/crypto, etc.). + +To achieve this, we need compile-time options to disable TLS, SPIRE, and any network-related functionality. + +This document provides instructions on compiling the entrypoint command to ensure FIPS compliance. + +## Disable SPIRE during Build +To disable SPIRE during the build process, use the following command + +```shell +CGO_ENABLED=0 go build -tags disable_spire -o bin/entrypoint ./cmd/entrypoint +``` diff --git a/docs/spire.md b/docs/spire.md index 28d2719c1ef..ae69ce940b4 100644 --- a/docs/spire.md +++ b/docs/spire.md @@ -61,6 +61,12 @@ When a TaskRun is created: 1. The entrypointer receives an x509 SVID, containing the x509 certificate and associated private key. 1. The entrypointer signs the results of the TaskRun and emits the signatures and x509 certificate to the TaskRun results for later verification. +## Enable SPIRE during Build +Users can enable SPIRE support in Tekton Pipelines during the build process by using the following build tag: +```shell +CGO_ENABLED=0 go build -tags "!disable_spire" -o bin/entrypoint ./cmd/entrypoint +``` + ## Enabling TaskRun result attestations To enable TaskRun attestations: diff --git a/pkg/entrypoint/entrypointer.go b/pkg/entrypoint/entrypointer.go index b3913665a75..23648c49a1f 100644 --- a/pkg/entrypoint/entrypointer.go +++ b/pkg/entrypoint/entrypointer.go @@ -38,7 +38,6 @@ import ( "github.com/tektoncd/pipeline/pkg/internal/resultref" "github.com/tektoncd/pipeline/pkg/pod" "github.com/tektoncd/pipeline/pkg/result" - "github.com/tektoncd/pipeline/pkg/spire" "github.com/tektoncd/pipeline/pkg/termination" "github.com/google/cel-go/cel" @@ -53,8 +52,9 @@ const ( ) const ( - breakpointExitSuffix = ".breakpointexit" - breakpointBeforeStepSuffix = ".beforestepexit" + breakpointExitSuffix = ".breakpointexit" + breakpointBeforeStepSuffix = ".beforestepexit" + ResultExtractionMethodTerminationMessage = "termination-message" ) // DebugBeforeStepError is an error means mark before step breakpoint failure @@ -147,7 +147,7 @@ type Entrypointer struct { // StepMetadataDir is the directory for a step where the step related metadata can be stored StepMetadataDir string // SpireWorkloadAPI connects to spire and does obtains SVID based on taskrun - SpireWorkloadAPI spire.EntrypointerAPIClient + SpireWorkloadAPI EntrypointerAPIClient // ResultsDirectory is the directory to find results, defaults to pipeline.DefaultResultPath ResultsDirectory string // ResultExtractionMethod is the method using which the controller extracts the results from the task pod. @@ -444,13 +444,11 @@ func (e Entrypointer) readResultsFromDisk(ctx context.Context, resultDir string, }) } - if e.SpireWorkloadAPI != nil { - signed, err := e.SpireWorkloadAPI.Sign(ctx, output) - if err != nil { - return err - } - output = append(output, signed...) + signed, err := signResults(ctx, e.SpireWorkloadAPI, output) + if err != nil { + return err } + output = append(output, signed...) // push output to termination path if e.ResultExtractionMethod == config.ResultExtractionMethodTerminationMessage && len(output) != 0 { diff --git a/pkg/entrypoint/spire.go b/pkg/entrypoint/spire.go new file mode 100644 index 00000000000..ed7e1c3d55b --- /dev/null +++ b/pkg/entrypoint/spire.go @@ -0,0 +1,38 @@ +//go:build !disable_spire + +/* +Copyright 2025 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 entrypoint + +import ( + "context" + + "github.com/tektoncd/pipeline/pkg/result" + "github.com/tektoncd/pipeline/pkg/spire" +) + +// EntrypointerAPIClient defines the interface for SPIRE operations +type EntrypointerAPIClient interface { + spire.EntrypointerAPIClient +} + +func signResults(ctx context.Context, api EntrypointerAPIClient, results []result.RunResult) ([]result.RunResult, error) { + if api == nil { + return nil, nil + } + return api.Sign(ctx, results) +} diff --git a/pkg/entrypoint/spire_disabled.go b/pkg/entrypoint/spire_disabled.go new file mode 100644 index 00000000000..0b66084e543 --- /dev/null +++ b/pkg/entrypoint/spire_disabled.go @@ -0,0 +1,34 @@ +//go:build disable_spire + +/* +Copyright 2025 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 entrypoint + +import ( + "context" + + "github.com/tektoncd/pipeline/pkg/result" +) + +// EntrypointerAPIClient defines the interface for SPIRE operations +type EntrypointerAPIClient interface { + Sign(ctx context.Context, results []result.RunResult) ([]result.RunResult, error) +} + +func signResults(ctx context.Context, api EntrypointerAPIClient, results []result.RunResult) ([]result.RunResult, error) { + return nil, nil +}