Prepare GitHub (GitHub Variant)¶
Use this page when the customer's repositories and pipelines are on GitHub. The phases are the same as for Azure DevOps. Only the preparation differs: a GitHub App instead of tokens, federated credentials instead of service connections with secrets, environments instead of Azure DevOps environments, and a different way to get self-hosted runners.
| Topic | Azure DevOps | GitHub |
|---|---|---|
| Sign in to Azure | Service connection (Prepare identity) | Service principal with federated credentials (OIDC), described below |
| Check out the code repository | Service connection to the host (mcp-code) |
GitHub App with a short-lived installation token |
| Production approval | Environment with approvers | Environment with required reviewers |
| Runners | Managed DevOps Pool (Prepare agents) | See Runners |
| Repository setup | Prepare repositories | The same page, GitHub sections |
Prerequisites on the organization¶
The platform team needs the organization roles CI/CD admin and App Manager, and must be able to create repositories. See Prerequisites and the GitHub checks there.
GitHub App for the workflows¶
The workflows do not use personal access tokens. They create a short-lived installation token for a GitHub App
(actions/create-github-app-token) and pass it to Terraform (TF_VAR_github_token).
- Create a GitHub App in the organization, or reuse one. Give it a name and description that say it is used by the platform workflows.
- Repository permissions: read access to code and metadata, read and write access to workflows.
- Store the App ID as the organization variable
cloud_platform_gh_app_idand the private key as the organization secretcloud_platform_gh_app_private_key(Pipelines). - Install the app in the organization with Only select repositories, and select only the code repositories.
- Store a copy of the private key in the secret store of the platform team, together with the app name and ID.
If spokes use the GitHub extension, the app needs a larger set of permissions (Prepare spoke integrations). When Terraform modules are downloaded from a GitHub Enterprise host, see Module source access.
This is a different app from the one that syncs the code repository (Prepare repositories). You may combine them if your security rules allow it, but separate apps keep the permissions small.
When mcp.json has a GitHub section (AppId, AppInstallationId, AppPrivateKeySecretName), it refers to the GitHub
App that registers the self-hosted runners (Config).
Federated credentials¶
With federated credentials the workflow signs in to Azure without a stored secret. Add three credentials to the deployment service principal (Microsoft Entra ID, App registrations, the app, Certificates & secrets, Federated credentials, Add credential, scenario GitHub Actions deploying Azure resources) for each configuration repository:
| Credential | Entity type | Subject identifier |
|---|---|---|
| Branch | Branch | repo:<organization>/<repository>:ref:refs/heads/main |
| Production | Environment, prod |
repo:<organization>/<repository>:environment:prod |
| Canary | Environment, canary |
repo:<organization>/<repository>:environment:canary |
- Issuer. For GitHub.com it is
https://token.actions.githubusercontent.com. For GitHub Enterprise on a dedicated domain (<domain>.ghe.com) it ishttps://token.actions.<domain>.ghe.com. The organization and repository names are the ones in the repository URL. - During the implementation, when the default branch is
initial, create the branch credential forinitial. Change it tomainwhen the implementation is done (Prepare repositories). - Put the client ID of the service principal in
Azure.TerraformState.Hub.ServicePrincipalId(and.Spoke.) inmcp.json.
Secrets in older workflows¶
Older entry workflows (main.yaml) read these repository secrets instead of mcp.json:
| Secret | Value |
|---|---|
AZURE_CLIENT_ID |
Client ID of the service principal |
AZURE_TENANT_ID |
Tenant ID |
AZURE_SUBSCRIPTION_ID |
Management subscription of the platform environment |
AZURE_RG_NAME, AZURE_SA_NAME |
Resource group and storage account of the Terraform state |
AZURE_SA_CONTAINER_NAME |
State container (a different container is used for spokes) |
AZURE_SA_LOG_CONTAINER_NAME |
Container for deployment logs |
Environments¶
Create the environments canary and prod in each configuration repository, plus approval-required if you use the
Approve* modes (Pipelines). For prod and approval-required:
- required reviewers: the approver group, which must have read access to the repositories,
- Prevent self-review on,
- Allow administrators to bypass configured protection rules off.
Without reviewers on approval-required the approval step continues without waiting.
Runners¶
Current approach¶
The platform's infrastructure and container workflows deploy the job runners, as for Azure DevOps
(Prepare agents). The runner registration uses the GitHub App in mcp.json. The deployment of the
hub runs on those runners.
Older approach: GitHub-hosted runners with virtual network integration¶
Earlier versions deployed the hub in two phases with a ghrunners layer. The layer is not part of the current hub
pipeline; this section is for tenants that still run the older workflows.
- Phase 1, default runners. The first layers (foundation, connectivity, ghrunners) run on a standard GitHub-hosted
runner group (a runner on the current Ubuntu image, for example 2 cores, 8 GB, 75 GB disk), because no network exists
yet. Point
defaultRunnerGroupin.github/workflows/main.yamlto that group. - Phase 2, virtual-network-integrated runners. Once the network exists, create runners that live in it:
-
Get the database ID of the organization or enterprise:
gh auth login -s 'read:enterprise' gh api graphql -f query='query($login: String!) { organization(login: $login) { login databaseId } }' -f login='<organization>'For an enterprise, query
enterprise (slug: $slug)instead. For aghe.comhost, add--hostname <subdomain>.ghe.com. 2. In the connectivity subscription, register theGitHub.Networkresource provider, delegate the runner subnet toGitHub.Network/networkSettings, and create the network settings resource (typeGitHub.Network/networkSettings, with the subnet ID and the database ID asbusinessId). Do this for canary and for prod. Use a region that GitHub-hosted runner networking supports (the runbook used North Europe because West Europe was not supported at that time; check the current list). 3. In the organization settings, Hosted compute networking, create a network configuration for each platform environment with the network settings resource ID. If the option is disabled, the enterprise owner must enable it. If the form returns a JSON error, wait a few minutes and retry. 4. Create a runner group per environment (for examplelz-canaryandlz-prod) with that network configuration and access for the four repositories, and in each group a GitHub-hosted runner. Wait until the runner status is Ready. 3. SwitchdefaultRunnerGroupinmain.yamlto the new group, then run the remaining layers in order: firewall, identity, management, postdeployment. 4. Add firewall rules so the runners can reach what they need, as in Network access of the agents.
-
See also Deploy the platform.