Unable to have multiple ServiceAccount subjects in RoleBinding & ClusterRoleBinding? - kubernetes

I'm encountering a weird problem and not sure if I'm going crazy. I have the following rolebinding and clusterrolebinding yaml:
# Standard CLI role, some executable dashboard permissions.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: company-engineer-binding
namespace: company-ns
subjects:
- kind: ServiceAccount
name: testseven
apiGroup: ""
- kind: ServiceAccount
name: testsix
apiGroup: ""
roleRef:
kind: Role
name: company-engineer
apiGroup: ""
---
# Used to handle a few read-only permissions on the dashboard (listing)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: company-engineer-dashboard-clusterbinding
subjects:
- kind: ServiceAccount
name: testseven
namespace: company-ns
- kind: ServiceAccount
name: testsix
namespace: company-ns
roleRef:
kind: ClusterRole
name: company-engineer-dashboard
apiGroup: rbac.authorization.k8s.io
Each of these have an associated role/clusterrole that are verified to work. The issue is that when applying this yaml with kubectl apply -f , it only applies the role to the first subject in the list. So in the above example, only the testseven ServiceAccount gets these roles, while the testsix account gets nothing.
[root#k8s-m01 yaml]# kubectl get rolebinding,clusterrolebinding,role,clusterrole --all-namespaces -o jsonpath='{range .items[?(#.subjects[0].name=="testseven")]}[{.roleRef.kind},{.roleRef.name}]{end}'
[Role,company-engineer][ClusterRole,company-engineer-dashboard]
[root#k8s-m01 yaml]# kubectl get rolebinding,clusterrolebinding,role,clusterrole --all-namespaces -o jsonpath='{range .items[?(#.subjects[0].name=="testsix")]}[{.roleRef.kind},{.roleRef.name}]{end}'
[No output returns]
Could someone point me in the right direction on this? As an aside, I have verified that this same issue does not occur with using Users generated from certificates - it only occurs with ServiceAccounts.
Thanks!

rolebindings & clusterrolebindings have got applied sucessfully
It is more of a jsonpath query problem than applying rolebindgs.
kubectl get -f company-engineer-binding.yaml -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: "2021-07-16T16:46:10Z"
name: company-engineer-binding
namespace: company-ns
resourceVersion: "1120710"
uid: da5e3a51-55c5-4cf5-896f-d89e87ca1553
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: company-engineer
subjects:
- kind: ServiceAccount #index 0
name: testseven
- kind: ServiceAccount #index 1
name: testsix
# following command is working(showing output) because you are looking for key named 'name' with value 'testseven' 'at' index '0' under array 'subjects' as you mentioned ?(#.subjects[0].name=="testseven")
kubectl get rolebinding --all-namespaces -o jsonpath='{range .items[?(#.subjects[0].name=="testseven")]}[{.roleRef.kind},{.roleRef.name}]{end}'
[Role,company-engineer]
#following command does not show any ouput because you looking for key named 'name' with value 'testseven' 'at' index '0' under array 'subjects' as you mentioned ?(#.subjects[0].name=="testsix") but we have 'testsix' at index '1'
kubectl get rolebinding --all-namespaces -o jsonpath='{range .items[?(#.subjects[0].name=="testsix")]}[{.roleRef.kind},{.roleRef.name}]{end}'
#so if i change the index to 1 , The command works fine and shows output .
#Also not that i had to run this command on a particular namespace because following command will throw json error because other namespaces might have a rolebinding where they have only one subject/service account means no index 1.
# error message would contain 'Error executing template: array index out of bounds:'
kubectl get rolebinding -n company-ns -o jsonpath='{range .items[?(#.subjects[1].name=="testsix")]}[{.roleRef.kind},{.roleRef.name}]{end}'
[Role,company-engineer]

Related

Run `kubectl apply` using yaml stored in a variable

I have a resource I want to apply as part of an automated script (running in powershell). I would rather not have to write it out to a file then have to deal with cleaning it up.
Is it possible to apply the yaml as part of a script?
Something similar to this:
$myYaml = #'
apiVersion: "rbac.authorization.k8s.io/v1"
kind: RoleBinding
metadata:
name: ServiceAccount-clusteradmin
roleRef:
apiGroup: "rbac.authorization.k8s.io"
kind: ClusterRole
name: ClusterAdmin
subjects:
- apiGroup: "rbac.authorization.k8s.io"
kind: User
name: "MyAdminServiceAccount"
'#
kubectl apply #myYaml
Clearly, the kubectl command above does not work.
My question is: Is a way to apply this yaml without creating a file (using powershell)?
myYaml is a variable having the data:
$myYaml = #'
apiVersion: "rbac.authorization.k8s.io/v1"
kind: RoleBinding
metadata:
name: ServiceAccount-clusteradmin
roleRef:
apiGroup: "rbac.authorization.k8s.io"
kind: ClusterRole
name: ClusterAdmin
subjects:
- apiGroup: "rbac.authorization.k8s.io"
kind: User
name: "MyAdminServiceAccount"
'#
Perform the following to echo the contents of $myYaml variable and pipe it to kubectl apply -f -, here last - is for piped input.
$myYaml |kubectl.exe apply -f -
rolebinding.rbac.authorization.k8s.io/ServiceAccount-clusteradmin created
kubectl.exe get rolebindings
NAME ROLE AGE
ServiceAccount-clusteradmin ClusterRole/ClusterAdmin 18s
This is very similar to linux environment where echo "$var" |kubectl apply -f - is used to perform same action.

Is there a way for K8s service account to create another service account in a different namespace?

I have an app which interacts with an existing service account ("the agent") on a designated namespace. I want the agent to be able to create additional service accounts and roles on other namespaces. Is there a way to do so?
I've already answered to this question in a comment section, but I've also decided to provide more comprehensive information with examples.
Background
Kubernetes includes RBAC (role-based access control) mechanism that enables you to specify which actions are permitted for specific user or group of users. From Kubernetes v1.6 RBAC is enabled by default.
There are four Kubernetes objects: Role, ClusterRole, RoleBinding and ClusterRoleBinding, that we can use to configure needed RBAC rules. Role and RoleBinding are namespaced and ClusterRole and ClusterRoleBinding are cluster scoped resources.
We use Role and RoleBinding to authorize user to namespaced resources and we use ClusterRole and ClusterRoleBinding for cluster wide resources.
However, we can also mix this resurces.
Below I will briefly describe common combinations.
NOTE: It is impossible to link ClusterRoleBindings with Role.
For every test case I created new test namespace and test-agent service account.
Role and RoleBinding
I created simple Role and RoleBinding in specific namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test-role
namespace: test
rules:
- apiGroups:
- ""
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rolebinding
namespace: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: test-role
subjects:
- kind: ServiceAccount
name: test-agent
We can see that test-agent has access only to resources in test namespace:
$ kubectl auth can-i get pod -n test --as=system:serviceaccount:test:test-agent
yes
$ kubectl auth can-i get pod -n default --as=system:serviceaccount:test:test-agent
no
ClusterRole and RoleBinding
I created ClusterRole and RoleBinding:
NOTE: I didn't specify any namespace for ClusterRole.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test-clusterrole
rules:
- apiGroups:
- ""
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rolebinding
namespace: test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: test-clusterrole
subjects:
- kind: ServiceAccount
name: test-agent
Now we can see, that if a ClusterRole is linked to a ServiceAccount using a RoleBinding, the ClusterRole permissions apply ONLY to the namespace in which this RoleBinding has been created:
$ kubectl auth can-i get pod -n test --as=system:serviceaccount:test:test-agent
yes
$ kubectl auth can-i get pod -n default --as=system:serviceaccount:test:test-agent
no
ClusterRole and ClusterRoleBinding
Finally I created ClusterRole and ClusterRoleBinding:
NOTE: I didn't specify any namespace for ClusterRole and ClusterRoleBinding.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: test-clusterrole
rules:
- apiGroups:
- ""
resources:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: test-clusterrolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: test-clusterrole
subjects:
- kind: ServiceAccount
name: test-agent
namespace: test
Now we can see, that if a ClusterRole is linked to a ServiceAccount using a ClusterRoleBinding, the ClusterRole permissions apply to all namespaces:
$ kubectl auth can-i get pod -n test --as=system:serviceaccount:test:test-agent
yes
$ kubectl auth can-i get pod -n default --as=system:serviceaccount:test:test-agent
yes
$ kubectl auth can-i get pod -n kube-system --as=system:serviceaccount:test:test-agent
yes
Useful note: You can display all possible verbs for specific resource using
kubectl api-resources -o wide, e.g. to display all possible verbs for Deployment we can use:
$ kubectl api-resources -o wide | grep deployment
deployments deploy apps/v1 true Deployment [create delete deletecollection get list patch update watch]

How to restrict a user to one namespace on kubernetes Dashboard?

I have a custom role related to a specific namespace. I want to create a service account that will have access to the Dashboard and only being able to see this namespace assigned to that role.
I have tried the following:
apiVersion: v1
kind: Namespace
metadata:
name: namespace-green
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: green
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-green
namespace: namespace-green
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testDashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-green
subjects:
- kind: ServiceAccount
name: green
namespace: kubernetes-dashboard
I retrieved the token with the following command:
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep green | awk '{print $1}')
When I login to the Dashboard I see only the default namespace although I have assigned the new namespace to that role.
I am not able to to figure out how to view the resources of the new namespace only and based on the permissions of the role the service account should have limited access.
You dont need to create a new role.
You can just create a RoleBinding to the 'edit' clusterrole with the new service account you have created and it will work as you expect it to. Also the access will be limited to just one namespace - kubernetes-dashboard
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: testDashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: green
namespace: kubernetes-dashboard
After that the you can use the same old token to test.

Kubernetes UI dashboard

I am trying to configure the Kubernetes UI dashboard. with full admin permissions, so created a YAML file: dashboard-admin.yaml.
contents of my file are below:
apiVersion: rbac.authorization.k8s.io/v1.12.1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
so when I am trying to apply changes to this file by executing the command
kubectl create -f dashboard-admin.yaml
1) I'm encountering with an error as stated below:
error: error parsing dashboard-admin.yaml: error converting YAML to JSON: yaml: line 12: mapping values are not allowed in this context
2) Also, after running the kubectl proxy command, I'm unable to open the dashboard in my local machine using the link below:
http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
Your error is related to YAML indentation. I've edited the question that shows the correct format. Or if you'd like you can use this one too.
apiVersion: rbac.authorization.k8s.io/v1.12.1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system
Your K8s dashboard will not work unless you have correctly setup the RBAC rule above,

