A typical organization will have several Applications & Deployments in multiple environments. Most of them would have some central Identity Provider like Keycloak or Azure AD/Okta...
While the identity provider issued OAuth2.0 token and solve the Identity problem, we didn't have a clean central way to handle API Authorization. This usually might be bundled along with the Application code.
For Authorization, OPA is an open-source CNCF graduated project that allows us to write Authorization logic in Declarative statements.
The goal today is to explore the OPA bundle feature. We can
- build policies using Rego,
- package them as bundles (tar files),
- and distribute them to various Applications or Deployment Clusters and the from a central location.
The central policy portal can organize your policies as the below diagram shows. An individual bundle is created at the environment level and it will have all the policies of the projects that the environment hosts.
In my organization, we had a similar distribution of environment.
All the APIs were fronted by various API Gateways. What we want is for every call should be intercepted by API Gateway and forwarded to the Authorization engine. If the Authorization engine returns false then the request should be declined with HTTP status 403. Below diagram represents this.
The below table gives details on how this can be achieved with different API Gateways.
API Gateway | Details |
---|---|
AWS API Gateway | - |
Traefik | Using Forward Auth Middleware |
NGINX | Module ngx_http_auth_request_module |
In our case, we have deployed OPA as a sidecar to a golang API project. The API receives a request from the API Gateway and then invokes the OPA. It parses the response received and if the Allow is set to false, then the API will return 403 to API Gateway.
Below is the yaml for the deployment of the API project and OPA. The configuration is from wsl2 desktop.
apiVersion: apps/v1
kind: Deployment
metadata:
name: authorization
namespace: default
labels:
app: authorization
spec:
replicas: 1
selector:
matchLabels:
app: authorization
template:
metadata:
labels:
app: authorization
spec:
containers:
- name: auth-policy-manager
image: naseemmohammed/policyengine:0.1.7
imagePullPolicy: IfNotPresent
env:
- name: ENV_AUTH_SERVER
value: ":8080"
- name: ENV_PPSA
value: "localhost"
- name: ENV_OPA_PORT
value: "8181"
ports:
- containerPort: 8080
- name: opa
image: openpolicyagent/opa:0.41.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8181
env:
# location to subscribe for new policy bundles
- name: AWS_REGION
value: us-east-2
- name: AWS_ACCESS_KEY_ID
value: AKIA52XXXUIISSCC-FAKE
- name: AWS_SECRET_ACCESS_KEY
value: E/VLCUZJ2G-NOTEXISTING-aUhmsMcI33yS8O
args:
- "run"
- "--ignore=.*" # exclude hidden dirs created by Kubernetes
- "--server"
- "--set=decision_logs.console=true"
- "--config-file"
- "/config/config.yaml"
volumeMounts:
- readOnly: true
mountPath: /config
name: config-volume
livenessProbe:
httpGet:
scheme: HTTP # assumes OPA listens on localhost:8181
port: 8181
initialDelaySeconds: 5 # tune these periods for your environemnt
periodSeconds: 5000 # in prod reduce to 5
readinessProbe:
httpGet:
path: /health?bundle=true # Include bundle activation in readiness
scheme: HTTP
port: 8181
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: config-volume
hostPath:
# directory location on host
path: /run/desktop/mnt/host/c/Users/nmohammed/Downloads/cluster-files
# this field is optional
type: Directory
imagePullSecrets:
- name: topsecret
Now the OPA configuration file below
services:
s3:
url: https://zohoohio.s3.us-east-2.amazonaws.com
credentials:
s3_signing:
environment_credentials: {}
bundles:
authz:
service: s3
resource: Zoho-onprem/bundle.tar.gz
persist: false
polling:
min_delay_seconds: 100
max_delay_seconds: 200
Top comments (0)