OAuth del 2 (Token Exchange)
Bakgrunn
I NAV er OAuth og OIDC de facto standard for å løse autentisering og autorisering i appene våre. I en løst koblet verden med mikrotjenester og zero trust er det imidlertid flere brikker som må på plass. Hvordan kan man på en trygg måte kalle andre tjenester videre bakover i kjeden og samtidig bevare sluttbrukerkonteksten? Tidligere har man benyttet såkalte “systembrukere”, dvs brukere som identifiserer systemet/tjenesten som det kalles fra. Man har hatt en eller flere Security Token Services som har vekslet systembrukerens brukernavn og passord inn i et access token som benyttes for videre kall. Dette har flere ulemper. Systembrukerene må ha ganske romslige rettigheter (som gjør det ekstra viktig at de ikke blir kompromittert), og informasjon om sluttbrukeren som initierte kallet blir borte med mindre man legger på hjemmesnekra hacks.
Token Exchange standarden
RFC 8693 - OAuth 2.0 Token Exchange adresserer akkurat dette problemet, og har nå endelig blitt en “proposed standard”. Azure AD (som vi bruker som ID-provider for egne ansatte) har lenge tilbydd en on-behalf-of flyt som er veldig lik den nye standarden, men for borgerne som logger på med ID-porten har vi ikke hatt noe tilsvarende.
Flyten
- Sluttbruker logger inn hos ID-provider.
- ID-provider returnerer et access token med audience
API 1
. - API 1 ber om å veksle tokenet fra ID-provider med et nytt access token for API 2 fra exchangeren
- Exchangeren validerer requesten og tokenet som skal veksles, sjekker om
API 1
er forhåndsgodkjent til å kalleAPI 2
og returnerer et nytt access token beregnet påAPI 2
med audience likAPI 2
. API 1
ber om data fraAPI 2
på vegne av sluttbruker vha det nye access tokenet.API 2
validerer access tokenet og returnerer de forespurte dataene.
Token exchange-forespørselen kan se ut som følger:
POST /token HTTP/1.1
Host: tokenxchange-server
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eY...............&
subject_token_type=urn:ietf:params:oauth:token-type:jwt&
subject_token=eY...............&
audience=app1
grant_type
er en fast verdi som er definert av standarden.
subject_token
inneholder tokenet som skal veksles og identifiserer sluttbrukeren (tokenet hen fikk fra id-provideren).
audience
inneholder identifikatoren til appen som skal motta tokenet du nå ber om
client_assertion
identifiserer appen mot exhangeren (i dette eksemplet App 1
). En client_assertion er en Base 64-kodet JWT som appen genererer og signerer vha sin private nøkkel. JWT-en inneholder følgende claims:
{
'sub': `api1`,
'aud': 'http://tokenxchange-server/token',
'iss': 'api1',
'exp': 1516239052
'iat': 1516239022,
'jti': 'a_unique_id',
'nbf': 1516239022
}
Token Exchange i NAV
Token Exchange-standarden er fortsatt fersk, og det er i skrivende stund ingen av de kommersielle leverandørene som har implementert den. Vi har derfor valgt å lage vår egen løsning som vi har kalt TokenX. Den mest sentrale komponenten i TokenX er Tokendings. Den er en OAuth 2.0 Authorization Server med funksjonalitet som en STS, men vi har valgt å ikke bruke den beskrivelsen fordi STS er et reservert ord i NAV. Provisjonering av nøkler som appene bruker til signering av assertions skjer automatisk ved deploy vha operatorer (Jwker og Naiserator) i k8s clusteret, og tilgjengeliggjøres som miljøvariabler i podene. Hvilke apper som skal få lov til å snakke sammen utledes automatisk ut fra Istio access policyene som appene uansett må sette opp for å fungere. Nøklene roteres ved hver deploy.