hashicorp/packer · error

signing_mode %q requires an ambient OIDC token; set SIGSTORE

Error message

signing_mode %q requires an ambient OIDC token; set SIGSTORE_ID_TOKEN, use a CI-provided OIDC token, or switch to signing_mode="none" or a key-backed mode

What it means

resolveAmbientIDToken could not find any ambient OIDC token for keyless signing. It checks SIGSTORE_ID_TOKEN, GitLab's CI_JOB_JWT_V2/CI_JOB_JWT, and GitHub Actions' OIDC endpoint (ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN); when none yield a token, keyless signing cannot obtain a Fulcio certificate and fails with this actionable message.

Source

Thrown at internal/attestation/sign_keyless.go:316

	return append([]byte(nil), p.certDER...), nil
}

func resolveAmbientIDToken(ctx context.Context, env map[string]string) (string, error) {
	if token := strings.TrimSpace(env["SIGSTORE_ID_TOKEN"]); token != "" {
		return token, nil
	}
	if token := strings.TrimSpace(env["CI_JOB_JWT_V2"]); token != "" {
		return token, nil
	}
	if token := strings.TrimSpace(env["CI_JOB_JWT"]); token != "" {
		return token, nil
	}
	if token, err := resolveGitHubActionsIDToken(ctx, env); err == nil && token != "" {
		return token, nil
	}

	return "", fmt.Errorf("signing_mode %q requires an ambient OIDC token; set SIGSTORE_ID_TOKEN, use a CI-provided OIDC token, or switch to signing_mode=\"none\" or a key-backed mode", SigningModeKeyless)
}

func resolveGitHubActionsIDToken(ctx context.Context, env map[string]string) (string, error) {
	requestURL := strings.TrimSpace(env["ACTIONS_ID_TOKEN_REQUEST_URL"])
	requestToken := strings.TrimSpace(env["ACTIONS_ID_TOKEN_REQUEST_TOKEN"])
	if requestURL == "" || requestToken == "" {
		return "", nil
	}

	parsedURL, err := url.Parse(requestURL)
	if err != nil {
		return "", fmt.Errorf("parse GitHub OIDC request URL: %w", err)
	}
	query := parsedURL.Query()
	if query.Get("audience") == "" {
		query.Set("audience", "sigstore")
		parsedURL.RawQuery = query.Encode()
	}

View on GitHub (pinned to eb36e3c3e4)

Solutions

  1. Set SIGSTORE_ID_TOKEN to a valid OIDC ID token whose issuer/identity match the configured keyless_identity and keyless_oidc_issuer.
  2. On GitHub Actions, add `permissions: id-token: write` to the workflow so ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN are injected.
  3. Switch to signing_mode="none" or a key-backed mode if no OIDC identity is available.
  4. If on GitHub Actions with permissions set, check why the OIDC request failed — the underlying error is suppressed; run resolveGitHubActionsIDToken directly to see it.

Example fix

// before (GitHub Actions workflow)
jobs:
  sign:
    steps:
      - run: packer ...
// after
jobs:
  sign:
    permissions:
      id-token: write
    steps:
      - run: packer ...
Defensive patterns

Strategy: validation

Validate before calling

func ambientTokenAvailable(env map[string]string) bool {
    if strings.TrimSpace(env["SIGSTORE_ID_TOKEN"]) != "" {
        return true
    }
    if strings.TrimSpace(env["CI_JOB_JWT_V2"]) != "" || strings.TrimSpace(env["CI_JOB_JWT"]) != "" {
        return true
    }
    return strings.TrimSpace(env["ACTIONS_ID_TOKEN_REQUEST_URL"]) != "" &&
        strings.TrimSpace(env["ACTIONS_ID_TOKEN_REQUEST_TOKEN"]) != ""
}
if !ambientTokenAvailable(cfg.Env) {
    return fmt.Errorf("no ambient OIDC token; set SIGSTORE_ID_TOKEN or run in CI with OIDC enabled")
}

Type guard

func hasCIContext(env map[string]string) bool {
    return strings.TrimSpace(env["ACTIONS_ID_TOKEN_REQUEST_URL"]) != "" ||
        strings.TrimSpace(env["CI_JOB_JWT"]) != ""
}

Try / catch

signer, err := newKeylessSigner(ctx, cfg)
if err != nil && strings.Contains(err.Error(), "requires an ambient OIDC token") {
    return fmt.Errorf("keyless signing unavailable outside OIDC-enabled CI; switch signing_mode or export SIGSTORE_ID_TOKEN: %w", err)
}

Prevention

When it happens

Trigger: newKeylessSigner runs with signing_mode="keyless" when: SIGSTORE_ID_TOKEN is unset/blank, CI_JOB_JWT(_V2) are unset, and either ACTIONS_ID_TOKEN_REQUEST_URL/ACTIONS_ID_TOKEN_REQUEST_TOKEN are unset or the GitHub OIDC request fails/returns empty (its errors are swallowed here).

Common situations: Running keyless signing locally without exporting SIGSTORE_ID_TOKEN (e.g. from `fulcio` or an OIDC flow); a GitHub Actions job missing `permissions: id-token: write` so the runtime env vars are absent; self-hosted runners without OIDC configured; GitLab CI with older JWT variables only partially set.

Related errors


AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05). Data as JSON: /api/errors/2b9ceef8a5fc76a6. Report an issue: GitHub.