-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Cedar does not allow for loops, to preserve its analyzability. Given how much of this other work depends on analyzability, indeed one would not want to give that away.
However, sometimes that indeed would be very useful. For example, the DRA AdminAccess feature could be expressed using this project like follows:
forbid(
principal,
action in [k8s::Action::"create", k8s::Action::"update", k8s::Action::"patch"],
resource is io::k8s::resource::resourceclaims // and templates
) when {
// resource has at least one devicerequest with the adminAccess flag set to true; how to express this?
} unless {
resource has namespaceMetadata.labels &&
resource.namespaceMetadata.labels.hasTag("resource.kubernetes.io/admin-access") &&
resource.namespaceMetadata.labels.getTag("resource.kubernetes.io/admin-access") == "true"
};
It might be worth exploring some Cedar extension function that
a) returns a simple Cedar value (that is analyzable)
b) was converted into a CEL expression on the way to the API server as-is
c) somehow, preserves enough "intent" with the non-analyzable extraction such that analysis with it makes sense
If that existed, one could think about something like this:
forbid(
principal,
action in [k8s::Action::"create", k8s::Action::"update", k8s::Action::"patch"],
resource is io::k8s::resource::resourceclaims // and templates
) when {
// Disallow enabling adminAccess, unless the namespace has the right annotation
// The CEL expression must evaluate to a boolean (which it does here)
// has() checks omitted for brevity here
cel_bool("object.spec.devices.requests.exists(r, r.adminAccess)")
} unless {
resource has namespaceMetadata.labels &&
resource.namespaceMetadata.labels.hasTag("resource.kubernetes.io/admin-access") &&
resource.namespaceMetadata.labels.getTag("resource.kubernetes.io/admin-access") == "true"
};
Another approach, would be to annotate the OpenAPI schema with high-level, authorization-related, simple-valued invariants that policy authors might be interested in, e.g. the if the ResourceClaim OpenAPI schema's DeviceClaim struct added a hasAdminAccessRequest boolean-valued function defined as self.requests.exists(r, r.adminAccess); then the extension function in Cedar could be registered as a method or attribute on the io::k8s::resource::V1DeviceClaim type as follows:
forbid(
principal,
action in [k8s::Action::"create", k8s::Action::"update", k8s::Action::"patch"],
resource is io::k8s::resource::resourceclaims // and templates
) when {
// Omitted enforcing this invariant for every available API version which has the adminAccess field
resource has request.v1 &&
resource.request.v1.spec.devices.hasAdminAccessRequest()
} unless {
resource has namespaceMetadata.labels &&
resource.namespaceMetadata.labels.hasTag("resource.kubernetes.io/admin-access") &&
resource.namespaceMetadata.labels.getTag("resource.kubernetes.io/admin-access") == "true"
};
This expressiveness might definitely be dangerous (maybe could do more harm than good), but it's worth exploring finding some good middle-ground between expressiveness and analyzability.