From 116c531ccc7c7975d886d30d423cbc1b4a5d8f8c Mon Sep 17 00:00:00 2001 From: Fabian Kramm Date: Wed, 7 Feb 2024 10:05:27 +0100 Subject: [PATCH] refactor: rbac & extraRules --- charts/eks/templates/_helpers.tpl | 103 +++++------------- charts/eks/templates/_kind.tpl | 64 +++++++++++ charts/eks/templates/rbac/clusterrole.yaml | 19 ++-- charts/eks/templates/rbac/role.yaml | 19 ++-- charts/eks/tests/README.md | 9 ++ charts/eks/tests/clusterrole_test.yaml | 41 +++++++ charts/eks/tests/role_test.yaml | 32 ++++++ charts/eks/values.yaml | 19 ++-- charts/k0s/templates/_helpers.tpl | 38 +++++-- charts/k0s/templates/rbac/clusterrole.yaml | 19 ++-- charts/k0s/templates/rbac/role.yaml | 19 ++-- charts/k0s/tests/README.md | 9 ++ charts/k0s/tests/clusterrole_test.yaml | 41 +++++++ charts/k0s/tests/role_test.yaml | 32 ++++++ charts/k0s/values.yaml | 19 ++-- charts/k3s/templates/_helpers.tpl | 38 +++++-- charts/k3s/templates/rbac/clusterrole.yaml | 19 ++-- charts/k3s/templates/rbac/role.yaml | 19 ++-- charts/k3s/tests/README.md | 9 ++ charts/k3s/tests/clusterrole_test.yaml | 41 +++++++ charts/k3s/tests/role_test.yaml | 32 ++++++ charts/k3s/values.yaml | 17 ++- charts/k8s/templates/_helpers.tpl | 103 +++++------------- charts/k8s/templates/_kind.tpl | 62 +++++++++++ charts/k8s/templates/rbac/clusterrole.yaml | 19 ++-- charts/k8s/templates/rbac/role.yaml | 19 ++-- charts/k8s/tests/README.md | 9 ++ charts/k8s/tests/clusterrole_test.yaml | 41 +++++++ charts/k8s/tests/role_test.yaml | 32 ++++++ charts/k8s/values.yaml | 19 ++-- go.mod | 2 +- go.sum | 4 +- .../vcluster-values/helmvalues/common.go | 41 +++++-- vendor/modules.txt | 2 +- 34 files changed, 714 insertions(+), 297 deletions(-) create mode 100644 charts/eks/templates/_kind.tpl create mode 100644 charts/eks/tests/README.md create mode 100644 charts/eks/tests/clusterrole_test.yaml create mode 100644 charts/eks/tests/role_test.yaml create mode 100644 charts/k0s/tests/README.md create mode 100644 charts/k0s/tests/clusterrole_test.yaml create mode 100644 charts/k0s/tests/role_test.yaml create mode 100644 charts/k3s/tests/README.md create mode 100644 charts/k3s/tests/clusterrole_test.yaml create mode 100644 charts/k3s/tests/role_test.yaml create mode 100644 charts/k8s/templates/_kind.tpl create mode 100644 charts/k8s/tests/README.md create mode 100644 charts/k8s/tests/clusterrole_test.yaml create mode 100644 charts/k8s/tests/role_test.yaml diff --git a/charts/eks/templates/_helpers.tpl b/charts/eks/templates/_helpers.tpl index eb627285a..50f08d6f9 100644 --- a/charts/eks/templates/_helpers.tpl +++ b/charts/eks/templates/_helpers.tpl @@ -39,17 +39,12 @@ Whether to create a cluster role or not */}} {{- define "vcluster.createClusterRole" -}} {{- if or - (not - (empty (include "vcluster.serviceMapping.fromHost" . ))) - (not - (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) - (not - (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.serviceMapping.fromHost" . ))) + (not (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) .Values.rbac.clusterRole.create .Values.sync.hoststorageclasses.enabled - (index - ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) - "enabled") + (index ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) "enabled") (include "vcluster.syncIngressclassesEnabled" . ) .Values.pro .Values.sync.nodes.enabled @@ -60,7 +55,7 @@ Whether to create a cluster role or not .Values.proxy.metricsServer.nodes.enabled .Values.multiNamespaceMode.enabled .Values.coredns.plugin.enabled -}} - {{- true -}} +{{- true -}} {{- end -}} {{- end -}} @@ -129,6 +124,29 @@ Prints only the flags that modify the defaults: {{- end }} {{- end -}} +{{/* + Cluster role rules defined on global level +*/}} +{{- define "vcluster.rbac.clusterRoleExtraRules" -}} +{{- if .Values.rbac.clusterRole.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.clusterRole.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + + +{{/* + Role rules defined on global level +*/}} +{{- define "vcluster.rbac.roleExtraRules" -}} +{{- if .Values.rbac.role.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.role.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + {{/* Role rules defined by plugins */}} @@ -176,68 +194,3 @@ Prints only the flags that modify the defaults: - '--map-host-service={{ $value.from }}={{ $value.to }}' {{- end }} {{- end -}} - - -{{/* - deployment kind -*/}} -{{- define "vcluster.kind" -}} -{{ if and .Values.embeddedEtcd.enabled .Values.pro }}StatefulSet{{ else }}Deployment{{ end }} -{{- end -}} - -{{/* - service name for statefulset -*/}} -{{- define "vcluster.statefulset.serviceName" }} -{{- if .Values.embeddedEtcd.enabled }} -serviceName: {{ .Release.Name }}-headless -{{- end }} -{{- end -}} - -{{/* - volumeClaimTemplate -*/}} -{{- define "vcluster.statefulset.volumeClaimTemplate" }} -{{- if .Values.embeddedEtcd.enabled }} -{{- if .Values.autoDeletePersistentVolumeClaims }} -{{- if ge (int .Capabilities.KubeVersion.Minor) 27 }} -persistentVolumeClaimRetentionPolicy: - whenDeleted: Delete -{{- end }} -{{- end }} -{{- if (hasKey .Values "volumeClaimTemplates") }} -volumeClaimTemplates: -{{ toYaml .Values.volumeClaimTemplates | indent 4 }} -{{- else if .Values.syncer.storage.persistence }} -volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - {{- if .Values.syncer.storage.className }} - storageClassName: {{ .Values.syncer.storage.className }} - {{- end }} - resources: - requests: - storage: {{ .Values.syncer.storage.size }} -{{- end }} -{{- end }} -{{- end -}} - - -{{/* - deployment strategy -*/}} -{{- define "vcluster.deployment.strategy" }} -{{- if not .Values.embeddedEtcd.enabled }} -strategy: - rollingUpdate: - maxSurge: 1 - {{- if (eq (int .Values.syncer.replicas) 1) }} - maxUnavailable: 0 - {{- else }} - maxUnavailable: 1 - {{- end }} - type: RollingUpdate -{{- end }} -{{- end -}} diff --git a/charts/eks/templates/_kind.tpl b/charts/eks/templates/_kind.tpl new file mode 100644 index 000000000..c560376e7 --- /dev/null +++ b/charts/eks/templates/_kind.tpl @@ -0,0 +1,64 @@ + +{{/* + deployment kind +*/}} +{{- define "vcluster.kind" -}} +{{ if and .Values.embeddedEtcd.enabled .Values.pro }}StatefulSet{{ else }}Deployment{{ end }} +{{- end -}} + +{{/* + service name for statefulset +*/}} +{{- define "vcluster.statefulset.serviceName" }} +{{- if .Values.embeddedEtcd.enabled }} +serviceName: {{ .Release.Name }}-headless +{{- end }} +{{- end -}} + +{{/* + volumeClaimTemplate +*/}} +{{- define "vcluster.statefulset.volumeClaimTemplate" }} +{{- if .Values.embeddedEtcd.enabled }} +{{- if .Values.autoDeletePersistentVolumeClaims }} +{{- if ge (int .Capabilities.KubeVersion.Minor) 27 }} +persistentVolumeClaimRetentionPolicy: + whenDeleted: Delete +{{- end }} +{{- end }} +{{- if (hasKey .Values "volumeClaimTemplates") }} +volumeClaimTemplates: +{{ toYaml .Values.volumeClaimTemplates | indent 4 }} +{{- else if .Values.syncer.storage.persistence }} +volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + {{- if .Values.syncer.storage.className }} + storageClassName: {{ .Values.syncer.storage.className }} + {{- end }} + resources: + requests: + storage: {{ .Values.syncer.storage.size }} +{{- end }} +{{- end }} +{{- end -}} + + +{{/* + deployment strategy +*/}} +{{- define "vcluster.deployment.strategy" }} +{{- if not .Values.embeddedEtcd.enabled }} +strategy: + rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.syncer.replicas) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} + type: RollingUpdate +{{- end }} +{{- end -}} diff --git a/charts/eks/templates/rbac/clusterrole.yaml b/charts/eks/templates/rbac/clusterrole.yaml index 684500c3d..984267cae 100644 --- a/charts/eks/templates/rbac/clusterrole.yaml +++ b/charts/eks/templates/rbac/clusterrole.yaml @@ -18,7 +18,7 @@ rules: resources: ["features", "virtualclusters"] verbs: ["get", "list", "watch"] {{- end }} - {{- if or .Values.pro .Values.sync.nodes.enabled .Values.rbac.clusterRole.create }} + {{- if or .Values.pro .Values.sync.nodes.enabled }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["get", "watch", "list"] @@ -31,17 +31,17 @@ rules: resources: [ "pods"] verbs: ["get", "watch", "list"] {{- end }} - {{- if and (or .Values.sync.nodes.enabled .Values.rbac.clusterRole.create) (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} + {{- if and .Values.sync.nodes.enabled (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} - apiGroups: [""] resources: ["nodes/proxy"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or (and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges) .Values.rbac.clusterRole.create }} + {{- if and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["update", "patch"] {{- end }} - {{- if or .Values.sync.persistentvolumes.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.persistentvolumes.enabled }} - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -56,7 +56,7 @@ rules: resources: ["ingressclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.storageclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.storageclasses.enabled }} - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -66,12 +66,12 @@ rules: resources: ["storageclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.priorityclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.priorityclasses.enabled }} - apiGroups: ["scheduling.k8s.io"] resources: ["priorityclasses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshotclasses"] verbs: ["get", "list", "watch"] @@ -79,8 +79,6 @@ rules: resources: ["volumesnapshotcontents"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} - {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} {{- if (not (empty (include "vcluster.serviceMapping.fromHost" . ))) }} - apiGroups: [""] resources: ["services", "endpoints"] @@ -99,4 +97,7 @@ rules: resources: ["nodes"] verbs: ["get", "list"] {{- end }} + {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.clusterRoleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/eks/templates/rbac/role.yaml b/charts/eks/templates/rbac/role.yaml index da4362387..de05bbb62 100644 --- a/charts/eks/templates/rbac/role.yaml +++ b/charts/eks/templates/rbac/role.yaml @@ -35,22 +35,22 @@ rules: resources: ["configmaps", "secrets", "services", "pods", "pods/attach", "pods/portforward", "pods/exec", "persistentvolumeclaims"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.status .Values.rbac.role.extended }} + {{- if .Values.sync.pods.status }} - apiGroups: [""] resources: ["pods/status"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.ephemeralContainers .Values.rbac.role.extended }} + {{- if .Values.sync.pods.ephemeralContainers }} - apiGroups: [""] resources: ["pods/ephemeralcontainers"] verbs: ["patch", "update"] {{- end }} - {{- if or .Values.sync.endpoints.enabled .Values.rbac.role.extended .Values.headless }} + {{- if or .Values.sync.endpoints.enabled .Values.headless }} - apiGroups: [""] resources: ["endpoints"] verbs: ["create", "delete", "patch", "update"] {{- end }} - {{- if or (gt (int .Values.syncer.replicas) 1) .Values.rbac.role.extended }} + {{- if gt (int .Values.syncer.replicas) 1 }} - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -58,7 +58,7 @@ rules: - apiGroups: [""] resources: ["endpoints", "events", "pods/log"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.ingresses.enabled}} + {{- if .Values.sync.ingresses.enabled}} - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -66,22 +66,22 @@ rules: - apiGroups: ["apps"] resources: ["statefulsets", "replicasets", "deployments"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.networkpolicies.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.networkpolicies.enabled }} - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshots"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.serviceaccounts.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.serviceaccounts.enabled }} - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.poddisruptionbudgets.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.poddisruptionbudgets.enabled }} - apiGroups: ["policy"] resources: ["poddisruptionbudgets"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -100,4 +100,5 @@ rules: {{- end }} {{- include "vcluster.plugin.roleExtraRules" . | indent 2 }} {{- include "vcluster.generic.roleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.roleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/eks/tests/README.md b/charts/eks/tests/README.md new file mode 100644 index 000000000..228e10d6e --- /dev/null +++ b/charts/eks/tests/README.md @@ -0,0 +1,9 @@ +Add [unittest plugin](https://github.com/helm-unittest/helm-unittest) via: +``` +helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` + +Run tests via: +``` +helm unittest charts/eks -d +``` diff --git a/charts/eks/tests/clusterrole_test.yaml b/charts/eks/tests/clusterrole_test.yaml new file mode 100644 index 000000000..3385c786c --- /dev/null +++ b/charts/eks/tests/clusterrole_test.yaml @@ -0,0 +1,41 @@ +suite: ClusterRole +templates: + - rbac/clusterrole.yaml + +tests: + - it: should create clusterrole + set: + rbac: + clusterRole: + create: true + asserts: + - hasDocuments: + count: 1 + - it: should not create clusterrole + set: + rbac: + clusterRole: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + clusterRole: + create: true + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/eks/tests/role_test.yaml b/charts/eks/tests/role_test.yaml new file mode 100644 index 000000000..5eeedba74 --- /dev/null +++ b/charts/eks/tests/role_test.yaml @@ -0,0 +1,32 @@ +suite: Role +templates: + - rbac/role.yaml + +tests: + - it: should not create role + set: + rbac: + role: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + role: + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/eks/values.yaml b/charts/eks/values.yaml index a58206882..3b8a541f5 100644 --- a/charts/eks/values.yaml +++ b/charts/eks/values.yaml @@ -334,22 +334,19 @@ workloadServiceAccount: # Roles & ClusterRoles for the vcluster rbac: clusterRole: - # Deprecated ! - # Necessary cluster roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster + # You don't need to toggle this as necessary cluster roles are created based on the enabled syncers (.sync.*.enabled). + # This only makes sense to enable if you want to use the extraRules below. create: false + # Extra Rules for the cluster role + extraRules: [] role: - # Deprecated ! - # Support for this value will be removed in a future version of the vcluster - # and basic role will always be created + # Disable this only if you don't want vCluster to create a role. This will break most functionality if disabled. create: true - # Deprecated ! - # Necessary extended roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster - extended: false + # Extra Rules for the role + extraRules: [] # all entries in excludedApiResources will be excluded from the Role created for vcluster excludedApiResources: - # - pods/exec + # - pods/exec # Syncer service configurations service: diff --git a/charts/k0s/templates/_helpers.tpl b/charts/k0s/templates/_helpers.tpl index 9872bf13c..50f08d6f9 100644 --- a/charts/k0s/templates/_helpers.tpl +++ b/charts/k0s/templates/_helpers.tpl @@ -39,17 +39,12 @@ Whether to create a cluster role or not */}} {{- define "vcluster.createClusterRole" -}} {{- if or - (not - (empty (include "vcluster.serviceMapping.fromHost" . ))) - (not - (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) - (not - (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.serviceMapping.fromHost" . ))) + (not (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) .Values.rbac.clusterRole.create .Values.sync.hoststorageclasses.enabled - (index - ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) - "enabled") + (index ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) "enabled") (include "vcluster.syncIngressclassesEnabled" . ) .Values.pro .Values.sync.nodes.enabled @@ -60,7 +55,7 @@ Whether to create a cluster role or not .Values.proxy.metricsServer.nodes.enabled .Values.multiNamespaceMode.enabled .Values.coredns.plugin.enabled -}} - {{- true -}} +{{- true -}} {{- end -}} {{- end -}} @@ -129,6 +124,29 @@ Prints only the flags that modify the defaults: {{- end }} {{- end -}} +{{/* + Cluster role rules defined on global level +*/}} +{{- define "vcluster.rbac.clusterRoleExtraRules" -}} +{{- if .Values.rbac.clusterRole.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.clusterRole.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + + +{{/* + Role rules defined on global level +*/}} +{{- define "vcluster.rbac.roleExtraRules" -}} +{{- if .Values.rbac.role.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.role.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + {{/* Role rules defined by plugins */}} diff --git a/charts/k0s/templates/rbac/clusterrole.yaml b/charts/k0s/templates/rbac/clusterrole.yaml index 684500c3d..984267cae 100644 --- a/charts/k0s/templates/rbac/clusterrole.yaml +++ b/charts/k0s/templates/rbac/clusterrole.yaml @@ -18,7 +18,7 @@ rules: resources: ["features", "virtualclusters"] verbs: ["get", "list", "watch"] {{- end }} - {{- if or .Values.pro .Values.sync.nodes.enabled .Values.rbac.clusterRole.create }} + {{- if or .Values.pro .Values.sync.nodes.enabled }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["get", "watch", "list"] @@ -31,17 +31,17 @@ rules: resources: [ "pods"] verbs: ["get", "watch", "list"] {{- end }} - {{- if and (or .Values.sync.nodes.enabled .Values.rbac.clusterRole.create) (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} + {{- if and .Values.sync.nodes.enabled (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} - apiGroups: [""] resources: ["nodes/proxy"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or (and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges) .Values.rbac.clusterRole.create }} + {{- if and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["update", "patch"] {{- end }} - {{- if or .Values.sync.persistentvolumes.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.persistentvolumes.enabled }} - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -56,7 +56,7 @@ rules: resources: ["ingressclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.storageclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.storageclasses.enabled }} - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -66,12 +66,12 @@ rules: resources: ["storageclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.priorityclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.priorityclasses.enabled }} - apiGroups: ["scheduling.k8s.io"] resources: ["priorityclasses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshotclasses"] verbs: ["get", "list", "watch"] @@ -79,8 +79,6 @@ rules: resources: ["volumesnapshotcontents"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} - {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} {{- if (not (empty (include "vcluster.serviceMapping.fromHost" . ))) }} - apiGroups: [""] resources: ["services", "endpoints"] @@ -99,4 +97,7 @@ rules: resources: ["nodes"] verbs: ["get", "list"] {{- end }} + {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.clusterRoleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k0s/templates/rbac/role.yaml b/charts/k0s/templates/rbac/role.yaml index f0280e31c..de05bbb62 100644 --- a/charts/k0s/templates/rbac/role.yaml +++ b/charts/k0s/templates/rbac/role.yaml @@ -35,22 +35,22 @@ rules: resources: ["configmaps", "secrets", "services", "pods", "pods/attach", "pods/portforward", "pods/exec", "persistentvolumeclaims"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.status .Values.rbac.role.extended }} + {{- if .Values.sync.pods.status }} - apiGroups: [""] resources: ["pods/status"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.ephemeralContainers .Values.rbac.role.extended }} + {{- if .Values.sync.pods.ephemeralContainers }} - apiGroups: [""] resources: ["pods/ephemeralcontainers"] verbs: ["patch", "update"] {{- end }} - {{- if or .Values.sync.endpoints.enabled .Values.rbac.role.extended .Values.headless }} + {{- if or .Values.sync.endpoints.enabled .Values.headless }} - apiGroups: [""] resources: ["endpoints"] verbs: ["create", "delete", "patch", "update"] {{- end }} - {{- if or ( gt (int (include "vcluster.replicas" . ) ) 1) .Values.rbac.role.extended }} + {{- if gt (int .Values.syncer.replicas) 1 }} - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -58,7 +58,7 @@ rules: - apiGroups: [""] resources: ["endpoints", "events", "pods/log"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.ingresses.enabled}} + {{- if .Values.sync.ingresses.enabled}} - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -66,22 +66,22 @@ rules: - apiGroups: ["apps"] resources: ["statefulsets", "replicasets", "deployments"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.networkpolicies.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.networkpolicies.enabled }} - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshots"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.serviceaccounts.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.serviceaccounts.enabled }} - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.poddisruptionbudgets.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.poddisruptionbudgets.enabled }} - apiGroups: ["policy"] resources: ["poddisruptionbudgets"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -100,4 +100,5 @@ rules: {{- end }} {{- include "vcluster.plugin.roleExtraRules" . | indent 2 }} {{- include "vcluster.generic.roleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.roleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k0s/tests/README.md b/charts/k0s/tests/README.md new file mode 100644 index 000000000..e6d4fa1c8 --- /dev/null +++ b/charts/k0s/tests/README.md @@ -0,0 +1,9 @@ +Add [unittest plugin](https://github.com/helm-unittest/helm-unittest) via: +``` +helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` + +Run tests via: +``` +helm unittest charts/k0s -d +``` diff --git a/charts/k0s/tests/clusterrole_test.yaml b/charts/k0s/tests/clusterrole_test.yaml new file mode 100644 index 000000000..3385c786c --- /dev/null +++ b/charts/k0s/tests/clusterrole_test.yaml @@ -0,0 +1,41 @@ +suite: ClusterRole +templates: + - rbac/clusterrole.yaml + +tests: + - it: should create clusterrole + set: + rbac: + clusterRole: + create: true + asserts: + - hasDocuments: + count: 1 + - it: should not create clusterrole + set: + rbac: + clusterRole: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + clusterRole: + create: true + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k0s/tests/role_test.yaml b/charts/k0s/tests/role_test.yaml new file mode 100644 index 000000000..5eeedba74 --- /dev/null +++ b/charts/k0s/tests/role_test.yaml @@ -0,0 +1,32 @@ +suite: Role +templates: + - rbac/role.yaml + +tests: + - it: should not create role + set: + rbac: + role: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + role: + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k0s/values.yaml b/charts/k0s/values.yaml index 8026e9259..2c18bf83f 100644 --- a/charts/k0s/values.yaml +++ b/charts/k0s/values.yaml @@ -211,22 +211,19 @@ workloadServiceAccount: # Roles & ClusterRoles for the vcluster rbac: clusterRole: - # Deprecated ! - # Necessary cluster roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster + # You don't need to toggle this as necessary cluster roles are created based on the enabled syncers (.sync.*.enabled). + # This only makes sense to enable if you want to use the extraRules below. create: false + # Extra Rules for the cluster role + extraRules: [] role: - # Deprecated ! - # Support for this value will be removed in a future version of the vcluster - # and basic role will always be created + # Disable this only if you don't want vCluster to create a role. This will break most functionality if disabled. create: true - # Deprecated ! - # Necessary extended roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster - extended: false + # Extra Rules for the role + extraRules: [] # all entries in excludedApiResources will be excluded from the Role created for vcluster excludedApiResources: - # - pods/exec + # - pods/exec # If vCluster persistent volume claims should get deleted automatically. autoDeletePersistentVolumeClaims: false diff --git a/charts/k3s/templates/_helpers.tpl b/charts/k3s/templates/_helpers.tpl index 9872bf13c..50f08d6f9 100644 --- a/charts/k3s/templates/_helpers.tpl +++ b/charts/k3s/templates/_helpers.tpl @@ -39,17 +39,12 @@ Whether to create a cluster role or not */}} {{- define "vcluster.createClusterRole" -}} {{- if or - (not - (empty (include "vcluster.serviceMapping.fromHost" . ))) - (not - (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) - (not - (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.serviceMapping.fromHost" . ))) + (not (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) .Values.rbac.clusterRole.create .Values.sync.hoststorageclasses.enabled - (index - ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) - "enabled") + (index ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) "enabled") (include "vcluster.syncIngressclassesEnabled" . ) .Values.pro .Values.sync.nodes.enabled @@ -60,7 +55,7 @@ Whether to create a cluster role or not .Values.proxy.metricsServer.nodes.enabled .Values.multiNamespaceMode.enabled .Values.coredns.plugin.enabled -}} - {{- true -}} +{{- true -}} {{- end -}} {{- end -}} @@ -129,6 +124,29 @@ Prints only the flags that modify the defaults: {{- end }} {{- end -}} +{{/* + Cluster role rules defined on global level +*/}} +{{- define "vcluster.rbac.clusterRoleExtraRules" -}} +{{- if .Values.rbac.clusterRole.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.clusterRole.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + + +{{/* + Role rules defined on global level +*/}} +{{- define "vcluster.rbac.roleExtraRules" -}} +{{- if .Values.rbac.role.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.role.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + {{/* Role rules defined by plugins */}} diff --git a/charts/k3s/templates/rbac/clusterrole.yaml b/charts/k3s/templates/rbac/clusterrole.yaml index 684500c3d..984267cae 100644 --- a/charts/k3s/templates/rbac/clusterrole.yaml +++ b/charts/k3s/templates/rbac/clusterrole.yaml @@ -18,7 +18,7 @@ rules: resources: ["features", "virtualclusters"] verbs: ["get", "list", "watch"] {{- end }} - {{- if or .Values.pro .Values.sync.nodes.enabled .Values.rbac.clusterRole.create }} + {{- if or .Values.pro .Values.sync.nodes.enabled }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["get", "watch", "list"] @@ -31,17 +31,17 @@ rules: resources: [ "pods"] verbs: ["get", "watch", "list"] {{- end }} - {{- if and (or .Values.sync.nodes.enabled .Values.rbac.clusterRole.create) (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} + {{- if and .Values.sync.nodes.enabled (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} - apiGroups: [""] resources: ["nodes/proxy"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or (and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges) .Values.rbac.clusterRole.create }} + {{- if and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["update", "patch"] {{- end }} - {{- if or .Values.sync.persistentvolumes.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.persistentvolumes.enabled }} - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -56,7 +56,7 @@ rules: resources: ["ingressclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.storageclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.storageclasses.enabled }} - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -66,12 +66,12 @@ rules: resources: ["storageclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.priorityclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.priorityclasses.enabled }} - apiGroups: ["scheduling.k8s.io"] resources: ["priorityclasses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshotclasses"] verbs: ["get", "list", "watch"] @@ -79,8 +79,6 @@ rules: resources: ["volumesnapshotcontents"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} - {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} {{- if (not (empty (include "vcluster.serviceMapping.fromHost" . ))) }} - apiGroups: [""] resources: ["services", "endpoints"] @@ -99,4 +97,7 @@ rules: resources: ["nodes"] verbs: ["get", "list"] {{- end }} + {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.clusterRoleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k3s/templates/rbac/role.yaml b/charts/k3s/templates/rbac/role.yaml index 70d89d548..de05bbb62 100644 --- a/charts/k3s/templates/rbac/role.yaml +++ b/charts/k3s/templates/rbac/role.yaml @@ -35,22 +35,22 @@ rules: resources: ["configmaps", "secrets", "services", "pods", "pods/attach", "pods/portforward", "pods/exec", "persistentvolumeclaims"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.status .Values.rbac.role.extended }} + {{- if .Values.sync.pods.status }} - apiGroups: [""] resources: ["pods/status"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.ephemeralContainers .Values.rbac.role.extended }} + {{- if .Values.sync.pods.ephemeralContainers }} - apiGroups: [""] resources: ["pods/ephemeralcontainers"] verbs: ["patch", "update"] {{- end }} - {{- if or .Values.sync.endpoints.enabled .Values.rbac.role.extended .Values.headless }} + {{- if or .Values.sync.endpoints.enabled .Values.headless }} - apiGroups: [""] resources: ["endpoints"] verbs: ["create", "delete", "patch", "update"] {{- end }} - {{- if or (gt (int ( include "vcluster.replicas" . )) 1 ) .Values.rbac.role.extended }} + {{- if gt (int .Values.syncer.replicas) 1 }} - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -58,7 +58,7 @@ rules: - apiGroups: [""] resources: ["endpoints", "events", "pods/log"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.ingresses.enabled}} + {{- if .Values.sync.ingresses.enabled}} - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -66,22 +66,22 @@ rules: - apiGroups: ["apps"] resources: ["statefulsets", "replicasets", "deployments"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.networkpolicies.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.networkpolicies.enabled }} - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshots"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.serviceaccounts.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.serviceaccounts.enabled }} - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.poddisruptionbudgets.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.poddisruptionbudgets.enabled }} - apiGroups: ["policy"] resources: ["poddisruptionbudgets"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -100,4 +100,5 @@ rules: {{- end }} {{- include "vcluster.plugin.roleExtraRules" . | indent 2 }} {{- include "vcluster.generic.roleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.roleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k3s/tests/README.md b/charts/k3s/tests/README.md new file mode 100644 index 000000000..bd826bdbe --- /dev/null +++ b/charts/k3s/tests/README.md @@ -0,0 +1,9 @@ +Add [unittest plugin](https://github.com/helm-unittest/helm-unittest) via: +``` +helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` + +Run tests via: +``` +helm unittest charts/k3s -d +``` diff --git a/charts/k3s/tests/clusterrole_test.yaml b/charts/k3s/tests/clusterrole_test.yaml new file mode 100644 index 000000000..3385c786c --- /dev/null +++ b/charts/k3s/tests/clusterrole_test.yaml @@ -0,0 +1,41 @@ +suite: ClusterRole +templates: + - rbac/clusterrole.yaml + +tests: + - it: should create clusterrole + set: + rbac: + clusterRole: + create: true + asserts: + - hasDocuments: + count: 1 + - it: should not create clusterrole + set: + rbac: + clusterRole: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + clusterRole: + create: true + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k3s/tests/role_test.yaml b/charts/k3s/tests/role_test.yaml new file mode 100644 index 000000000..5eeedba74 --- /dev/null +++ b/charts/k3s/tests/role_test.yaml @@ -0,0 +1,32 @@ +suite: Role +templates: + - rbac/role.yaml + +tests: + - it: should not create role + set: + rbac: + role: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + role: + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k3s/values.yaml b/charts/k3s/values.yaml index c97fdd53a..de2e86aac 100644 --- a/charts/k3s/values.yaml +++ b/charts/k3s/values.yaml @@ -236,19 +236,16 @@ workloadServiceAccount: # Roles & ClusterRoles for the vcluster rbac: clusterRole: - # Deprecated ! - # Necessary cluster roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster + # You don't need to toggle this as necessary cluster roles are created based on the enabled syncers (.sync.*.enabled). + # This only makes sense to enable if you want to use the extraRules below. create: false + # Extra Rules for the cluster role + extraRules: [] role: - # Deprecated ! - # Support for this value will be removed in a future version of the vcluster - # and basic role will always be created + # Disable this only if you don't want vCluster to create a role. This will break most functionality if disabled. create: true - # Deprecated ! - # Necessary extended roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster - extended: false + # Extra Rules for the role + extraRules: [] # all entries in excludedApiResources will be excluded from the Role created for vcluster excludedApiResources: # - pods/exec diff --git a/charts/k8s/templates/_helpers.tpl b/charts/k8s/templates/_helpers.tpl index eb627285a..50f08d6f9 100644 --- a/charts/k8s/templates/_helpers.tpl +++ b/charts/k8s/templates/_helpers.tpl @@ -39,17 +39,12 @@ Whether to create a cluster role or not */}} {{- define "vcluster.createClusterRole" -}} {{- if or - (not - (empty (include "vcluster.serviceMapping.fromHost" . ))) - (not - (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) - (not - (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.serviceMapping.fromHost" . ))) + (not (empty (include "vcluster.plugin.clusterRoleExtraRules" . ))) + (not (empty (include "vcluster.generic.clusterRoleExtraRules" . ))) .Values.rbac.clusterRole.create .Values.sync.hoststorageclasses.enabled - (index - ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) - "enabled") + (index ((index .Values.sync "legacy-storageclasses") | default (dict "enabled" false)) "enabled") (include "vcluster.syncIngressclassesEnabled" . ) .Values.pro .Values.sync.nodes.enabled @@ -60,7 +55,7 @@ Whether to create a cluster role or not .Values.proxy.metricsServer.nodes.enabled .Values.multiNamespaceMode.enabled .Values.coredns.plugin.enabled -}} - {{- true -}} +{{- true -}} {{- end -}} {{- end -}} @@ -129,6 +124,29 @@ Prints only the flags that modify the defaults: {{- end }} {{- end -}} +{{/* + Cluster role rules defined on global level +*/}} +{{- define "vcluster.rbac.clusterRoleExtraRules" -}} +{{- if .Values.rbac.clusterRole.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.clusterRole.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + + +{{/* + Role rules defined on global level +*/}} +{{- define "vcluster.rbac.roleExtraRules" -}} +{{- if .Values.rbac.role.extraRules }} +{{- range $ruleIndex, $rule := .Values.rbac.role.extraRules }} +- {{ toJson $rule }} +{{- end }} +{{- end }} +{{- end -}} + {{/* Role rules defined by plugins */}} @@ -176,68 +194,3 @@ Prints only the flags that modify the defaults: - '--map-host-service={{ $value.from }}={{ $value.to }}' {{- end }} {{- end -}} - - -{{/* - deployment kind -*/}} -{{- define "vcluster.kind" -}} -{{ if and .Values.embeddedEtcd.enabled .Values.pro }}StatefulSet{{ else }}Deployment{{ end }} -{{- end -}} - -{{/* - service name for statefulset -*/}} -{{- define "vcluster.statefulset.serviceName" }} -{{- if .Values.embeddedEtcd.enabled }} -serviceName: {{ .Release.Name }}-headless -{{- end }} -{{- end -}} - -{{/* - volumeClaimTemplate -*/}} -{{- define "vcluster.statefulset.volumeClaimTemplate" }} -{{- if .Values.embeddedEtcd.enabled }} -{{- if .Values.autoDeletePersistentVolumeClaims }} -{{- if ge (int .Capabilities.KubeVersion.Minor) 27 }} -persistentVolumeClaimRetentionPolicy: - whenDeleted: Delete -{{- end }} -{{- end }} -{{- if (hasKey .Values "volumeClaimTemplates") }} -volumeClaimTemplates: -{{ toYaml .Values.volumeClaimTemplates | indent 4 }} -{{- else if .Values.syncer.storage.persistence }} -volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: [ "ReadWriteOnce" ] - {{- if .Values.syncer.storage.className }} - storageClassName: {{ .Values.syncer.storage.className }} - {{- end }} - resources: - requests: - storage: {{ .Values.syncer.storage.size }} -{{- end }} -{{- end }} -{{- end -}} - - -{{/* - deployment strategy -*/}} -{{- define "vcluster.deployment.strategy" }} -{{- if not .Values.embeddedEtcd.enabled }} -strategy: - rollingUpdate: - maxSurge: 1 - {{- if (eq (int .Values.syncer.replicas) 1) }} - maxUnavailable: 0 - {{- else }} - maxUnavailable: 1 - {{- end }} - type: RollingUpdate -{{- end }} -{{- end -}} diff --git a/charts/k8s/templates/_kind.tpl b/charts/k8s/templates/_kind.tpl new file mode 100644 index 000000000..23009704f --- /dev/null +++ b/charts/k8s/templates/_kind.tpl @@ -0,0 +1,62 @@ +{{/* + deployment kind +*/}} +{{- define "vcluster.kind" -}} +{{ if and .Values.embeddedEtcd.enabled .Values.pro }}StatefulSet{{ else }}Deployment{{ end }} +{{- end -}} + +{{/* + service name for statefulset +*/}} +{{- define "vcluster.statefulset.serviceName" }} +{{- if .Values.embeddedEtcd.enabled }} +serviceName: {{ .Release.Name }}-headless +{{- end }} +{{- end -}} + +{{/* + volumeClaimTemplate +*/}} +{{- define "vcluster.statefulset.volumeClaimTemplate" }} +{{- if .Values.embeddedEtcd.enabled }} +{{- if .Values.autoDeletePersistentVolumeClaims }} +{{- if ge (int .Capabilities.KubeVersion.Minor) 27 }} +persistentVolumeClaimRetentionPolicy: + whenDeleted: Delete +{{- end }} +{{- end }} +{{- if (hasKey .Values "volumeClaimTemplates") }} +volumeClaimTemplates: +{{ toYaml .Values.volumeClaimTemplates | indent 4 }} +{{- else if .Values.syncer.storage.persistence }} +volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + {{- if .Values.syncer.storage.className }} + storageClassName: {{ .Values.syncer.storage.className }} + {{- end }} + resources: + requests: + storage: {{ .Values.syncer.storage.size }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* + deployment strategy +*/}} +{{- define "vcluster.deployment.strategy" }} +{{- if not .Values.embeddedEtcd.enabled }} +strategy: + rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.syncer.replicas) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} + type: RollingUpdate +{{- end }} +{{- end -}} diff --git a/charts/k8s/templates/rbac/clusterrole.yaml b/charts/k8s/templates/rbac/clusterrole.yaml index 684500c3d..984267cae 100644 --- a/charts/k8s/templates/rbac/clusterrole.yaml +++ b/charts/k8s/templates/rbac/clusterrole.yaml @@ -18,7 +18,7 @@ rules: resources: ["features", "virtualclusters"] verbs: ["get", "list", "watch"] {{- end }} - {{- if or .Values.pro .Values.sync.nodes.enabled .Values.rbac.clusterRole.create }} + {{- if or .Values.pro .Values.sync.nodes.enabled }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["get", "watch", "list"] @@ -31,17 +31,17 @@ rules: resources: [ "pods"] verbs: ["get", "watch", "list"] {{- end }} - {{- if and (or .Values.sync.nodes.enabled .Values.rbac.clusterRole.create) (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} + {{- if and .Values.sync.nodes.enabled (or (not .Values.isolation.enabled) (and .Values.isolation.nodeProxyPermission.enabled .Values.isolation.enabled)) }} - apiGroups: [""] resources: ["nodes/proxy"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or (and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges) .Values.rbac.clusterRole.create }} + {{- if and .Values.sync.nodes.enabled .Values.sync.nodes.syncNodeChanges }} - apiGroups: [""] resources: ["nodes", "nodes/status"] verbs: ["update", "patch"] {{- end }} - {{- if or .Values.sync.persistentvolumes.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.persistentvolumes.enabled }} - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -56,7 +56,7 @@ rules: resources: ["ingressclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.storageclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.storageclasses.enabled }} - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] @@ -66,12 +66,12 @@ rules: resources: ["storageclasses"] verbs: ["get", "watch", "list"] {{- end }} - {{- if or .Values.sync.priorityclasses.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.priorityclasses.enabled }} - apiGroups: ["scheduling.k8s.io"] resources: ["priorityclasses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.clusterRole.create }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshotclasses"] verbs: ["get", "list", "watch"] @@ -79,8 +79,6 @@ rules: resources: ["volumesnapshotcontents"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} - {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} {{- if (not (empty (include "vcluster.serviceMapping.fromHost" . ))) }} - apiGroups: [""] resources: ["services", "endpoints"] @@ -99,4 +97,7 @@ rules: resources: ["nodes"] verbs: ["get", "list"] {{- end }} + {{- include "vcluster.plugin.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.generic.clusterRoleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.clusterRoleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k8s/templates/rbac/role.yaml b/charts/k8s/templates/rbac/role.yaml index da4362387..de05bbb62 100644 --- a/charts/k8s/templates/rbac/role.yaml +++ b/charts/k8s/templates/rbac/role.yaml @@ -35,22 +35,22 @@ rules: resources: ["configmaps", "secrets", "services", "pods", "pods/attach", "pods/portforward", "pods/exec", "persistentvolumeclaims"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.status .Values.rbac.role.extended }} + {{- if .Values.sync.pods.status }} - apiGroups: [""] resources: ["pods/status"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.pods.ephemeralContainers .Values.rbac.role.extended }} + {{- if .Values.sync.pods.ephemeralContainers }} - apiGroups: [""] resources: ["pods/ephemeralcontainers"] verbs: ["patch", "update"] {{- end }} - {{- if or .Values.sync.endpoints.enabled .Values.rbac.role.extended .Values.headless }} + {{- if or .Values.sync.endpoints.enabled .Values.headless }} - apiGroups: [""] resources: ["endpoints"] verbs: ["create", "delete", "patch", "update"] {{- end }} - {{- if or (gt (int .Values.syncer.replicas) 1) .Values.rbac.role.extended }} + {{- if gt (int .Values.syncer.replicas) 1 }} - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -58,7 +58,7 @@ rules: - apiGroups: [""] resources: ["endpoints", "events", "pods/log"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.ingresses.enabled}} + {{- if .Values.sync.ingresses.enabled}} - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -66,22 +66,22 @@ rules: - apiGroups: ["apps"] resources: ["statefulsets", "replicasets", "deployments"] verbs: ["get", "list", "watch"] - {{- if or .Values.sync.networkpolicies.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.networkpolicies.enabled }} - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.volumesnapshots.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.volumesnapshots.enabled }} - apiGroups: ["snapshot.storage.k8s.io"] resources: ["volumesnapshots"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.serviceaccounts.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.serviceaccounts.enabled }} - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] {{- end }} - {{- if or .Values.sync.poddisruptionbudgets.enabled .Values.rbac.role.extended }} + {{- if .Values.sync.poddisruptionbudgets.enabled }} - apiGroups: ["policy"] resources: ["poddisruptionbudgets"] verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] @@ -100,4 +100,5 @@ rules: {{- end }} {{- include "vcluster.plugin.roleExtraRules" . | indent 2 }} {{- include "vcluster.generic.roleExtraRules" . | indent 2 }} + {{- include "vcluster.rbac.roleExtraRules" . | indent 2 }} {{- end }} diff --git a/charts/k8s/tests/README.md b/charts/k8s/tests/README.md new file mode 100644 index 000000000..24d888a08 --- /dev/null +++ b/charts/k8s/tests/README.md @@ -0,0 +1,9 @@ +Add [unittest plugin](https://github.com/helm-unittest/helm-unittest) via: +``` +helm plugin install https://github.com/helm-unittest/helm-unittest.git +``` + +Run tests via: +``` +helm unittest charts/k8s -d +``` diff --git a/charts/k8s/tests/clusterrole_test.yaml b/charts/k8s/tests/clusterrole_test.yaml new file mode 100644 index 000000000..3385c786c --- /dev/null +++ b/charts/k8s/tests/clusterrole_test.yaml @@ -0,0 +1,41 @@ +suite: ClusterRole +templates: + - rbac/clusterrole.yaml + +tests: + - it: should create clusterrole + set: + rbac: + clusterRole: + create: true + asserts: + - hasDocuments: + count: 1 + - it: should not create clusterrole + set: + rbac: + clusterRole: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + clusterRole: + create: true + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k8s/tests/role_test.yaml b/charts/k8s/tests/role_test.yaml new file mode 100644 index 000000000..5eeedba74 --- /dev/null +++ b/charts/k8s/tests/role_test.yaml @@ -0,0 +1,32 @@ +suite: Role +templates: + - rbac/role.yaml + +tests: + - it: should not create role + set: + rbac: + role: + create: false + asserts: + - hasDocuments: + count: 0 + - it: should contain extra rule + set: + rbac: + role: + extraRules: + - apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + asserts: + - hasDocuments: + count: 1 + - contains: + path: rules + content: + apiGroups: ["test"] + resources: ["tests"] + verbs: ["test"] + count: 1 + diff --git a/charts/k8s/values.yaml b/charts/k8s/values.yaml index 5ce7d620c..cae5a2dc8 100644 --- a/charts/k8s/values.yaml +++ b/charts/k8s/values.yaml @@ -272,22 +272,19 @@ workloadServiceAccount: # Roles & ClusterRoles for the vcluster rbac: clusterRole: - # Deprecated ! - # Necessary cluster roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster + # You don't need to toggle this as necessary cluster roles are created based on the enabled syncers (.sync.*.enabled). + # This only makes sense to enable if you want to use the extraRules below. create: false + # Extra Rules for the cluster role + extraRules: [] role: - # Deprecated ! - # Support for this value will be removed in a future version of the vcluster - # and basic role will always be created + # Disable this only if you don't want vCluster to create a role. This will break most functionality if disabled. create: true - # Deprecated ! - # Necessary extended roles are created based on the enabled syncers (.sync.*.enabled) - # Support for this value will be removed in a future version of the vcluster - extended: false + # Extra Rules for the role + extraRules: [] # all entries in excludedApiResources will be excluded from the Role created for vcluster excludedApiResources: - # - pods/exec + # - pods/exec # Syncer service configurations service: diff --git a/go.mod b/go.mod index c2df9fcfd..2355a3163 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/loft-sh/api/v3 v3.0.0-20240202135831-33c4357035e6 github.com/loft-sh/loftctl/v3 v3.0.0-20240202135933-6548c1e817a7 github.com/loft-sh/utils v0.0.29 - github.com/loft-sh/vcluster-values v0.0.0-20240207073754-18fb56471594 + github.com/loft-sh/vcluster-values v0.0.0-20240207093357-a012ecc33e4c github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/mitchellh/go-homedir v1.1.0 github.com/moby/locker v1.0.1 diff --git a/go.sum b/go.sum index de87a2afe..9c3362065 100644 --- a/go.sum +++ b/go.sum @@ -643,8 +643,8 @@ github.com/loft-sh/log v0.0.0-20230824104949-bd516c25712a h1:/gqqjKpcHEdFXIX41lx github.com/loft-sh/log v0.0.0-20230824104949-bd516c25712a/go.mod h1:YImeRjXH34Yf5E79T7UHBQpDZl9fIaaFRgyZ/bkY+UQ= github.com/loft-sh/utils v0.0.29 h1:P/MObccXToAZy2QoJSQDJ+OJx1qHitpFHEVj3QBSNJs= github.com/loft-sh/utils v0.0.29/go.mod h1:9hlX9cGpWHg3mNi/oBlv3X4ePGDMK66k8MbOZGFMDTI= -github.com/loft-sh/vcluster-values v0.0.0-20240207073754-18fb56471594 h1:w98N8zTBD0Upvk1LPJFotq66ACFwiE9AgTuNyEkSGLk= -github.com/loft-sh/vcluster-values v0.0.0-20240207073754-18fb56471594/go.mod h1:J34xtWyMbjM+NRgVWxO0IVDB5XYUaX52jPQNqEAhu4M= +github.com/loft-sh/vcluster-values v0.0.0-20240207093357-a012ecc33e4c h1:8iFPdLBgwzYp1AqKp6Auw5ViCEgBcKWEz6bNHM9klgU= +github.com/loft-sh/vcluster-values v0.0.0-20240207093357-a012ecc33e4c/go.mod h1:J34xtWyMbjM+NRgVWxO0IVDB5XYUaX52jPQNqEAhu4M= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= diff --git a/vendor/github.com/loft-sh/vcluster-values/helmvalues/common.go b/vendor/github.com/loft-sh/vcluster-values/helmvalues/common.go index 2827b1851..9c6bcd6cd 100644 --- a/vendor/github.com/loft-sh/vcluster-values/helmvalues/common.go +++ b/vendor/github.com/loft-sh/vcluster-values/helmvalues/common.go @@ -175,14 +175,39 @@ type VClusterValues struct { // These should be remove from the chart first as they are deprecated there type RBACValues struct { - ClusterRole struct { - Create bool `json:"create,omitempty"` - } `json:"clusterRole,omitempty"` - Role struct { - Create bool `json:"create,omitempty"` - Extended bool `json:"extended,omitempty"` - ExcludedAPIResources []string `json:"excludedAPIResources,omitempty"` - } `json:"role,omitempty"` + ClusterRole RBACClusterRoleValues `json:"clusterRole,omitempty"` + Role RBACRoleValues `json:"role,omitempty"` +} + +type RBACClusterRoleValues struct { + Create bool `json:"create,omitempty"` + ExtraRules []RBACRule `json:"extraRules,omitempty"` +} + +type RBACRoleValues struct { + Create bool `json:"create,omitempty"` + ExtraRules []RBACRule `json:"extraRules,omitempty"` + ExcludedAPIResources []string `json:"excludedAPIResources,omitempty"` +} + +type RBACRule struct { + // Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. + Verbs []string `json:"verbs" protobuf:"bytes,1,rep,name=verbs"` + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. + // +optional + APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"` + // Resources is a list of resources this rule applies to. '*' represents all resources. + // +optional + Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"` + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,4,rep,name=resourceNames"` + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + NonResourceURLs []string `json:"nonResourceURLs,omitempty" protobuf:"bytes,5,rep,name=nonResourceURLs"` } type PDBValues struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index 2c57dcb00..d8474068e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -432,7 +432,7 @@ github.com/loft-sh/utils/pkg/command github.com/loft-sh/utils/pkg/downloader github.com/loft-sh/utils/pkg/downloader/commands github.com/loft-sh/utils/pkg/extract -# github.com/loft-sh/vcluster-values v0.0.0-20240207073754-18fb56471594 +# github.com/loft-sh/vcluster-values v0.0.0-20240207093357-a012ecc33e4c ## explicit; go 1.21.5 github.com/loft-sh/vcluster-values/helmvalues github.com/loft-sh/vcluster-values/values