Skip to content

Commit d771db9

Browse files
authored
feat: add the code of Kubernetes CRD-backed persistence adapter for Casbin
1 parent 4e725f7 commit d771db9

File tree

13 files changed

+1327
-1
lines changed

13 files changed

+1327
-1
lines changed

.github/workflows/ci.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
test:
13+
name: Test
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v5
23+
with:
24+
go-version: '1.23.0'
25+
26+
- name: Download dependencies
27+
run: go mod download
28+
29+
- name: Run tests
30+
run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
31+
32+
- name: Upload coverage to Codecov
33+
uses: codecov/codecov-action@v4
34+
with:
35+
file: ./coverage.txt
36+
flags: unittests
37+
token: ${{ secrets.CODECOV_TOKEN }}
38+
39+
lint:
40+
name: Lint
41+
runs-on: ubuntu-latest
42+
permissions:
43+
contents: read
44+
steps:
45+
- name: Checkout code
46+
uses: actions/checkout@v4
47+
48+
- name: Set up Go
49+
uses: actions/setup-go@v5
50+
with:
51+
go-version: '1.23.0'
52+
53+
- name: golangci-lint
54+
uses: golangci/golangci-lint-action@v6
55+
with:
56+
version: latest
57+
58+
release:
59+
name: Release
60+
runs-on: ubuntu-latest
61+
needs: [test, lint]
62+
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
63+
permissions:
64+
contents: write
65+
issues: write
66+
pull-requests: write
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v4
70+
with:
71+
fetch-depth: 0
72+
persist-credentials: false
73+
74+
- name: Set up Node.js
75+
uses: actions/setup-node@v4
76+
with:
77+
node-version: '20'
78+
79+
- name: Install semantic-release
80+
run: |
81+
npm install -g semantic-release@24 @semantic-release/git@10 @semantic-release/changelog@6 @semantic-release/github@10
82+
83+
- name: Release
84+
env:
85+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
86+
run: npx semantic-release

.golangci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
linters:
2+
enable:
3+
- gofmt
4+
- govet
5+
- errcheck
6+
- staticcheck
7+
- unused
8+
- gosimple
9+
- ineffassign
10+
- misspell
11+
- gocyclo
12+
- revive
13+
14+
linters-settings:
15+
gocyclo:
16+
min-complexity: 15
17+
revive:
18+
rules:
19+
- name: exported
20+
disabled: false
21+
22+
issues:
23+
exclude-use-default: false
24+
max-issues-per-linter: 0
25+
max-same-issues: 0
26+
27+
run:
28+
timeout: 5m
29+
go: '1.23'

.releaserc.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"branches": ["master"],
3+
"plugins": [
4+
"@semantic-release/commit-analyzer",
5+
"@semantic-release/release-notes-generator",
6+
"@semantic-release/changelog",
7+
[
8+
"@semantic-release/git",
9+
{
10+
"assets": ["CHANGELOG.md"],
11+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
12+
}
13+
],
14+
"@semantic-release/github"
15+
]
16+
}

README.md

