diff --git a/go.mod b/go.mod index 7b223520ef5..8be820c2575 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( cuelang.org/go v0.4.3 github.com/ThalesIgnite/crypto11 v1.2.5 github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 + github.com/buildkite/agent/v3 v3.44.0 github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 github.com/cyberphone/json-canonicalization v0.0.0-20210823021906-dc406ceaf94b github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 @@ -186,6 +187,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect diff --git a/go.sum b/go.sum index 7ecd595a9e4..3d1beba9587 100644 --- a/go.sum +++ b/go.sum @@ -211,6 +211,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/buildkite/agent/v3 v3.44.0 h1:+bEVJAUX0d6QhJ/aBJDmqYuQQSgF6WL+3cLDTH4txew= +github.com/buildkite/agent/v3 v3.44.0/go.mod h1:zlU7kysCkSqr7AD4scFzuz3O8NUVXoHb8e8DaO4vaP4= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -502,6 +504,7 @@ github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/trillian v1.5.1-0.20220819043421-0a389c4bb8d9 h1:GFmzYtwUMi1S2mjLxfrJ/CZ9gWDG+zeLtZByg/QEBkk= github.com/google/trillian v1.5.1-0.20220819043421-0a389c4bb8d9/go.mod h1:vywkS3p2SgNmPL7oAWqU5PiiknzRMp+ol3a19jfY2PQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -710,6 +713,8 @@ github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6 github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= diff --git a/pkg/cosign/env/env.go b/pkg/cosign/env/env.go index 773b3521339..d6448a4c683 100644 --- a/pkg/cosign/env/env.go +++ b/pkg/cosign/env/env.go @@ -57,14 +57,18 @@ const ( VariableSigstoreRekorPublicKey Variable = "SIGSTORE_REKOR_PUBLIC_KEY" // Other external environment variables - VariableGitHubHost Variable = "GITHUB_HOST" - VariableGitHubToken Variable = "GITHUB_TOKEN" //nolint:gosec - VariableGitHubRequestToken Variable = "ACTIONS_ID_TOKEN_REQUEST_TOKEN" - VariableGitHubRequestURL Variable = "ACTIONS_ID_TOKEN_REQUEST_URL" - VariableSPIFFEEndpointSocket Variable = "SPIFFE_ENDPOINT_SOCKET" - VariableGoogleServiceAccountName Variable = "GOOGLE_SERVICE_ACCOUNT_NAME" - VariableGitLabHost Variable = "GITLAB_HOST" - VariableGitLabToken Variable = "GITLAB_TOKEN" + VariableGitHubHost Variable = "GITHUB_HOST" + VariableGitHubToken Variable = "GITHUB_TOKEN" //nolint:gosec + VariableGitHubRequestToken Variable = "ACTIONS_ID_TOKEN_REQUEST_TOKEN" + VariableGitHubRequestURL Variable = "ACTIONS_ID_TOKEN_REQUEST_URL" + VariableSPIFFEEndpointSocket Variable = "SPIFFE_ENDPOINT_SOCKET" + VariableGoogleServiceAccountName Variable = "GOOGLE_SERVICE_ACCOUNT_NAME" + VariableGitLabHost Variable = "GITLAB_HOST" + VariableGitLabToken Variable = "GITLAB_TOKEN" + VariableBuildkiteAgentAccessToken Variable = "BUILDKITE_AGENT_ACCESS_TOKEN" + VariableBuildkiteAgentEndpoint Variable = "BUILDKITE_AGENT_ENDPOINT" + VariableBuildkiteJobID Variable = "BUILDKITE_JOB_ID" + VariableBuildkiteAgentLogLevel Variable = "BUILDKITE_AGENT_LOG_LEVEL" ) var ( @@ -169,6 +173,30 @@ var ( Sensitive: true, External: true, }, + VariableBuildkiteAgentAccessToken: { + Description: "is an access token used to identify the Buildkite agent", + Expects: "string with an access token", + Sensitive: true, + External: true, + }, + VariableBuildkiteAgentEndpoint: { + Description: "the Buildkite agent endpoint", + Expects: "string with an endpoint", + Sensitive: false, + External: true, + }, + VariableBuildkiteJobID: { + Description: "the Buildkite job ID to claim in the OIDC token", + Expects: "string with a job ID", + Sensitive: false, + External: true, + }, + VariableBuildkiteAgentLogLevel: { + Description: "the log level for the Buildkite agent", + Expects: "string with log level, either debug, notice, info, error, warn, fatal (default: notice)", + Sensitive: false, + External: true, + }, } ) diff --git a/pkg/providers/all/all.go b/pkg/providers/all/all.go index 33e032aed49..c49dbea4e6a 100644 --- a/pkg/providers/all/all.go +++ b/pkg/providers/all/all.go @@ -19,6 +19,7 @@ import ( "github.com/sigstore/cosign/v2/pkg/providers" // Link in all of the providers. + _ "github.com/sigstore/cosign/v2/pkg/providers/buildkite" _ "github.com/sigstore/cosign/v2/pkg/providers/filesystem" _ "github.com/sigstore/cosign/v2/pkg/providers/github" _ "github.com/sigstore/cosign/v2/pkg/providers/google" diff --git a/pkg/providers/buildkite/buildkite.go b/pkg/providers/buildkite/buildkite.go new file mode 100644 index 00000000000..99ccebdda13 --- /dev/null +++ b/pkg/providers/buildkite/buildkite.go @@ -0,0 +1,71 @@ +// Copyright 2023 The Sigstore 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 buildkite + +import ( + "context" + "fmt" + "net/http" + "os" + + "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v3/logger" + "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v2/pkg/providers" +) + +func init() { + providers.Register("buildkite-agent", &buildkiteAgent{}) +} + +type buildkiteAgent struct{} + +var _ providers.Interface = (*buildkiteAgent)(nil) + +// Enabled implements providers.Interface +func (ba *buildkiteAgent) Enabled(ctx context.Context) bool { + return env.Getenv(env.VariableBuildkiteAgentAccessToken) != "" +} + +// Provide implements providers.Interface +func (ba *buildkiteAgent) Provide(ctx context.Context, audience string) (string, error) { + agentToken := env.Getenv(env.VariableBuildkiteAgentAccessToken) + endpoint := env.Getenv(env.VariableBuildkiteAgentEndpoint) + if endpoint == "" { + endpoint = "https://agent.buildkite.com/v3" + } + jobID := env.Getenv(env.VariableBuildkiteJobID) + logLevel := env.Getenv(env.VariableBuildkiteAgentLogLevel) + if logLevel == "" { + logLevel = "notice" + } + + l := logger.NewConsoleLogger(logger.NewTextPrinter(os.Stderr), os.Exit) + level, err := logger.LevelFromString(logLevel) + if err != nil { + return "", err + } + l.SetLevel(level) + + client := api.NewClient(l, api.Config{Token: agentToken, Endpoint: endpoint}) + token, response, err := client.OIDCToken(ctx, &api.OIDCTokenRequest{Audience: audience, Job: jobID}) + if err != nil { + return "", err + } + if response != nil && response.StatusCode != http.StatusOK { + return "", fmt.Errorf("buildkite agent request failed with status: %s", response.Status) + } + return token.Token, nil +} diff --git a/pkg/providers/buildkite/doc.go b/pkg/providers/buildkite/doc.go new file mode 100644 index 00000000000..6ed854aa603 --- /dev/null +++ b/pkg/providers/buildkite/doc.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Sigstore 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 buildkite