Access Private Terraform Modules in GitHub Actions¶
This guide explains how to securely pull a Terraform module from a private GitHub repository using HTTPS and a GitHub Personal Access Token (PAT). This is ideal for CI/CD workflows where module sources must remain private but accessible.
Scenario¶
You have two GitHub Organizations.
GitHub Owner | GitHub Organization | GitHub Repository | Purpose |
---|---|---|---|
Admin | deployment-org | deployment-repo-x |
Terraform IaC used to CRUD resources |
Admin | module-org | terraform-azurerm-<resource_x> |
Terraform IaC reusable modules |
Your IaC in the deployment-repo references the module in the module-repo meaning when it runs in a GitHub Action the deployment-repo needs to have credentials to pull the module-repo data.
Step 1: Create a fine-grained, repository-scoped token suitable for personal API use and for using Git over HTTPS¶
This is configured at the GitHub Owner level, the layer at the top of Organizations
- Goto Settings → Developer Settings → Personal access tokens → Fine-grained tokens
- Select Generate new token
- Give the PAT a good name, good practice is to make it immediately clear what it’s for, where it’s used, and when it was created — so that months from now, you can glance at the list and know exactly which ones to keep or revoke.
- For this example we'll call it
azure_deploy_to_module_ro_2025_09
- For this example we'll call it
- Select the GitHub Organization for the module-org as the Resource Owner
- Set an expiration date that suits your security policy
- For best security, only grant access to the selected repositories in your module organization that are needed
- Limit access to the following
- Contents : Read-Only
- Metadata
- Generate the token
Warning
The token is visible once at creation then never again
Step 2: Add the PAT to the deployment repo¶
- Go to Settings → Secrets and variables → Actions in your deployment repo in the deployment org.
- Create a new repository secret, use the same name as the PAT created earlier or use a generic name. If you create a generic one it's less admin when you rotate the secret value as you only need to change it here and all the workflow files don't need to be changed. For example, use
azure_deploy_to_module_ro
. - Paste the token value.
Step 3: Use the PAT in your GitHub Action file¶
To use a Personal Access Token (PAT) in GitHub Actions, you first declare it as a required secret in your workflow file. In the example below, the secret is called AZURE_DEPLOY_TO_MODULE_RO. The workflow makes this secret available as an environment variable for the job and configures Git to use it for any https://github.com/ URL, enabling access to private repositories or modules.
This setup ensures that Git operations in your workflow (such as cloning private Terraform modules) will authenticate using your PAT.
name: Terraform Plan
description: Run terraform plan via script
on:
workflow_call:
secrets:
AZURE_DEPLOY_TO_MODULE_RO:
required: true
jobs:
terraform-plan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure Git to use secret for module access
run: |
git config --global url."https://${{ secrets.AZURE_DEPLOY_TO_MODULE_RO }}@github.com/".insteadOf "https://github.com/"
- name: Run Terraform Plan
env:
AZURE_DEPLOY_TO_MODULE_RO: ${{ secrets.AZURE_DEPLOY_TO_MODULE_RO }}
run: |
terraform plan
Step 4: Use HTTPS Source in Terraform¶
In the deployments themselves you just need to reference the module using HTTPS as below.
module "azure_resource_group" {
source = "git::https://github.com/acme-terraform-modules-azure/terraform-azurerm-resource_group.git?ref=main"
}
No need to embed credentials in the URL—GitHub Actions handles authentication via the config.