Run `kubectl apply` using yaml stored in a variable - powershell

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.

Related

How can a k8s namespace admin use top?

We have a shared tenant cluster, and we want our developers to be able to run kubectl top pods --namespace dev-namespace
But it seems to me that for top to be usable, you need to be able to run kubectl get nodes. But nodes are not namespaced.
Is there a solution?
We the namespace admin setup like this:
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: username#domain
And as a cluster admin I can run the top command, so metrics-server seems to be working fine.
Kubernetes has API group metrics.k8s.io, that you can use to give read permission for kubectl top pods -n <namespace>. If you grant get and list permissions for pods, you can run the command.
I tested the configuration below in a GKE cluster running Kubernetes 1.21 with kubectl top pod --as=system:serviceaccount:monitoring:test-account -n monitoring. With these permissions, I can only run kubectl top pod in the monitoring namespace, other commands will fail.
apiVersion: v1
kind: ServiceAccount
metadata:
name: test-account
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: monitoring
rules:
- apiGroups: ["metrics.k8s.io"]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: monitoring
subjects:
- kind: ServiceAccount
name: test-account
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

Unable to have multiple ServiceAccount subjects in RoleBinding & ClusterRoleBinding?

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]

Kubernetes RBAC roles with resourceName and listing objects

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: p-viewer-role
namespace: pepsi
rules:
- apiGroups:
- ""
resourceNames:
- p83
resources:
- pods
verbs:
- list
- get
- watch
When we use resourceNames in the Roles, the following command works
kubectl get pods -n pepsi p83
returns a proper value. However,
kubectl get pods -n pepsi
returns forbidden. Why doesn't it list p83
RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: p-viewer-rolebinding
namespace: pepsi
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: p-viewer-role
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: pepsi-project-viewer
namespace: project
This is expected behavior. You have defined a role which is scoped to the namespace pepsi to pod resources with specific resourceName p83.
For kubectl get pods -n peps command to work you need to remove the resourceNames p83 from the Role
This kind of advanced validation is best handled by OPA where you can define fine grained policies.
Short answer:
list(and watch)actually can be restricted by their resource name, and permits list(and watch) requests using a fieldSelector of metadata.name=... to match a single object (for example, /api/v1/namespaces/$ns/configmaps?fieldSelector=metadata.name=foo)
For more details and some tests you can check this link: https://github.com/kubernetes/website/pull/29468
#sftim and #liggitt do offer a lot of help!

kubectl to allow user to only to copy files in and out of the pods

I have a Kubernetes cluster where my application is deployed.
there are some other users they should only be able to copy files into and from a pod. Using kubectl cp command.
This user context should not allow the user to do any other operations on the cluster other than kubectl cp.
kubectl cp internally uses exec. There is no way to provide permission to only copy but you can provide only exec permission.
Create a role with permission to pods/exec
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-exec
rules:
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
Create a Rolebinding to assign the above role to a user.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-exec-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-exec
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: user
Rather than use kubectl cp, instead run a sidecar container with an sftp or rsync server. That will give you better control at all levels.
You can use opa and admission controller which only permit to run api manifest has a specific label like "cp" or "username" etc. and also benefits from gatekeeper
https://www.youtube.com/watch?v=ZJgaGJm9NJE&t=3040s

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