What happens when multiple cluster roles are assigned to one service account in kubernetes? - kubernetes

I know that you can assign multiple roles to one service account when you want your service account to access multiple namespaces, but what I wonder is how it will behave when you assign to it more than one clusterrole which is cluster scoped. From my perspective, I think that it will choose one of them but I'm not sure.

Permissions are purely additive (there are no "deny" rules).
reference
This is the golden 🥇 rule here that we must memorize for kubernetes RBAC roles.
"purely additive" means always ALLOW no revoke.
Hence, "purely additive" means there are neither conflicts nor order of precedence.
It's not like AWS IAM policies where we have DENY and ALLOW .. That's time, we have to know which one has the highest order of precedence.
It's not like also subnets ACL , where we have DENY and ALLOW .. That's time, we need to assign number for each rule. This number will decide the order of precedence.
Example:
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: pod-reader
subjects:
- kind: User
name: abdennour
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: pod-reader
apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: node-reader
subjects:
- kind: User
name: abdennour
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
as you can see in this example, the user Abdennour should have at the end the wide read access for both: nodes & pods.

If you assign a service account multiple clusterroles using multiple role or clusterrole bindings the service account will have permission which is aggregate of all of those cluster roles meaning all the verbs on all the resources defined in those clusterroles.

Related

Cluster Rolebinding not working for GKE Cluster + OIDC settings

I followed all the instructions from here : https://console.cloud.google.com/kubernetes/clusters/details/us-central1-c/myapp/details?project=plenary-axon-332219&pli=1
So far I can log in successfully, but I cannot list any pods.
I tried checking different formats for the cluster role binding but still no difference
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: people-who-view-secrets
subjects:
- kind: User
name: Issuer_URI#email
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-viewer
apiGroup: rbac.authorization.k8s.io
Has anyone seen this?
You need to add resources to manipulate
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-viewer
rules:
- apiGroups: [""]
# The resource type for which access is granted
resources: ["secrets", "pods"] #here or namespaces , nodes
# The permissions granted by the ClusterRole
verbs: ["get", "watch", "list"]

How to configure a ClusterRole for namespaced resources

