Secretless authentication to cloud providers using OpenID Connect federation. GCP, Azure, and cloud-agnostic examples with subject claim patterns and trust policies.
Eliminates stored cloud credentials by using OIDC tokens from GitHub Actions. Use this when you need to authenticate to GCP, Azure, or other clouds without secrets, enabling short-lived, cryptographically-bound credentials tied to your workflow context.
/plugin marketplace add adaptive-enforcement-lab/claude-skills/plugin install secure@ael-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
examples.mdscripts/example-1.textscripts/example-2.textscripts/example-3.textscripts/example-4.textscripts/example-5.shscripts/example-6.shscripts/example-7.shscripts/example-8.shscripts/example-9.yamlEliminate stored credentials entirely. OIDC federation replaces long-lived secrets with short-lived tokens tied to workflow context.
The Win
OIDC federation means zero stored secrets for cloud authentication. No rotation burden, no credential sprawl, no leaked keys in logs. Tokens expire in minutes and are cryptographically bound to your repository, branch, and commit.
See the full implementation guide in the source documentation.
OpenID Connect (OIDC) allows GitHub Actions to authenticate to cloud providers without storing credentials as secrets.
How It Works:
id-token: write permissionKey Benefits:
GitHub OIDC tokens include claims identifying the workflow context.
Standard Claims:
| Claim | Example | Description |
|---|---|---|
sub | repo:org/repo:ref:refs/heads/main | Subject identifier (most important for trust policies) |
aud | https://github.com/org | Audience (usually organization or repo URL) |
iss | https://token.actions.githubusercontent.com | Issuer (GitHub Actions) |
repository | org/repo | Repository name |
repository_owner | org | Organization or user |
ref | refs/heads/main | Git ref that triggered workflow |
sha | abc123... | Commit SHA |
workflow | CI | Workflow name |
job_workflow_ref | org/repo/.github/workflows/ci.yml@refs/heads/main | Workflow file reference |
environment | production | Environment name (if used) |
The sub claim determines which workflows can assume cloud roles. Design subject patterns for least privilege.
Pattern: Allow any workflow in specific repository
Subject: repo:org/repo-name:*
Use Case: All workflows in repository can access cloud resources
Risk: Any workflow file change can access credentials
Example:
repo:adaptive-enforcement-lab/api-service:*
Pattern: Allow workflows from specific branch only
Subject: repo:org/repo-name:ref:refs/heads/main
Use Case: Only main branch deployments
Risk: Lower risk, but all main workflows have access
Example:
repo:adaptive-enforcement-lab/api-service:ref:refs/heads/main
Pattern: Allow workflows targeting specific environment
Subject: repo:org/repo-name:environment:production
Use Case: Production deployments with approval gates
Risk: Lowest risk, combined with environment protection rules
Example:
repo:adaptive-enforcement-lab/api-service:environment:production
Pattern: Block pull requests from assuming role
Subject: repo:org/repo-name:ref:refs/heads/* (excludes refs/pull/*)
Use Case: Prevent fork PRs from accessing production
Risk: Blocks legitimate PR workflows that need cloud access
Example Subject Filter:
token.actions.githubusercontent.com:sub = "repo:adaptive-enforcement-lab/api-service:ref:refs/heads/*"
Cloud Provider OIDC Examples
For detailed cloud provider setup including GCP Workload Identity Federation and Azure Federated Credentials, see Cloud Provider OIDC Patterns.
GCP uses Workload Identity Pools and Providers to validate GitHub tokens.
gcloud iam workload-identity-pools create github-pool \
--location=global \
--display-name="GitHub Actions Pool"
gcloud iam workload-identity-pools providers create-oidc github-provider \
--location=global \
--workload-identity-pool=github-pool \
--issuer-uri=https://token.actions.githubusercontent.com \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner,attribute.ref=assertion.ref" \
--attribute-condition="assertion.repository_owner == 'adaptive-enforcement-lab'"
Key Configuration:
issuer-uri: GitHub OIDC token issuerattribute-mapping: Maps GitHub claims to GCP attributesattribute-condition: Additional filtering (organization-level trust)gcloud iam service-accounts add-iam-policy-binding deploy@my-project.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github-pool/attribute.repository/adaptive-enforcement-lab/api-service"
Attribute Filtering (environment-level):
--member="principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github-pool/attribute.repository/adaptive-enforcement-lab/api-service/attribute.environment/production"
name: Deploy to GCP
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
## Examples
See [examples.md](examples.md) for code examples.
## References
- [Source Documentation](https://adaptive-enforcement-lab.com/secure/github-actions-security/)
- [AEL Secure](https://adaptive-enforcement-lab.com/secure/)