Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Beyond RBAC: Implementing Relation-based Access Control for Kubernetes with OpenFGA

Beyond RBAC: Implementing Relation-based Access Control for Kubernetes with OpenFGA

Talk presented at Cloud Native Rejekts in Chicago: https://cloud-native.rejekts.io
Location: TeamWorking by TechNexus, Chicago
Code is available on GitHub: https://github.com/luxas/kube-rebac-authorizer
Youtube: https://www.youtube.com/live/tWWBzsZLrIw?t=396

Abstract as follows:
The Kubernetes API server is a declarative, uniform and extensible REST API server capable of storing a diverse set of APIs for infrastructure control. API objects tend to contain parent-child and sibling relations such as “ReplicaSet owns Pod refers to Node”. However, with this graph-based structure, access control and multi-tenancy become a real challenge. The default RBAC authorizer is best for resource-scoped authorization (“allow listing all Pods”), not fine-grained authorization (“allow listing Pods of these Deployments”).

OpenFGA is a Relationship-Based Access Control (ReBAC) engine inspired by Google Zanzibar and a CNCF sandbox project. ReBAC is a superset of RBAC, and empowers administrators to configure authorization in an object-scoped manner with minimal configuration sprawl.

A Kubernetes contributor and a OpenFGA maintainer will demo an open-source implementation of a Kubernetes authorizer and controller that configures and queries OpenFGA for authorization decisions.

In today’s world, security requirements grow ever-more more demanding and important. Kubernetes Role-Based Access Control (RBAC) is a critical piece of the security in the Kubernetes cluster, e.g. guarding all (unencrypted) Secret API objects from being accessed by unauthorized parties. RBAC is inherently best used for collection-scoped rules, as if object-scoped rules are wanted, all the API object names need to be hard-coded into the rule; which effectively creates a lot of “rule sprawl”.

It is not possible to force a user to list or watch a strict subset of the API objects of a given kind in a namespace; it is all of the objects in the namespace or none. It is thus a pain point, almost impossible, to configure authorization for Kubernetes operator to only list/watch a subset of resources (the resources it manages).

Kubernetes has actually implemented object-scoped authorization as a special case, the Node authorizer, which enforces that a kubelet can only access Secrets, ConfigMaps, etc. that are bound to a workload running on that given node. However, this implementation is hard-coded (written in Go) in the API server, not a generic implementation for which many other controllers and users would benefit.

Thus, we are demonstrating a Proof-of-Concept implementation as a generic alternative for this problem, using the OpenFGA engine.

This talk would highlight improvement suggestions for both Kubernetes and OpenFGA for increased security and increased administrator awareness.

Lucas Käldström

November 05, 2023
Tweet

More Decks by Lucas Käldström

Other Decks in Technology

