GitHub App Setup Guide
This guide explains how to create a GitHub App and use it to generate temporary tokens for use in GitHub Actions workflows.
Why Use a GitHub App?
GitHub Apps provide several advantages over personal access tokens (PATs):
- Enhanced Security: Tokens are short-lived (1 hour by default) and scoped to specific repositories
- Fine-grained Permissions: Grant only the permissions needed for specific operations
- Organization-level Authentication: Not tied to individual user accounts
- Audit Trail: Better tracking of which app performed which actions
- Higher Rate Limits: GitHub Apps typically get higher API rate limits
Creating a GitHub App
Step 1: Access GitHub App Settings
- Navigate to your GitHub organization settings
- Go to Settings → Developer settings → GitHub Apps
- Click New GitHub App
Step 2: Configure Basic Information
Fill in the following required fields:
- GitHub App name: Choose a descriptive name (e.g.,
staff-sts-terraform-automation) - Homepage URL: Your organization or project URL
- Webhook: Uncheck “Active” (not needed for automation workflows)
Step 3: Set Repository Permissions
Configure the permissions based on your needs. For the Terraform CI workflow managing GitHub teams, you’ll need:
Repository permissions: - Administration: Read and write (for managing repository settings) - Contents: Read and write (for reading/updating repository content) - Metadata: Read-only (automatically granted)
Organization permissions: - Members: Read and write (for managing team memberships) - Administration: Read and write (for managing teams and settings)
Step 4: Set Installation Options
- Where can this GitHub App be installed?: Choose “Only on this account”
Step 5: Create the App
- Click Create GitHub App
- You’ll be redirected to the app’s settings page
Step 6: Generate a Private Key
- Scroll down to the Private keys section
- Click Generate a private key
- A
.pemfile will be downloaded automatically - Store this file securely - you’ll need it for authentication
Tip: Store both the App ID and private key in AWS Secrets Manager for long-term operational reference (audit, rotation, recovery). Use a consistent naming pattern like:
github_app/<app-name>/app_id(e.g.,github_app/staff-sts-terraform-automation/app_id)github_app/<app-name>/private_key(e.g.,github_app/staff-sts-terraform-automation/private_key)
Ensure IAM policies restrict who can read these secrets and prefer encryption using a customer-managed KMS key where required.
Step 7: Note the App ID
- At the top of the app settings page, note the App ID
- You’ll need this ID along with the private key
Step 8: Install the App
- Click Install App in the left sidebar
- Select your organization
- Choose whether to install on:
- All repositories (easier but less secure)
- Only select repositories (recommended - select the repositories that need access)
- Click Install
Installation approval: For app installation on organization repositories, request approval from the Operations Engineering team by posting in the #ask-operations-engineering Slack channel. Include the App name, App ID, the list of repositories, and required permissions so the team can review and approve the installation.
Storing Credentials in AWS Secrets Manager
GitHub App credentials are stored in AWS Secrets Manager rather than as GitHub repository secrets. This provides better security, centralized management, and audit capabilities.
Required Secrets in AWS Secrets Manager
Store the following secrets in AWS Secrets Manager in the appropriate AWS account:
App ID secret - example name:
github_app/staff-sts-terraform-automation/app_id- Value: The App ID from Step 7 (plain text number)
Private key secret - example name:
github_app/staff-sts-terraform-automation/private_key- Value: The entire contents of the
.pemfile from Step 6
- Value: The entire contents of the
Storing in AWS Secrets Manager
Use the AWS CLI or Console to create the secrets:
# Store App ID
aws secretsmanager create-secret \
--name github_app/staff-sts-terraform-automation/app_id \
--description "GitHub App ID for Staff Technology Services automation" \
--secret-string "123456" \
--region eu-west-2
# Store private key (reads from file)
aws secretsmanager create-secret \
--name github_app/staff-sts-terraform-automation/private_key \
--description "GitHub App private key for Staff Technology Services automation" \
--secret-string file://your-app-private-key.pem \
--region eu-west-2
Important: Ensure appropriate IAM policies restrict access to these secrets. Only the GitHub Actions OIDC role should have secretsmanager:GetSecretValue permission for these specific secrets.
Using the GitHub App in Workflows
Prerequisites
Your workflow must authenticate to AWS using OIDC to retrieve secrets from AWS Secrets Manager:
permissions:
id-token: write # Required for AWS OIDC authentication
contents: read # Allows checkout and reading repo content
jobs:
your-job:
runs-on: ubuntu-latest
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: eu-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-session-name: GitHubWorkflow
Retrieve Credentials from AWS Secrets Manager
Use the aws-secretsmanager-get-secrets action to retrieve the GitHub App credentials and set them as environment variables:
- name: Get GitHub App Credentials from AWS Secrets Manager
id: get-github-app-secrets
uses: aws-actions/aws-secretsmanager-get-secrets@v2
with:
secret-ids: |
GITHUB_APP_ID, github_app/staff-sts-terraform-automation/app_id
GITHUB_APP_PRIVATE_KEY, github_app/staff-sts-terraform-automation/private_key
This creates GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY environment variables automatically.
Generate Installation Token
Use the credentials from AWS Secrets Manager to generate a short-lived GitHub App token:
- name: Generate GitHub App installation token
id: gh_app_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ env.GITHUB_APP_ID }}
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
owner: ministryofjustice # Your organization name
repositories: |
repo-one
repo-two
repo-three
Using the Token
The generated token is available as an output from the step:
- name: Use the token
env:
GH_TOKEN: ${{ steps.gh_app_token.outputs.token }}
run: |
# Use the token for GitHub API calls or with gh CLI
gh api user
For Terraform Provider
Export the token as an environment variable that Terraform can use:
- name: Export Terraform GitHub token
run: echo "TF_VAR_github_token=${{ steps.gh_app_token.outputs.token }}" >> "$GITHUB_ENV"
Terraform will automatically load variables prefixed with TF_VAR_.
Complete Workflow Example
Here’s a complete example showing AWS OIDC authentication, credential retrieval, and Terraform usage:
name: Terraform CI
on:
pull_request:
branches: ["main"]
push:
branches: ["main"]
workflow_dispatch:
inputs:
terraform_apply:
description: "Run terraform apply (true|false)"
required: false
default: "false"
permissions:
id-token: write
contents: read
jobs:
terraform-apply-prod:
name: "GitHub"
runs-on: ubuntu-latest
environment: GitHub
env:
ENV: "github"
TF_VAR_github_owner: "ministryofjustice"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: eu-west-2
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-session-name: GitHubWorkflow
- name: Get GitHub App Credentials from AWS Secrets Manager
uses: aws-actions/aws-secretsmanager-get-secrets@v2
with:
secret-ids: |
GITHUB_APP_ID, github_app/staff-sts-terraform-automation/app_id
GITHUB_APP_PRIVATE_KEY, github_app/staff-sts-terraform-automation/private_key
- name: Generate GitHub App installation token
id: gh_app_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ env.GITHUB_APP_ID }}
private-key: ${{ env.GITHUB_APP_PRIVATE_KEY }}
owner: ${{ env.TF_VAR_github_owner }}
repositories: |
staff-technology-services-github-teams
nvvs-devops
- name: Export Terraform GitHub token
run: echo "TF_VAR_github_token=${{ steps.gh_app_token.outputs.token }}" >> "$GITHUB_ENV"
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init -reconfigure
- name: Terraform Plan
run: terraform plan
- name: Terraform Apply
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: terraform apply -auto-approve
Token Lifecycle
- Duration: Tokens expire after 1 hour by default
- Scope: Limited to repositories specified in the workflow
- Permissions: Restricted to the permissions granted to the GitHub App
- Renewal: Generate a new token for each workflow run
Security Best Practices
- Least Privilege: Only grant permissions the app actually needs
- Repository Scoping: Limit installation to specific repositories when possible
- Rotate Keys: Periodically generate new private keys and update secrets
- Monitor Usage: Regularly review the app’s activity in audit logs
- Secure Storage: Never commit private keys or secrets to version control
- Environment Protection: Use GitHub environment protection rules for production workflows
Troubleshooting
“Bad Credentials” Error
- Verify the App ID is correct
- Ensure the private key secret contains the full PEM content
- Check that the app is installed on the target organization/repositories
“Resource not accessible by integration” Error
- Review the app’s permissions - you may need additional scopes
- Verify the app is installed on the specific repository
- Check that the repository is listed in the workflow’s
repositories:field
Token Expires During Long Workflows
- GitHub App tokens expire after 1 hour
- For long-running workflows, generate a new token as needed
- Consider breaking workflows into smaller jobs