How to protect k8s secrets using rbac?

I set up a k8s cluster in GKE with rbac enabled, and I install Istio into the cluster.
I follow this step (link) to create key/certs for the Istio ingress controller, and key/certs are stored as secret whose name is istio-ingress-certs.
Now I want to use RBAC to limit access to istio-ingress-certs, so that every component in istio-system is allowed to read the secret, but none could modify or delete it.
I create a secrets-rbac.yaml file, and run kubectl apply -f secrets-rbac.yaml, which creates a role to read the secret, and binds this role to all serviceaccounts in istio-system namespace.
To verify that a serviceaccount is not allowed to modify istio-ingress-certs. I use this command to test.
kubectl auth can-i edit secrets/istio-ingress-certs -n istio-system --as system:serviceaccount:istio-system:istio-pilot-service-account
I expect that the command would return false, but it returns true. I think I didn't set up rbac correctly in the yaml file, but I am not clear which part is not correct.
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: istio-system
name: istio-ingress-certs-reader
rules:
- apiGroups: ["*"]
resources: ["secrets"]
resourceNames: ["istio-ingress-certs"]
verbs: ["get"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: istio-system
name: read-istio-ingress-certs
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: istio-ingress-certs-reader
subjects:
- kind: Group
name: system:serviceaccounts:istio-system
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io