Skip to content

Commit

Permalink
Add tokenProvider configuration for forcing OIDC providers. (#446)
Browse files Browse the repository at this point in the history
This is useful when running in a remote environment where there may be
multiple providers available.

This is functionally equivalent to cosign's `--oidc-provider` flag.
Instead of also providing a `--oidc-disable-ambient-providers` flag,
this PR opts to use `--oidc-provider=interactive` as equivalent
behavior.
  • Loading branch information
wlynch authored Feb 9, 2024
1 parent bbd2c9c commit ff05b31
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 19 deletions.
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:<br>- `https://github.com/login/oauth`<br>- `https://accounts.google.com`<br>- `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:<br>- `https://github.com/login/oauth`<br>- `https://accounts.google.com`<br>- `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:<br>- `interactive`<br>- `spiffe`<br>- `google-workload-identity`<br>- `google-impersonation`<br>- `github-actions`<br>- `filesystem`<br>- `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

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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"):
Expand Down
31 changes: 29 additions & 2 deletions internal/fulcio/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand Down Expand Up @@ -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)
}

0 comments on commit ff05b31

Please sign in to comment.