Proof of concept integrating Cedar with Kubernetes, leveraging in particular the Typed Partial Evaluation feature of Cedar, in order to unify Kubernetes authorization and admission request stages. The design for this work is found in my MSc thesis, please read that work to understand the context. Slides from the MSc thesis presentation are available here.
This project is intended to be merged into Cedar Access Control for Kubernetes when/if this experiment proves viable. In addition, this project serves as a temporary playground for experimenting with how/if Kubernetes could add support for Conditional Authorization, discussed for example in this SIG Auth meeting. Hopefully, a Kubernetes Enhancement Proposal could be written for the Conditional Authorization, given promising enough results here and/or later in Cedar Access Control for Kubernetes.
Let Lucas know if you have feedback or ideas.
NOTE: This project is an experiment, and is not yet ready for production use. Do not under any circumstances use it in production. This is not an Upbound product.
By design, Kubernetes authorization operates only on metadata, on attributes that can be inferred from the URL without deserializing the request payload. This means that Kubernetes authorizers can offer users pretty limited expressitivity. However, later in the admission stage, more data is available, for example, the request body and currently stored object in etcd. In order to write an authorization policy which targets both metadata and data, a user must use two different paradigms: Kubernetes RBAC and ValidatingAdmissionPolicy (VAP).
Even though the policy author would manage to coordinate the two policy types to yield a unified result, there are limitations, due to e.g. admission only being invoked for write requests. In addition, it is hard to understand what the effective set of access is, if one takes both RBAC and admission into account.
The idea with this project is to experiment with and demonstrate how Kubernetes authorization and admission could get new capabilities and an improved UX by integrating with Cedar.
- Allow one uniform user interface across both authorization and admission.
Allow a policy author to write an authorization policy that only applies if
some property of the request payload, stored object in etcd, or namespace
metadata holds. For example,
- only allow a principal to create
CertificateSigningRequestswith a given signer, or - only allow a principal to update a resource as long as a sensitive field is not changed, or
- only allow a principal to issue a
ServiceAccounttoken with a given audience, or - only allow a controller to use a specific finalizer.
- only allow a principal to create
- Allow limiting the lists and watches to only return resources with certain
field and label values, using the exact same syntax as for write requests.
- For example, only allow Gateway/Ingress controllers to list
Secretsof.type=kubernetes.io/tlsand/or with labelingress-bindable=true - This is basically a uniform interface for expressing policies using the Authorize with Selectors KEP
- For example, only allow Gateway/Ingress controllers to list
- Allow more expressiveness than RBAC's
bound_rule1 || bound_rule2 || ... || bound_ruleN, where a rule is logicallyapi_group_matches && combinedresource_matches && namespace_matches && name_matches.- Allow binding some data from the user in the condition for what kind of resource matches.
- For example, only allow a node agent to handle resources where
.spec.nodeName=<bound-node>. - Allow string matching (principal name, resource name(space)) by prefix or suffix.
- Absence of prefix matching is discussed in kubernetes#122154 and kubernetes#56582 (for better and worse, subdiving namespaces is still not a good idea).
- Expose the UserInfo
uidandextrafields to the policy author. - Allow for more fine-grained impersonation. Today, one can only express whether
a principal can impersonate a given UserInfo attribute independently of all
other impersonated values. In addition, it is not possible to constrain the
impersonation to only apply for a given verb or resource.
- Constrained Impersonation is useful e.g. for letting a node agent impersonate the node it is running on to get access to a limited set of the node's linked resources (e.g. Pods, Secrets, etc.)
- Combining fine-grained impersonation with string prefix matching allows for
limiting the permissions of an authenticating front proxy (e.g.
kube-oidc-proxy). Without prefix matching, most likely the RBAC rule
giving the front proxy ability to impersonate allows impersonating all
groups, including
system:masterswhich gives effectively root cluster access, which is most likely not desired.
- Make authoring a policy across authorization and admission stage atomic. In other words, make it impossible for e.g. the RBAC (allow) rule to apply when the VAP (deny) rule does not (yet).
- Allow restricting the names that can be used when creating an API object
(including when using
generateName) kubernetes#54080 - Potentially, in the future, allow for writing a limited set of deny rules.
- 100% compability with Kubernetes RBAC
- Support any built-in Kubernetes and CRD resource and subresource.
- Fast, bounded policy evaluation time.
- Seamless integration with the Kubernetes API server, and the existing CEL infrastructure, by converting from Cedar to CEL where needed.
- Improve the user experience for policy authors, e.g. by instant feedback (validation, syntax highlighting, autocompletion, and linting) in the IDE (e.g. VS Code)
- Support writing policies simultaneously against multiple API versions of the API object, and seamless up- and downgrades.
- Privilege escalation prevention support.
- Allow mathematical analysis of the Kubernetes authorization state using SMT
solvers, based on the Cedar Symbolic Compiler.
- This allows e.g. for finding logical inconsistencies in the policies, checking if a refactor was done correctly (are the policies before mathematically equivalent to the policies after), and more.
- Allow for principal and resource querying, that is, asking for example:
- "What resources can principal P perform what actions on?"
- "What principals can perform what actions on resource R?"
- This is useful for auditing that the end result of all policies combined indeed are the desired result.
- Allow increasing expressivity without forcing the cluster administrator to build their custom webhook authorizer, which is (understandably) not supported in most hosted Kubernetes distributions.
- Don't reinvent the wheel. Use the unique strengths of Cedar and CEL, and the vast effort that have gone into SMT solver implementation and research.
Cedar is an authorization engine and policy language that is designed to be expressive, fast, safe, analyzable. The language has a formal specification, and the implementation is formally verified to conform to the specification. Cedar is open source, Apache 2.0 licensed, and is in the process of being donated to the CNCF. Effectively, Cedar is a stateless authorization library, written in Rust, and can thus be integrated into almost any environment. This project utilizes Cedar to solve challenges encountered in Kubernetes authorization.
See the Cedar website for more information. In Lucas' opinion, the best resource on how Cedar works and is designed in detail, is the Cedar OOPSLA paper.
A couple of critical features of Cedar are:
- The Typed Partial Evaluation feature, which (while only supplying metadata) empowers denying such requests, where there is either at least one deny policy that is guaranteed to evaluate to true, or all allow policies are guaranteed to evaluate to false.
- The Cedar Symbolic Compiler, which translates Cedar policies into mathematical logic, more precisely, SMT-LIB format.
- The typed schema, which allows for type-safe policies, and for the policy author to reason about the policy in the IDE using the Cedar IDE plugin.
Install kind v0.29.0 and kubectl v1.33.0, e.g. through Homebrew on macOS:
$ brew install kind kubectl
...
$ kind version
kind v0.29.0 go1.24.6 darwin/arm64
$ kubectl version
Client Version: v1.33.4You'll also need make and docker (or a CLI-compatible alternative, activate
with e.g. DOCKER=podman make ...).
Clone Lucas' Kubernetes fork, and checkout the conditional_authz_2 branch:
cd .. # Go to the parent directory of this repository
git clone https://github.com/luxas/kubernetes.git
cd kubernetes
git checkout conditional_authz_2
cd ../kubernetes-cedar-authorizerCompile Kubernetes from source:
kind build node-image /path/to/kubernetes/source --image kindest/node:luxas_conditional_authz_2_latestNext, generate a self-signed certificate for the webhook server, and name the
cert server.crt and the key server.key, and put them in the localdev/mount/certs
directory. The certificate must be valid for the hostname localhost.
Note: There is a thousand things that can fail when compiling Kubernetes from
source. For example, if you're on a Mac, you most likely need to install gnu tar
(brew install gnu-tar), and set your default shell to bash from homebrew
(brew install bash, sudo ln -s <bash install path> /usr/local/bin/bash, and
chpass -s /usr/local/bin/bash) in order for kubernetes to compile correctly.
Finally, we are ready to build the webhook image and start kind:
make kindThen, follow the getting started guide.
How does this project differ from the Cedar Access Control for Kubernetes project?
This project:
- Provides the policy author with a uniform interface for expressing policies. In the current Cedar Access Control for Kubernetes, the policy author must author policies for authorization and admission separately.
- Allows read and write policies to be authorized in a uniform way.
- Showcases how atomically applicable policies can be written and enforced by the Kubernetes core API server (as per Lucas' conditional_authz_2 Kubernetes branch), instead of by twice by the webhook (both at authorization and admission time).
- Is written in Rust; Cedar Access Control for Kubernetes is written in Go.
- Is aimed to be donated and merged into the Cedar Access Control for Kubernetes project, if this experiment proves valuable, and when Cedar is donated to the CNCF.