Skip to content

Commit

Permalink
Document all environment variables used by cosign
Browse files Browse the repository at this point in the history
Signed-off-by: Marko Mudrinić <mudrinic.mare@gmail.com>
  • Loading branch information
xmudrii committed Oct 17, 2022
1 parent f3d1aa8 commit 3b98d00
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 60 deletions.
10 changes: 4 additions & 6 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,14 @@ issues:
linters:
- errcheck
- gosec
# We want to allow using os.Getenv and os.Setenv in tests because it
# might be easier (and needed in some cases)
- forbidigo
# pkg/cosign/env implements working with environment variables in cosign
# and is based on os.Getenv and os.LookupEnv
- path: pkg/cosign/env
linters:
- forbidigo
- path: pkg/providers/
linters:
- forbidigo
- path: pkg/cosign/git/gitlab
linters:
- forbidigo
max-issues-per-linter: 0
max-same-issues: 0
run:
Expand Down
7 changes: 2 additions & 5 deletions cmd/cosign/cli/fulcio/fulcioverifier/ctl/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
ctx509 "github.com/google/certificate-transparency-go/x509"
"github.com/google/certificate-transparency-go/x509util"
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioverifier/ctutil"
"github.com/sigstore/cosign/pkg/cosign/env"

"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/tuf"
Expand All @@ -36,10 +37,6 @@ import (
// This is the CT log public key target name
var ctPublicKeyStr = `ctfe.pub`

// Setting this env variable will over ride what is used to validate
// the SCT coming back from Fulcio.
const altCTLogPublicKeyLocation = "SIGSTORE_CT_LOG_PUBLIC_KEY_FILE"

// logIDMetadata holds information for mapping a key ID hash (log ID) to associated data.
type logIDMetadata struct {
pubKey crypto.PublicKey
Expand Down Expand Up @@ -74,7 +71,7 @@ func ContainsSCT(cert []byte) (bool, error) {
func VerifySCT(ctx context.Context, certPEM, chainPEM, rawSCT []byte) error {
// fetch SCT verification key
pubKeys := make(map[[sha256.Size]byte]logIDMetadata)
rootEnv := os.Getenv(altCTLogPublicKeyLocation) //nolint:forbidigo
rootEnv := env.Getenv(env.VariableSigstoreCTLogPublicKeyFile)
if rootEnv == "" {
tufClient, err := tuf.NewFromEnv(ctx)
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"sync"

"github.com/sigstore/cosign/pkg/cosign/env"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/fulcioroots"
)
Expand All @@ -33,8 +34,6 @@ var (
singletonRootErr error
)

const altRoot = "SIGSTORE_ROOT_FILE"

// Get returns the Fulcio root certificate.
//
// If the SIGSTORE_ROOT_FILE environment variable is set, the root config found
Expand Down Expand Up @@ -62,7 +61,7 @@ func initRoots() (*x509.CertPool, *x509.CertPool, error) {
// intermediatePool should be nil if no intermediates are found
var intermediatePool *x509.CertPool

rootEnv := os.Getenv(altRoot) //nolint:forbidigo
rootEnv := env.Getenv(env.VariableSigstoreRootFile)
if rootEnv != "" {
raw, err := os.ReadFile(rootEnv)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions pkg/blob/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ func LoadFileOrURL(fileRef string) ([]byte, error) {
}
case "env://":
envVar := parts[1]
// Most of Cosign should use `env.LookupEnv` (see #2236) to restrict us to known environment variables
// (usually `$COSIGN_*`). However, in this case, `envVar` is user-provided and not one of the allow-listed
// env vars.
value, found := os.LookupEnv(envVar) //nolint:forbidigo
if !found {
return nil, fmt.Errorf("loading URL: env var $%s not found", envVar)
Expand Down
104 changes: 99 additions & 5 deletions pkg/cosign/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,50 @@ import (
"strings"
)

// Variable is a type representing an environment variable
type Variable string

// VariableOpts closely describes a Variable
type VariableOpts struct {
// Description contains description for the environment variable
Description string
Expects string
Sensitive bool
// Expects describes what value is expected by the environment variable
Expects string
// Sensitive is used for environment variables with sensitive values
// (e.g. passwords, credentials, etc.)
Sensitive bool
// External is used for environment variables coming from external projects
// and dependencies (e.g. GITHUB_TOKEN, SIGSTORE_, TUF_)
External bool
}

func (v Variable) String() string {
return string(v)
}

const (
// Cosign environment variables
VariableExperimental Variable = "COSIGN_EXPERIMENTAL"
VariableDockerMediaTypes Variable = "COSIGN_DOCKER_MEDIA_TYPES"
VariablePassword Variable = "COSIGN_PASSWORD"
VariablePKCS11Pin Variable = "COSIGN_PKCS11_PIN"
VariablePKCS11ModulePath Variable = "COSIGN_PKCS11_MODULE_PATH"
VariableRepository Variable = "COSIGN_REPOSITORY"

// Sigstore environment variables
VariableSigstoreCTLogPublicKeyFile Variable = "SIGSTORE_CT_LOG_PUBLIC_KEY_FILE"
VariableSigstoreRootFile Variable = "SIGSTORE_ROOT_FILE"
VariableSigstoreTrustRekorPublicKey Variable = "SIGSTORE_TRUST_REKOR_API_PUBLIC_KEY"
VariableSigstoreRekorPublicKey Variable = "SIGSTORE_REKOR_PUBLIC_KEY"

// Other external environment variables
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"
)

var (
Expand Down Expand Up @@ -75,15 +100,84 @@ var (
Expects: "string with a repository",
Sensitive: false,
},

VariableSigstoreCTLogPublicKeyFile: {
Description: "overrides what is used to validate the SCT coming back from Fulcio",
Expects: "path to the public key file",
Sensitive: false,
External: true,
},
VariableSigstoreRootFile: {
Description: "overrides the public good instance root CA",
Expects: "path to the root CA",
Sensitive: false,
External: true,
},
VariableSigstoreTrustRekorPublicKey: {
Description: "if specified, will fetch the Rekor Public Key from the specified Rekor server and add it to RekorPubKeys. This env var is only for testing!",
Expects: "any string to trigger this behavior",
Sensitive: false,
External: true,
},
VariableSigstoreRekorPublicKey: {
Description: "if specified, you can specify an oob Public Key that Rekor uses",
Expects: "path to the public key",
Sensitive: false,
External: true,
},

VariableGitHubToken: {
Description: "is a token used to authenticate with GitHub",
Expects: "token generated on GitHub",
Sensitive: true,
External: true,
},
VariableGitHubRequestToken: {
Description: "is bearer token for the request to the OIDC provider",
Expects: "string with a bearer token",
Sensitive: true,
External: true,
},
VariableGitHubRequestURL: {
Description: "is the URL for GitHub's OIDC provider",
Expects: "string with the URL for the OIDC provider",
Sensitive: false,
External: true,
},
VariableSPIFFEEndpointSocket: {
Description: "allows you to specify non-default SPIFFE socket to use.",
Expects: "string with SPIFFE socket path",
Sensitive: false,
External: true,
},
VariableGoogleServiceAccountName: {
Description: "is a service account name to be used with the Google provider",
Expects: "string with the service account's name",
Sensitive: false,
External: false,
},
VariableGitLabHost: {
Description: "is URL of the GitLab instance",
Expects: "string with the URL of GitLab instance",
Sensitive: false,
External: true,
},
VariableGitLabToken: {
Description: "is a token used to authenticate with GitLab",
Expects: "string with a token",
Sensitive: true,
External: true,
},
}
)

func mustRegisterEnv(name Variable) {
if _, ok := environmentVariables[name]; !ok {
opts, ok := environmentVariables[name]
if !ok {
panic(fmt.Sprintf("environment variable %q is not registered in pkg/cosign/env", name.String()))
}
if !strings.HasPrefix(name.String(), "COSIGN_") {
panic(fmt.Sprintf("environment varialbe %q must start with COSIGN_ prefix", name.String()))
if !opts.External && !strings.HasPrefix(name.String(), "COSIGN_") {
panic(fmt.Sprintf("cosign environment variable %q must start with COSIGN_ prefix", name.String()))
}
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/cosign/git/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"golang.org/x/oauth2"

"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/env"
)

const (
Expand All @@ -44,13 +45,13 @@ func New() *Gh {

func (g *Gh) PutSecret(ctx context.Context, ref string, pf cosign.PassFunc) error {
var httpClient *http.Client
if token, ok := os.LookupEnv("GITHUB_TOKEN"); ok { //nolint:forbidigo
if token, ok := env.LookupEnv(env.VariableGitHubToken); ok {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
httpClient = oauth2.NewClient(ctx, ts)
} else {
return errors.New("could not find \"GITHUB_TOKEN\" environment variable")
return fmt.Errorf("could not find %q environment variable", env.VariableGitHubRequestToken.String())
}
client := github.NewClient(httpClient)

Expand Down
14 changes: 7 additions & 7 deletions pkg/cosign/git/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ package gitlab

import (
"context"
"errors"
"fmt"
"io"
"os"

"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/env"
"github.com/xanzy/go-gitlab"
)

Expand All @@ -42,14 +42,14 @@ func (g *Gl) PutSecret(ctx context.Context, ref string, pf cosign.PassFunc) erro
return fmt.Errorf("generating key pair: %w", err)
}

token, tokenExists := os.LookupEnv("GITLAB_TOKEN")
token, tokenExists := env.LookupEnv(env.VariableGitLabToken)

if !tokenExists {
return errors.New("could not find \"GITLAB_TOKEN\"")
return fmt.Errorf("could not find %q", env.VariableGitLabToken.String())
}

var client *gitlab.Client
if url, baseURLExists := os.LookupEnv("GITLAB_HOST"); baseURLExists {
if url, baseURLExists := env.LookupEnv(env.VariableGitLabHost); baseURLExists {
client, err = gitlab.NewClient(token, gitlab.WithBaseURL(url))
if err != nil {
return fmt.Errorf("could not create GitLab client: %w", err)
Expand Down Expand Up @@ -125,15 +125,15 @@ func (g *Gl) PutSecret(ctx context.Context, ref string, pf cosign.PassFunc) erro
}

func (g *Gl) GetSecret(ctx context.Context, ref string, key string) (string, error) {
token, tokenExists := os.LookupEnv("GITLAB_TOKEN")
token, tokenExists := env.LookupEnv(env.VariableGitLabToken)
var varPubKeyValue string
if !tokenExists {
return varPubKeyValue, errors.New("could not find \"GITLAB_TOKEN\"")
return varPubKeyValue, fmt.Errorf("could not find %q", env.VariableGitLabToken.String())
}

var client *gitlab.Client
var err error
if url, baseURLExists := os.LookupEnv("GITLAB_HOST"); baseURLExists {
if url, baseURLExists := env.LookupEnv(env.VariableGitLabHost); baseURLExists {
client, err = gitlab.NewClient(token, gitlab.WithBaseURL(url))
if err != nil {
return varPubKeyValue, fmt.Errorf("could not create GitLab client): %w", err)
Expand Down
20 changes: 4 additions & 16 deletions pkg/cosign/tlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/transparency-dev/merkle/rfc6962"

"github.com/sigstore/cosign/pkg/cosign/bundle"
"github.com/sigstore/cosign/pkg/cosign/env"
"github.com/sigstore/rekor/pkg/generated/client"
"github.com/sigstore/rekor/pkg/generated/client/entries"
"github.com/sigstore/rekor/pkg/generated/client/index"
Expand All @@ -56,19 +57,6 @@ type RekorPubKey struct {
Status tuf.StatusKind
}

const (
// If specified, you can specify an oob Public Key that Rekor uses using
// this ENV variable.
altRekorPublicKey = "SIGSTORE_REKOR_PUBLIC_KEY"
// Add Rekor API Public Key
// If specified, will fetch the Rekor Public Key from the specified Rekor
// server and add it to RekorPubKeys. This ENV var is only for testing
// purposes, as users should distribute keys out of band.
// TODO(vaikas): Implement storing state like Rekor does so that if tree
// state ever changes, it will make lots of noise.
addRekorPublicKeyFromRekor = "SIGSTORE_TRUST_REKOR_API_PUBLIC_KEY"
)

const treeIDHexStringLen = 16
const uuidHexStringLen = 64
const entryIDHexStringLen = treeIDHexStringLen + uuidHexStringLen
Expand Down Expand Up @@ -110,7 +98,7 @@ func intotoEntry(ctx context.Context, signature, pubKey []byte) (models.Proposed
// TODO: Rename SIGSTORE_TRUST_REKOR_API_PUBLIC_KEY to be test-only or remove.
func GetRekorPubs(ctx context.Context, rekorClient *client.Rekor) (map[string]RekorPubKey, error) {
publicKeys := make(map[string]RekorPubKey)
altRekorPub := os.Getenv(altRekorPublicKey) //nolint:forbidigo
altRekorPub := env.Getenv(env.VariableSigstoreRekorPublicKey)

if altRekorPub != "" {
raw, err := os.ReadFile(altRekorPub)
Expand Down Expand Up @@ -150,9 +138,9 @@ func GetRekorPubs(ctx context.Context, rekorClient *client.Rekor) (map[string]Re

// If we have a Rekor client and we've been told to fetch the Public Key from Rekor,
// additionally fetch it here.
addRekorPublic := os.Getenv(addRekorPublicKeyFromRekor) //nolint:forbidigo
addRekorPublic := env.Getenv(env.VariableSigstoreTrustRekorPublicKey)
if addRekorPublic != "" && rekorClient != nil {
fmt.Fprintf(os.Stderr, "**Warning ('%s' is only for testing)** Fetching public key from Rekor API directly\n", addRekorPublicKeyFromRekor)
fmt.Fprintf(os.Stderr, "**Warning ('%s' is only for testing)** Fetching public key from Rekor API directly\n", env.VariableSigstoreTrustRekorPublicKey.String())
pubOK, err := rekorClient.Pubkey.GetPublicKey(nil)
if err != nil {
return nil, fmt.Errorf("unable to fetch rekor public key from rekor: %w", err)
Expand Down
15 changes: 5 additions & 10 deletions pkg/providers/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import (
"context"
"encoding/json"
"net/http"
"os"

"github.com/sigstore/cosign/pkg/cosign/env"
"github.com/sigstore/cosign/pkg/providers"
)

Expand All @@ -32,32 +32,27 @@ type githubActions struct{}

var _ providers.Interface = (*githubActions)(nil)

const (
RequestTokenEnvKey = "ACTIONS_ID_TOKEN_REQUEST_TOKEN"
RequestURLEnvKey = "ACTIONS_ID_TOKEN_REQUEST_URL"
)

// Enabled implements providers.Interface
func (ga *githubActions) Enabled(ctx context.Context) bool {
if os.Getenv(RequestTokenEnvKey) == "" {
if env.Getenv(env.VariableGitHubRequestToken) == "" {
return false
}
if os.Getenv(RequestURLEnvKey) == "" {
if env.Getenv(env.VariableGitHubRequestURL) == "" {
return false
}
return true
}

// Provide implements providers.Interface
func (ga *githubActions) Provide(ctx context.Context, audience string) (string, error) {
url := os.Getenv(RequestURLEnvKey) + "&audience=" + audience
url := env.Getenv(env.VariableGitHubRequestURL) + "&audience=" + audience

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}

req.Header.Add("Authorization", "bearer "+os.Getenv(RequestTokenEnvKey))
req.Header.Add("Authorization", "bearer "+env.Getenv(env.VariableGitHubRequestToken))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
Expand Down
Loading

0 comments on commit 3b98d00

Please sign in to comment.