To update environment variables defined in GitHub environment, via a GitHub action workflow we cannot use the default GITHUB_TOKEN .
GITHUB_TOKEN can interact with repository contents (depending on permissions), create releases, comment on PRs, update issues, etc.
GITHUB_TOKEN cannot update repository environments, environment secrets, or environment variables via the GitHub REST API.Therefore, we need to use a Fine-Grained Personal Access Token (PAT) , provided it has the appropriate repository permissions.
For updating GitHub environment variables, the token needs:
- Repository access to the target repository.
- Environments permission: Read and write.
Let's see how we can setup such a token step by steps.
- Go to GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens.
- Click Generate new token.
-
Configure the token:
- Resource owner: Select the owner of the repository.
Common name variable_read_write used as later it can expand to other repos as and when needed. Set to expire in 90 days.
Repository access limited to the required repo for now.
- Configure the token:
- Repository access: Select Only select repositories (or All repositories if appropriate) and choose your repository.
The permisions for environments read and write set explicitly. No addtional permision except required metadata read.
- Configure the token:
- Repository permissions:
- Environments → Read and write.
- Generate and copy the token.
- Store the token as a secret, for example:
- Repository secret:
GH_VARIABLES_PAT, or - Environment secret if only workflows targeting a specific environment should be able to use it.
- Repository secret:
on: workflow_call: inputs: environment: required: true type: string stage: required: true type: string jobs: setup_blue_green_control: name: "${{ inputs.stage }}: setup_blue_green_control" runs-on: ubuntu-24.04 environment: ${{ inputs.environment }} steps: - uses: actions/checkout@v6.0.3 - uses: ./.github/actions/step/log_blue_green_parameters with: environment: ${{ inputs.environment }} stage: ${{ inputs.stage }} sys_is_blue_deployed: ${{ vars.SYS_IS_BLUE_DEPLOYED }} sys_is_green_deployed: ${{ vars.SYS_IS_GREEN_DEPLOYED }} sys_is_green_live: ${{ vars.SYS_IS_GREEN_LIVE }} sys_is_skip_healthcheck: ${{ vars.SYS_IS_SKIP_HEALTHCHECK }} sys_live_aks_nodepool: ${{ vars.SYS_LIVE_AKS_NODEPOOL }} sys_svc_deploy_dns_zone: ${{ vars.SYS_SVC_DEPLOY_DNS_ZONE }} sys_svc_deploy_nodepool_suffix: ${{ vars.SYS_SVC_DEPLOY_NODEPOOL_SUFFIX }} - name: "${{ inputs.stage }}: setup_blue_green_control" shell: bash env: GH_VAR_TOKEN: ${{ secrets.GH_VARIABLES_PAT }} GH_REPO: ${{ github.repository }} GH_ENVIRONMENT: ${{ inputs.environment }} SYS_DEPLOYMENT_PHASE: ${{ inputs.stage }} SYS_IS_BLUE_DEPLOYED: ${{ vars.SYS_IS_BLUE_DEPLOYED }} SYS_IS_GREEN_DEPLOYED: ${{ vars.SYS_IS_GREEN_DEPLOYED }} SYS_IS_GREEN_LIVE: ${{ vars.SYS_IS_GREEN_LIVE }} SYS_SVC_DEPLOY_NODEPOOL_SUFFIX: ${{ vars.SYS_SVC_DEPLOY_NODEPOOL_SUFFIX }} SYS_LIVE_AKS_NODEPOOL: ${{ vars.SYS_LIVE_AKS_NODEPOOL }} run: | update_var() { local var_name="$1" local var_value="$2" local api_base="https://api.github.com/repos/${GH_REPO}/environments/${GH_ENVIRONMENT}/variables" echo "Updating ${var_name} to '${var_value}'..." http_status=$(curl -s -o /tmp/gh_api_response.json -w "%{http_code}" -X PATCH \ -H "Authorization: Bearer ${GH_VAR_TOKEN}" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "${api_base}/${var_name}" \ -d "{\"name\":\"${var_name}\",\"value\":\"${var_value}\"}") if [ "${http_status}" = "204" ]; then echo "Updated ${var_name} successfully (HTTP ${http_status})." else echo "ERROR: Failed to update ${var_name}. HTTP ${http_status}. Response:" cat /tmp/gh_api_response.json exit 1 fi } if [ "${SYS_DEPLOYMENT_PHASE}" = "deploy" ]; then update_var "SYS_IS_SKIP_HEALTHCHECK" "false" if [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_IS_BLUE_DEPLOYED}" = "false" ]; then echo "Green is live. Setting blue nodepool to deploy..." update_var "SYS_IS_BLUE_DEPLOYED" "true" elif [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_IS_GREEN_DEPLOYED}" = "false" ]; then echo "Blue is live. Setting green nodepool to deploy..." update_var "SYS_IS_GREEN_DEPLOYED" "true" elif [ "${SYS_IS_GREEN_LIVE}" = "true" ]; then echo "Green is live. Retry deploying blue nodepool..." else echo "Blue is live. Retry deploying green nodepool..." fi elif [ "${SYS_DEPLOYMENT_PHASE}" = "switch" ]; then if [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}" = "green" ]; then echo "Green deployed. Setting green to go live..." update_var "SYS_IS_GREEN_LIVE" "true" elif [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}" = "blue" ]; then echo "Blue deployed. Setting blue to go live..." update_var "SYS_IS_GREEN_LIVE" "false" else echo "New app deployed instance is ${SYS_SVC_DEPLOY_NODEPOOL_SUFFIX}. Setting as live..." fi elif [ "${SYS_DEPLOYMENT_PHASE}" = "destroy" ]; then if [ "${SYS_IS_GREEN_LIVE}" = "true" ] && [ "${SYS_IS_BLUE_DEPLOYED}" = "true" ]; then echo "New green nodepool is live now. Setting blue nodepool to destroy..." update_var "SYS_IS_BLUE_DEPLOYED" "false" elif [ "${SYS_IS_GREEN_LIVE}" = "false" ] && [ "${SYS_IS_GREEN_DEPLOYED}" = "true" ]; then echo "New blue nodepool is live now. Setting green nodepool to destroy..." update_var "SYS_IS_GREEN_DEPLOYED" "false" else echo "Live nodepool is ${SYS_LIVE_AKS_NODEPOOL}. Retry destroying none live nodepool..." fi fi
No comments:
Post a Comment