Skip to content

GitHub Token Operations

Guide to GitHub token creation and management for cluster services.

Quick Reference

Property Value
Actions Runner Token Path secret/fzymgc-house/cluster/github
Token Key windmill_actions_runner_token
Runner Namespace actions-runner-system
Runner Label windmill-sync

Token Types

Type Use Case Expiry Security
Fine-grained PAT Service automation Configurable Higher (recommended)
Classic PAT Legacy integrations Configurable Lower
GitHub App Org-level automation No expiry Highest

Required Tokens

Actions Runner Controller

Repository access for self-hosted runners.

  • Scope: repo, workflow
  • Stored: secret/fzymgc-house/cluster/github

ArgoCD

Repository access for GitOps sync.

  • Scope: Repository read
  • Stored: secret/fzymgc-house/cluster/argocd

HCP Terraform

VCS integration for speculative plans.

  • Type: GitHub App
  • Configuration: HCP Terraform settings

Token Creation

Option 1: Personal Access Token (Classic)

  1. Navigate to GitHub Settings
  2. Go to https://github.com/settings/tokens
  3. Or: GitHub > Settings > Developer settings > Personal access tokens > Tokens (classic)

  4. Generate New Token

  5. Click "Generate new token" > "Generate new token (classic)"
  6. Note: Give it a descriptive name like actions-runner-controller-selfhosted-cluster
  7. Expiration: Recommended: 90 days (you'll need to rotate it)

  8. Select Scopes

For repository-level runners, select these scopes:

  • repo (Full control of private repositories)
  • workflow (Update GitHub Action workflows)

Important: These are the ONLY two scopes needed.

  1. Generate and Copy Token
  2. Click "Generate token" at the bottom
  3. IMPORTANT: Copy the token immediately - you won't see it again
  4. Token format: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  1. Navigate to Fine-Grained Tokens
  2. Go to https://github.com/settings/personal-access-tokens/new
  3. Or: GitHub > Settings > Developer settings > Personal access tokens > Fine-grained tokens

  4. Configure Token

  5. Token name: actions-runner-controller-selfhosted
  6. Expiration: 90 days (recommended)
  7. Description: Self-hosted GitHub Actions runner
  8. Resource owner: fzymgc-house

  9. Repository Access

  10. Select: Only select repositories
  11. Choose: fzymgc-house/selfhosted-cluster

  12. Permissions

Under "Repository permissions": - Actions: Read and write - Contents: Read-only - Metadata: Read-only (automatically selected) - Workflows: Read and write

  1. Generate and Copy Token
  2. Click "Generate token"
  3. Copy the token: github_pat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Store Token in Vault

# Make sure you're authenticated to Vault
vault token lookup

# Store the token
vault kv put secret/fzymgc-house/cluster/github \
  windmill_actions_runner_token="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Verify it was stored
vault kv get secret/fzymgc-house/cluster/github

# Get the actual token value (if needed for debugging)
vault kv get -field=windmill_actions_runner_token secret/fzymgc-house/cluster/github

Token Rotation

Since tokens expire, you'll need to rotate them periodically:

  1. Generate a new token following the same steps
  2. Update Vault:
    vault kv patch secret/fzymgc-house/cluster/github \
      windmill_actions_runner_token="<new-token>"
    
  3. ExternalSecret will automatically sync the new token
  4. Runner pods will automatically use the new token

Verify Runner Deployment

After storing the token:

# Check if ExternalSecret synced the token
kubectl --context fzymgc-house get externalsecret github-token -n actions-runner-system
kubectl --context fzymgc-house get secret github-token -n actions-runner-system

# Check controller deployment
kubectl --context fzymgc-house get pods -n actions-runner-system

# Verify runner registered with GitHub
kubectl --context fzymgc-house get runnerdeployment -n actions-runner-system
kubectl --context fzymgc-house describe runnerdeployment windmill-sync-runner -n actions-runner-system

Verify on GitHub

Check that the runner appears in GitHub:

  1. Go to: https://github.com/fzymgc-house/selfhosted-cluster/settings/actions/runners
  2. You should see a runner listed with label: windmill-sync
  3. Status should show as "Idle" (green)

Troubleshooting

Token Not Working

# Check controller logs
kubectl --context fzymgc-house logs -n actions-runner-system \
  -l app.kubernetes.io/name=actions-runner-controller --tail=100

# Common errors:
# - "401 Unauthorized": Token invalid or expired
# - "403 Forbidden": Insufficient permissions
# - "404 Not Found": Repository access not granted

Runner Not Appearing in GitHub

  1. Check token scopes: Must have repo and workflow (classic) or equivalent fine-grained permissions
  2. Verify repository access: Token must have access to fzymgc-house/selfhosted-cluster
  3. Check controller status: kubectl get pods -n actions-runner-system
  4. Review logs: Look for authentication errors in controller logs

ExternalSecret Not Syncing

# Check ExternalSecret status
kubectl --context fzymgc-house describe externalsecret github-token -n actions-runner-system

# Common issues:
# - Vault path wrong: Should be secret/fzymgc-house/cluster/github
# - Vault key wrong: Should be windmill_actions_runner_token
# - ClusterSecretStore not configured: Check 'vault' ClusterSecretStore exists

Token Comparison

Feature Classic PAT Fine-Grained PAT
Scope All repos user has access to Specific repositories only
Permissions Broad (repo, workflow) Granular (Actions, Workflows, etc.)
Expiration Custom (max 1 year) Custom (max 1 year)
Security Lower Higher (recommended)
Setup Simpler More complex

Recommendation: Use Fine-Grained PAT for better security.

Security Best Practices

  • Token Storage: Never commit tokens to Git. Always use Vault.
  • Token Scope: Use minimum required scopes. Fine-grained tokens are more secure.
  • Token Expiration: Set reasonable expiration (90 days recommended).
  • Token Rotation: Have a process to rotate before expiration.
  • Access Control: Limit who can access the Vault secret.
  • Rotate immediately if compromised

See Also