diff --git a/README.md b/README.md
index 734aa53b..cc158d4d 100644
--- a/README.md
+++ b/README.md
@@ -62,18 +62,19 @@ $ git config --local gitsign.fulcio https://fulcio.example.com
The following config options are supported:
-| Option | Default | Description |
-| ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| fulcio | https://fulcio.sigstore.dev | Address of Fulcio server |
-| logPath | | Path to log status output. Helpful for debugging when no TTY is available in the environment. |
-| clientID | sigstore | OIDC client ID for application |
-| issuer | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token |
-| matchCommitter | false | If true, verify that the committer matches certificate user identity. See [docs/committer-verification.md](./docs/committer-verification.md) for more details. |
-| redirectURL | | OIDC Redirect URL |
-| rekor | https://rekor.sigstore.dev | Address of Rekor server |
-| connectorID | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` |
-| timestampServerURL | | Address of timestamping authority. If set, a trusted timestamp will be included in the signature. |
-| timestampCertChain | | Path to PEM encoded certificate chain for RFC3161 Timestamp Authority verification. |
+| Option | Default | Description |
+| ------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| fulcio | https://fulcio.sigstore.dev | Address of Fulcio server |
+| logPath | | Path to log status output. Helpful for debugging when no TTY is available in the environment. |
+| clientID | sigstore | OIDC client ID for application |
+| issuer | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token |
+| matchCommitter | false | If true, verify that the committer matches certificate user identity. See [docs/committer-verification.md](./docs/committer-verification.md) for more details. |
+| redirectURL | | OIDC Redirect URL |
+| rekor | https://rekor.sigstore.dev | Address of Rekor server |
+| connectorID | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` |
+| tokenProvider | | Optional OIDC token provider to use to fetch tokens. If not set, any available providers are used. valid values are:
- `interactive`
- `spiffe`
- `google-workload-identity`
- `google-impersonation`
- `github-actions`
- `filesystem`
- `buildkite-agent` |
+| timestampServerURL | | Address of timestamping authority. If set, a trusted timestamp will be included in the signature. |
+| timestampCertChain | | Path to PEM encoded certificate chain for RFC3161 Timestamp Authority verification. |
### Environment Variables
@@ -153,10 +154,10 @@ Validated Certificate claims: true
**NOTE**: `gitsign verify` is preferred over
[`git verify-commit`](https://git-scm.com/docs/git-verify-commit) and
-[`git verify-tag`](https://git-scm.com/docs/git-verify-tag). The git commands
-do not pass through any expected identity information to the signing tools, so
-they only verify cryptographic integrity and that the data exists on Rekor, but
-not **who** put the data there.
+[`git verify-tag`](https://git-scm.com/docs/git-verify-tag). The git commands do
+not pass through any expected identity information to the signing tools, so they
+only verify cryptographic integrity and that the data exists on Rekor, but not
+**who** put the data there.
Using these commands will still work, but a warning being displayed.
@@ -293,7 +294,8 @@ Gitsign stores data in 2 places:
- If `rekorMode = offline`
- Note: offline verification is new, and should be considered experimental for now.
+ Note: offline verification is new, and should be considered experimental for
+ now.
By default, data is written to the
[public Rekor instance](https://docs.sigstore.dev/rekor/public-instance). In
diff --git a/internal/config/config.go b/internal/config/config.go
index ab11208b..84490093 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -63,6 +63,10 @@ type Config struct {
// See https://github.com/sigstore/sigstore/blob/c645ceb9d075499f3a4b3f183d3a6864640fa956/pkg/oauthflow/flow.go#L49-L53
// for more details.
ConnectorID string
+ // TokenProviders select a OIDC token provider to use to fetch tokens. If not set, all providers are attempted.
+ // See https://github.com/sigstore/cosign/tree/main/pkg/providers for more details.
+ // Valid values are: [interactive, spiffe, google-workload-identity, google-impersonation, github-actions, filesystem, buildkite-agent]
+ TokenProvider string
// Timestamp Authority address to use to get a trusted timestamp
TimestampURL string
@@ -117,6 +121,7 @@ func Get() (*Config, error) {
out.RedirectURL = envOrValue(fmt.Sprintf("%s_OIDC_REDIRECT_URL", prefix), out.RedirectURL)
out.Issuer = envOrValue(fmt.Sprintf("%s_OIDC_ISSUER", prefix), out.Issuer)
out.ConnectorID = envOrValue(fmt.Sprintf("%s_CONNECTOR_ID", prefix), out.ConnectorID)
+ out.TokenProvider = envOrValue(fmt.Sprintf("%s_TOKEN_PROVIDER", prefix), out.TokenProvider)
out.TimestampURL = envOrValue(fmt.Sprintf("%s_TIMESTAMP_SERVER_URL", prefix), out.TimestampURL)
out.TimestampCert = envOrValue(fmt.Sprintf("%s_TIMESTAMP_CERT_CHAIN", prefix), out.TimestampCert)
}
@@ -190,6 +195,8 @@ func applyGitOptions(out *Config, cfg map[string]string) {
out.LogPath = v
case strings.EqualFold(k, "gitsign.connectorID"):
out.ConnectorID = v
+ case strings.EqualFold(k, "gitsign.tokenProvider"):
+ out.TokenProvider = v
case strings.EqualFold(k, "gitsign.timestampServerURL"):
out.TimestampURL = v
case strings.EqualFold(k, "gitsign.timestampCertChain"):
diff --git a/internal/fulcio/identity.go b/internal/fulcio/identity.go
index ac5bc278..c64e9240 100644
--- a/internal/fulcio/identity.go
+++ b/internal/fulcio/identity.go
@@ -203,10 +203,27 @@ func (f *IdentityFactory) NewIdentity(ctx context.Context, cfg *config.Config) (
}
var authFlow oauthflow.TokenGetter = defaultFlow
- if providers.Enabled(ctx) {
- idToken, err := providers.Provide(ctx, clientID)
+ // If enabled, try OIDC token providers to get a token. unless the token provider is "interactive" (in which case always do default interactive flow).
+ var provider providers.Interface
+ if cfg.TokenProvider == "" && providers.Enabled(ctx) {
+ // If no token provider is set, look for any available provider to use.
+ provider = defaultFlowProvider{}
+ } else if cfg.TokenProvider != "" && cfg.TokenProvider != "interactive" {
+ fmt.Fprintln(f.out, "using token provider", cfg.TokenProvider)
+
+ // If a token provider is explicitly set always use it, unless it's "interactive",
+ // which means always use the default interactive flow.
+ p, err := providers.ProvideFrom(ctx, cfg.TokenProvider)
+ if err != nil {
+ return nil, fmt.Errorf("error getting token provider %q: %w", cfg.TokenProvider, err)
+ }
+ provider = p
+ }
+ if provider != nil {
+ idToken, err := provider.Provide(ctx, clientID)
if err != nil {
fmt.Fprintln(f.out, "error getting id token:", err)
+ return nil, fmt.Errorf("error getting id token: %w", err)
}
authFlow = &oauthflow.StaticTokenGetter{RawToken: idToken}
}
@@ -239,3 +256,13 @@ func (f *IdentityFactory) NewIdentity(ctx context.Context, cfg *config.Config) (
ChainPEM: cert.ChainPEM,
}, nil
}
+
+type defaultFlowProvider struct{}
+
+func (defaultFlowProvider) Enabled(ctx context.Context) bool {
+ return providers.Enabled(ctx)
+}
+
+func (defaultFlowProvider) Provide(ctx context.Context, audience string) (string, error) {
+ return providers.Provide(ctx, audience)
+}