Skip to content

OIDC auth flow inside Docker #473

@ibrahimparvez2

Description

@ibrahimparvez2

TL;DR

When using this action to obtain impersonated credentials I can setup my docker compose override to update my credential path (GOOGLE_APPLICATION_CREDENTIALS) path variable via volume mounting which I can inspect upon running container exec commands alongside printenv to confirm my docker service has resolved the mounted credentials. My issue is the OIDC flow does not work inside the container which I am running...
here is a breakdown of my workflow

     - name: Checkout repo
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "20"
          cache: "npm"
          cache-dependency-path: "./app/package-lock.json"

      - uses: "google-github-actions/auth@v2"
        id: auth
        with:
          token_format: 'access_token'
          workload_identity_provider: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: [email protected]
          create_credentials_file: true

      - name: Generate docker-compose.override.yml
        run: |
          CREDENTIALS_PATH=${{ steps.auth.outputs.credentials_file_path }}
          echo "Using credentials file at $CREDENTIALS_PATH"
          # Create the override file
          cat <<EOF > docker-compose.override.yml
          services:
            firebase-functions:
              volumes:
                - $CREDENTIALS_PATH:/root/.config/gcloud/application_default_credentials.json:ro
              environment:
                GOOGLE_APPLICATION_CREDENTIALS: "/root/.config/gcloud/application_default_credentials.json"
          EOF
          echo "docker-compose.override.yml created with dynamic volume and environment variable."
      - name: cat dockerfile.functions
        run: cat dockerfile.functions

      - name: Run Docker Compose
        run: |
          docker compose down
          docker compose up -d
      - name: confirm volume mounting
        run: |
          docker exec firebase-functions-1 printenv && \
          docker exec firebase-functions-1 cat /root/.config/gcloud//application_default_credentials.json
      

from debug.logs:
[warn] ⚠ functions: Your GOOGLE_APPLICATION_CREDENTIALS environment variable points to /root/.config/gcloud/application_default_credentials.json. Non-emulated services will access production using these credentials. Be careful! {"metadata":{"emulator":{"name":"functions"},"message":"Your GOOGLE_APPLICATION_CREDENTIALS environment variable points to /root/.config/gcloud/application_default_credentials.json. Non-emulated services will access production using these credentials. Be careful!"}}

above docker commands / logs confirm volume mouting is there inside the container and credentials are picked up, however any calls to my service inside the container running in github action fail on authentication

Does the OIDC auth pattern persist when working in github actions with docker? I do not see why this would fail other than if something has been configured with the resulting credentials provided by auth action step

Expected behavior

calls to dockerized app would use service account impersonsation, just as it does with running any app with the credentials provided on the github action runner

Observed behavior

I get failed to impersonated errors:

[info] > ('Unable to acquire impersonated credentials', '{\n "error": {\n "code": 403,\n "message": "Caller does not have required permission to use project abc. Grant the caller the roles/serviceusage.serviceUsageConsumer role, or a custom role with the serviceusage.services.use permission, by visiting https://console.developers.google.com/iam-admin/iam/project?project=abc and then retry. Propagation of the new permission may take a few minutes.",\n "status": "PERMISSION_DENIED",\n "details": [\n {\n "@type": "type.googleapis.com/google.rpc.ErrorInfo",\n "reason": "USER_PROJECT_DENIED",\n "domain": "googleapis.com",\n "metadata": {\n "containerInfo": "abc",\n "service": "iamcredentials.googleapis.com",\n "consumer": "projects/abcv"\n }\n },\n {\n "@type": "type.googleapis.com/google.rpc.LocalizedMessage",\n "locale": "en-US",\n "message": "Caller does not have required permission to use project abc. Grant the caller the roles/serviceusage.serviceUsageConsumer role, or a custom role with the serviceusage.services.use permission, by visiting https://console.developers.google.com/iam-admin/iam/project?project=abc and then retry. Prop

Action YAML

name: (run-e2e-tests) with docker
on:
  workflow_call:
    inputs:
      environment:
        description: environment to run e2e tests against
        required: true
        type: string
        default: dev
  push:
    branches:
      - my-branch

permissions:
  contents: read
  id-token: write

jobs:
  run-e2e-tests:
    environment: ${{ inputs.environment || 'dev' }}
    runs-on: ubuntu-latest
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        app: ["highways"]

    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: "20"
          cache: "npm"
          cache-dependency-path: "./app/package-lock.json"

      - uses: "google-github-actions/auth@v2"
        id: auth
        with:
          token_format: 'access_token'
          workload_identity_provider: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }}
          service_account: [email protected]
          create_credentials_file: true

      - name: Generate docker-compose.override.yml
        run: |
          CREDENTIALS_PATH=${{ steps.auth.outputs.credentials_file_path }}
          echo "Using credentials file at $CREDENTIALS_PATH"
          # Create the override file
          cat <<EOF > docker-compose.override.yml
          services:
            firebase-functions:
              volumes:
                - $CREDENTIALS_PATH:/root/.config/gcloud/application_default_credentials.json:ro
              environment:
                GOOGLE_APPLICATION_CREDENTIALS: "/root/.config/gcloud/application_default_credentials.json"
          EOF
          echo "docker-compose.override.yml created with dynamic volume and environment variable."
      - name: cat dockerfile.functions
        run: cat dockerfile.functions

      - name: Run Docker Compose
        run: |
          docker compose down
          docker compose up -d
      - name: confirm volume mounting
        run: |
          docker exec firebase-functions-1 printenv && \
          docker exec firebase-functions-1 cat /root/.config/gcloud//application_default_credentials.json
      
  
      - name: Install Frontend Dependencies
        working-directory: ./app
        run: |
          cp ".env.dev" .env || true
          npm ci
          npm list
      - name: Create cypress.env.json
        run: |
          echo '{
            "USERNAME": "${{ secrets.USERNAME }}",
            "PASSWORD": "${{ secrets.PASSWORD }}",
            "CHAT_URL": "http://127.0.0.1:5173",
            "LOGIN_URL": "${{ vars.CYPRESS_B2C_ENVIRONMENT }}"
          }' > ./cypress.env.json
        shell: bash
        working-directory: ./e2e-tests
      
      - name: Configure hosts file
        run: |
          echo "127.0.0.1       ipv4-localhost" | sudo tee -a /etc/hosts
          cat /etc/hosts | grep ipv4-localhost
        working-directory: ./app
    
      - name: Start server in the background
        run: |
          npm run start -- --host 127.0.0.1 &
          sleep 5
          netstat -tulpn | grep 5173
        working-directory: ./app
      
      - name: Wait for server
        run: |
          # Force IPv4 resolution
          export NODE_OPTIONS="--dns-result-order=ipv4first"
          npx wait-on http://127.0.0.1:5173 --timeout 180000 --interval 5000
        working-directory: ./app
      
      - name: Confirm server is up
        run: curl -v http://localhost:5173
      
      
      - name: Cypress run
        uses: cypress-io/github-action@v6
        with:
          working-directory: ./e2e-tests
          browser: chrome
          spec: cypress/e2e/${{ matrix.app }}/Jailbreak.feature
          wait-on: "http://127.0.0.1:5173"
          wait-on-timeout: 120
        env:
          DEBUG: 'cypress:*'
          CYPRESS_BASE_URL: "http://127.0.0.1:5173"
          NODE_OPTIONS: "--dns-result-order=ipv4first"
      
      - name: Get Debug Logs
        if: failure()
        run: |
          docker exec firebase-functions-1 cat firebase-debug.log 
      
      - name: Upload Cypress Videos
        uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: cypress-videos
          path: ./e2e-tests/cypress/videos

Log output


Additional information

regarding error message roles/serviceusage.serviceUsageConsumer impersonated service account is working via docker compose locally and has all relevant permissions

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions