Add object to an array in yaml via Kustomize - kubernetes

how can I add object to array via Kustomize? As a result I would like to have two ServiceAccounts added to subjects, like so:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: name
namespace: test1
- kind: ServiceAccount
name: name
namespace: test2
I'm trying with that patch:
- op: add
path: "/subjects/0"
value:
kind: ServiceAccount
name: name
namespace: test1
And another patch for second environment:
- op: add
path: "/subjects/1"
value:
kind: ServiceAccount
name: name
namespace: test2
But in result I'm getting duplicated subjects, so of course it is wrong:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: name
namespace: test1 // the same...
- kind: ServiceAccount
name: name
namespace: test1 // ...as here
What would be a proper way to add it?

If I start with a ClusterRoleBinding that looks like this in crb.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects: []
And I create a kustomization.yaml file like this:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- crb.yaml
patches:
- target:
kind: ClusterRoleBinding
name: binding
patch: |
- op: add
path: /subjects/0
value:
kind: ServiceAccount
name: name
namespace: test1
- target:
kind: ClusterRoleBinding
name: binding
patch: |
- op: add
path: /subjects/1
value:
kind: ServiceAccount
name: name
namespace: test2
Then I get as output:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: name
namespace: test1
- kind: ServiceAccount
name: name
namespace: test2
Which is I think what you're looking for. Does this help? Note that instead of explicitly setting an index in the path, like:
path: /subjects/0
We can instead specify:
path: /subjects/-
Which means "append to the list", and in this case will generate the same output.

Related

kubernetes ServiceAccount Role Verification failed

questions:
Create a service account name dev-sa in default namespace, dev-sa can create below components in dev namespace:
Deployment
StatefulSet
DaemonSet
result:
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: dev-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: dev
name: sa-role
rules:
- apiGroups: [""]
resources: ["deployment","statefulset","daemonset"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sa-rolebinding
namespace: dev
subjects:
- kind: ServiceAccount
name: dev-sa
namespace: default
roleRef:
kind: Role
name: sa-role
apiGroup: rbac.authorization.k8s.io
Validation:
kubectl auth can-i create deployment -n dev \
--as=system:serviceaccount:default:dev-sa
no
This is an exam question, but I can't pass
Can you tell me where the mistake is? thx
in Role, use * on api group, and add s on resource name.
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: dev-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: dev
name: sa-role
rules:
- apiGroups: ["*"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sa-rolebinding
namespace: dev
subjects:
- kind: ServiceAccount
name: dev-sa
namespace: default
roleRef:
kind: Role
name: sa-role
apiGroup: rbac.authorization.k8s.io
First, the apiGroups of Deployment, daemonSet, and statefulSet is apps, not core. So, for the apiGroups value, instead of "", put "apps". (an empty string representing core)
Second, remember: resources always define in Plural of "kind". So, for resources values, you always should use plural names. e.g. instead of deployment, you use deployments
So, your file should be something like this:
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: dev-sa
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: dev
name: sa-role
rules:
- apiGroups: ["apps"]
resources: ["deployments","statefulsets","daemonsets"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sa-rolebinding
namespace: dev
subjects:
- kind: ServiceAccount
name: dev-sa
namespace: default
roleRef:
kind: Role
name: sa-role
apiGroup: rbac.authorization.k8s.io
For apiGroups's values, be sure to check the docs
I suggest you read this article about Users and Permissions in Kubernetes.

Patch namespace and change resource kind for a role binding

Using kustomize, I'd like to set namespace field for all my objects.
Here is my kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesJson6902:
- patch: |-
- op: replace
path: /kind
value: RoleBinding
target:
group: rbac.authorization.k8s.io
kind: ClusterRoleBinding
name: manager-rolebinding
version: v1
resources:
- role_binding.yaml
namespace: <NAMESPACE>
Here is my resource file: role_binding.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
labels:
control-plane: controller-manager
spec:
containers:
- command:
- /manager
args:
- --enable-leader-election
image: controller:latest
name: manager
And kustomize output:
$ kustomize build
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: <NAMESPACE>
spec:
replicas: 1
selector:
matchLabels:
control-plane: controller-manager
template:
metadata:
labels:
control-plane: controller-manager
spec:
containers:
- args:
- --enable-leader-election
command:
- /manager
image: controller:latest
name: manager
How can I patch the namespace field in the RoleBinding and set it to <NAMESPACE>? In above example, it works perfectly for the Deployment resource but not for the RoleBinding.
Here is a solution which solves the issue, using kustomize-v4.0.5:
cat <<EOF > kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesJson6902:
- patch: |-
- op: replace
path: /kind
value: RoleBinding
- op: add
path: /metadata/namespace
value:
<NAMESPACE>
target:
group: rbac.authorization.k8s.io
kind: ClusterRoleBinding
name: manager-rolebinding
version: v1
resources:
- role_binding.yaml
- service_account.yaml
namespace: <NAMESPACE>
EOF
cat <<EOF > role_binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
labels:
control-plane: controller-manager
spec:
containers:
- command:
- /manager
args:
- --enable-leader-election
image: controller:latest
name: manager
EOF
cat <<EOF > service_account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: controller-manager
namespace: system
EOF
Adding the ServiceAccount resource, and the Namespace field in the RoleBinding resource allows to correctly set the subject field in the RoleBinding.
Looking directly from the code:
// roleBindingHack is a hack for implementing the namespace transform
// for RoleBinding and ClusterRoleBinding resource types.
// RoleBinding and ClusterRoleBinding have namespace set on
// elements of the "subjects" field if and only if the subject elements
// "name" is "default". Otherwise the namespace is not set.
//
// Example:
//
// kind: RoleBinding
// subjects:
// - name: "default" # this will have the namespace set
// ...
// - name: "something-else" # this will not have the namespace set
// ...
The ServiceAccount and the reference on the ClusterRoleBinding needs to have "default" as namespace or otherwise it won't be replaced.
Check the example below:
$ cat <<EOF > my-resources.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-clusterrole
subjects:
- kind: ServiceAccount
name: my-service-account
namespace: default
EOF
$ cat <<EOF > kustomization.yaml
namespace: foo-namespace
namePrefix: foo-prefix-
resources:
- my-resources.yaml
EOF
$ kustomize build
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-prefix-my-service-account
namespace: foo-namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: foo-prefix-my-cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: my-clusterrole
subjects:
- kind: ServiceAccount
name: foo-prefix-my-service-account
namespace: foo-namespace

How to add a new ClusterRoleBinding with Kustomize in k8s without removing existing bindings?

When I type kubectl edit clusterrolebinding foo-role, I can see something like:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: foo-role
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: foo-user
namespace: ns1
- kind: ServiceAccount
name: foo-user
namespace: ns2
I can add a new ClusterRoleBinding for namespace ns3 by appending the following config to above file:
- kind: ServiceAccount
name: foo-user
namespace: ns3
However, I want to use Kustomize to add new bindings instead of manually modifying the above file.
I tried to apply the .yaml file below:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: foo-role
selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/foo-role
uid: 64a4a787-d5ab-4c83-be2b-476c1bcb6c96
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: foo-user
namespace: ns3
It did add a new ClusterRoleBinding in the namespace ns3, but it will remove existing ClusterRoleBindings for ns1 and ns2.
Is there a way to add new ClusterRoleBinding with Kustomize without removing existing ones?
Give them different names in the metadata. You didn't make a new one, you just overwrote the same one.

Question about using apiGroup with RoleRef when creating ClusterRoleBinding

Here is a ClusterRoleBinding syntax that I found for creating Cluster role binding. Why does apiGroup needed to be specified when referring to role in roleRef? I have seen similar example in the Kubernetes docs. What is the possible explanation?
Example 1
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # Name is case sensitive
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
Example 2
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
All Kubernetes resources have group, version, name, so an apiGroup field is required to identify a group.
For example, if you create your Custom Resource Definition(CRD), you need setting these fields.
below is the sample controller example:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: foos.samplecontroller.k8s.io
spec:
group: samplecontroller.k8s.io
version: v1alpha1
names:
kind: Foo
plural: foos
scope: Namespaced
(ServiceAccount resource is the core group. so I think ServiceAccount could be omitted a group field.)

Unsupported value: "rbac.authorization.k8s.io"

When I try to
kubectl create -f cloudflare-argo-rolebinding.yml
this RoleBinding
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cloudflare-argo-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: cloudflare-argo
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: cloudflare-argo-role
apiGroup: rbac.authorization.k8s.io
I get this error :
The RoleBinding "cloudflare-argo-rolebinding" is invalid: subjects[0].apiGroup: Unsupported value: "rbac.authorization.k8s.io": supported values: ""
Any idea ? I'm on DigitalOcean using their new Kubernetes service if it helps.
I think problem is using wrong apiGroup.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cloudflare-argo-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: cloudflare-argo
# apiGroup is ""(core/v1) for service_account
apiGroup: ""
roleRef:
kind: Role
name: cloudflare-argo-role
apiGroup: rbac.authorization.k8s.io
ServiceAccount subjects are in the v1 API, which is apiGroup ""