Skip to main content

Autentisering med Workload Identity Federation

Når man bruker langlevde tokens til autentisering, slik som for eksempel servicekonto-tokens, er det en risiko for at disse blir lekket og blir en angrepsvektor mot infrastrukturen. Dette vil vi unngå, og det er også grunnen til at Google anbefaler å ikke bruke slike servicekonto-tokens, til fordel for Workload Identity Federation der det er mulig.

GitHub skriver om noen fordeler med å bruke dette i About security hardening with OpenID Connect.

Kort oppsummert er Workload Identity Federation en måte å lese signerte JWT-er fra andre identity providers og bruke dette til å gi tilgang til servicekontoer i GCP. Google forteller mer om dette her: https://cloud.google.com/iam/docs/workload-identity-federation

Når vi bruker GitHub Actions har GitHub en egen OIDC identity provider som vi kan ta i bruk. Vi kan da bruke OIDC identity provideren i GitHub til å utstede en JWT signert av GitHub hver gang et bygg kjøres. På denne måten kan SKIP vite at autentiseringsforespørselen ble kjørt i tilknytning til bygget deres, og gi dere de tilgangene dere krever, for eksempel tilgang til å deploye til namespacet deres på Kubernetes. Da bruker man kun kortlevde nøkler og unngår å bruke servicekontoer med lang varighet som kan lekkes.

Oppsett av GitHub Action

Når man skal sette opp autentisering mot GCP med Workload Identity Federation er det en fordel å ha lest gjennom GitHub sin artikkel om https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform#updating-your-github-actions-workflow , og spesifikt kapittelet som heter “Updating your GitHub Actions workflow”. Her beskriver de de to trinnene man må gjøre:

SKIP-teamet vil ha konfigurert en workload identity provider og service account som dere kan putte rett inn i provideren over. Disse er ikke hemmelige men vil variere avhengig av miljø man skal deploye mot, så det kan være hensiktsmessig å ha de som variabler, som vist lenger nede.

permissions:
contents: read
id-token: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- id: auth
name: Authenticate to GCP
uses: google-github-actions/auth@v0
with:
workload_identity_provider: projects/your-project-number/locations/global/workloadIdentityPools/your-pool/providers/your-provider
service_account: your-account@your-project.iam.gserviceaccount.com
project_id: kubernetes-dev-94b9

Eventuelt kan du ha en egen setup-env jobb som lager outputs du kan bruke senere, slik at provider, service account og project id er variabler i stedet for hardkodede strings.

Eksempel:

permissions:
contents: read
id-token: write

env:
PROJECT_ID: kubernetes-dev-94b9
SERVICE_ACCOUNT: your-account@your-project.iam.gserviceaccount.com
WORKLOAD_IDENTITY_PROVIDER: projects/your-project-number/locations/global/workloadIdentityPools/your-pool/providers/your-provider

jobs:
setup-env:
runs-on: ubuntu-latest
outputs:
project_id: ${{ steps.set-output.outputs.project_id }}
service_account: ${{ steps.set-output.outputs.service_account }}
workload_identity_provider: ${{ steps.set-output.outputs.workload_identity_provider }}
steps:
- name: Set outputs
id: set-output
run: |
echo "project_id=$PROJECT_ID" >> $GITHUB_OUTPUT
echo "service_account=$SERVICE_ACCOUNT" >> $GITHUB_OUTPUT
echo "workload_identity_provider=$WORKLOAD_IDENTITY_PROVIDER" >> $GITHUB_OUTPUT

build:
needs: [setup_env]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- id: auth
name: Authenticate to GCP
uses: google-github-actions/auth@v0
with:
workload_identity_provider: ${{ needs.setup-env.outputs.workload_identity_provider }}
service_account: ${{ needs.setup-env.outputs.service_account }}
project_id: ${{ needs.setup-env.outputs.project_id }}

build-again:
needs: [setup_env]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- id: auth
name: Authenticate to GCP
uses: google-github-actions/auth@v0
with:
workload_identity_provider: ${{ needs.setup-env.outputs.workload_identity_provider }}
service_account: ${{ needs.setup-env.outputs.service_account }}
project_id: ${{ needs.setup-env.outputs.project_id }}