Add GitHub Actions CI workflow for automated testing and building Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
A Kubernetes informer-based watcher for Casbin that monitors CRD policy updates and keeps in-memory Casbin state synchronized without periodic polling.
SyncedEnforcer for thread-safe operationsgo get github.com/casbin/casbin-informer-watcher
First, apply the CasbinPolicy CRD to your Kubernetes cluster:
kubectl apply -f config/crd/casbinpolicy.yaml
Create CasbinPolicy resources in your cluster:
apiVersion: casbin.org/v1alpha1 kind: CasbinPolicy metadata: name: alice-data1-read namespace: default spec: ptype: p rule: - alice - data1 - read --- apiVersion: casbin.org/v1alpha1 kind: CasbinPolicy metadata: name: alice-admin-role namespace: default spec: ptype: g rule: - alice - admin
Apply the policies:
kubectl apply -f examples/policies.yaml
package main import ( "log" "time" "github.com/casbin/casbin/v2" watcher "github.com/casbin/casbin-informer-watcher" ) func main() { // Create a Casbin enforcer e, err := casbin.NewEnforcer("model.conf", "policy.csv") if err != nil { log.Fatal(err) } // Create and attach the watcher w, err := watcher.NewEnforcerWatcher(e, watcher.Options{ Namespace: "default", ResyncPeriod: 30 * time.Second, }) if err != nil { log.Fatal(err) } defer w.Close() // Start watching for policy changes if err := w.Start(); err != nil { log.Fatal(err) } log.Println("Watcher started, policies will be auto-reloaded on CRD changes") // Your application logic here // The enforcer will automatically reload when CRDs change select {} }
For concurrent environments, use SyncedEnforcer:
package main import ( "log" "time" "github.com/casbin/casbin/v2" watcher "github.com/casbin/casbin-informer-watcher" ) func main() { // Create a thread-safe SyncedEnforcer se, err := casbin.NewSyncedEnforcer("model.conf", "policy.csv") if err != nil { log.Fatal(err) } // Create and attach the watcher w, err := watcher.NewEnforcerWatcher(se, watcher.Options{ Namespace: "default", ResyncPeriod: 30 * time.Second, }) if err != nil { log.Fatal(err) } defer w.Close() // Start watching if err := w.Start(); err != nil { log.Fatal(err) } // Now safe for concurrent use // Policy updates from CRDs are automatically synchronized select {} }
The Options struct allows you to configure the watcher:
type Options struct { // Namespace to watch (empty string for all namespaces) Namespace string // KubeConfig path (empty for in-cluster config) KubeConfig string // ResyncPeriod for the informer (default: 30s) ResyncPeriod time.Duration }
You can set a custom callback to handle policy updates:
w, err := watcher.NewWatcher(watcher.Options{ Namespace: "default", }) if err != nil { log.Fatal(err) } err = w.SetUpdateCallback(func(msg string) { log.Printf("Policy update received: %s", msg) // Your custom logic here }) if err != nil { log.Fatal(err) } if err := w.Start(); err != nil { log.Fatal(err) }
The CasbinPolicy CRD has the following structure:
apiVersion: casbin.org/v1alpha1 kind: CasbinPolicy metadata: name: <policy-name> namespace: <namespace> spec: ptype: <policy-type> # p, p2, g, g2, etc. rule: # Policy rule as array of strings - <subject> - <object> - <action> status: synced: <boolean> lastSyncTime: <timestamp> message: <status-message>
CasbinPolicy CRDsSyncedEnforcer, the reload is thread-safe and atomicThis watcher is designed to work seamlessly with GitOps workflows:
CasbinPolicy CRDs in GitRun the tests:
go test -v ./...
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.