Skip to content

Commit c164ae2

Browse files
committed
guides: auth authzd/spicedb
Signed-off-by: KevFan <[email protected]>
1 parent ebdce57 commit c164ae2

File tree

1 file changed

+371
-0
lines changed

1 file changed

+371
-0
lines changed

doc/user-guides/authzed.md

+371
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
# AuthPolicy Integration with Authzed/SpiceDB
2+
3+
This guide explains how to configure permission requests for a Google Zanzibar-based [Authzed/SpiceDB](https://authzed.com) instance using gRPC.
4+
5+
## Requisites
6+
7+
- [Docker](https://docker.io)
8+
9+
## Run the guide ① → ⑥
10+
11+
### ① Setup
12+
13+
Clone the repo:
14+
15+
```sh
16+
git clone [email protected]:Kuadrant/kuadrant-operator.git && cd kuadrant-operator
17+
```
18+
19+
Run the following command to create a local Kubernetes cluster with [Kind](https://kind.sigs.k8s.io/), install & deploy Kuadrant:
20+
21+
```sh
22+
make local-setup
23+
```
24+
25+
Request an instance of Kuadrant in the `kuadrant-system` namespace:
26+
27+
```sh
28+
kubectl -n kuadrant-system apply -f - <<EOF
29+
apiVersion: kuadrant.io/v1beta1
30+
kind: Kuadrant
31+
metadata:
32+
name: kuadrant
33+
spec: {}
34+
EOF
35+
```
36+
37+
### ② Deploy the Talker API
38+
39+
```sh
40+
kubectl apply -f examples/toystore/toystore.yaml
41+
42+
kubectl apply -f - <<EOF
43+
apiVersion: gateway.networking.k8s.io/v1
44+
kind: HTTPRoute
45+
metadata:
46+
name: toystore
47+
spec:
48+
parentRefs:
49+
- name: kuadrant-ingressgateway
50+
namespace: gateway-system
51+
hostnames:
52+
- api.toystore.com
53+
rules:
54+
- matches:
55+
- method: GET
56+
path:
57+
type: PathPrefix
58+
value: "/posts"
59+
- method: POST
60+
path:
61+
type: PathPrefix
62+
value: "/posts"
63+
backendRefs:
64+
- name: toystore
65+
port: 80
66+
EOF
67+
```
68+
69+
Export the gateway hostname and port:
70+
71+
```sh
72+
export INGRESS_HOST=$(kubectl get gtw kuadrant-ingressgateway -n gateway-system -o jsonpath='{.status.addresses[0].value}')
73+
export INGRESS_PORT=$(kubectl get gtw kuadrant-ingressgateway -n gateway-system -o jsonpath='{.spec.listeners[?(@.name=="http")].port}')
74+
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
75+
```
76+
77+
Test requests to the unprotected application:
78+
79+
```sh
80+
curl -H 'Host: api.toystore.com' http://$GATEWAY_URL/posts -i
81+
# HTTP/1.1 200 OK
82+
```
83+
84+
### ③ Create the permission database
85+
86+
Create the namespace for SpiceDB:
87+
88+
```sh
89+
kubectl create namespace spicedb
90+
```
91+
92+
Deploy the SpiceDB instance:
93+
94+
```sh
95+
kubectl -n spicedb apply -f -<<EOF
96+
apiVersion: apps/v1
97+
kind: Deployment
98+
metadata:
99+
name: spicedb
100+
labels:
101+
app: spicedb
102+
spec:
103+
selector:
104+
matchLabels:
105+
app: spicedb
106+
template:
107+
metadata:
108+
labels:
109+
app: spicedb
110+
spec:
111+
containers:
112+
- name: spicedb
113+
image: authzed/spicedb
114+
args:
115+
- serve
116+
- "--grpc-preshared-key"
117+
- secret
118+
- "--http-enabled"
119+
ports:
120+
- containerPort: 50051
121+
- containerPort: 8443
122+
replicas: 1
123+
---
124+
apiVersion: v1
125+
kind: Service
126+
metadata:
127+
name: spicedb
128+
spec:
129+
selector:
130+
app: spicedb
131+
ports:
132+
- name: grpc
133+
port: 50051
134+
protocol: TCP
135+
- name: http
136+
port: 8443
137+
protocol: TCP
138+
EOF
139+
```
140+
141+
Forward local request to the SpiceDB service inside the cluster:
142+
143+
```sh
144+
kubectl -n spicedb port-forward service/spicedb 8443:8443 2>&1 >/dev/null &
145+
```
146+
147+
Create the permission schema:
148+
149+
```sh
150+
curl -X POST http://localhost:8443/v1/schema/write \
151+
-H 'Authorization: Bearer secret' \
152+
-H 'Content-Type: application/json' \
153+
-d @- << EOF
154+
{
155+
"schema": "definition blog/user {}\ndefinition blog/post {\n\trelation reader: blog/user\n\trelation writer: blog/user\n\n\tpermission read = reader + writer\n\tpermission write = writer\n}"
156+
}
157+
EOF
158+
```
159+
160+
Create the relationships:
161+
162+
- `blog/user:emilia``writer` of `blog/post:1`
163+
- `blog/user:beatrice``reader` of `blog/post:1`
164+
165+
```sh
166+
curl -X POST http://localhost:8443/v1/relationships/write \
167+
-H 'Authorization: Bearer secret' \
168+
-H 'Content-Type: application/json' \
169+
-d @- << EOF
170+
{
171+
"updates": [
172+
{
173+
"operation": "OPERATION_CREATE",
174+
"relationship": {
175+
"resource": {
176+
"objectType": "blog/post",
177+
"objectId": "1"
178+
},
179+
"relation": "writer",
180+
"subject": {
181+
"object": {
182+
"objectType": "blog/user",
183+
"objectId": "emilia"
184+
}
185+
}
186+
}
187+
},
188+
{
189+
"operation": "OPERATION_CREATE",
190+
"relationship": {
191+
"resource": {
192+
"objectType": "blog/post",
193+
"objectId": "1"
194+
},
195+
"relation": "reader",
196+
"subject": {
197+
"object": {
198+
"objectType": "blog/user",
199+
"objectId": "beatrice"
200+
}
201+
}
202+
}
203+
}
204+
]
205+
}
206+
EOF
207+
```
208+
209+
### ④ Create an `AuthPolicy`
210+
211+
Store the shared token for Authorino authentication with the SpiceDB instance (must be created in the same namespace as the Kuadrant CR):
212+
213+
```sh
214+
kubectl -n kuadrant-system apply -f -<<EOF
215+
apiVersion: v1
216+
kind: Secret
217+
metadata:
218+
name: spicedb
219+
labels:
220+
app: spicedb
221+
stringData:
222+
grpc-preshared-key: secret
223+
EOF
224+
```
225+
226+
Create `AuthPolicy` custom resource declaring the auth rules to be enforced:
227+
228+
```sh
229+
kubectl apply -f - <<EOF
230+
apiVersion: kuadrant.io/v1
231+
kind: AuthPolicy
232+
metadata:
233+
name: route-auth
234+
spec:
235+
targetRef:
236+
group: gateway.networking.k8s.io
237+
kind: HTTPRoute
238+
name: toystore
239+
defaults:
240+
strategy: atomic
241+
rules:
242+
authentication:
243+
"blog-users":
244+
apiKey:
245+
selector:
246+
matchLabels:
247+
app: talker-api
248+
allNamespaces: true
249+
credentials:
250+
authorizationHeader:
251+
prefix: APIKEY
252+
authorization:
253+
"authzed-spicedb":
254+
spicedb:
255+
endpoint: spicedb.spicedb.svc.cluster.local:50051
256+
insecure: true
257+
sharedSecretRef:
258+
name: spicedb
259+
key: grpc-preshared-key
260+
subject:
261+
kind:
262+
value: blog/user
263+
name:
264+
selector: auth.identity.metadata.annotations.username
265+
resource:
266+
kind:
267+
value: blog/post
268+
name:
269+
selector: context.request.http.path.@extract:{"sep":"/","pos":2}
270+
permission:
271+
selector: context.request.http.method.@replace:{"old":"GET","new":"read"}.@replace:{"old":"POST","new":"write"}
272+
EOF
273+
```
274+
275+
### ⑤ Create the API keys
276+
277+
For Emilia (writer):
278+
279+
```sh
280+
kubectl apply -f -<<EOF
281+
apiVersion: v1
282+
kind: Secret
283+
metadata:
284+
name: api-key-writer
285+
labels:
286+
authorino.kuadrant.io/managed-by: authorino
287+
app: talker-api
288+
annotations:
289+
username: emilia
290+
stringData:
291+
api_key: IAMEMILIA
292+
EOF
293+
```
294+
295+
For Beatrice (reader):
296+
297+
```sh
298+
kubectl apply -f -<<EOF
299+
apiVersion: v1
300+
kind: Secret
301+
metadata:
302+
name: api-key-reader
303+
labels:
304+
authorino.kuadrant.io/managed-by: authorino
305+
app: talker-api
306+
annotations:
307+
username: beatrice
308+
stringData:
309+
api_key: IAMBEATRICE
310+
EOF
311+
```
312+
313+
### ⑥ Consume the API
314+
315+
As Emilia, send a GET request:
316+
317+
```sh
318+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMEMILIA' \
319+
-X GET \
320+
http://$GATEWAY_URL/posts/1 -i
321+
# HTTP/1.1 200 OK
322+
```
323+
324+
As Emilia, send a POST request:
325+
326+
```sh
327+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMEMILIA' \
328+
-X POST \
329+
http://$GATEWAY_URL/posts/1 -i
330+
# HTTP/1.1 200 OK
331+
```
332+
333+
As Beatrice, send a GET request:
334+
335+
```sh
336+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMBEATRICE' \
337+
-X GET \
338+
http://$GATEWAY_URL/posts/1 -i
339+
# HTTP/1.1 200 OK
340+
```
341+
342+
As Beatrice, send a POST request:
343+
344+
```sh
345+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMBEATRICE' \
346+
-X POST \
347+
http://$GATEWAY_URL/posts/1 -i
348+
# HTTP/1.1 403 Forbidden
349+
# x-ext-auth-reason: PERMISSIONSHIP_NO_PERMISSION;token=GhUKEzE2NzU3MDE3MjAwMDAwMDAwMDA=
350+
```
351+
352+
## Cleanup
353+
354+
If you have started a Kubernetes cluster locally with Kind to try this user guide, delete it by running:
355+
356+
```sh
357+
make local-cleanup
358+
```
359+
360+
Otherwise, delete the resources created in each step:
361+
362+
```sh
363+
kubectl delete -f examples/toystore/toystore.yaml
364+
kubectl delete httproute toystore
365+
kubectl delete authpolicy route-auth
366+
kubectl delete kuadrant kuadrant -n kuadrant-system
367+
kubectl delete namespace spicedb
368+
kubectl delete secret api-key-reader
369+
kubectl delete secret api-key-writer
370+
kubectl delete secret spicedb -n kuadrant-system
371+
```

0 commit comments

Comments
 (0)