From 5ef05876f2ca93e5d51e85b84d3ee1efdc38b665 Mon Sep 17 00:00:00 2001 From: Stavros kois Date: Tue, 22 Nov 2022 19:48:00 +0200 Subject: [PATCH] add rbac and first rbac tests --- library/common-test/tests/rbac/rbac_test.yaml | 568 ++++++++++++++++++ .../common/1.0.0/templates/class/_rbac.tpl | 58 +- .../common/1.0.0/templates/loader/_apply.tpl | 2 + .../common/1.0.0/templates/spawner/_rbac.tpl | 23 + library/common/1.0.0/values.yaml | 6 + 5 files changed, 646 insertions(+), 11 deletions(-) create mode 100644 library/common-test/tests/rbac/rbac_test.yaml diff --git a/library/common-test/tests/rbac/rbac_test.yaml b/library/common-test/tests/rbac/rbac_test.yaml new file mode 100644 index 0000000000..e7655ba014 --- /dev/null +++ b/library/common-test/tests/rbac/rbac_test.yaml @@ -0,0 +1,568 @@ + +suite: rbac test +templates: + - common.yaml +chart: + appVersion: &appVer v1.2.3 +release: + namespace: &ns some_name_space +tests: + - it: should pass with default values + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Deployment + + - it: should pass with rbac account enabled (Role) + documentIndex: &roleDoc 0 + set: + rbac: + main: + enabled: true + asserts: + - isKind: + of: Role + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.namespace + value: *ns + + - it: should pass with rbac account enabled (RoleBinding) + documentIndex: &roleBindingDoc 1 + set: + rbac: + main: + enabled: true + asserts: + - isKind: + of: RoleBinding + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.namespace + value: *ns + + - it: should pass with rbac account enabled (ClusterRole) + documentIndex: &roleDoc 0 + set: + rbac: + main: + enabled: true + clusterWide: true + asserts: + - isKind: + of: ClusterRole + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + + - it: should pass with rbac account enabled (ClusterRoleBinding) + documentIndex: &roleBindingDoc 1 + set: + rbac: + main: + enabled: true + clusterWide: true + asserts: + - isKind: + of: ClusterRoleBinding + - isAPIVersion: + of: rbac.authorization.k8s.io/v1 + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + + - it: should pass with primary service account enabled and nameOverride defined (Role) + documentIndex: *roleDoc + set: + rbac: + main: + enabled: true + nameOverride: some-name + asserts: + - isKind: + of: Role + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with primary service account enabled and nameOverride defined (RoleBinding) + documentIndex: *roleBindingDoc + set: + rbac: + main: + enabled: true + nameOverride: some-name + asserts: + - isKind: + of: RoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with primary service account enabled and nameOverride defined (ClusterRole) + documentIndex: *roleDoc + set: + rbac: + main: + enabled: true + nameOverride: some-name + clusterWide: true + asserts: + - isKind: + of: ClusterRole + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with primary service account enabled and nameOverride defined (ClusterRoleBinding) + documentIndex: *roleBindingDoc + set: + rbac: + main: + enabled: true + nameOverride: some-name + clusterWide: true + asserts: + - isKind: + of: ClusterRoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with primary service account enabled annotations and labels added (Role) + documentIndex: *roleDoc + set: + rbac: + main: + enabled: true + annotations: + key1: value1 + key2: value2 + labels: + key3: value3 + key4: value4 + asserts: + - isKind: + of: Role + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added (RoleBinding) + documentIndex: *roleBindingDoc + set: + rbac: + main: + enabled: true + annotations: + key1: value1 + key2: value2 + labels: + key3: value3 + key4: value4 + asserts: + - isKind: + of: RoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added (ClusterRole) + documentIndex: *roleDoc + set: + rbac: + main: + enabled: true + clusterWide: true + annotations: + key1: value1 + key2: value2 + labels: + key3: value3 + key4: value4 + asserts: + - isKind: + of: ClusterRole + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added (ClusterRoleBinding) + documentIndex: *roleBindingDoc + set: + rbac: + main: + enabled: true + clusterWide: true + annotations: + key1: value1 + key2: value2 + labels: + key3: value3 + key4: value4 + asserts: + - isKind: + of: ClusterRoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 +### + - it: should pass with primary service account enabled annotations and labels added from tpl (Role) + documentIndex: *roleDoc + set: + k1: value1 + k2: value2 + k3: value3 + k4: value4 + rbac: + main: + enabled: true + annotations: + key1: "{{ .Values.k1 }}" + key2: "{{ .Values.k2 }}" + labels: + key3: "{{ .Values.k3 }}" + key4: "{{ .Values.k4 }}" + asserts: + - isKind: + of: Role + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added from tpl (RoleBinding) + documentIndex: *roleBindingDoc + set: + k1: value1 + k2: value2 + k3: value3 + k4: value4 + rbac: + main: + enabled: true + annotations: + key1: "{{ .Values.k1 }}" + key2: "{{ .Values.k2 }}" + labels: + key3: "{{ .Values.k3 }}" + key4: "{{ .Values.k4 }}" + asserts: + - isKind: + of: RoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added (ClusterRole) + documentIndex: *roleDoc + set: + k1: value1 + k2: value2 + k3: value3 + k4: value4 + rbac: + main: + enabled: true + clusterWide: true + annotations: + key1: "{{ .Values.k1 }}" + key2: "{{ .Values.k2 }}" + labels: + key3: "{{ .Values.k3 }}" + key4: "{{ .Values.k4 }}" + asserts: + - isKind: + of: ClusterRole + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + - it: should pass with primary service account enabled annotations and labels added (ClusterRoleBinding) + documentIndex: *roleBindingDoc + set: + k1: value1 + k2: value2 + k3: value3 + k4: value4 + rbac: + main: + enabled: true + clusterWide: true + annotations: + key1: "{{ .Values.k1 }}" + key2: "{{ .Values.k2 }}" + labels: + key3: "{{ .Values.k3 }}" + key4: "{{ .Values.k4 }}" + asserts: + - isKind: + of: ClusterRoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + - equal: + path: metadata.annotations + value: + key1: value1 + key2: value2 + - equal: + path: metadata.labels + value: + app: common-test + app.kubernetes.io/instance: RELEASE-NAME + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: RELEASE-NAME + key3: value3 + key4: value4 + + + - it: should pass with non-primary service account enabled and nameOverride defined (Role - main) + documentIndex: *roleDoc + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + nameOverride: some-name + asserts: + - isKind: + of: Role + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + + - it: should pass with non-primary service account enabled and nameOverride defined (RoleBinding - main) + documentIndex: *roleBindingDoc + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + nameOverride: some-name + asserts: + - isKind: + of: RoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test + + - it: should pass with non-primary service account enabled and nameOverride defined (Role - main) + documentIndex: &otherRoleDoc 2 + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + nameOverride: some-name + asserts: + - isKind: + of: Role + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with non-primary service account enabled and nameOverride defined (RoleBinding - other) + documentIndex: &otherRoleBindingDoc 3 + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + nameOverride: some-name + asserts: + - isKind: + of: RoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with non-primary service account enabled and nameOverride defined (ClusterRole - other) + documentIndex: &otherRoleDoc 2 + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + clusterWide: true + nameOverride: some-name + asserts: + - isKind: + of: ClusterRole + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name + + - it: should pass with non-primary service account enabled and nameOverride defined (ClusterRoleBinding - other) + documentIndex: &otherRoleBindingDoc 3 + set: + rbac: + main: + enabled: true + primary: true + other: + enabled: true + primary: false + clusterWide: true + nameOverride: some-name + asserts: + - isKind: + of: ClusterRoleBinding + - equal: + path: metadata.name + value: RELEASE-NAME-common-test-some-name diff --git a/library/common/1.0.0/templates/class/_rbac.tpl b/library/common/1.0.0/templates/class/_rbac.tpl index fd792e4876..23971a1d30 100644 --- a/library/common/1.0.0/templates/class/_rbac.tpl +++ b/library/common/1.0.0/templates/class/_rbac.tpl @@ -1,6 +1,6 @@ {{/* Template for RBAC object ((Cluster)Role, (Cluster)RoleBinding), can only be called by the spawner */}} {{/* An rbac object, an SA object and "root" is passed from the spawner */}} -{{- define "ix.v1.common.spawner.rbac" -}} +{{- define "ix.v1.common.class.rbac" -}} {{- $rbacValues := .rbac -}} {{- $saValues := .serviceAccount -}} {{- $root := .root -}} @@ -9,7 +9,7 @@ {{- $rbacName := include "ix.v1.common.names.fullname" $root -}} {{- if and (hasKey $rbacValues "nameOverride") $rbacValues.nameOverride -}} - {{- $rbacName = (printf "%v:%v" $rbacName $rbacValues.nameOverride) -}} + {{- $rbacName = (printf "%v-%v" $rbacName $rbacValues.nameOverride) -}} {{- end -}} {{/* Prepare values for either cluster rbac or namespaced rbac */}} @@ -34,12 +34,35 @@ kind: {{ $roleKind }} metadata: name: {{ $rbacName }} {{- if not $clusterWide }} - namespace: {{ .Release.Namespace }} + namespace: {{ $root.Release.Namespace }} + {{- end }} + {{- $labels := (mustMerge ($rbacValues.labels | default dict) (include "ix.v1.common.labels" $root | fromYaml)) -}} + {{- with (include "ix.v1.common.util.labels.render" (dict "root" $root "labels" $labels) | trim) }} + labels: + {{- . | nindent 4 }} + {{- end }} + {{- $annotations := (mustMerge ($rbacValues.annotations | default dict) (include "ix.v1.common.annotations" $root | fromYaml)) -}} + {{- with (include "ix.v1.common.util.annotations.render" (dict "root" $root "annotations" $annotations) | trim) }} + annotations: + {{- . | nindent 4 }} {{- end }} - # TODO: annotations, labels {{- with $rbacValues.rules -}} rules: - # TODO: rules + {{/* Make sure that still works with values like "" also with tpl */}} + {{- range . }} + - apiGroups: + {{- range (required " are required in RBAC rules" .apiGroups) }} + - {{ tpl . $root }} + {{- end }} + resources: + {{- range (required " are required in RBAC rules" .resources) }} + - {{ tpl . $root }} + {{- end }} + verbs: + {{- range (required " are required in RBAC rules" .verbs) }} + - {{ tpl . $root }} + {{- end }} + {{- end }} {{- end }} --- @@ -48,9 +71,18 @@ kind: {{ $roleBindingKind }} metadata: name: {{ $rbacName }} {{- if not $clusterWide }} - namespace: {{ .Release.Namespace }} + namespace: {{ $root.Release.Namespace }} + {{- end }} + {{- $labels := (mustMerge ($rbacValues.labels | default dict) (include "ix.v1.common.labels" $root | fromYaml)) -}} + {{- with (include "ix.v1.common.util.labels.render" (dict "root" $root "labels" $labels) | trim) }} + labels: + {{- . | nindent 4 }} + {{- end }} + {{- $annotations := (mustMerge ($rbacValues.annotations | default dict) (include "ix.v1.common.annotations" $root | fromYaml)) -}} + {{- with (include "ix.v1.common.util.annotations.render" (dict "root" $root "annotations" $annotations) | trim) }} + annotations: + {{- . | nindent 4 }} {{- end }} - # TODO: annotations, labels roleRef: apiGroup: {{ $roleAPI }} kind: {{ $roleKind }} @@ -58,8 +90,12 @@ roleRef: subjects: - kind: ServiceAccount name: {{ $saName }} - namespace: {{ .Release.Namespace }} -# TODO: subjects - - + namespace: {{ $root.Release.Namespace }} + {{- with $rbacValues.subjects -}} + {{- range . }} + - kind: {{ tpl (required " is required in RBAC subjects" .kind) $root }} + name: {{ tpl (required " is required in RBAC subjects" .name) $root }} + apiGroup: {{ tpl (required " is required in RBAC subjects" .apiGroup) $root }} + {{- end }} + {{- end -}} {{- end -}} diff --git a/library/common/1.0.0/templates/loader/_apply.tpl b/library/common/1.0.0/templates/loader/_apply.tpl index b40fb479cb..d6f87903c6 100644 --- a/library/common/1.0.0/templates/loader/_apply.tpl +++ b/library/common/1.0.0/templates/loader/_apply.tpl @@ -1,6 +1,8 @@ {{- define "ix.v1.common.loader.apply" -}} {{- include "ix.v1.common.spawner.serviceAccount" . | nindent 0 -}} + {{- include "ix.v1.common.spawner.rbac" . | nindent 0 -}} + {{- if .Values.controller.enabled -}} {{- if eq (.Values.controller.type | lower) "deployment" -}} {{- include "ix.v1.common.deployment" . | nindent 0 }} diff --git a/library/common/1.0.0/templates/spawner/_rbac.tpl b/library/common/1.0.0/templates/spawner/_rbac.tpl index e69de29bb2..b3e92ca006 100644 --- a/library/common/1.0.0/templates/spawner/_rbac.tpl +++ b/library/common/1.0.0/templates/spawner/_rbac.tpl @@ -0,0 +1,23 @@ +{{/* Renders the RBAC object(s) */}} +{{- define "ix.v1.common.spawner.rbac" -}} + {{- range $name, $rbac := .Values.rbac -}} + {{- if $rbac.enabled -}} + {{- $rbacValues := $rbac -}} + + {{/* + If it's not the primary RBAC, and no name override is defined, make sure + we have a unique name passed to the RBAC class. + Primary RBAC cannot have it's nameOverride + */}} + {{- if and (not $rbacValues.nameOverride) (ne $name (include "ix.v1.common.lib.util.rbac.primary" $)) -}} + {{- $_ := set $rbacValues "nameOverride" $name -}} + {{- end -}} + + {{/* + Pass a serviceAccount object containing this single SA to the class, + in order to create the object. Also pass "root" for includes to work. + */}} + {{- include "ix.v1.common.class.rbac" (dict "rbac" $rbacValues "root" $) -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/1.0.0/values.yaml b/library/common/1.0.0/values.yaml index 73d2da1ee1..cfe0f19405 100644 --- a/library/common/1.0.0/values.yaml +++ b/library/common/1.0.0/values.yaml @@ -67,6 +67,12 @@ serviceAccount: enabled: false primary: true +rbac: + main: + enabled: false + primary: true + clusterWide: false + # TODO: docs podSecurityContext: runAsUser: 568