Lines changed: 243 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,243 @@
1-
# casbin-crd-adapter
1+
# Casbin CRD Adapter
2+
3+
[![Go Report Card](https://goreportcard.com/badge/github.com/casbin/casbin-crd-adapter)](https://goreportcard.com/report/github.com/casbin/casbin-crd-adapter)
4+
[![CI](https://github.com/casbin/casbin-crd-adapter/workflows/CI/badge.svg)](https://github.com/casbin/casbin-crd-adapter/actions)
5+
[![Coverage Status](https://codecov.io/gh/casbin/casbin-crd-adapter/branch/master/graph/badge.svg)](https://codecov.io/gh/casbin/casbin-crd-adapter)
6+
[![GoDoc](https://godoc.org/github.com/casbin/casbin-crd-adapter?status.svg)](https://godoc.org/github.com/casbin/casbin-crd-adapter)
7+
[![Release](https://img.shields.io/github/release/casbin/casbin-crd-adapter.svg)](https://github.com/casbin/casbin-crd-adapter/releases/latest)
8+
[![Discord](https://img.shields.io/discord/1022748306096537660?logo=discord&label=discord&color=5865F2)](https://discord.gg/S5UjpzGZjN)
9+
10+
A Kubernetes Custom Resource Definition (CRD) adapter for [Casbin](https://github.com/casbin/casbin). With this adapter, Casbin can load policy rules from Kubernetes Custom Resources instead of traditional databases.
11+
12+
## Features
13+
14+
- **Read-Only Adapter**: Designed to keep Kubernetes CRDs as the single source of truth for policies
15+
- **Namespace-Scoped and Cluster-Scoped**: Supports both namespace-scoped and cluster-scoped policy resources
16+
- **Duplicate Handling**: Automatically deduplicates policies when loading from multiple CRs
17+
- **Deterministic Ordering**: Ensures consistent policy loading order across multiple invocations
18+
- **RBAC Support**: Handles both permission rules (p) and role/group bindings (g)
19+
- **No Database Required**: Eliminates the need for external database dependencies at runtime
20+
21+
## Installation
22+
23+
```bash
24+
go get github.com/casbin/casbin-crd-adapter
25+
```
26+
27+
## CRD Schema
28+
29+
The adapter expects CasbinPolicy custom resources with the following structure:
30+
31+
```yaml
32+
apiVersion: casbin.org/v1alpha1
33+
kind: CasbinPolicy
34+
metadata:
35+
name: example-policy
36+
namespace: default # optional, omit for cluster-scoped
37+
spec:
38+
policyType: p # or "g" for grouping policies
39+
rules:
40+
- values: ["alice", "data1", "read"]
41+
- values: ["bob", "data2", "write"]
42+
```
43+
44+
### Policy Types
45+
46+
- **p**: Permission policies (who can do what on which resource)
47+
- **g**: Grouping policies (role/group bindings)
48+
49+
## Usage
50+
51+
### Basic Usage (Namespace-Scoped)
52+
53+
```go
54+
package main
55+
56+
import (
57+
"log"
58+
59+
"github.com/casbin/casbin/v3"
60+
crdadapter "github.com/casbin/casbin-crd-adapter"
61+
)
62+
63+
func main() {
64+
// Create adapter for namespace-scoped policies
65+
adapter, err := crdadapter.NewAdapter("default")
66+
if err != nil {
67+
log.Fatal(err)
68+
}
69+
70+
// Create enforcer with the adapter
71+
e, err := casbin.NewEnforcer("model.conf", adapter)
72+
if err != nil {
73+
log.Fatal(err)
74+
}
75+
76+
// Use the enforcer
77+
ok, err := e.Enforce("alice", "data1", "read")
78+
if err != nil {
79+
log.Fatal(err)
80+
}
81+
log.Printf("Alice can read data1: %v", ok)
82+
}
83+
```
84+
85+
### Cluster-Scoped Usage
86+
87+
```go
88+
// Create adapter for cluster-scoped policies
89+
adapter, err := crdadapter.NewAdapter("")
90+
if err != nil {
91+
log.Fatal(err)
92+
}
93+
```
94+
95+
### Using with Fake Client (for Testing)
96+
97+
```go
98+
import (
99+
"k8s.io/apimachinery/pkg/runtime"
100+
"k8s.io/client-go/dynamic/fake"
101+
crdadapter "github.com/casbin/casbin-crd-adapter"
102+
)
103+
104+
func TestWithFakeClient() {
105+
scheme := runtime.NewScheme()
106+
client := fake.NewSimpleDynamicClient(scheme)
107+
108+
adapter := crdadapter.NewAdapterWithClient(client, "default")
109+
110+
e, err := casbin.NewEnforcer("model.conf", adapter)
111+
// ...
112+
}
113+
```
114+
115+
## Example CRD Definitions
116+
117+
### Permission Policy
118+
119+
```yaml
120+
apiVersion: casbin.org/v1alpha1
121+
kind: CasbinPolicy
122+
metadata:
123+
name: user-permissions
124+
namespace: default
125+
spec:
126+
policyType: p
127+
rules:
128+
- values: ["alice", "data1", "read"]
129+
- values: ["alice", "data1", "write"]
130+
- values: ["bob", "data2", "write"]
131+
```
132+
133+
### Role/Group Bindings
134+
135+
```yaml
136+
apiVersion: casbin.org/v1alpha1
137+
kind: CasbinPolicy
138+
metadata:
139+
name: role-bindings
140+
namespace: default
141+
spec:
142+
policyType: g
143+
rules:
144+
- values: ["alice", "admin"]
145+
- values: ["bob", "developer"]
146+
```
147+
148+
## RBAC Model Example
149+
150+
```ini
151+
[request_definition]
152+
r = sub, obj, act
153+
154+
[policy_definition]
155+
p = sub, obj, act
156+
157+
[role_definition]
158+
g = _, _
159+
160+
[policy_effect]
161+
e = some(where (p.eft == allow))
162+
163+
[matchers]
164+
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
165+
```
166+
167+
## Write Operations
168+
169+
This adapter is **read-only** by design. All write operations (`SavePolicy`, `AddPolicy`, `RemovePolicy`, `RemoveFilteredPolicy`) will return `ErrWriteNotSupported`.
170+
171+
To modify policies, update the Kubernetes CRD resources directly using `kubectl` or the Kubernetes API:
172+
173+
```bash
174+
# Apply a new policy
175+
kubectl apply -f policy.yaml
176+
177+
# Update existing policy
178+
kubectl edit casbinpolicy example-policy -n default
179+
180+
# Delete a policy
181+
kubectl delete casbinpolicy example-policy -n default
182+
```
183+
184+
## How It Works
185+
186+
1. The adapter connects to the Kubernetes API server (either in-cluster or via kubeconfig)
187+
2. It lists all CasbinPolicy custom resources (filtered by namespace if specified)
188+
3. Policies are sorted deterministically by namespace, name, and policy type
189+
4. Duplicate policies are automatically removed
190+
5. Policies are loaded into the Casbin enforcer
191+
192+
## Testing
193+
194+
Run the test suite:
195+
196+
```bash
197+
go test -v ./...
198+
```
199+
200+
With coverage:
201+
202+
```bash
203+
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
204+
```
205+
206+
## Development
207+
208+
### Prerequisites
209+
210+
- Go 1.23.0 or higher
211+
- Access to a Kubernetes cluster (for integration testing)
212+
213+
### Building
214+
215+
```bash
216+
go build ./...
217+
```
218+
219+
### Running Tests
220+
221+
```bash
222+
go test ./...
223+
```
224+
225+
## Contributing
226+
227+
Contributions are welcome! Please feel free to submit a Pull Request.
228+
229+
## License
230+
231+
This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.
232+
233+
## Related Projects
234+
235+
- [Casbin](https://github.com/casbin/casbin) - An authorization library that supports access control models like ACL, RBAC, ABAC
236+
- [gorm-adapter](https://github.com/casbin/gorm-adapter) - GORM adapter for Casbin
237+
- [ent-adapter](https://github.com/casbin/ent-adapter) - Ent adapter for Casbin
238+
239+
## Support
240+
241+
- [Discord](https://discord.gg/S5UjpzGZjN)
242+
- [Forum](https://forum.casbin.org)
243+
- [GitHub Issues](https://github.com/casbin/casbin-crd-adapter/issues)

0 commit comments

Comments
 (0)