This repository is no longer maintained. This repository served as a proof of concept to demonstrate how Cedar could be used with Kubernetes. Development will be moving to a new Rust-based implementation (location TBD) for the following reasons:
-
Cedar's Partial Evaluation and Typed Partial Evaluation could work very well with Kubernetes, but are only available in the Rust library.
Partial Evaluation can return a set of policies (residuals) that might apply to the request when you don't know the full request content yet (as is the case in Kubernetes Authorization). These policies can be propagated to a later point where the full request content is known (as is the case in Kubernetes Admission) where they can be evaluated.
-
We want a unified schema between Authorization and Admission, rather than separate namespaces requiring two rules (a permit in authZ and a corresponding forbid in admission). This repository's approach where Authorization is deny-by-default and Admission is allow-by-default creates confusing pairs of policy statements to enforce a single intent.
In this repository, if you wanted to allow
test-userto create ConfigMaps that have do not start withprodin the default namespace, you would need two policies like the following:// Authorization policy // test-user can do Action::"create" on configmaps in the default namespace permit ( principal is k8s::User, action == k8s::Action::"create", // authorization create action resource is k8s::Resource // authorization resource ) when { principal.name == "test-user" && resource has namespace && resource.namespace == "default" && resource.apiGroup == "" && resource.resource == "configmaps" }; // Admission policy preventing test-user from creating configmaps with name starting with "prod" forbid ( principal is k8s::User, action == k8s::admission::Action::"create", // admission create action resource is core::v1::ConfigMap // admission resource ) when { principal.name == "test-user" && resource.metadata.name like "prod*" };With a unified schema, partial authorization, and some pending Kubernetes changes, we can enable a single policy to govern this action
permit ( principal is k8s::User, action == k8s::Action::"create", // a single unified action resource is core::configmaps ) when { principal.username == "test-user" && resource.namespace == "default" } unless { resource.name like "prod*" };
This project allows users to enforce access control on Kubernetes API requests using Cedar policies. Users can dynamically create authorization policies for Kubernetes that support features like request or user attribute based rules, label-based access controls, conditions, and enforce denial policies. Users can also create admission policies in the same file as authorization policy, giving policy authors a single language to write and reason about.
// Authorization cedar policy to create a secret. Create authorization requests
// do not contain the resource's name
permit (
principal in k8s::Group::"personal-secret-creators",
action == k8s::Action::"create",
resource is k8s::Resource
) when {
resource.apiGroup == "" && // "" is the core API group in Kubernetes
resource.resource == "secret"
};
// Authorization cedar policy permitting actions on a secret that match a user's name
permit (
principal is k8s::User,
action in [k8s::Action::"get", k8s::Action::"update", k8s::Action::"delete"],
resource is k8s::Resource
) when {
principal in k8s::Group::"personal-secret-creators" &&
resource.resource == "secret" &&
resource.apiGroup == "" &&
resource has name &&
resource.name == principal.name
};
// Admission policy enforcing that a secret name in create requests match the user's name
forbid (
principal is k8s::User,
action == k8s::admission::Action::"create",
resource is core::v1::Secret
) when {
principal in k8s::Group::"personal-secret-creators"
} unless {
// forbid doesn't apply under these conditions
resource.metadata.name == principal.name
};
Administrators who want to secure their Kubernetes clusters today have to learn and use multiple different policy languages, and ensure those policies are individually applied on all their clusters. For example, if an administrator wants to allow users to create deployments, but prevent them from creating pods that don't have a required label pair, they must write two policies in separate languages: one authorization policy permitting pod creation, and another validation policy preventing pods with offending label.
An example authorization RBAC policy might look like:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-manager
rules:
- apiGroups:
- "apps"
resources:
- deployments
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: deployment-manager
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deployment-manager
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: developersWith an Open Policy Agent/Gatekeeper policy written in Rego like so:
package k8srequiredlabels
get_message(parameters, _default) := _default {
not parameters.message
}
get_message(parameters, _) := parameters.message
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_].key}
missing := required - provided
count(missing) > 0
def_msg := sprintf("you must provide labels: %v", [missing])
msg := get_message(input.parameters, def_msg)
}
violation[{"msg": msg}] {
value := input.review.object.metadata.labels[key]
expected := input.parameters.labels[_]
expected.key == key
# do not match if allowedRegex is not defined, or is an empty string
expected.allowedRegex != ""
not regex.match(expected.allowedRegex, value)
def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
msg := get_message(input.parameters, def_msg)
}(borrowed from the OPA Gatekeeper library)
Defining permit actions in one file and restrictions in separate policy files, languages, and frameworks introduces high cognitive overhead to administrators tasked with defending their clusters. The risk of an unintended effect increases when writing and reviewing code changes to existing policies, as a reviewer might not be aware of all permissions or restrictions if only one is being modified.
Cedar access control for Kubernetes helps solve these problems. By using the same language for both authorization and admission policies, administrators can quickly reason about what permissions are granted and what restrictions are applied in the same policy file. Additionally, policies can be specified outside a cluster and apply to whole fleets of clusters. This gives administrators powerful and unmatched new tools to secure their clusters.
| Title | Description |
|---|---|
| Setup | A quick start guide to running this project in a local Kind cluster |
| Cedar Introduction | An introduction on Cedar policies and request evaluation |
| Cedar Schemas | An overview of the Cedar structures used in policies in this project |
| Demonstration | A walkthrough using Cedar access controls for Kubernetes |
| RBAC Converter | A quick demo on how to convert Kubernetes RBACs on Cedar Policies |
| Limitations | A list of limitations of Cedar access control for Kubernetes |
| Potential Features | A list of potential features to add to this project |
| Rejected Features | Features that were tried but failed to work out |
| Development | A guide to developing and contributing to this project |
| Operations | A guide to operating the webhook in a cluster |
-
How does Cedar differ from Kubernetes RBAC?
Kubernetes Role Based Access Control (RBAC) is a built-in authorization policy framework used to authorize Kubernetes requests. With RBAC, you define a policy (
ClusterRoleorRole) that enumerates what API groups, resources, and verbs are permitted. You then define a binding (ClusterRoleBindingorRoleBinding) that associates Users, Groups, or ServiceAccounts to one of those policies. RBAC is allow-only (no denials), and is suited for authorizing clients that need to access either specifically named resources, or whole sets of resources.Cedar enables you to define policies that can reference the requester or attributes of the request, conditions, and also supports denials. Because Cedar works on admission too, Cedar admission policies can evaluate the full request.
-
What is Cedar?
Cedar is an open source policy language for defining permissions as policies, which describe who should have access to what. It is also a specification for evaluating those policies. Cedar policies can control what each user is permitted to do and what resources they may access.
Cedar is fast and scalable. The policy structure is designed to be indexed for quick retrieval and to support fast and scalable real-time evaluation, with bounded latency.
Cedar is designed for analysis using Automated Reasoning. This enables analyzer tools capable of optimizing your policies and proving that your security model is what you believe it is.
-
Do I need to have an AWS account to use this?
No, you can try this out locally with kind today, and even run it on a cloud cluster that you manage.
-
Can I use this in production?
While Cedar is a production-ready policy language, this project is still in active development and not yet intended for production use. The Kubernetes Custom Resource Definitions (CRDs) and Cedar schemas used in this project are not solidified and highly subject to change. If you think you've found a security issue, please let AWS know!
-
Can I use Cedar for Kubernetes policy enforcement?
While Cedar offers powerful authorization guarantees, there are policy enforcement requirements common to Kubernetes that are not formally analyzable. An example use case that illustrates this is an enforcement that all containers in all pods in a cluster have maximum memory limit set. Cedar is powered by automated reasoning, including an SMT solver, which does not implement loops or map functions. Rather than viewing Cedar as a replacement for admission restrictions tools like Open Policy Agent/Gatekeeper or Kyverno, it is best seen as an additional tool for access control enforcement.
-
Will this be built into Amazon Elastic Kubernetes Service (EKS)?
This project is a public experiment, and not currently integrated into Amazon EKS. We welcome your feedback, want to know what does or doesn't work for your use cases, and whether you'd like to see this integrated into Amazon EKS.
If you think you've found a security issue, please let AWS know!