I want to allow a ServiceAccount in namespace A to access a resource in namespace B.
To achieve this I connect the ServiceAccount to a ClusterRole via a ClusterRoleBinding.
The documentation says I can "use a ClusterRole to [1.] define permissions on namespaced resources and be granted within individual namespace(s)"
But looking through the K8s documentation I can't find a way how to create a ClusterRole with namespaced resources. How can I achieve this?
...how to create a ClusterRole with namespaced resources...
Read further down a bit:
A ClusterRole can be used to grant the same permissions as a Role.
Because ClusterRoles are cluster-scoped. You can also use them to
grant access to:
...
namespaced resources (like Pods), across all namespaces
ClusterRole won't help you to restraint access to a single namespaced object. You can however use RoleBinding to reference a ClusterRole and restraint access to the object in the namespace of the RoleBinding.
I believe you need to create clusterrole not role.
example:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-grantor
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["create"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles"]
verbs: ["bind"]
# omit resourceNames to allow binding any ClusterRole
resourceNames: ["admin","edit","view"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: role-grantor-binding
namespace: user-1-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: role-grantor
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: user-1
above example is from this link.
I find both other answers a little confusing, hopefully this is clearer.
You did the right thing in creating a ClusterRole, but you want to bind it using a namespaced RoleBinding, not a ClusterRoleBinding.
Example using your examples. Notice how the RoleBinding is in the B namespace, giving A's ServiceAccount the permissions defined in the ClusterRole, but limited to the B namespace.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: what-a-is-allowed-to-do-in-b
rules:
- apiGroups: [""]
resources: ["pods", "deployments"] # etc
verbs: ["get", "list", "create"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: namespace-a
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: what-a-is-allowed-to-do-in-b
namespace: namespace-b
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: what-a-is-allowed-to-do-in-b
subjects:
- kind: ServiceAccount
name: my-app
namespace: namespace-a
Notes:
You have to use the ClusterRole because you can't get outside your own namespace without one. By using a RoleBinding, which is namespaced, you can then limit the access to the scope of the namespace of that RoleBinding.

How to set up permissions for Kubernetes resources?

First off, I'm aware of the Kubernetes RBAC method. My question is: is there a way to create Kubernetes resources that can only be read and/or written by a specific Role (or a ClusterRole)?
For example, let's say I have a Kubernetes Secret. I want this Secret to be bound to a specific ClusterRole, then only a ServiceAccount bound to this specific ClusterRole could read it. Is there a way to set up something like that?
Edit: it looks like what I want here is not possible. Kubernetes RBAC was designed to GRANT access to certain resources. I wanted to DENY access based on a specific group (or set of rules).
You can use the RBAC for managing the Role-based access in K8s
For example, let's say I have a Kubernetes Secret. I want this Secret
to be bound to a specific ClusterRole, so only a ServiceAccount bound
to this specific ClusterRole could read it. Is there a way to set up
something like that?
No, you can not use the ClusterRole for granular level access, however, you can create some Role to restrict secret.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: secret-read-role
rules:
- apiGroups: ["*"]
resources: ["secret"]
verbs: ["get", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: secret-read-sa
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: secret-read-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: secret-read-sa
apiGroup: ""
roleRef:
kind: Role
name: secret-read-role
apiGroup: ""
Checkout about the resourceNames you can also give a name or pattern in name so this way it might be helpful to attach a specific secret to Role.
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
resourceNames: ["userA-*"]
If you planning to Go with RBAC you can use the RBAC manager for better management : https://github.com/FairwindsOps/rbac-manager
Extra :
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: data-engineering
name: umbrella:data-engineering-app
rules:
– apiGroups: [“”]
resources: [“configmaps”]
resourceNames: [“data-engineering-app-configmap”] <<<<<<<<<
verbs: [“get”]
—
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: umbrella:data-engineering-app
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: umbrella:data-engineering-app
subjects:
– kind: ServiceAccount
name: data-engineering-app
namespace: data-engineering
You can also refer to resources by name for certain requests through the resourceNames list. When specified, requests can be restricted to individual instances of a resource. Here is an example that restricts its subject to only get or update a ConfigMap named my-configmap
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: configmap-updater
rules:
- apiGroups: [""]
#
# at the HTTP level, the name of the resource for accessing ConfigMap
# objects is "configmaps"
resources: ["configmaps"]
resourceNames: ["my-configmap"]
verbs: ["update", "get"]
https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-resources
Good Example : https://thenewstack.io/three-realistic-approaches-to-kubernetes-rbac/
It is not possible to restrict access on a resource per resource basis.
The RBAC framework works by allowing specified Roles to perform certain actions (get, update, delete etc.) over certain resources (pods, secrets etc) in a certain namespace.
Clusterroles are used to grant access across all namespaces or to non namespaced resources like nodes.
To achieve what you are looking for you need to isolate your Kubernetes secret in a namespace where you only allow your specific role to read secrets.

Kubernetes - grant full access to all namespaces matching prefix or regex

I am planning to deploy review-apps to kubernetes using namespaces. That is, my CI generates a random ID, I build a namespace from this like review-app-xxx and inside I'm deploying several helm charts.
How can I easily give access to all those namespaces to a group of people ?
Concrete example: assume I have several of those namespaces
review-app-aaaa
review-app-bbbb
review-app-cccc
What is the most simple way to give full access to those namespaces for a user belonging to group tech:dev ?
EDIT:
The non-dry way to think about it is to have one roleBinding per namespace like this
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: namespace-full-access-cluster-role
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: full-access-staging-namespace-for-devs
namespace: review-app-aaaa
subjects:
- kind: Group
name: devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-full-access-cluster-role
apiGroup: rbac.authorization.k8s.io
but is there a way to dry this ?

Why is my PodSecurityPolicy applied even if I don't have access?

I have two PodSecurityPolicy:
000-privileged (only kube-system service accounts and admin users)
100-restricted (everything else)
I have a problem with their assignment to pods.
First policy binding:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:privileged
rules:
- apiGroups:
- extensions
resources:
- podsecuritypolicies
resourceNames:
- 000-privileged
verbs:
- use
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:privileged-kube-system
namespace: kube-system
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: psp:privileged
apiGroup: rbac.authorization.k8s.io
Second policy binding:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:restricted
rules:
- apiGroups:
- extensions
resources:
- podsecuritypolicies
resourceNames:
- 100-restricted
verbs:
- use
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:restricted
subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: psp:restricted
apiGroup: rbac.authorization.k8s.io
Everything works fine in kube-system.
However, in other namespaces, it does not work as expected:
If I create a Deployment (kubectl apply -f deployment.yml), its pod gets tagged with psp 100-restricted.
If I create a Pod (kubectl apply -f pod.yml), it gets tagged with psp 000-privileged. I really don't get why its not 100-restricted.
My kubectl is configured with external authentication token from OpenID Connect (OIDC).
I verified the access and everything seems ok:
kubectl auth can-i use psp/100-restricted
yes
kubectl auth can-i use psp/000-privileged
no
Any clue?
The problem was that my user had access to all verbs (*) of all resources (*) of the 'extensions' apiGroup in its Role.
The documentation is a bit unclear (https://github.com/kubernetes/examples/tree/master/staging/podsecuritypolicy/rbac):
The use verb is a special verb that grants access to use a policy while not permitting any other access. Note that a user with superuser permissions within a namespace (access to * verbs on * resources) would be allowed to use any PodSecurityPolicy within that namespace.
I got confused by the mention of 'within that namespace'. Since PodSecurityGroup are not "namespaced", I assumed they could not be used without a ClusterRole/RoleBinding in the namespace giving explicit access. Seems I was wrong...
I modified my role to specify the following:
rules:
- apiGroups: ["", "apps", "autoscaling", "batch"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["extensions"]
resources: ["*"]
# Avoid using * here to prevent use of 'use' verb for podsecuritypolicies resource
verbs: ["create", "get", "watch", "list", "patch", "delete", "deletecollection", "update"]
And now it picks up the proper PSP. One interesting thing, it also prevent users from modifying (create/delete/update/etc) podsecuritypolicies.
It seems 'use' verb is quite special after all.....