Skip to content

Commit b5089ba

Browse files
authored
Merge pull request #100 from josephschorr/small-improvements
Small improvements to the proxy
2 parents ea67681 + 4745925 commit b5089ba

File tree

12 files changed

+86
-82
lines changed

12 files changed

+86
-82
lines changed

README.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# spicedb-kubeapi-proxy
22

3-
`spicedb-kubeapi-proxy` is a proxy that runs in between clients and the kube
4-
apiserver that can authorize requests and filter responses using an embedded or
3+
`spicedb-kubeapi-proxy` is a proxy that runs in between clients and the kube
4+
apiserver that can authorize requests and filter responses using an embedded or
55
remote SpiceDB.
66

77
## Status
@@ -30,13 +30,13 @@ the current state of the project, but the primary goals before 1.0 are:
3030
![Arch Diagram Dark](./docs/proxy-arch-dark.png#gh-dark-mode-only)![Arch Diagram Light](./docs/proxy-arch-light.png#gh-light-mode-only)
3131

3232
The proxy authenticates itself with the downstream kube-apiserver (client certs
33-
if running out-of-cluster, service account token if running in-cluster).
33+
if running out-of-cluster, service account token if running in-cluster).
3434
The proxy is configured with a set of rules that define how to authorize requests
3535
and how to filter responses by communicating with SpiceDB.
3636

3737
There are three basic types of rule:
3838

39-
- **Check** rules: these are used to authorize whether a request is allowed to
39+
- **Check** rules: these are used to authorize whether a request is allowed to
4040
proceed at all. For example, a rule might say that a user can only list pods
4141
in a namespace `foo` if they have a `namespace:foo#list@user:alice` permission
4242
in SpiceDB.
@@ -46,34 +46,36 @@ There are three basic types of rule:
4646
in SpiceDB that enumerate the allowed pods, like `pod:foo/a#view@user:alice`
4747
and `pod:foo/b#view@user:alice`. In this example, `alice` would see pods `a`
4848
and `b` in namespace `foo`, but no others.
49-
- **Write** rules: these are used to write data to SpiceDB based on the request
50-
that the proxy is authorizing. For example, if `alice` creates a new pod `c`
51-
in namespace `foo`, a rule can determine that a relationship should be written
52-
to SpiceDB that grants ownership, i.e. `pod:foo/a#view@user:alice`.
49+
- **Update Relationship** rules: these are used to write/delete data in
50+
SpiceDB based on the request that the proxy is authorizing. For example,
51+
if `alice` creates a new pod `c` in namespace `foo`, a rule can determine
52+
that a relationship should be written to SpiceDB that grants ownership,
53+
i.e. `pod:foo/a#view@user:alice`.
5354

5455
Rules often work in tendem; for example, a `Check` rule might authorize a request
5556
to list pods in a namespace, and a `Filter` rule might further restrict the
5657
response to only include certain pods.
5758

5859
Note that the proxy does not assume anything about the structure of the data in
5960
SpiceDB. It is up to the user to define the data in SpiceDB and the rules that
60-
the proxy uses to authorize and filter requests.
61+
the proxy uses to authorize and filter requests.
6162

62-
The proxy rejects any request for which it doesn't find a matching rule.
63+
The proxy rejects any request for which it doesn't find a matching rule.
6364

6465
# Development
6566

6667
This project uses `mage` to offer various development-related commands.
6768

6869
```bash
69-
# run to get all available commands
70+
# run to get all available commands
7071
brew install mage
7172
mage
7273
```
7374

7475
## Tests
7576

7677
Runs both unit and e2e tests
78+
7779
```bash
7880
mage test:all
7981
```

