Skip to content

Commit d42bc4f

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

File tree

1 file changed

+370
-0
lines changed

1 file changed

+370
-0
lines changed

doc/user-guides/authzed.md

+370
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
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:
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+
credentials:
249+
authorizationHeader:
250+
prefix: APIKEY
251+
authorization:
252+
"authzed-spicedb":
253+
spicedb:
254+
endpoint: spicedb.spicedb.svc.cluster.local:50051
255+
insecure: true
256+
sharedSecretRef:
257+
name: spicedb
258+
key: grpc-preshared-key
259+
subject:
260+
kind:
261+
value: blog/user
262+
name:
263+
selector: auth.identity.metadata.annotations.username
264+
resource:
265+
kind:
266+
value: blog/post
267+
name:
268+
selector: context.request.http.path.@extract:{"sep":"/","pos":2}
269+
permission:
270+
selector: context.request.http.method.@replace:{"old":"GET","new":"read"}.@replace:{"old":"POST","new":"write"}
271+
EOF
272+
```
273+
274+
### ⑤ Create the API keys
275+
276+
For Emilia (writer):
277+
278+
```sh
279+
kubectl -n kuadrant-system apply -f -<<EOF
280+
apiVersion: v1
281+
kind: Secret
282+
metadata:
283+
name: api-key-writer
284+
labels:
285+
authorino.kuadrant.io/managed-by: authorino
286+
app: talker-api
287+
annotations:
288+
username: emilia
289+
stringData:
290+
api_key: IAMEMILIA
291+
EOF
292+
```
293+
294+
For Beatrice (reader):
295+
296+
```sh
297+
kubectl -n kuadrant-system apply -f -<<EOF
298+
apiVersion: v1
299+
kind: Secret
300+
metadata:
301+
name: api-key-reader
302+
labels:
303+
authorino.kuadrant.io/managed-by: authorino
304+
app: talker-api
305+
annotations:
306+
username: beatrice
307+
stringData:
308+
api_key: IAMBEATRICE
309+
EOF
310+
```
311+
312+
### ⑥ Consume the API
313+
314+
As Emilia, send a GET request:
315+
316+
```sh
317+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMEMILIA' \
318+
-X GET \
319+
http://$GATEWAY_URL/posts/1 -i
320+
# HTTP/1.1 200 OK
321+
```
322+
323+
As Emilia, send a POST request:
324+
325+
```sh
326+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMEMILIA' \
327+
-X POST \
328+
http://$GATEWAY_URL/posts/1 -i
329+
# HTTP/1.1 200 OK
330+
```
331+
332+
As Beatrice, send a GET request:
333+
334+
```sh
335+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMBEATRICE' \
336+
-X GET \
337+
http://$GATEWAY_URL/posts/1 -i
338+
# HTTP/1.1 200 OK
339+
```
340+
341+
As Beatrice, send a POST request:
342+
343+
```sh
344+
curl -H 'Host: api.toystore.com' -H 'Authorization: APIKEY IAMBEATRICE' \
345+
-X POST \
346+
http://$GATEWAY_URL/posts/1 -i
347+
# HTTP/1.1 403 Forbidden
348+
# x-ext-auth-reason: PERMISSIONSHIP_NO_PERMISSION;token=GhUKEzE2NzU3MDE3MjAwMDAwMDAwMDA=
349+
```
350+
351+
## Cleanup
352+
353+
If you have started a Kubernetes cluster locally with Kind to try this user guide, delete it by running:
354+
355+
```sh
356+
make local-cleanup
357+
```
358+
359+
Otherwise, delete the resources created in each step:
360+
361+
```sh
362+
kubectl delete -f examples/toystore/toystore.yaml
363+
kubectl delete httproute toystore
364+
kubectl delete authpolicy route-auth
365+
kubectl delete kuadrant kuadrant -n kuadrant-system
366+
kubectl delete namespace spicedb
367+
kubectl delete secret api-key-reader -n kuadrant-system
368+
kubectl delete secret api-key-writer -n kuadrant-system
369+
kubectl delete secret spicedb -n kuadrant-system
370+
```

0 commit comments

Comments
 (0)