2020 required : false
2121 description : Repo to deploy the runner to. Only needed if runner_scope is set to "repo-level" (defaults to current repository)
2222 deallocate_immediately :
23- type : string
23+ type : choice
24+ options :
25+ - false
26+ - true
2427 required : true
2528 description : Deallocate the runner immediately after creating it (useful for spinning up runners preemptively)
2629 default : " false"
30+ ephemeral :
31+ type : choice
32+ options :
33+ - false
34+ - true
35+ required : true
36+ description : Start the runner in ephemeral mode (i.e. unregister after running one job)
37+ default : " true"
2738
2839env :
2940 ACTIONS_RUNNER_SCOPE : ${{ github.event.inputs.runner_scope }}
3041 ACTIONS_RUNNER_ORG : " ${{ github.event.inputs.runner_org || github.repository_owner }}"
3142 ACTIONS_RUNNER_REPO : " ${{ github.event.inputs.runner_repo || github.event.repository.name }}"
3243 DEALLOCATE_IMMEDIATELY : ${{ github.event.inputs.deallocate_immediately }}
33- # This has to be a public URL that the VM can access after creation
34- POST_DEPLOYMENT_SCRIPT_URL : https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref }}/azure-self-hosted-runners/post-deployment-script.ps1
44+ EPHEMERAL_RUNNER : ${{ github.event.inputs.ephemeral }}
3545 # Note that you'll need "p" (arm64 processor) and ideally "d" (local temp disk). The number 4 stands for 4 CPU-cores.
3646 # For a convenient overview of all arm64 VM types, see e.g. https://azureprice.net/?_cpuArchitecture=Arm64
3747 AZURE_VM_TYPE : Standard_D4plds_v5
4151 AZURE_VM_REGION : westus2
4252 AZURE_VM_IMAGE : win11-24h2-ent
4353
54+ permissions :
55+ id-token : write # required for Azure login via OIDC
56+ contents : read
57+
4458# The following secrets are required for this workflow to run:
45- # AZURE_CREDENTIALS - Credentials for the Azure CLI. It's recommended to set up a resource
46- # group specifically for self-hosted Actions Runners.
47- # az ad sp create-for-rbac --name "{YOUR_DESCRIPTIVE_NAME_HERE}" --role contributor \
48- # --scopes /subscriptions/{SUBSCRIPTION_ID_HERE}/resourceGroups/{RESOURCE_GROUP_HERE} \
49- # --sdk-auth
59+ # AZURE_CLIENT_ID - The Client ID of an Azure Managed Identity. It is recommended to set up a resource
60+ # group specifically for self-hosted Actions Runners, and to add a federated identity
61+ # to authenticate as the currently-running GitHub workflow.
62+ # az identity create --name <managed-identity-name> -g <resource-group>
63+ # az identity federated-credential create \
64+ # --identity-name <managed-identity-name> \
65+ # --resource-group <resource-group> \
66+ # --name github-workflow \
67+ # --issuer https://token.actions.githubusercontent.com \
68+ # --subject repo:git-for-windows/git-for-windows-automation:ref:refs/heads/main \
69+ # --audiences api://AzureADTokenExchange
70+ # MSYS_NO_PATHCONV=1 \
71+ # az role assignment create \
72+ # --assignee <client-id-of-managed-identity> \
73+ # --scope '/subscriptions/<subscription-id>/resourceGroups/<resource-group>' \
74+ # --role 'Contributor'
75+ # AZURE_TENANT_ID - The Tenant ID of the Azure Managed Identity (i.e. the Azure Active Directory in which
76+ # the Identity lives)
77+ # AZURE_SUBSCRIPTION_ID - The Subscription ID with which the Azure Managed Identity is associated
78+ # (technically, this is not necessary for `az login --service-principal` with a
79+ # managed identity, but `Azure/login` requires it anyway)
5080# AZURE_RESOURCE_GROUP - Resource group to create the runner(s) in
5181# AZURE_VM_USERNAME - Username of the VM so you can RDP into it
5282# AZURE_VM_PASSWORD - Password of the VM so you can RDP into it
83+ # GH_APP_ID - The ID of the GitHub App whose credentials are to be used to obtain the runner token
84+ # GH_APP_PRIVATE_KEY - The private key of the GitHub App whose credentials are to be used to obtain the runner token
5385jobs :
5486 create-runner :
5587 runs-on : ubuntu-latest
@@ -94,14 +126,21 @@ jobs:
94126 # https://github.com/actions/runner/issues/475
95127 - name : Generate Actions Runner token and registration URL
96128 run : |
129+ # We need to URL-encode the user name because it usually is a GitHub App, which means that
130+ # it has the suffix `[bot]`. If un-encoded, this would cause a cURL error "bad range in URL"
131+ # because it would mistake this for an IPv6 address or something like that.
132+ user_pwd="$(jq -n \
133+ --arg user '${{ github.actor }}' \
134+ --arg pwd '${{ secrets.GITHUB_TOKEN }}' \
135+ '$user | @uri + ":" + $pwd')"
97136 case "$ACTIONS_RUNNER_SCOPE" in
98137 "org-level")
99- ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/actions/runners/registration-token"
100- ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG"
138+ ACTIONS_API_URL="https://$user_pwd@ api.github.com/repos/$ACTIONS_RUNNER_ORG/actions/runners/registration-token"
139+ ACTIONS_RUNNER_REGISTRATION_URL="https://$user_pwd@ github.com/$ACTIONS_RUNNER_ORG"
101140 ;;
102141 "repo-level")
103- ACTIONS_API_URL="https://api.github.com/repos/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO/actions/runners/registration-token"
104- ACTIONS_RUNNER_REGISTRATION_URL="https://github.com/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO"
142+ ACTIONS_API_URL="https://$user_pwd@ api.github.com/repos/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO/actions/runners/registration-token"
143+ ACTIONS_RUNNER_REGISTRATION_URL="https://$user_pwd@ github.com/$ACTIONS_RUNNER_ORG/$ACTIONS_RUNNER_REPO"
105144 ;;
106145 *)
107146 echo "Unsupported runner scope: $ACTIONS_RUNNER_SCOPE"
@@ -127,16 +166,30 @@ jobs:
127166 ACTIONS_RUNNER_PATH="D:\a"
128167 fi
129168
169+ # Zip up and Base64-encode the post-deployment script; We used to provide a public URL
170+ # for that script instead, but that does not work in private repositories (and we could
171+ # not even use the `GITHUB_TOKEN` to access the file because it lacks the necessary
172+ # scope to read repository contents).
173+ POST_DEPLOYMENT_SCRIPT_ZIP_BASE64="$(
174+ cd azure-self-hosted-runners &&
175+ zip -9 tmp.zip post-deployment-script.ps1 >&2 &&
176+ base64 -w 0 tmp.zip
177+ )"
178+
179+ PUBLIC_IP_ADDRESS_NAME1="${{ github.repository_visibility != 'private' && format('{0}-ip', steps.generate-vm-name.outputs.vm_name) || '' }}"
180+
130181 AZURE_ARM_PARAMETERS=$(tr '\n' ' ' <<-END
131182 githubActionsRunnerRegistrationUrl="$ACTIONS_RUNNER_REGISTRATION_URL"
132183 githubActionsRunnerToken="$ACTIONS_RUNNER_TOKEN"
133- postDeploymentPsScriptUrl="$POST_DEPLOYMENT_SCRIPT_URL"
184+ postDeploymentScriptZipBase64="$POST_DEPLOYMENT_SCRIPT_ZIP_BASE64"
185+ postDeploymentScriptFileName="post-deployment-script.ps1"
134186 virtualMachineImage="$AZURE_VM_IMAGE"
135187 virtualMachineName="${{ steps.generate-vm-name.outputs.vm_name }}"
136188 virtualMachineSize="$AZURE_VM_TYPE"
137- publicIpAddressName1="${{ steps.generate-vm-name.outputs.vm_name }}-ip "
189+ publicIpAddressName1="$PUBLIC_IP_ADDRESS_NAME1 "
138190 adminUsername="${{ secrets.AZURE_VM_USERNAME }}"
139191 adminPassword="${{ secrets.AZURE_VM_PASSWORD }}"
192+ ephemeral="$EPHEMERAL_RUNNER"
140193 stopService="$DEALLOCATE_IMMEDIATELY"
141194 githubActionsRunnerPath="$ACTIONS_RUNNER_PATH"
142195 location="$AZURE_VM_REGION"
@@ -146,10 +199,12 @@ jobs:
146199 echo "AZURE_ARM_PARAMETERS=$AZURE_ARM_PARAMETERS" >> $GITHUB_ENV
147200
148201 - name : Azure Login
149- uses : ./.github/workflows/ azure- login
202+ uses : azure/ login@v2
150203 with :
151- credentials : ${{ secrets.AZURE_CREDENTIALS }}
152-
204+ client-id : ${{ secrets.AZURE_CLIENT_ID }}
205+ tenant-id : ${{ secrets.AZURE_TENANT_ID }}
206+ subscription-id : ${{ secrets.AZURE_SUBSCRIPTION_ID }}
207+
153208 - uses : azure/arm-deploy@v2
154209 id : deploy-arm-template
155210 with :
@@ -179,7 +234,7 @@ jobs:
179234 if : always()
180235 env :
181236 CUSTOM_SCRIPT_OUTPUT : ${{ steps.deploy-arm-template.outputs.customScriptInstanceView }}
182- run : echo "$CUSTOM_SCRIPT_OUTPUT" | jq -r '.substatuses[0].message'
237+ run : echo "$CUSTOM_SCRIPT_OUTPUT" | jq -r '.substatuses[0].message' | sed 's/${{ secrets.GITHUB_TOKEN }}/***/g'
183238
184239 - name : Deallocate the VM for later use
185240 if : env.DEALLOCATE_IMMEDIATELY == 'true'
0 commit comments