Request-evaluering med OPA
Request-evaluering med OPA er når èn OPA-regel evaluerer innkommende requests før de når applikasjonen din. Dette kan brukes til å utføre autorisasjonssjekker, berike requesten med headere, eller avvise requesten før den når applikasjonen din. Det første man må gjøre for å bruke request-evaluering med OPA er å skrive OPA-regelen som skal evaluere requesten.
OPA-regel for request-evaluering
En OPA-regel for request-evaluering vil få inn et input-objekt som inneholder informasjon om requesten, inkludert
HTTP-metode, path, query-parametere, headere, med mer. Regelen skal returnere et objekt som forteller om requesten skal
slippes gjennom eller ikke. Det gjøres med feltet allowed. I tillegg kan regelen sette headere, statuskode og body som
skal brukes når requesten enten skal avvises eller sendes videre til applikasjonen.
Eksempel input
{
"attributes": {
"source": {
"address": {
"socketAddress": {
"address": "172.17.0.1",
"portValue": 61402
}
}
},
"destination": {
"address": {
"socketAddress": {
"address": "172.17.06",
"portValue": 8000
}
}
},
"request": {
"time": "2020-11-20T09:47:47.722473Z",
"http": {
"id": "13519049518330544501",
"method": "POST",
"headers": {
":authority": "192.168.99.206:30164",
":method": "POST",
":path": "/people?lang=en",
"accept": "*/*",
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJzdWIiOiJZbTlpIiwibmJmIjoxNTE0ODUxMTM5LCJleHAiOjE2NDEwODE1Mzl9.WCxNAveAVAdRCmkpIObOTaSd0AJRECY2Ch2Qdic3kU8",
"content-length": "41",
"content-type": "application/json",
"user-agent": "curl/7.54.0",
"x-forwarded-proto": "http",
"x-request-id": "7bca5c86-bf55-432c-b212-8c0f1dc999ec"
},
"host": "192.168.99.206:30164",
"path": "/people?lang=en",
"protocol": "HTTP/1.1",
"body": "{\"firstname\":\"Charlie\", \"lastname\":\"Opa\"}",
"size": 41
}
},
"metadataContext": {}
},
"parsed_body": { "firstname": "Charlie", "lastname": "Opa" },
"parsed_path": ["people"],
"parsed_query": { "lang": ["en"] },
"truncated_body": false,
"version": {
"encoding": "protojson",
"ext_authz": "v3"
}
}
Eksempel output
{
"allowed": true,
"headers": {
"x-subject": "Ym9i"
},
"response_headers_to_add": {
"x-opa-eval": "true"
},
"request_headers_to_remove": [
"x-remove-me"
],
"http_status": 403,
"body": "{\"error\":\"Forbidden\"}",
"query_parameters_to_set": {
"lang": [
"no"
]
},
"query_parameters_to_remove": [
"debug"
]
}
| Felt | Påkrevd | Beskrivelse |
|---|---|---|
allowed | Ja | Boolean som avgjør om requesten skal slippes gjennom eller ikke |
headers | Nei | Objekt med headere. Ved avvist request sendes disse til klienten (downstream). Ved tillatt request legges de til på requesten videre til applikasjonen (upstream) |
response_headers_to_add | Nei | Objekt med headere som skal legges til på responsen til klienten når requesten tillates |
request_headers_to_remove | Nei | Liste med header-navn som skal fjernes fra requesten før den sendes videre til applikasjonen |
http_status | Nei | HTTP-statuskode som sendes til klienten når requesten avvises. Standard er 403 |
body | Nei | Response body som sendes til klienten når requesten avvises |
query_parameters_to_set | Nei | Objekt som legger til eller overskriver query-parametere på requesten videre til applikasjonen |
query_parameters_to_remove | Nei | Liste med query-parameternavn som skal fjernes fra requesten videre til applikasjonen |
Eksempel
Under følger et eksempel på en regel som krever rollen admin i Bearer-tokenet på alle kall mot /api/admin, og slipper
gjennom alle andre kall. Headeren x-subject blir også populert med sub-claimet fra Bearer-tokenet.
# METADATA
# entrypoint: true
package request
import rego.v1
default permit := true
permit := false if {
input.parsed_path[0] == "api"
input.parsed_path[1] == "admin"
token.payload.role != "admin"
}
allow := {
"allowed": permit,
"headers": {"x-subject": token.payload.sub},
}
token := {"payload": payload} if {
[_, encoded] := split(input.attributes.request.http.headers.authorization, " ")
# NB: io.jwt.decode validerer IKKE tokenet, men kun dekoder det.
# Ønsker du å validere tokenet kan du bruke io.jwt.decode_verify.
[_, payload, _] := io.jwt.decode(encoded)
}
Request-evaluering med OPA på SKIP
Request-evaluering med OPA på SKIP konfigureres gjennom Kubernetes-ressursen SecurityConfig. Følgende er et
eksempel på en SecurityConfig som konfigurer opp request-evaluering. OPA-regelen som skal ta imot requesten ligger på
stien /v1/data/request/allow. Resten av feltene og dens betydning kan du lese mer om i accesserator sin
API-doc.
apiVersion: accesserator.kartverket.no/v1alpha
kind: SecurityConfig
metadata:
name: security-config
namespace: tilgangsstyring-main
spec:
applicationRef: min-app
opa:
...
requestPolicy:
enabled: true
failureMode: DENY
endpoint: /v1/data/request/allow
requestBody:
include: true
maxRequestBodyBytes: 8192 # 8 KiB
Lokal kjøring av request-evaluering med OPA
Du kan utvikle og teste request-evaluering med OPA lokalt ved å bruke docker-imaget
ghcr.io/kartverket/skip-tilgangsstyring-local. Hvis SecurityConfig-ressursen fra filen konfigurert i
miljøvariabelen SECURITY_CONFIG_PATH har request-evaluering aktivert, vil OPA starte opp med request-evaluering
aktivert. Det vil også starte opp en proxy som vil rute innkommende trafikk via OPA for request-evluering, før den sender
requesten hvis OPA tillater det. Proxyen konfigureres med to miljøvariabeler:
UPSTREAM_URL: URL-en til applikasjonen din.PROXY_PORT: Hvilken port proxyen skal lytte på..
SECURITY_CONFIG_PATH støtter YAML, JSON og Jsonnet. Inneholder filen flere SecurityConfig-ressurser, kan du
spesifisere hvilken som skal brukes med SECURITY_CONFIG_NAME. Består Jsonnet-en av flere filer som importerer
hverandre fra ulike mapper, kan du sette JSONNET_PATH til en kolonseparert liste med mapper Jsonnet skal søke i
under evaluering.
Eksempel
- MacOS
- Linux
- Windows
Følgende docker-compose.yaml kjører opp en proxy på port 8080 som tar imot requests, sender dem til OPA sin
gRPC-port på :9191, og sender requesten videre til http://host.docker.internal:3000
(http://localhost:3000på din maskin) hvis OPA tillater det.
Kjører applikasjonen din lokalt på maskinen (altså ikke i Docker) kan du bruke
host.docker.internal:<PORT> som UPSTREAM_HOST for å nå den. For at Docker containeren skal kunne nå
applikasjonen din må applikasjonen din lytte på 0.0.0.0 for å kunne nås fra containeren.
# docker-compose.yml
services:
skip-tilgangsstyring-local:
image: ghcr.io/kartverket/skip-tilgangsstyring-local:latest-dev
ports:
- "3010:3010"
- "8080:8080"
environment:
SECURITY_CONFIG_PATH: /securityconfig.yaml
OPA_HTTP_PORT: 3010
OPA_GRPC_PORT: 9191
PROXY_PORT: 8080
UPSTREAM_URL: http://host.docker.internal:3000
OPA_PATHS: /opa/policies,/opa/data/local
volumes:
- ./opa/policies:/opa/policies:ro
- ./opa/data/local:/opa/data/local:ro
- ./securityconfig.yaml:/securityconfig.yaml:ro
Følgende docker-compose.yaml kjører opp en proxy på port 8080 som tar imot requests, sender dem til OPA sin
gRPC-port på :9191, og sender requesten videre til http://localhost:3000 hvis OPA tillater det.
# docker-compose.yml
services:
skip-tilgangsstyring-local:
image: ghcr.io/kartverket/skip-tilgangsstyring-local:latest-dev
ports:
- "3010:3010"
- "8080:8080"
environment:
SECURITY_CONFIG_PATH: /securityconfig.yaml
OPA_HTTP_PORT: 3010
OPA_GRPC_PORT: 9191
PROXY_PORT: 8080
UPSTREAM_URL: http://localhost:3000
OPA_PATHS: /opa/policies,/opa/data/local
network_mode: host # NB: Dette settes for å kunne nå applikasjonen din på localhost
volumes:
- ./opa/policies:/opa/policies:ro
- ./opa/data/local:/opa/data/local:ro
- ./securityconfig.yaml:/securityconfig.yaml:ro
Følgende docker-compose.yaml kjører opp en proxy på port 8080 som tar imot requests, sender dem til OPA sin
gRPC-port på :9191, og sender requesten videre til http://host.docker.internal:3000
(http://localhost:3000på din maskin) hvis OPA tillater det.
Kjører applikasjonen din lokalt på maskinen (altså ikke i Docker) kan du bruke
host.docker.internal:<PORT> som UPSTREAM_HOST for å nå den. For at Docker containeren skal kunne nå
applikasjonen din må applikasjonen din lytte på 0.0.0.0 for å kunne nås fra containeren.
# docker-compose.yml
services:
skip-tilgangsstyring-local:
image: ghcr.io/kartverket/skip-tilgangsstyring-local:latest-dev
ports:
- "3010:3010"
- "8080:8080"
environment:
SECURITY_CONFIG_PATH: /securityconfig.yaml
OPA_HTTP_PORT: 3010
OPA_GRPC_PORT: 9191
PROXY_PORT: 8080
UPSTREAM_URL: http://host.docker.internal:3000
OPA_PATHS: /opa/policies,/opa/data/local
volumes:
- ./opa/policies:/opa/policies:ro
- ./opa/data/local:/opa/data/local:ro
- ./securityconfig.yaml:/securityconfig.yaml:ro