CI/CD with OIDC
Kyku supports OIDC-based authentication for CI/CD platforms. No long-lived access keys needed — temporary credentials are exchanged for each deployment.
Supported Platforms
Section titled “Supported Platforms”| Platform | AWS | GCP | Hetzner | DO |
|---|---|---|---|---|
| GitHub Actions | ✅ STS AssumeRoleWithWebIdentity | ✅ Workload Identity Federation | Token env var | Token env var |
| GitLab CI | ✅ | ✅ | Token env var | Token env var |
| CircleCI | ✅ | ✅ | Token env var | Token env var |
Hetzner and DigitalOcean do not support OIDC federation. Use their API tokens as env vars in CI secrets.
GitHub Actions
Section titled “GitHub Actions”name: Deployon: push: branches: [main]
permissions: id-token: write contents: read
jobs: deploy: runs-on: ubuntu-latest steps: - uses: oven-sh/setup-bun@v2 - uses: actions/checkout@v4 - name: Drift check run: kyku plan --env=prod --detailed-exitcode env: KYKU_AWS_ROLE_ARN: arn:aws:iam::123456789012:role/KykuDeployRole KYKU_PASSPHRASE: ${{ secrets.KYKU_PASSPHRASE }} - name: Deploy run: kyku apply --env=prod --auto-approve env: KYKU_AWS_ROLE_ARN: arn:aws:iam::123456789012:role/KykuDeployRole KYKU_PASSPHRASE: ${{ secrets.KYKU_PASSPHRASE }}Kyku auto-detects the GitHub Actions OIDC token at ACTIONS_ID_TOKEN_REQUEST_URL and exchanges it via STS AssumeRoleWithWebIdentity.
Prerequisites:
- Create an IAM OIDC identity provider for GitHub (
token.actions.githubusercontent.com) - Create a role with a trust policy for your repo
- Set
KYKU_AWS_ROLE_ARNas a GitHub Actions secret
name: Deployon: push: branches: [main]
permissions: id-token: write contents: read
jobs: deploy: runs-on: ubuntu-latest steps: - uses: google-github-actions/auth@v2 with: workload_identity_provider: projects/123/locations/global/workloadIdentityPools/my-pool/providers/github - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - name: Deploy run: kyku apply --env=prod --auto-approve env: KYKU_PASSPHRASE: ${{ secrets.KYKU_PASSPHRASE }}Or let Kyku handle OIDC directly by setting env vars:
env: KYKU_GCP_WORKLOAD_PROVIDER: projects/123/... KYKU_GCP_PROJECT_ID: my-projectGitLab CI
Section titled “GitLab CI”deploy: stage: deploy image: oven/bun:latest id_tokens: INFRA_OIDC_TOKEN: aud: https://gitlab.com variables: KYKU_AWS_ROLE_ARN: arn:aws:iam::123456789012:role/KykuDeployRole script: - kyku plan --env=prod - kyku apply --env=prod --auto-approveCircleCI
Section titled “CircleCI”version: 2.1orbs:
jobs: deploy: docker: - image: oven/bun:latest steps: - checkout - aws-cli/setup: role-arn: arn:aws:iam::123456789012:role/KykuDeployRole - run: kyku apply --env=prod --auto-approvePlan Review in CI
Section titled “Plan Review in CI”Use plan files for review gates:
- name: Generate Plan run: kyku plan --env=prod --out=plan.json
- name: Upload Plan Artifact uses: actions/upload-artifact@v4 with: name: plan path: plan.json
- name: Apply (manual trigger) if: github.event_name == 'workflow_dispatch' run: kyku apply --env=prod --auto-approve --plan=plan.jsonEnv-Specific Deployments
Section titled “Env-Specific Deployments”name: Deployon: push: branches: - main # → prod - dev # → dev
jobs: deploy: runs-on: ubuntu-latest environment: ${{ github.ref_name == 'main' && 'prod' || 'dev' }} steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: kyku apply --env=${{ github.ref_name == 'main' && 'prod' || 'dev' }} --auto-approve env: KYKU_AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} KYKU_PASSPHRASE: ${{ secrets.KYKU_PASSPHRASE }}Secrets in CI
Section titled “Secrets in CI”Set KYKU_PASSPHRASE as a secret in your CI platform to enable state encryption:
# During apply, passphrase decrypts secrets for provider operationsexport KYKU_PASSPHRASE="your-secure-passphrase"Without the passphrase, plan works but shows [encrypted] for secret fields.