deploy/rules.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ match:
77
verbs: ["create"]
88
mustNot:
99
- tpl: "namespace:{{name}}#cluster@cluster:cluster"
10-
write:
10+
update:
1111
- tpl: "namespace:{{name}}#creator@user:{{user.Name}}"
1212
- tpl: "namespace:{{name}}#cluster@cluster:cluster"
1313
---
@@ -18,7 +18,7 @@ match:
1818
- apiVersion: v1
1919
resource: namespaces
2020
verbs: ["delete"]
21-
write:
21+
update:
2222
- tpl: "namespace:{{name}}#creator@user:{{user.Name}}"
2323
- tpl: "namespace:{{name}}#cluster@cluster:cluster"
2424
---
@@ -40,7 +40,7 @@ match:
4040
prefilter:
4141
- name: "resourceId"
4242
byResource:
43-
tpl: "namespace:*#view@user:{{user.Name}}"
43+
tpl: "namespace:$resourceID#view@user:{{user.Name}}"
4444
---
4545
apiVersion: authzed.com/v1alpha1
4646
kind: ProxyRule
@@ -51,7 +51,7 @@ match:
5151
verbs: ["create"]
5252
mustNot:
5353
- tpl: "pod:{{name}}#namespace@namespace:{{namespace}}"
54-
write:
54+
update:
5555
- tpl: "pod:{{namespacedName}}#creator@user:{{user.Name}}"
5656
- tpl: "pod:{{name}}#namespace@namespace:{{namespace}}"
5757
---
@@ -62,7 +62,7 @@ match:
6262
- apiVersion: v1
6363
resource: pods
6464
verbs: ["delete"]
65-
write:
65+
update:
6666
- tpl: "pod:{{namespacedName}}#creator@user:{{user.Name}}"
6767
- tpl: "pod:{{name}}#namespace@namespace:{{namespace}}"
6868
---
@@ -85,4 +85,4 @@ prefilter:
8585
- namespace: "splitNamespace(resourceId)"
8686
name: "splitName(resourceId)"
8787
byResource:
88-
tpl: "pod:*#view@user:{{user.Name}}"
88+
tpl: "pod:$resourceID#view@user:{{user.Name}}"

