-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Namespace scoped RoleAssignments that mitigate privilege escalation risks #3645
Comments
You're right that this can be an escalation of privilege, but I don't think that forbidding the ASO sits at the intersection of Kubernetes and Azure and as such developing a secure solution on it I think involves use of both Kubernetes RBAC and Azure RBAC. Before I go any further I think we do a bad job describing how to do this in the ASO documentation. I've filed #3714 which tracks a number of documentation improvements we should make, and this is one of them. One "solution" to this problem is to avoid installing the ASO Other solutions all basically boil down to:
Ensure that you follow the principle of least privilege when assigning ASO identitiesDoing this generally looks something like:
The above model works best if a given namespace in ASO maps onto a fixed set of somethings in Azure. For example 1 NS -> 1 subscription, or 1NS -> 1 RG. Even 1NS -> N RGs is fine as long as the set of RGs is fixed. That way the permissions can be set up once when the credential is provisioned for the namespace and don't need to be updated again to add new scopes, etc. Ensure that access to resources in your Kubernetes cluster (at least in sensitive namespaces) is tightly controlled.This is accomplished on AKS through AAD (now Entra) integration and disabling local users along with optionally defining JIT/Conditional access policies. A possible setupA possible setup might be a
This means that developers can do basically whatever they want in the dev namespace, including assign roles to themselves at the Azure level in the dev subscription. This isn't really a privilege escalation though because you've already granted them those permissions (through ASO+Kubernetes RBAC). In all liklihood to enable other tools their Azure AD identities already have contributor on the
When users do JIT they then would have the ability to privilege escalate, but only while they're escalated which can be more easily audited. Often users will use something like Argo or Flux here instead of having direct JITs be the flow for running updates, which also means that the proposed changes need to first meet the merge bar (pass through code review, etc) to make it into the repo before Argo/Flux will deploy them to Then it's still possible to sneak a privilege escalation through (it's hard to totally forbid this, whether you're using ASO or not), but quite a bit harder, needing some manual approval either of an AAD conditional access JIT or a PR to a repo to modify the yaml and trigger a deployment which likely requires approvers and is easily auditable, while keeping the Note that the above is just one way to lay things out. The same ideas can be applied to a Let me know if this helps at all or if you have more questions. This topic is complex and I am not a security expert so there's likely more that can be done than the above as well. |
Thanks, @matthchr! Here is what I would expect as a user of ASO, e.g., a person, who has access to a namespace in Kubernetes cluster equipped with ASO:
Currently, granting access to resources created with ASO is possible with a few CRDs, namely: UserManagedIdentity, FederatedIdentity, and RoleAssignment, and then annotating ServiceAccount somehow. However, RoleAssignment allows granting access to any resource to which ASO has access itself, which breaks these assumptions, because the only safe way would be someone else with elevated privileges doing that (e.g., these skipping installing RoleAssingment controller, and/or disabling write access to namespace in favor of gitops with peer review). Regarding auto-importing resources, I belive it would be extermely helpful having an option of disabling it globally, so let's assume we have that. Then we just need to check that RoleAssignment CRD in the namespace grants access to ASO resources deployed in that namespace, which is exactly what would be expected. And, regarding the security model, I believe we should have Cluster-wide resources and namespaced resources, e.g., ClusterRoleAssignment should allow specifying ArmID, and for that matter, reference to any ASO CRD deployed, while namespaced RoleAssignment should not. Another nice to have security feature would be an annotation to namespace to restrict deployments to given Azure ResourceGroup[s]. |
To be clear, we don't really "auto import" arbitrary resources. Instead, users who have the ability to create say, a This can obviously be prevented today by:
I think a better way to accomplish this is to use an Azure Identity (UMI or ServicePrincipal, but prefer UMI) that only has permissions to create resources in a particular resource group. The advantage of doing it that way over having it be ASO enforcement is that even if somebody gets access to that credential and goes directly to azure CLI or portal they still are locked to the specified RG, rather than now having access to the whole sub if they somehow break the credential out of the k8s context. This also solves (at least some) of the Let me focus on the ask you've got though: am I correct that what you're asking for w/ the namespace scoped |
Yeah, pretty much. Namespace-scoped RoleAssignment should assign roles only to the ASO CRDs in the same namespace, and should not have armId escape hatch, which should go to ClusterRoleAssignment CRD. And, to your point, ideally we should be able to restrict all ASO CRDs in the namespace to given Azure resource group(s), e.g., by labeling/annotating the namespace. To be fair, I've implemented these restrictions with cluster-wide Kyverno mutating policies, but this feels rather unnatural. |
I'd say that it is not obvious at all that the moment a cluster admin enables RoleAssignment CRD it opens a way of taking ownership of any Azure resource ASO have access to, which is recommended to set having admin access to subscription by documentation. Personally, I was really surprised, and to me it's a critical security issue. |
Yes sorry, agreed it is not obvious at the moment because it's not documented - so clearly not obvious. What I was trying to say is: "there is a way to accomplish this today". I'll be updating the documentation for this release to give significantly clearer, prescriptive guidance. Will also leave this issue open and discuss with colleagues about this ask:
|
We've documented the currently supported approaches to mitigate this escalation risk. |
I've retitled this issue to try to more accurately reflect the user ask. Hopefully the documentation we have now at least makes folks aware of this risk and we can investigate doing a namespace scoped role assignment in a future release. Along w/ namespace scope we may need to prevent or limit resource imports as well if we were to go that route. For now, as the document @theunrepentantgeek linked suggests, using Azure policies + JIT (and/or Kyverno like you're doing) are mitigations. |
Thanks! Meanwhile, are there any plans to make it scoped to namespaces? |
We're considering the idea and what additional requirements (blocking imports?) would have to come along with it to make it actually secure. There's no concrete plan yet but we're open to the idea and thinking about what it might look like. In terms of actual timeline, I don't really have one but wouldn't expect it in 2.8 or 2.9 as we've got other things on those lists already and now that we've actually documented some security best practices to mitigate the risk of privilege escalation with Role Assignment (and just to control access in general) we're in a better spot than we were when you raised this issue at least from an awareness perspective. |
I was re-reading this and realized I hadn't really explicitly replied to this. We're open to doing the That same approach works if you want to limit to a particular subscription, or to particular types of resources (even when ASO has installed more CRDs at the cluster level) and so is significantly more flexible than trying to do limits via namespace annotations or similar. Does that solution not work for your use-case, and if not can you expand on why? Does it have to do with the difficulty of dynamically producing identities and assigning them to dynamically created namespaces? Or is the issue primarily needing to do RoleAssignments via ASO which requires high privilege that's problematic, and if you had NamespacedRoleAssignment you could then create these per-namespace identities and give them permissions more easily? |
We think that this is a reasonable ask, but haven't had the time to design + implement it yet. |
Currently it's possible to grant access to arbitrary resource in subscription by setting up owner.armId and Contributor role:
I believe RoleAssignment owner should be scoped to namespace only by disallowing armId field in owner, and we also need a ClusterRoleAssignment CRD which can refer to owners in different namespaces and allow armId field.
The text was updated successfully, but these errors were encountered: