Repository navigation
The Kubernetes credential provider can grant tenant namespaces selected by label - #2877
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
The Kubernetes credential provider grants each atespace a fixed list of namespaces, read once at startup. A platform that creates a namespace per tenant at run time, and runs each tenant's actors in the atespace named after it, cannot follow those namespaces with a fixed list. A namespace policy can now carry an ownNamespaceSelector, a Kubernetes label selector, in place of atespace and allowedNamespaces. Each namespace the selector matches may be read by the atespace of the same name and by no other, so one tenant's actors never read another tenant's Secrets. The provider watches namespaces and matches each request against the namespace's labels at that moment: a namespace created, labeled, unlabeled or deleted after startup is granted or refused without a restart. A secretSelector narrows a selected grant as it narrows a listed one. An empty selector, or an ownNamespaceSelector combined with atespace or allowedNamespaces, fails loading. The provider starts the namespace watch only when a policy selects namespaces, so a policy file without one parses and behaves as before. The provider's ClusterRole gains list and watch on namespaces, and /statusz lists the namespaces the selectors match now. Signed-off-by: Jose Armesto <github@armesto.net>
fba26c5 to
49ee2fe
Compare
Pin that combining static and selector grants never writes into the policy's shared slice.
Eitan Yarmush (EItanya)
left a comment
There was a problem hiding this comment.
I agree that something like this is useful, but I also think it's a bit overly specific. What do you think about starting with a filewatch + reload on the configmap, (assuming this doesn't exist today), and then we can ideate on how to improve the API going forward. This feels to me like the perfect use of a simple policy language like CEL.
Bowei Du (@bowei) I'm a little worried that more requirements like this will come up so we should decide our stance on this component.
|
Reload doesn't exist today; the policy is read once at startup. I'm happy to start there, I'll open a small PR for it. It won't cover our case on its own: we create a namespace and an atespace per tenant at run time, so something would still have to edit the shared policy for every tenant, and whatever can do that can grant any atespace any namespace. On CEL: it would cover our case as long as rules can see the namespace's current labels, which means keeping the namespace watch from this PR as the input. One alternative to weigh before adding a policy language: have the provider ask Kubernetes RBAC with a SubjectAccessReview (can substrate:atespace: get this Secret in this namespace?), so a grant is just a RoleBinding in the tenant namespace. Happy to write both up in #2876 and close this PR once we pick one |
|
Reload PR #2959 |
|
I'll let Taahir Ahmed (@ahmedtd) confirm on the security side of the RBAC approach. Watching the CM for changes seems like a good temporary middle ground to me. As I mentioned, I think the question here is more about what the project as a whole sees for this component. On the one hand, addressing k8s secrets is clearly an important base case, but maintaining this also means we're on the hook for this API forever etc. The credential API is extendable exactly to make sure that folks can bring whatever implementation they want it the upstream one doesn't match what's needed. |
|
Thanks, that's clear. We'll wait for the direction on the component before proposing anything further on the policy API; #2959 stands as the reload middle ground, and I'll close this PR once it merges. One thing that helps either way: |
|
It's a good question how feature-rich this "example cred provider" should become. The biggest concern is whether or not we accidentally open a can of CVEs (ref: ingress-nginx) that can be hard to close. |
The Kubernetes secrets provider grants each atespace a fixed namespace list read at startup, so a platform that creates one namespace and one atespace per tenant at run time needs a policy edit and a restart for every tenant.
A namespace policy can now carry
ownNamespaceSelector, a label selector, in place ofatespaceandallowedNamespaces: each namespace it matches is readable by the atespace of the same name and no other. The provider watches namespaces only when a policy has a selector, matches each request against current labels, andsecretSelectornarrows a selected grant as it does a listed one. The provider's ClusterRole gains list/watch on namespaces.ownNamespaceSelectoris a fullmetav1.LabelSelector, unlikesecretSelector, because the tenant case needs theExistsoperator.Fixes #2876
AI use: AI-assisted, Claude Code wrote the change and tests; I reviewed and tested it.