Skip to content

Use Workload Identity Federation for GCP auth #2

Description

@seanlip

This comment came up as part of a Copilot review in #1 (comment):

This workflow relies on a long-lived service account JSON key and assumes gcloud is available on the runner. Prefer GitHub’s recommended GCP auth approach (Workload Identity Federation via google-github-actions/auth) and, if gcloud is needed, install/configure it explicitly (e.g., google-github-actions/setup-gcloud). This reduces key-leak risk and avoids failures on runners without gcloud.

If we go this route, this would need to be done for all our github workflows (e.g. pr_validation and weekly_run). It requires setting up a Workload Identity Pool/Provider in GCP and adding two new repo secrets, GCP_WORKLOAD_IDENTITY_PROVIDER and GCP_SERVICE_ACCOUNT_EMAIL, then removing the old GCP_SERVICE_ACCOUNT_KEY secret once the integration is confirmed working.

Sample patch file with expected changes:

--- a/.github/workflows/weekly_run.yml
+++ b/.github/workflows/weekly_run.yml
@@ -9,7 +9,7 @@ name: Weekly Production Analytics Run
 #
 # Environment Target: Production (oppia-analytics-prod)
 # Key Operations:
-#   1. Authenticates to GCP using an automated service account.
+#   1. Authenticates to GCP via Workload Identity Federation (no long-lived keys).
 #   2. Dynamically isolates database credentials to prevent local Git leaks.
 #   3. Runs data quality assertions and transforms fresh production analytics logs.
 # ==============================================================================
@@ -25,6 +25,9 @@ jobs:
   dbt_run:
     name: Execute dbt Production Pipeline
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      id-token: write # required to mint the OIDC token for Workload Identity Federation
 
     steps:
       # Clone the repository codebase onto the temporary GitHub virtual runner
@@ -43,21 +46,14 @@ jobs:
           pip install --upgrade pip
           pip install dbt-bigquery
 
-      # Exchange GitHub secret tokens for active, authenticated Google Cloud sessions
-      - name: Authenticate to GCP Natively
-        run: |
-          # Write the secret JSON token safely as a raw literal string
-          cat << 'EOF' > ${HOME}/gcp_key.json
-          ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}
-          EOF
-
-          # Activate the service account using the pre-installed gcloud CLI
-          gcloud auth activate-service-account --key-file=${HOME}/gcp_key.json
-
-          # Set the application default credentials environment variable for dbt
-          echo "GOOGLE_APPLICATION_CREDENTIALS=${HOME}/gcp_key.json" >> $GITHUB_ENV
+      # Keyless auth: exchanges a GitHub OIDC token for short-lived GCP credentials
+      - name: Authenticate to GCP via Workload Identity Federation
+        uses: google-github-actions/auth@v2
+        with:
+          workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
+          service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }}
 
-      # Generate a production connection profile using service-account credentials
+      # Generate a production connection profile using the ADC credentials from the auth step
       - name: Create dynamic profiles.yml for dbt
         run: |
           cat << EOF > profiles.yml
@@ -66,8 +62,7 @@ jobs:
             outputs:
               prod:
                 type: bigquery
-                method: service-account
-                keyfile: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
+                method: oauth
                 project: oppia-analytics-prod
                 dataset: analytics_production
                 threads: 4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions