Skip to main content

Eksempeloppsett av Ztoperator

For å illustrere hvordan en Ztoperator-AuthPolicy fungerer, kan vi se på følgende eksempel-applikasjon kalt demo-app. demo-app er en Python-applikasjon med et enkelt REST-API, som også distribuerer en Single Page Application (SPA). I kildekoden til demo-app finnes det ingen mekanismer for tilgangsstyring eller beskyttelse av REST-API-endepunktene, og den har heller ikke funksjonalitet for å logge inn brukere med Microsoft Entra ID. Ztoperator-AuthPolicyen tar seg av alt dette.

Kildekoden til demo-app kan finnes på github.com/kartverket/skip-tilgangsstyring-demo. Dette repoet lar deg også teste og verifisere oppførselen til Ztoperator med et lokalt Kubernetes-cluster som likner på SKIP.

demo-app består av tre ressurser:

  • En AzureAdApplication som setter opp en klientregistrering mot Kartverkets Microsoft Entra ID.
  • En Skiperator-Application som enkelt ruller ut applikasjonen på SKIP.
  • En Ztoperator-AuthPolicy som håndhever at angitte endepunkter presentere et gyldig access_token, og i tillegg logger inn brukere der det er angitt.

Manifestene for disse ressursene finner du i tilgangsstyring-apps på GitHub.

🔹 AzureAdApplication

Før man går i gang med å sette opp en Ztoperator-AuthPolicy må man ha en klienregistrering opprettet hos en OAuth 2.0 identitetstilbyder. Ettersom demo-app er ment for intern bruk av Kartverket-ansatte, så er Microsoft Entra ID en passende identitetstilbyder. En AzureAdApplication kan brukes for å opprette klientregistreringen, og følgende manifest oppretter en. Den er konfigurert til å tillate alle brukere innenfor Kartverket's Entra ID tenant, og har en redirect-url som peker til applikasjonen sin konfiguererte redirect-url. Dette er noe vi senere konfigurerer i Ztoperator-AuthPolicyen, og Ztoperator håndterer dette endepunktet for oss. Etter å ha opprettet en klientregistrering i Microsoft Entra ID oppretter Azurerator også en Kubernetes-hemmelighet kalt entraid-secret. Klientregistreringen kan ses i Azure Portal.

note

Redirect-url er noe demo-app ikke trenger å forholde seg til. Ztoperator-AuthPolicy konfigures med en redirect-url når man konfigurerer innlogging av brukere, og håndterer callbacks i authorization code flow.

azureadapplication.yaml
apiVersion: nais.io/v1
kind: AzureAdApplication
metadata:
name: entraid-reg
namespace: ztoperator-demo
spec:
claims:
groups:
- id: a6578085-e0ee-4168-bf97-1b3026f6f3bd # Kartverket@kartverket.no
replyUrls:
- url: https://demo-app.atgcp1-sandbox.kartverket.cloud/oauth2/callback
secretName: entraid-secret
Resulterende hemmelighet opprettet av Azurerator
apiVersion: v1
kind: Secret
metadata:
name: entraid-secret
namespace: ztoperator-demo
type: Opaque
data:
AZURE_APP_CERTIFICATE_KEY_ID: ++++++++
AZURE_APP_CLIENT_ID: ++++++++
AZURE_APP_CLIENT_SECRET: ++++++++
AZURE_APP_JWK: ++++++++
AZURE_APP_JWKS: ++++++++
AZURE_APP_NEXT_CERTIFICATE_KEY_ID: ++++++++
AZURE_APP_NEXT_CLIENT_SECRET: ++++++++
AZURE_APP_NEXT_JWK: ++++++++
AZURE_APP_NEXT_PASSWORD_KEY_ID: ++++++++
AZURE_APP_PASSWORD_KEY_ID: ++++++++
AZURE_APP_PRE_AUTHORIZED_APPS: ++++++++
AZURE_APP_TENANT_ID: ++++++++
AZURE_APP_WELL_KNOWN_URL: ++++++++
AZURE_OPENID_CONFIG_ISSUER: ++++++++
AZURE_OPENID_CONFIG_JWKS_URI: ++++++++
AZURE_OPENID_CONFIG_TOKEN_ENDPOINT: ++++++++

🤖 Skiperator-Application

demo-app er bygget til et Docker-image og lastet opp på GitHub Container Registry med følgende image-url: ghcr.io/kartverket/skip-tilgangsstyring-demo. Den kan da deployes på SKIP med følgende manifest og nås på https://demo-app.atgcp1-sandbox.kartverket.cloud.

Den uthevede delen av koden er viktig for at innlogging av sluttbrukere skal fungere. Hvorfor denne konfigurasjonen er viktig etterlates som en oppgave for leseren. Det brukeren forholde seg til er hvilket secretName det skal refereres til. Dette må matche en Kuberenetes-hemmelighet som Ztoperator oppretter som har navneformatet <NAVN PÅ AUTHPOLICY>-envoy-secret. Ettersom demo-app sin Ztoperator-AuthPolicy heter auth-policy, blir det korrekt med "secretName": "auth-policy-envoy-secret".

demo-app.yaml
apiVersion: skiperator.kartverket.no/v1alpha1
kind: Application
metadata:
name: demo-app
namespace: ztoperator-demo
spec:
podSettings:
annotations:
sidecar.istio.io/userVolume: '[
{
"name": "istio-oauth2",
"secret": {
"secretName": "auth-policy-envoy-secret" # 👈 Må matche <NAVN PÅ AUTHPOLICY>-envoy-secret
}
}
]'
sidecar.istio.io/userVolumeMount: '[
{
"name": "istio-oauth2",
"mountPath": "/etc/istio/config",
"readonly": true
}
]'
image: ghcr.io/kartverket/skip-tilgangsstyring-demo@sha256:cde1805d4e87b99a6d8d73fd6ed6666eaef1691a598f0377d3a716366cc4c9e8
port: 5000
ingresses:
- demo-app.atgcp1-sandbox.kartverket.cloud

⛔️ Ztoperator-AuthPolicy

Vi har nå registrert en klient hos Microsoft Entra ID ved hjelp av Azurerator, og spunnet opp demo-appsom en Skiperator-Application. Det siste steget er nå å beskytte applikasjonen med en Ztoperator-AuthPolicy. Følgende manifest beskytter demo-app og håndterer innlogging av brukere opp mot Microsoft Entra ID. Under går vi gjennom hvordan og hvorfor vi har konfigurert Ztoperator-AuthPolicy som vi har gjort.

auth-policy.yaml
apiVersion: ztoperator.kartverket.no/v1alpha1
kind: AuthPolicy
metadata:
name: auth-policy
namespace: ztoperator-demo
spec:
enabled: true
selector:
matchLabels:
app: demo-app
wellKnownURI: https://login.microsoftonline.com/7f74c8a2-43ce-46b2-b0e8-b6306cba73a3/v2.0/.well-known/openid-configuration
audience:
- dcc29452-1fbc-4805-aeb9-cdb8f4e62147
ignoreAuthRules:
- paths:
- /*
authRules:
- paths:
- /api/beskyttet*
methods:
- POST
denyRedirect: true
- paths:
- /beskyttet
autoLogin:
enabled: true
loginPath: /login
logoutPath: /logout
redirectPath: /oauth2/callback
scopes:
- dcc29452-1fbc-4805-aeb9-cdb8f4e62147/.default
oAuthCredentials:
clientIDKey: AZURE_APP_CLIENT_ID
clientSecretKey: AZURE_APP_CLIENT_SECRET
secretRef: entraid-secret
outputClaimToHeaders:
- claim: preferred_username
header: x-email
- claim: name
header: x-name

spec.enabled

spec.enabled lar deg toggle om tilgangsstyring skal være aktivert eller ikke.

spec.selector

spec.selector spesifiserer hvilke pod-er som skal beskyttes. Når man deployer en applikasjon med Skiperator så vil alle pod-er få labelen app: <NAVN PÅ SKIPERTOR-APPLICATION>.

spec.wellKnownURI

spec.wellKnownURI trengs for å utføre OpenID Connect Discovery og hente ut relevant informasjon om identitetstilbyderren brukt under autentisering. Det er her man knytter Ztoperator-AuthPolicy til en identitetstilbyder.

spec.audience

spec.audience spesifiserer tiltenkt mottaker av aksess-tokenet. Dette er typisk en klient-ID eller en annen unik identifikator knyttet til klientregistreringen utført tidligere. Dette feltet et viktig å inkludere for å skille klientregistreringer hos en identitetstilbyder fra andre. spec.audience sikrer at kun din klientregistrering kan bruke tokenet til å aksessere applikasjonens beskyttede endepunkter.

spec.ignoreAuthRules

I utgangspunktet er alle endepunkter mot demo-app åpne, noe som angis med paths: [/*]. Når HTTP-verb ikke er spesifisert, gjelder regelen for alle metoder. Dersom et endepunkt ikke er eksplisitt definert – eller det finnes overlapp mellom spec.ignoreAuthRules og spec.authRules – vil Ztoperator alltid falle tilbake til å beskytte endepunktet.

spec.authRules

POST mot endpunktene /api/beskyttet* (/api/beskyttet og alle under-stier) skal være beskyttet. Ettersom kall mot /api/beskyttet* gjøres av en Single Page Application i en AJAX-request, har man ikke muligheten til å følge 302 Redirect og logge inn brukeren automatisk. For å løse dette kan man spesifisere denyRedirect: true for å forhindre at Ztoperator returnerer en 302 Redirect (den sender da en 401 Unauthorized i stedet), og heller omdirigere brukeren selv i frontend-koden til den konfigurerte innloggingsstien (/login i dette tilfellet). Stien /beskyttet skal også beskyttes, og ettersom det ikke spesifiseres denyRedirect: true vil uautentiserte brukere automatisk bli omdirigert til innlogging mot Microsoft Entra ID.

spec.autoLogin

spec.autoLogin lar deg konfigurere innlogging mot identitetstilbyderen. Innlogging vil bli gjort automatisk hvis brukere aksesserer beskyttede endepunkt uten en sesjon (med mindre spec.authRules[].denyRedirect er satt til true). I tillegg konfigureres det en dedikert innloggingssti som brukere kan navigeres til for å starte en inlogget sesjon.

  • spec.autoLogin.enabled lar deg toggle om innlogging skal være aktivert eller ikke.
  • spec.autoLogin.loginPath spesifiserer hvilken sti man skal aksessere for å starte en innlogget sesjon. Etter vellykket innlogging vil en forespørsel sendes til den konfigurerte innloggingsstien i applikasjonen din, og det er da opp til deg å håndtere hva som skal skje.
  • spec.autoLogin.logoutPath spesifiserer hvilken sti man skal aksessere for å logge ut brukeren lokalt og opp mot den konfigurerte identitetstilbyderen (RP-initiated logout). Etter vellykket utlogging vil brukeren bli omdirigert til nettsiden sin rotsti (dvs. https://<HOST>/).
  • spec.autoLogin.redirectPath spesifiserer omdirigeringssti brukt under Authorization Code Flow. Dette er en sti som du ikke tregner å håndtere i applikasjonskoden din, men den må samsvare med en av de konfigurerte omdirigeringsstiene i klientregistreringen din.
  • spec.autoLogin.scopes spesifiserer hvilke scopes som skal brukes i under Authorization Code Flow. I dette eksempelet er det spesifisert som <CLIENT ID>/.default, som er et scope Microsoft Entra ID tilbyr som implisitt inneholder alle tilgjengelige scopes for klientregistreringen.
warning

Ztoperator-AuthPolicy benytter seg av cookies for å lagre innlogget sesjon i nettleseren. OIDC Single Logout (SLO) benytter seg av iframe for å logge brukeren ut av alle nettstedene som brukeren har en aktiv SSO-sesjon hos. Ettersom cookies som Ztoperator-AuthPolicy setter er HTTP-only så vil de ikke kunne aksesseres i en iframe, og SLO er derfor ikke støttet av Ztoperator-AuthPolicy.

spec.oAuthCredentials

spec.oAuthCredentials spesifiserer hvilken klient-ID og klient-hemmelighet som skal brukes under innlogging av brukere.

  • spec.oAuthCredentials.secretRef spesifiserer hvilken Kubernetes-hemmelighet som har hemmelightene.
  • spec.oAuthCredentials.clientIDKey spesifiserer hvilken data-nøkkel i Kuberenetes-hemmeligheten som har klient-IDen.
  • spec.oAuthCredentials.clientSecretKey spesifiserer hvilken data-nøkkel i Kuberenetes-hemmeligheten som har klient-hemmeligheten.

spec.outputClaimToHeaders

spec.outputClaimToHeaders spesifiserer hvilke claims i access_token som skal sendes som HTTP-headers til applikasjonen.

👀 Lett å overse

Selv om Ztoperator-AuthPolicy skal gjøre det lettere å sikre appllikasjonen sin med OAuth 2.0 og OIDC, så er det fortsatt enkelte ting man lett kan overse.

Audience-begrensing i ID-porten og Maksinporten

Både ID-porten og Maksinporten benytter seg av audience-begrensing, en mekanisme basert på RFC 8707 Resource Indicators for Oauth2, som motvirker at tokens kan misbrukes mot andre APIer enn de som er tiltenkt. En konsekvens av dette er at det er klienten sitt ansvar å be om et audience-begrenset token. Dette er støttet i Ztoperator-AuthPolicy med feltet spec.acceptedResources. Dette feltet spesifiserer hvilke APIer tokenet skal kunne brukes mot.

Client authentication

Per nå støtter Ztoperator kun å autentisere klienter ved bruk av client_secret_post. Selve klient-autentiseringen gjøres av Ztoperator, men det er viktig at det er konfigurert i klientregistreringen mot identitetstilbyderen at man bruker client_secret_post.

caution

Klientregistrering med Digdirator antar at klienten kun benytter seg av private_key_jwt som klient-autentiseringsmetode, noe som gjør at klientintegrasjoner satt opp med Digdirator per nå ikke er kompatibelt med Ztoperator-AuthPolicy.