e2e/proxy_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ var (
623623
Resource: "namespaces",
624624
Verbs: []string{"create"},
625625
}},
626-
Writes: []proxyrule.StringOrTemplate{{
626+
Updates: []proxyrule.StringOrTemplate{{
627627
Template: "namespace:{{name}}#creator@user:{{user.Name}}",
628628
}, {
629629
Template: "namespace:{{name}}#cluster@cluster:cluster",
@@ -639,7 +639,7 @@ var (
639639
Resource: "namespaces",
640640
Verbs: []string{"delete"},
641641
}},
642-
Writes: []proxyrule.StringOrTemplate{{
642+
Updates: []proxyrule.StringOrTemplate{{
643643
Template: "namespace:{{name}}#creator@user:{{user.Name}}",
644644
}, {
645645
Template: "namespace:{{name}}#cluster@cluster:cluster",
@@ -669,7 +669,7 @@ var (
669669
}},
670670
PreFilters: []proxyrule.PreFilter{{
671671
Name: "resourceId",
672-
ByResource: &proxyrule.StringOrTemplate{Template: "namespace:*#view@user:{{user.Name}}"},
672+
ByResource: &proxyrule.StringOrTemplate{Template: "namespace:$resourceID#view@user:{{user.Name}}"},
673673
}},
674674
},
675675
}
@@ -682,7 +682,7 @@ var (
682682
Resource: "pods",
683683
Verbs: []string{"create"},
684684
}},
685-
Writes: []proxyrule.StringOrTemplate{{
685+
Updates: []proxyrule.StringOrTemplate{{
686686
Template: "pod:{{namespacedName}}#creator@user:{{user.Name}}",
687687
}, {
688688
Template: "pod:{{name}}#namespace@namespace:{{namespace}}",
@@ -701,7 +701,7 @@ var (
701701
Checks: []proxyrule.StringOrTemplate{{
702702
Template: "pod:{{namespacedName}}#edit@user:{{user.Name}}",
703703
}},
704-
Writes: []proxyrule.StringOrTemplate{{
704+
Updates: []proxyrule.StringOrTemplate{{
705705
Template: "pod:{{namespacedName}}#creator@user:{{user.Name}}",
706706
}, {
707707
Template: "pod:{{name}}#namespace@namespace:{{namespace}}",
@@ -745,7 +745,7 @@ var (
745745
PreFilters: []proxyrule.PreFilter{{
746746
Namespace: "splitNamespace(resourceId)",
747747
Name: "splitName(resourceId)",
748-
ByResource: &proxyrule.StringOrTemplate{Template: "pod:*#view@user:{{user.Name}}"},
748+
ByResource: &proxyrule.StringOrTemplate{Template: "pod:$resourceID#view@user:{{user.Name}}"},
749749
}},
750750
},
751751
}

pkg/authz/distributedtx/workflow.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package distributedtx
22

33
import (
44
"fmt"
5-
"k8s.io/klog/v2"
65
"net/http"
76
"time"
87

8+
"k8s.io/klog/v2"
9+
910
"google.golang.org/grpc/codes"
1011
"google.golang.org/grpc/status"
1112
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -43,7 +44,7 @@ type WriteObjInput struct {
4344
Header http.Header
4445
UserInfo *user.DefaultInfo
4546
ObjectMeta *metav1.ObjectMeta
46-
Rels []*v1.Relationship
47+
UpdateRels []*v1.Relationship
4748
Preconditions []*v1.Precondition
4849
Body []byte
4950
}
@@ -142,13 +143,14 @@ func PessimisticWriteToSpiceDBAndKube(ctx workflow.Context, input *WriteObjInput
142143
}
143144
preconditions = append(preconditions, input.Preconditions...)
144145

146+
rels := input.UpdateRels
145147
operation := v1.RelationshipUpdate_OPERATION_TOUCH
146148
if input.RequestInfo.Verb == "delete" {
147149
operation = v1.RelationshipUpdate_OPERATION_DELETE
148150
}
149151

150-
updates := make([]*v1.RelationshipUpdate, 0, len(input.Rels))
151-
for _, r := range input.Rels {
152+
updates := make([]*v1.RelationshipUpdate, 0, len(rels))
153+
for _, r := range rels {
152154
updates = append(updates, &v1.RelationshipUpdate{
153155
Operation: operation,
154156
Relationship: r,
@@ -239,13 +241,14 @@ func OptimisticWriteToSpiceDBAndKube(ctx workflow.Context, input *WriteObjInput)
239241
}
240242

241243
// TODO: this could optionally use dry-run to preflight the kube request
244+
rels := input.UpdateRels
242245
operation := v1.RelationshipUpdate_OPERATION_CREATE
243246
if input.RequestInfo.Verb == "delete" {
244247
operation = v1.RelationshipUpdate_OPERATION_DELETE
245248
}
246249

247-
updates := make([]*v1.RelationshipUpdate, 0, len(input.Rels))
248-
for _, r := range input.Rels {
250+
updates := make([]*v1.RelationshipUpdate, 0, len(rels))
251+
for _, r := range rels {
249252
updates = append(updates, &v1.RelationshipUpdate{
250253
Operation: operation,
251254
Relationship: r,

pkg/authz/distributedtx/workflow_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestWorkflow(t *testing.T) {
7070
RequestInfo: &request.RequestInfo{Verb: "create"},
7171
UserInfo: &user.DefaultInfo{Name: "janedoe"},
7272
ObjectMeta: &metav1.ObjectMeta{Name: "my_object_meta"},
73-
Rels: []*v1.Relationship{{
73+
UpdateRels: []*v1.Relationship{{
7474
Resource: &v1.ObjectReference{
7575
ObjectType: "namespace",
7676
ObjectId: "my_object_meta",

pkg/authz/filter.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,18 @@ func filterWatch(ctx context.Context, client v1.PermissionsServiceClient, watchC
177177
OptionalObjectTypes: []string{filter.Rel.ResourceType},
178178
})
179179
if err != nil {
180-
fmt.Println(err)
180+
klog.V(3).ErrorS(err, "error on filterWatch")
181181
return
182182
}
183+
183184
for {
184185
resp, err := watchResource.Recv()
185186
if errors.Is(err, io.EOF) {
186187
break
187188
}
188189

189190
if err != nil {
190-
fmt.Println(err)
191+
klog.V(3).ErrorS(err, "error on watchResource.Recv")
191192
return
192193
}
193194

@@ -211,7 +212,7 @@ func filterWatch(ctx context.Context, client v1.PermissionsServiceClient, watchC
211212
},
212213
})
213214
if err != nil {
214-
fmt.Println(err)
215+
klog.V(3).ErrorS(err, "error on CheckPermission")
215216
return
216217
}
217218

@@ -225,32 +226,30 @@ func filterWatch(ctx context.Context, client v1.PermissionsServiceClient, watchC
225226
fmt.Println(err)
226227
return
227228
}
228-
fmt.Println(data)
229-
fmt.Println("RESPONSE", string(byteIn))
230229

231230
name, err := filter.Name.Search(data)
232231
if err != nil {
233-
fmt.Println(err)
232+
klog.V(3).ErrorS(err, "error on filter.Name.Search")
234233
return
235234
}
236-
fmt.Println("GOT NAME", name)
235+
237236
if name == nil || len(name.(string)) == 0 {
238237
return
239238
}
239+
240240
namespace, err := filter.Namespace.Search(data)
241241
if err != nil {
242-
fmt.Println(err)
242+
klog.V(3).ErrorS(err, "error on filter.Namespace.Search")
243243
return
244244
}
245-
fmt.Println("GOT NAMESPACE", namespace)
246245
if namespace == nil {
247246
namespace = ""
248247
}
248+
249249
nn := types.NamespacedName{Name: name.(string), Namespace: namespace.(string)}
250250

251251
// TODO: this should really be over a single channel to prevent
252252
// races on add/remove
253-
fmt.Println(u.Relationship.Resource.ObjectId, cr.Permissionship)
254253
if cr.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION {
255254
authzData.allowedNNC <- nn
256255
} else {

pkg/authz/write.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ import (
1616

1717
// write performs a dual write according to the passed rule
1818
func write(ctx context.Context, w http.ResponseWriter, r *rules.RunnableRule, input *rules.ResolveInput, workflowClient *client.Client) error {
19-
writeRels := make([]*v1.Relationship, 0, len(r.Writes))
20-
for _, write := range r.Writes {
19+
updateRels := make([]*v1.Relationship, 0, len(r.Updates))
20+
for _, write := range r.Updates {
2121
write := write
2222
rel, err := rules.ResolveRel(write, input)
2323
if err != nil {
2424
return fmt.Errorf("unable to resolve write rule (%v): %w", rel, err)
2525
}
26-
writeRels = append(writeRels, &v1.Relationship{
26+
updateRels = append(updateRels, &v1.Relationship{
2727
Resource: &v1.ObjectReference{
2828
ObjectType: rel.ResourceType,
2929
ObjectId: rel.ResourceID,
@@ -59,7 +59,7 @@ func write(ctx context.Context, w http.ResponseWriter, r *rules.RunnableRule, in
5959
preconditions = append(preconditions, p)
6060
}
6161

62-
resp, err := dualWrite(ctx, workflowClient, input, writeRels, preconditions, r.LockMode)
62+
resp, err := dualWrite(ctx, workflowClient, input, updateRels, preconditions, r.LockMode)
6363
if err != nil {
6464
return fmt.Errorf("dual write failed: %w", err)
6565
}
@@ -82,7 +82,7 @@ func write(ctx context.Context, w http.ResponseWriter, r *rules.RunnableRule, in
8282
// getWriteRule returns the first matching rule with `write` defined
8383
func getWriteRule(matchingRules []*rules.RunnableRule) *rules.RunnableRule {
8484
for _, r := range matchingRules {
85-
if len(r.Writes) > 0 {
85+
if len(r.Updates) > 0 {
8686
// we can only do one dual-write per request without some way of
8787
// marking some writes async.
8888
return r
@@ -93,13 +93,13 @@ func getWriteRule(matchingRules []*rules.RunnableRule) *rules.RunnableRule {
9393

9494
// dualWrite configures the dtx for writing to kube and spicedb and waits for
9595
// the response
96-
func dualWrite(ctx context.Context, workflowClient *client.Client, input *rules.ResolveInput, rels []*v1.Relationship, preconditions []*v1.Precondition, lockMode proxyrule.LockMode) (*distributedtx.KubeResp, error) {
96+
func dualWrite(ctx context.Context, workflowClient *client.Client, input *rules.ResolveInput, updateRels []*v1.Relationship, preconditions []*v1.Precondition, lockMode proxyrule.LockMode) (*distributedtx.KubeResp, error) {
9797
writeInput := &distributedtx.WriteObjInput{
9898
RequestInfo: input.Request,
9999
UserInfo: input.User,
100100
Body: input.Body,
101101
Header: input.Headers,
102-
Rels: rels,
102+
UpdateRels: updateRels,
103103
Preconditions: preconditions,
104104
}
105105
if input.Object != nil {
@@ -129,22 +129,22 @@ func preconditionFromRel(rel *rules.ResolvedRel) *v1.Precondition {
129129
ResourceType: rel.ResourceType,
130130
},
131131
}
132-
if rel.ResourceID != "*" {
132+
if rel.ResourceID != "$resourceID" {
133133
p.Filter.OptionalResourceId = rel.ResourceID
134134
}
135-
if rel.ResourceRelation != "*" {
135+
if rel.ResourceRelation != "$resourceRelation" {
136136
p.Filter.OptionalRelation = rel.ResourceRelation
137137
}
138-
if rel.SubjectType != "*" || rel.SubjectID != "*" || rel.SubjectRelation != "*" {
138+
if rel.SubjectType != "$subjectType" || rel.SubjectID != "$subjectID" || rel.SubjectRelation != "$subjectRelation" {
139139
p.Filter.OptionalSubjectFilter = &v1.SubjectFilter{}
140140
}
141-
if rel.SubjectType != "*" {
141+
if rel.SubjectType != "$subjectType" {
142142
p.Filter.OptionalSubjectFilter.SubjectType = rel.SubjectType
143143
}
144-
if rel.SubjectID != "*" {
144+
if rel.SubjectID != "$subjectID" {
145145
p.Filter.OptionalSubjectFilter.OptionalSubjectId = rel.SubjectID
146146
}
147-
if rel.SubjectRelation != "*" && rel.SubjectRelation != "" {
147+
if rel.SubjectRelation != "$subjectRelation" && rel.SubjectRelation != "" {
148148
p.Filter.OptionalSubjectFilter.OptionalRelation = &v1.SubjectFilter_RelationFilter{
149149
Relation: rel.SubjectRelation,
150150
}

0 commit comments

Comments
 (0)