Transcript

  1. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Beyond RBAC Implementing Relation-based Access Control

    for Kubernetes with OpenFGA Jonathan Whitaker Staff Software Engineering, Okta/Auth0 Lucas Käldström Cloud Native Researcher, CNCF Ambassador
  2. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Agenda • Overview of OpenFGA •

    Overview of Kubernetes Authorization and RBAC • Modeling Kubernetes with Relationship-based Access Control (ReBAC) • Demo of a Kubernetes Authorizer with OpenFGA • Beyond RBAC - what comes next? • Q/A
  3. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer • Flexible and performant engine built

    to solve Fine-Grained Authorization (FGA) • Inspired by Google's Zanzibar paper, which describes how authorization for all of Google's services was built • CNCF Sandbox project - OpenFGA on CNCF • Created and actively maintained by Okta/Auth0 • Growing community and various project integrations ◦ Please join the community! https://openfga.dev What is OpenFGA?
  4. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Developer Experience with OpenFGA 1. App

    developer specifies an authorization model a. “Users can view folders, folders contain documents” 2. Write or import relationship data a. “User Lucas can view folder ‘customers’, and folder ‘customers’ has document ‘secret’” 3. Query OpenFGA a. “Can user Lucas view document ‘secret’?” ⇒ true b. “What documents can user Lucas view?” ⇒ [“document:secret”, … ]
  5. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer OpenFGA Deployment Models • Embed as

    library in Go • Deploy as sidecar service • Deploy as standalone service ◦ Horizontally scalable ◦ Persistence in popular databases (Postgres, MySQL) or in-memory ◦ Accessible through gRPC or HTTP
  6. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer FGA Models: Overview • Relationship Tuples

    establish concrete paths in the graph - defined as {src_node, relation, dst_node} user:lucas document:secret read delete actual relation possible relation Concrete Tuples: user:lucas document:secret read • Modeled as a graph with types (nodes) and relations (directed edges). • Relations define relationships between related types.
  7. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# get@user:lucas) role:getter assignee assignee assignee assignee
  8. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# get@user:lucas) role:getter assignee assignee assignee assignee
  9. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# get@user:lucas) → {allowed: true} role:getter assignee assignee assignee assignee
  10. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# delete@user:lucas) role:getter assignee assignee assignee assignee
  11. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# delete@user:lucas) role:getter assignee assignee assignee assignee
  12. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC with ReBAC user:lucas rolebinding:getters resource:pods

    assignee assignee get rolebinding:deleters role:deleter assignee assignee delete Evaluating Check(resource:pods# delete@user:lucas) → {allowed: true} role:getter assignee assignee assignee assignee
  13. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer FGA Model Rewrites 1. Computed userset

    rewrites “If you can edit the document, then you can view the document” 2. Inheritance (Tuple to userset) “If you can view the parent folder, then you can view the document” 3. Set operations a. Union b. Intersection c. Exclusion
  14. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Kubernetes: API Basic Concepts API Groups

    apiVersion: apps/v1 apiVersion: networking.k8s.io/v1 Resources kind: Deployment kind: NetworkPolicy Verbs • GET • POST • PUT • PATCH • DELETE Resource URIs to Authorization Attributes • GET /apis/apps/v1/deployments/my-deployment ◦ get • GET /apis/apps/v1/deployments ◦ list • GET /apis/apps/v1/deployments?watch=1 ◦ watch • POST /apis/apps/v1/deployments ◦ create • PUT /apis/apps/v1/deployments/my-deployment ◦ update • PATCH /apis/apps/v1/deployments/my-deployment ◦ patch • DELETE /apis/apps/v1/deployments/my-deployment ◦ delete
  15. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Kubernetes Authorizer The Authorizer determines if

    a user can perform a given action (before the body is deserialized) Attributes (Input): • User Info {Name, Groups, UID} • API group: apps • Resource: Deployment • Verb: create • (Object Name) • (Namespace) Response Output: • Allow • NoOpinion (RBAC never denies, it is purely additive) • Deny Kubernetes supports multiple Authorizers in a chain
  16. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer RBAC in Kubernetes: Roles and Role

    Bindings apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: reconcile-deployments rules: - apiGroups: ["apps"] verbs: ["get", "list", "watch"] resources: ["deployments"] - apiGroups: ["apps"] verbs: ["update"] resources: ["deployments/status"] apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: deployment-users roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: reconcile-deployments subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: lucas - apiGroup: rbac.authorization.k8s.io kind: Group name: team-members • Additionally, Roles and RoleBinding (scoped to a namespace) • Namespaces provide isolation of groups of resources within a cluster ClusterRole - defines the actions an actor can perform on the given resources (cluster-wide). ClusterRoleBinding - binds a single role to one or more subjects.
  17. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer ClusterRole-owned Tuple RBAC in Kubernetes: Roles

    and Role Bindings apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: reconcile-deployments rules: - apiGroups: ["apps"] verbs: ["get", "list", "watch"] resources: ["deployments"] - apiGroups: ["apps"] verbs: ["update"] resources: ["deployments/status"] resource: apps.deployments resource: apps.deployments/status clusterrole: reconcile-deployments #assignee update get list watch apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: deployment-users roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: reconcile-deployments subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: lucas - apiGroup: rbac.authorization.k8s.io kind: Group name: team-members
  18. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer ClusterRole-owned Tuple ClusterRoleBinding-owned Tuple RBAC in

    Kubernetes: Roles and Role Bindings apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: reconcile-deployments rules: - apiGroups: ["apps"] verbs: ["get", "list", "watch"] resources: ["deployments"] - apiGroups: ["apps"] verbs: ["update"] resources: ["deployments/status"] resource: apps.deployments resource: apps.deployments/status clusterrole: reconcile-deployments #assignee clusterrolebinding: deployment-users #assignee update get list watch apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: deployment-users roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: reconcile-deployments subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: lucas - apiGroup: rbac.authorization.k8s.io kind: Group name: team-members user: lucas group: team-members assignee assignee assignee
  19. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Mapping Kubernetes API objects to Tuples

    We propose a controller that: • Processes Kubernetes API objects containing authorization policies (such as RBAC definitions), and • Derives the desired tuples for the relationship graph based on the API object and declarative mapping policy • Writes these Tuples to OpenFGA
  20. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get user:lucas clusterrole:view-all-apps resource:apps.*

    resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  21. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get assignee user:lucas clusterrole:view-all-apps

    resource:apps.* resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  22. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get assignee get user:lucas

    clusterrole:view-all-apps resource:apps.* resource:apps.deployments resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  23. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get assignee get contains

    get user:lucas namespace:team-1 clusterrole:view-all-apps role:team-1-view-deploys resource:apps.* resource:apps.deployments resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  24. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get assignee get contains

    assignee get user:lucas namespace:team-1 clusterrole:view-all-apps role:team-1-view-deploys resource:apps.* resource:apps.deployments resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  25. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer GET /apis/apps/v1/namespaces/team-1/deployments/my-deployment get assignee get operates_in

    contains assignee get AND user:lucas namespace:team-1 clusterrole:view-all-apps role:team-1-view-deploys resource:apps.* resource:apps.deployments resourceinstance: apps.deployments/ my-deployment get Concrete Tuple Contextual Tuple Graph-based Authorizer Implementation
  26. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer A node should only see linked

    pods’ resources node:b pod:foo-1 pod:bar-1 secret:cert-keys configmap:app-cfg persistentvolumeclaim:pvc-1 Implemented statically in Go code by the Node authorizer. ⇒ we want to generalize this for control planes in general. node a cannot see secret cert-keys, pvc-1, nor pv-1 node b cannot see pvc-0 nor pv-0 node:a pod:bar-0 persistentvolumeclaim:pvc-0 serviceaccount:sa-1 persistentvolume:pv-1 persistentvolume:pv-0
  27. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Let’s generalize that through declarative config

    deployment:foo replicaset:foo-2 replicaset:foo-1 pod:foo-2-a pod:foo-2-b pod:foo-1-a RBAC can allow access to individual resource instances, but you need to specify the names ⇒ not scalable and often names are random Idea is to provide a declarative way to define desired authorization policies of related objects in Kubernetes (and beyond) Can be useful for limiting e.g. the number of controllers that need cluster-wide access to read/write all secrets.
  28. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Goals: Kubernetes Authorizer with OpenFGA •

    Implement RBAC & Node Authorizer with OpenFGA • Support existing RBAC APIs • Showcase extensibility of Kubernetes • Prototype more fine-grained authorization paradigms
  29. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Kubernetes API object Kubernetes with OpenFGA

    Demo ReBAC Authorizer kube-api- to-tuples- controller API Server async API object watch async tuple write sync check sync webhook OpenFGA Tuples
  30. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Going Beyond RBAC in Kubernetes •

    Implement the RulesReview using OpenFGA ListObjects API • Expanding the scope of authorization to the so-called “validating admission” stage • Define a generic CRD API for declaratively specifying how to map an API object to Tuples using CEL • Integrate support in controllers (e.g. using controller-runtime) for reconciling only subsets of items of a given resource • Experiment further with ABAC or listing by e.g. label selector • Integration with kcp for generic control planes • Enforce immutability of links between nodes through an admission controller • Integrate with other sources of authorization data (e.g. authentication providers) • Add possibility to specify Deny roles
  31. @kubernetesonarm + @openfga github.com/luxas/kube-rebac-authorizer Thanks! Jonathan Whitaker Staff Software Engineering,

    Okta/Auth0 GitHub: @jon-whit [email protected] Lucas Käldström Cloud Native Researcher, CNCF Ambassador GitHub: @luxas LinkedIn: @luxas Twitter: @kubernetesonarm [email protected]