diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e0f623be..e1bce111f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,14 +6,36 @@ jobs: bats-unit-test: docker: # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/vault-helm-test:0.1.0 + - image: docker.mirror.hashicorp.services/hashicorpdev/vault-helm-test:0.2.0 steps: - checkout - run: bats ./test/unit -t + + chart-verifier: + docker: + - image: docker.mirror.hashicorp.services/cimg/go:1.16 + environment: + BATS_VERSION: "1.3.0" + CHART_VERIFIER_VERSION: "1.0.0" + steps: + - checkout + - run: + name: install chart-verifier + command: go get github.com/redhat-certification/chart-verifier@${CHART_VERIFIER_VERSION} + - run: + name: install bats + command: | + curl -sSL https://github.com/bats-core/bats-core/archive/v${BATS_VERSION}.tar.gz -o /tmp/bats.tgz + tar -zxf /tmp/bats.tgz -C /tmp + sudo /bin/bash /tmp/bats-core-${BATS_VERSION}/install.sh /usr/local + - run: + name: run chart-verifier tests + command: bats ./test/chart -t + acceptance: docker: # This image is build from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/vault-helm-test:0.1.0 + - image: docker.mirror.hashicorp.services/hashicorpdev/vault-helm-test:0.2.0 steps: - checkout @@ -66,6 +88,7 @@ workflows: build_and_test: jobs: - bats-unit-test + - chart-verifier - acceptance: requires: - bats-unit-test @@ -75,7 +98,7 @@ workflows: update-helm-charts-index: jobs: - update-helm-charts-index: - context: helm-charts-trigger + context: helm-charts-trigger-vault filters: tags: only: /^v.*/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 67e53fce8..5c58777ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,55 @@ ## Unreleased +## 0.13.0 (June 17th, 2021) + +Improvements: +* Added a helm test for vault server [GH-531](https://github.com/hashicorp/vault-helm/pull/531) +* Added server.enterpriseLicense option [GH-547](https://github.com/hashicorp/vault-helm/pull/547) +* Added OpenShift overrides [GH-549](https://github.com/hashicorp/vault-helm/pull/549) + +Bugs: +* Fix ui.serviceNodePort schema [GH-537](https://github.com/hashicorp/vault-helm/pull/537) +* Fix server.ha.disruptionBudget.maxUnavailable schema [GH-535](https://github.com/hashicorp/vault-helm/pull/535) +* Added webhook-certs volume mount to sidecar injector [GH-545](https://github.com/hashicorp/vault-helm/pull/545) + +## 0.12.0 (May 25th, 2021) + +Features: +* Pass additional arguments to `vault-csi-provider` using `csi.extraArgs` [GH-526](https://github.com/hashicorp/vault-helm/pull/526) + +Improvements: +* Set chart kubeVersion and added chart-verifier tests [GH-510](https://github.com/hashicorp/vault-helm/pull/510) +* Added values json schema [GH-513](https://github.com/hashicorp/vault-helm/pull/513) +* Ability to set tolerations for CSI daemonset pods [GH-521](https://github.com/hashicorp/vault-helm/pull/521) +* UI target port is now configurable [GH-437](https://github.com/hashicorp/vault-helm/pull/437) + +Bugs: +* CSI: `global.imagePullSecrets` are now also used for CSI daemonset [GH-519](https://github.com/hashicorp/vault-helm/pull/519) + +## 0.11.0 (April 14th, 2021) + +Features: +* Added `server.enabled` to explicitly skip installing a Vault server [GH-486](https://github.com/hashicorp/vault-helm/pull/486) +* Injector now supports enabling host network [GH-471](https://github.com/hashicorp/vault-helm/pull/471) +* Injector port is now configurable [GH-489](https://github.com/hashicorp/vault-helm/pull/489) +* Injector Vault Agent resource defaults are now configurable [GH-493](https://github.com/hashicorp/vault-helm/pull/493) +* Extra paths can now be added to the Vault ingress service [GH-460](https://github.com/hashicorp/vault-helm/pull/460) +* Log level and format can now be set directly using `server.logFormat` and `server.logLevel` [GH-488](https://github.com/hashicorp/vault-helm/pull/488) + +Improvements: +* Added `https` name to injector service port [GH-495](https://github.com/hashicorp/vault-helm/pull/495) + +Bugs: +* CSI: Fix ClusterRole name and DaemonSet's service account to properly match deployment name [GH-486](https://github.com/hashicorp/vault-helm/pull/486) + +## 0.10.0 (March 25th, 2021) + +Features: +* Add support for [Vault CSI provider](https://github.com/hashicorp/vault-csi-provider) [GH-461](https://github.com/hashicorp/vault-helm/pull/461) + +Improvements: +* `objectSelector` can now be set on the mutating admission webhook [GH-456](https://github.com/hashicorp/vault-helm/pull/456) + ## 0.9.1 (February 2nd, 2021) Bugs: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 431dfa897..f83d56747 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,7 +62,37 @@ The unit tests don't require any active Kubernetes cluster and complete very quickly. These should be used for fast feedback during development. The acceptance tests require a Kubernetes cluster with a configured `kubectl`. -### Prequisites +### Test Using Docker Container + +The following are the instructions for running bats tests using a Docker container. + +#### Prerequisites + +* Docker installed +* `vault-helm` checked out locally + +#### Test + +**Note:** the following commands should be run from the `vault-helm` directory. + +First, build the Docker image for running the tests: + +```shell +docker build -f ${PWD}/test/docker/Test.dockerfile ${PWD}/test/docker/ -t vault-helm-test +``` +Next, execute the tests with the following commands: +```shell +docker run -it --rm -v "${PWD}:/test" vault-helm-test bats /test/test/unit +``` +It's possible to only run specific bats tests using regular expressions. +For example, the following will run only tests with "injector" in the name: +```shell +docker run -it --rm -v "${PWD}:/test" vault-helm-test bats /test/test/unit -f "injector" +``` + +### Test Manually +The following are the instructions for running bats tests on your workstation. +#### Prerequisites * [Bats](https://github.com/bats-core/bats-core) ```bash brew install bats-core @@ -76,7 +106,7 @@ The acceptance tests require a Kubernetes cluster with a configured `kubectl`. brew install kubernetes-helm ``` -### Running The Tests +#### Test To run the unit tests: diff --git a/Chart.yaml b/Chart.yaml index 3456fa48f..045116268 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -1,7 +1,8 @@ apiVersion: v2 name: vault -version: 0.9.1 -appVersion: 1.6.2 +version: 0.13.0 +appVersion: 1.7.3 +kubeVersion: ">= 1.14.0-0" description: Official HashiCorp Vault Chart home: https://www.vaultproject.io icon: https://github.com/hashicorp/vault/raw/f22d202cde2018f9455dec755118a9b84586e082/Vault_PrimaryLogo_Black.png @@ -10,3 +11,4 @@ sources: - https://github.com/hashicorp/vault - https://github.com/hashicorp/vault-helm - https://github.com/hashicorp/vault-k8s + - https://github.com/hashicorp/vault-csi-provider diff --git a/Makefile b/Makefile index 96bb17ebe..1b3020c59 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,10 @@ CLOUDSDK_CORE_PROJECT?=vault-helm-dev-246514 # set to run a single test - e.g acceptance/server-ha-enterprise-dr.bats ACCEPTANCE_TESTS?=acceptance +# Generate json schema for chart values. See test/README.md for more details. +values-schema: + helm schema-gen values.yaml > values.schema.json + test-image: @docker build --rm -t $(TEST_IMAGE) -f $(CURDIR)/test/docker/Test.dockerfile $(CURDIR) @@ -62,4 +66,4 @@ provision-cluster: destroy-cluster: terraform destroy -auto-approve -.PHONY: test-image test-unit test-bats test test-acceptance test-destroy test-provision acceptance provision-cluster destroy-cluster +.PHONY: values-schema test-image test-unit test-bats test test-acceptance test-destroy test-provision acceptance provision-cluster destroy-cluster diff --git a/README.md b/README.md index e824b82db..8096d7f79 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,16 @@ use Vault with Kubernetes, please see the ## Prerequisites To use the charts here, [Helm](https://helm.sh/) must be configured for your -Kubernetes cluster. Setting up Kubernetes and Helm and is outside the scope of +Kubernetes cluster. Setting up Kubernetes and Helm is outside the scope of this README. Please refer to the Kubernetes and Helm documentation. The versions required are: * **Helm 3.0+** - This is the earliest version of Helm tested. It is possible it works with earlier versions but this chart is untested for those versions. - * **Kubernetes 1.9+** - This is the earliest version of Kubernetes tested. + * **Kubernetes 1.14+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is - untested. Other versions verified are Kubernetes 1.10, 1.11. + untested. ## Usage @@ -48,6 +48,7 @@ fully documented directly on the [Vault website](https://www.vaultproject.io/docs/platform/k8s/helm) along with more detailed installation instructions. + ## Customizations This Helm chart has been customized in the following ways: diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index bb5ec082e..5e3269f78 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -53,6 +53,8 @@ template logic. {{- define "vault.mode" -}} {{- if .Values.injector.externalVaultAddr -}} {{- $_ := set . "mode" "external" -}} + {{- else if ne (.Values.server.enabled | toString) "true" -}} + {{- $_ := set . "mode" "external" -}} {{- else if eq (.Values.server.dev.enabled | toString) "true" -}} {{- $_ := set . "mode" "dev" -}} {{- else if eq (.Values.server.ha.enabled | toString) "true" -}} @@ -109,6 +111,12 @@ extra volumes the user may have specified (such as a secret with TLS). {{- if .Values.server.volumes }} {{- toYaml .Values.server.volumes | nindent 8}} {{- end }} + {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey) }} + - name: vault-license + secret: + secretName: {{ .Values.server.enterpriseLicense.secretName }} + defaultMode: 0440 + {{- end }} {{- end -}} {{/* @@ -172,6 +180,11 @@ based on the mode configured. {{- if .Values.server.volumeMounts }} {{- toYaml .Values.server.volumeMounts | nindent 12}} {{- end }} + {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey) }} + - name: vault-license + mountPath: /vault/license + readOnly: true + {{- end }} {{- end -}} {{/* @@ -483,6 +496,71 @@ Sets the container resources if the user has set any. {{ end }} {{- end -}} +{{/* +Sets the container resources if the user has set any. +*/}} +{{- define "csi.resources" -}} + {{- if .Values.csi.resources -}} + resources: +{{ toYaml .Values.csi.resources | indent 12}} + {{ end }} +{{- end -}} + +{{/* +Sets extra CSI daemonset annotations +*/}} +{{- define "csi.daemonSet.annotations" -}} + {{- if .Values.csi.daemonSet.annotations }} + annotations: + {{- $tp := typeOf .Values.csi.daemonSet.annotations }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.daemonSet.annotations . | nindent 4 }} + {{- else }} + {{- toYaml .Values.csi.daemonSet.annotations | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the injector toleration for pod placement +*/}} +{{- define "csi.pod.tolerations" -}} + {{- if .Values.csi.pod.tolerations }} + tolerations: + {{ tpl .Values.csi.pod.tolerations . | nindent 8 | trim }} + {{- end }} +{{- end -}} + +{{/* +Sets extra CSI provider pod annotations +*/}} +{{- define "csi.pod.annotations" -}} + {{- if .Values.csi.pod.annotations }} + annotations: + {{- $tp := typeOf .Values.csi.pod.annotations }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.pod.annotations . | nindent 8 }} + {{- else }} + {{- toYaml .Values.csi.pod.annotations | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets extra CSI service account annotations +*/}} +{{- define "csi.serviceAccount.annotations" -}} + {{- if .Values.csi.serviceAccount.annotations }} + annotations: + {{- $tp := typeOf .Values.csi.serviceAccount.annotations }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.serviceAccount.annotations . | nindent 4 }} + {{- else }} + {{- toYaml .Values.csi.serviceAccount.annotations | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + {{/* Inject extra environment vars in the format key:value, if populated */}} diff --git a/templates/csi-clusterrole.yaml b/templates/csi-clusterrole.yaml new file mode 100644 index 000000000..a19e520f5 --- /dev/null +++ b/templates/csi-clusterrole.yaml @@ -0,0 +1,17 @@ +{{- if and (eq (.Values.csi.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "vault.fullname" . }}-csi-provider-clusterrole + labels: + app.kubernetes.io/name: {{ include "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: + - "" + resources: + - serviceaccounts/token + verbs: + - create +{{- end }} diff --git a/templates/csi-clusterrolebinding.yaml b/templates/csi-clusterrolebinding.yaml new file mode 100644 index 000000000..63d69c7b1 --- /dev/null +++ b/templates/csi-clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{- if and (eq (.Values.csi.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "vault.fullname" . }}-csi-provider-clusterrolebinding + labels: + app.kubernetes.io/name: {{ include "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "vault.fullname" . }}-csi-provider-clusterrole +subjects: +- kind: ServiceAccount + name: {{ template "vault.fullname" . }}-csi-provider + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/templates/csi-daemonset.yaml b/templates/csi-daemonset.yaml new file mode 100644 index 000000000..75bde9a32 --- /dev/null +++ b/templates/csi-daemonset.yaml @@ -0,0 +1,84 @@ +{{- if and (eq (.Values.csi.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ template "vault.fullname" . }}-csi-provider + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{ template "csi.daemonSet.annotations" . }} +spec: + updateStrategy: + type: {{ .Values.csi.daemonSet.updateStrategy.type }} + {{- if .Values.csi.daemonSet.updateStrategy.maxUnavailable }} + rollingUpdate: + maxUnavailable: {{ .Values.csi.daemonSet.updateStrategy.maxUnavailable }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + {{ template "csi.pod.annotations" . }} + spec: + serviceAccountName: {{ template "vault.fullname" . }}-csi-provider + {{- template "csi.pod.tolerations" . }} + containers: + - name: {{ include "vault.name" . }}-csi-provider + {{ template "csi.resources" . }} + image: "{{ .Values.csi.image.repository }}:{{ .Values.csi.image.tag }}" + imagePullPolicy: {{ .Values.csi.image.pullPolicy }} + args: + - --endpoint=/provider/vault.sock + - --debug={{ .Values.csi.debug }} + {{- if .Values.csi.extraArgs }} + {{- toYaml .Values.csi.extraArgs | nindent 12 }} + {{- end }} + volumeMounts: + - name: providervol + mountPath: "/provider" + - name: mountpoint-dir + mountPath: /var/lib/kubelet/pods + mountPropagation: HostToContainer + {{- if .Values.csi.volumeMounts }} + {{- toYaml .Values.csi.volumeMounts | nindent 12}} + {{- end }} + livenessProbe: + httpGet: + path: /health/ready + port: 8080 + failureThreshold: {{ .Values.csi.livenessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.csi.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.csi.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.csi.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.csi.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: /health/ready + port: 8080 + failureThreshold: {{ .Values.csi.readinessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.csi.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.csi.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.csi.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.csi.readinessProbe.timeoutSeconds }} + volumes: + - name: providervol + hostPath: + path: "/etc/kubernetes/secrets-store-csi-providers" + - name: mountpoint-dir + hostPath: + path: /var/lib/kubelet/pods + {{- if .Values.csi.volumes }} + {{- toYaml .Values.csi.volumes | nindent 8}} + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.global.imagePullSecrets | nindent 8 }} + {{- end }} +{{- end }} diff --git a/templates/csi-serviceaccount.yaml b/templates/csi-serviceaccount.yaml new file mode 100644 index 000000000..ee127481b --- /dev/null +++ b/templates/csi-serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if and (eq (.Values.csi.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "vault.fullname" . }}-csi-provider + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "vault.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{ template "csi.serviceAccount.annotations" . }} +{{- end }} diff --git a/templates/injector-deployment.yaml b/templates/injector-deployment.yaml index f5d8fc2ef..4756a253d 100644 --- a/templates/injector-deployment.yaml +++ b/templates/injector-deployment.yaml @@ -36,6 +36,7 @@ spec: {{- end }} serviceAccountName: "{{ template "vault.fullname" . }}-agent-injector" {{- if not .Values.global.openshift }} + hostNetwork: {{ .Values.injector.hostNetwork }} securityContext: runAsNonRoot: true runAsGroup: {{ .Values.injector.gid | default 1000 }} @@ -52,7 +53,7 @@ spec: {{- end }} env: - name: AGENT_INJECT_LISTEN - value: ":8080" + value: {{ printf ":%v" .Values.injector.port }} - name: AGENT_INJECT_LOG_LEVEL value: {{ .Values.injector.logLevel | default "info" }} - name: AGENT_INJECT_VAULT_ADDR @@ -96,6 +97,16 @@ spec: fieldRef: fieldPath: metadata.namespace {{- end }} + - name: AGENT_INJECT_CPU_REQUEST + value: "{{ .Values.injector.agentDefaults.cpuRequest }}" + - name: AGENT_INJECT_CPU_LIMIT + value: "{{ .Values.injector.agentDefaults.cpuLimit }}" + - name: AGENT_INJECT_MEM_REQUEST + value: "{{ .Values.injector.agentDefaults.memRequest }}" + - name: AGENT_INJECT_MEM_LIMIT + value: "{{ .Values.injector.agentDefaults.memLimit }}" + - name: AGENT_INJECT_DEFAULT_TEMPLATE + value: "{{ .Values.injector.agentDefaults.template }}" {{- include "vault.extraEnvironmentVars" .Values.injector | nindent 12 }} args: - agent-inject @@ -103,7 +114,7 @@ spec: livenessProbe: httpGet: path: /health/ready - port: 8080 + port: {{ .Values.injector.port }} scheme: HTTPS failureThreshold: 2 initialDelaySeconds: 5 @@ -113,13 +124,19 @@ spec: readinessProbe: httpGet: path: /health/ready - port: 8080 + port: {{ .Values.injector.port }} scheme: HTTPS failureThreshold: 2 initialDelaySeconds: 5 periodSeconds: 2 successThreshold: 1 timeoutSeconds: 5 +{{- if .Values.injector.certs.secretName }} + volumeMounts: + - name: webhook-certs + mountPath: /etc/webhook/certs + readOnly: true +{{- end }} {{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} - name: leader-elector image: {{ .Values.injector.leaderElector.image.repository }}:{{ .Values.injector.leaderElector.image.tag }} @@ -150,10 +167,6 @@ spec: timeoutSeconds: 5 {{- end }} {{- if .Values.injector.certs.secretName }} - volumeMounts: - - name: webhook-certs - mountPath: /etc/webhook/certs - readOnly: true volumes: - name: webhook-certs secret: diff --git a/templates/injector-mutating-webhook.yaml b/templates/injector-mutating-webhook.yaml index df28dc81a..abe23aabc 100644 --- a/templates/injector-mutating-webhook.yaml +++ b/templates/injector-mutating-webhook.yaml @@ -32,6 +32,10 @@ webhooks: namespaceSelector: {{ toYaml .Values.injector.namespaceSelector | indent 6}} {{ end }} +{{- if .Values.injector.objectSelector }} + objectSelector: +{{ toYaml .Values.injector.objectSelector | indent 6}} +{{ end }} {{- with .Values.injector.failurePolicy }} failurePolicy: {{.}} {{ end }} diff --git a/templates/injector-network-policy.yaml b/templates/injector-network-policy.yaml index f2dfd511e..7a399a538 100644 --- a/templates/injector-network-policy.yaml +++ b/templates/injector-network-policy.yaml @@ -1,4 +1,4 @@ -{{- if and (eq (.Values.injector.enabled | toString) "true" ) (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.openshift | toString) "true") ) }} +{{- if and (eq (.Values.injector.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.openshift | toString) "true") }} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: diff --git a/templates/injector-psp-role.yaml b/templates/injector-psp-role.yaml index 5fd264923..20c87bb2a 100644 --- a/templates/injector-psp-role.yaml +++ b/templates/injector-psp-role.yaml @@ -1,4 +1,4 @@ -{{- if and (eq (.Values.injector.enabled | toString) "true" ) (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (eq (.Values.injector.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/templates/injector-psp-rolebinding.yaml b/templates/injector-psp-rolebinding.yaml index f7ae7fe6d..d6d0d5e24 100644 --- a/templates/injector-psp-rolebinding.yaml +++ b/templates/injector-psp-rolebinding.yaml @@ -1,4 +1,4 @@ -{{- if and (eq (.Values.injector.enabled | toString) "true" ) (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (eq (.Values.injector.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/templates/injector-psp.yaml b/templates/injector-psp.yaml index 5871eb91d..c024ac107 100644 --- a/templates/injector-psp.yaml +++ b/templates/injector-psp.yaml @@ -1,4 +1,4 @@ -{{- if and (eq (.Values.injector.enabled | toString) "true" ) (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (eq (.Values.injector.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: diff --git a/templates/injector-service.yaml b/templates/injector-service.yaml index 0e5172743..3138b7a5b 100644 --- a/templates/injector-service.yaml +++ b/templates/injector-service.yaml @@ -11,8 +11,9 @@ metadata: {{ template "injector.service.annotations" . }} spec: ports: - - port: 443 - targetPort: 8080 + - name: https + port: 443 + targetPort: {{ .Values.injector.port }} selector: app.kubernetes.io/name: {{ include "vault.name" . }}-agent-injector app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/templates/server-clusterrolebinding.yaml b/templates/server-clusterrolebinding.yaml index ecf6a705e..e5e0f5fec 100644 --- a/templates/server-clusterrolebinding.yaml +++ b/templates/server-clusterrolebinding.yaml @@ -1,5 +1,5 @@ {{ template "vault.mode" . }} -{{- if and (ne .mode "") (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.server.authDelegator.enabled | toString) "true")) }} +{{- if and (ne .mode "") (eq (.Values.global.enabled | toString) "true") (eq (.Values.server.authDelegator.enabled | toString) "true") }} {{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" -}} apiVersion: rbac.authorization.k8s.io/v1 {{- else }} diff --git a/templates/server-disruptionbudget.yaml b/templates/server-disruptionbudget.yaml index 6d7f8240a..3c45cc04e 100644 --- a/templates/server-disruptionbudget.yaml +++ b/templates/server-disruptionbudget.yaml @@ -1,6 +1,6 @@ {{ template "vault.mode" . }} {{- if ne .mode "external" -}} -{{- if and (and (eq (.Values.global.enabled | toString) "true") (eq .mode "ha")) (eq (.Values.server.ha.disruptionBudget.enabled | toString) "true") -}} +{{- if and (eq (.Values.global.enabled | toString) "true") (eq .mode "ha") (eq (.Values.server.ha.disruptionBudget.enabled | toString) "true") -}} # PodDisruptionBudget to prevent degrading the server cluster through # voluntary cluster changes. apiVersion: policy/v1beta1 diff --git a/templates/server-ha-active-service.yaml b/templates/server-ha-active-service.yaml index b6366b022..74fca41d7 100644 --- a/templates/server-ha-active-service.yaml +++ b/templates/server-ha-active-service.yaml @@ -1,6 +1,6 @@ {{ template "vault.mode" . }} {{- if ne .mode "external" }} -{{- if and (eq .mode "ha" ) (and (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true")) }} +{{- if and (eq .mode "ha" ) (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} # Service for active Vault pod apiVersion: v1 kind: Service diff --git a/templates/server-ha-standby-service.yaml b/templates/server-ha-standby-service.yaml index 473de5517..9213b7452 100644 --- a/templates/server-ha-standby-service.yaml +++ b/templates/server-ha-standby-service.yaml @@ -1,6 +1,6 @@ {{ template "vault.mode" . }} {{- if ne .mode "external" }} -{{- if and (eq .mode "ha" ) (and (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true")) }} +{{- if and (eq .mode "ha" ) (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} # Service for standby Vault pod apiVersion: v1 kind: Service @@ -38,4 +38,4 @@ spec: component: server vault-active: "false" {{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/server-ingress.yaml b/templates/server-ingress.yaml index 7c19f5fea..deaa0dd55 100644 --- a/templates/server-ingress.yaml +++ b/templates/server-ingress.yaml @@ -2,8 +2,9 @@ {{ template "vault.mode" . }} {{- if ne .mode "external" }} {{- if .Values.server.ingress.enabled -}} +{{- $extraPaths := .Values.server.ingress.extraPaths -}} {{- $serviceName := include "vault.fullname" . -}} -{{- if and (eq .mode "ha" ) (and (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true")) }} +{{- if and (eq .mode "ha" ) (eq (.Values.server.service.enabled | toString) "true" ) (eq (.Values.global.enabled | toString) "true") }} {{- $serviceName = printf "%s-%s" $serviceName "active" -}} {{- end }} {{- $servicePort := .Values.server.service.port -}} @@ -41,6 +42,9 @@ spec: - host: {{ .host | quote }} http: paths: +{{ if $extraPaths }} +{{ toYaml $extraPaths | indent 10 }} +{{- end }} {{- range (.paths | default (list "/")) }} - path: {{ . }} backend: diff --git a/templates/server-psp-role.yaml b/templates/server-psp-role.yaml index b4bea0602..fd12e1eb3 100644 --- a/templates/server-psp-role.yaml +++ b/templates/server-psp-role.yaml @@ -1,5 +1,5 @@ {{ template "vault.mode" . }} -{{- if and (ne .mode "") (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (ne .mode "") (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/templates/server-psp-rolebinding.yaml b/templates/server-psp-rolebinding.yaml index 923102733..b2a43c834 100644 --- a/templates/server-psp-rolebinding.yaml +++ b/templates/server-psp-rolebinding.yaml @@ -1,5 +1,5 @@ {{ template "vault.mode" . }} -{{- if and (ne .mode "") (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (ne .mode "") (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/templates/server-psp.yaml b/templates/server-psp.yaml index 32c152634..2d9426819 100644 --- a/templates/server-psp.yaml +++ b/templates/server-psp.yaml @@ -1,5 +1,5 @@ {{ template "vault.mode" . }} -{{- if and (ne .mode "") (and (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") ) }} +{{- if and (ne .mode "") (eq (.Values.global.enabled | toString) "true") (eq (.Values.global.psp.enable | toString) "true") }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: diff --git a/templates/server-statefulset.yaml b/templates/server-statefulset.yaml index 62296af5e..718c9a03e 100644 --- a/templates/server-statefulset.yaml +++ b/templates/server-statefulset.yaml @@ -117,6 +117,18 @@ spec: {{- end }} - name: HOME value: "/home/vault" + {{- if .Values.server.logLevel }} + - name: VAULT_LOG_LEVEL + value: "{{ .Values.server.logLevel }}" + {{- end }} + {{- if .Values.server.logFormat }} + - name: VAULT_LOG_FORMAT + value: "{{ .Values.server.logFormat }}" + {{- end }} + {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey) }} + - name: VAULT_LICENSE_PATH + value: /vault/license/{{ .Values.server.enterpriseLicense.secretKey }} + {{- end }} {{ template "vault.envs" . }} {{- include "vault.extraEnvironmentVars" .Values.server | nindent 12 }} {{- include "vault.extraSecretEnvironmentVars" .Values.server | nindent 12 }} diff --git a/templates/tests/server-test.yaml b/templates/tests/server-test.yaml new file mode 100644 index 000000000..37819de5c --- /dev/null +++ b/templates/tests/server-test.yaml @@ -0,0 +1,39 @@ +{{- if .Values.server.enabled }} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ .Release.Name }}-server-test" + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: {{ .Release.Name }}-server-test + image: {{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default "latest" }} + imagePullPolicy: {{ .Values.server.image.pullPolicy }} + env: + - name: VAULT_ADDR + value: {{ include "vault.scheme" . }}://{{ template "vault.fullname" . }}.{{ .Release.Namespace }}.svc:{{ .Values.server.service.port }} + command: + - /bin/sh + - -c + - | + echo "Checking for sealed info in 'vault status' output" + ATTEMPTS=10 + n=0 + until [ "$n" -ge $ATTEMPTS ] + do + echo "Attempt" $n... + vault status -format yaml | grep -E '^sealed: (true|false)' && break + n=$((n+1)) + sleep 5 + done + if [ $n -ge $ATTEMPTS ]; then + echo "timed out looking for sealed info in 'vault status' output" + exit 1 + fi + + exit 0 + + restartPolicy: Never +{{- end }} diff --git a/templates/ui-service.yaml b/templates/ui-service.yaml index a1498d5fd..9e90af4bb 100644 --- a/templates/ui-service.yaml +++ b/templates/ui-service.yaml @@ -25,7 +25,7 @@ spec: ports: - name: {{ include "vault.scheme" . }} port: {{ .Values.ui.externalPort }} - targetPort: 8200 + targetPort: {{ .Values.ui.targetPort }} {{- if .Values.ui.serviceNodePort }} nodePort: {{ .Values.ui.serviceNodePort }} {{- end }} diff --git a/test/README.md b/test/README.md index e4ce89144..28431dbf9 100644 --- a/test/README.md +++ b/test/README.md @@ -1,4 +1,6 @@ -# Running Vault Helm Acceptance tests +# Vault Helm Tests + +## Running Vault Helm Acceptance tests The Makefile at the top level of this repo contains a few target that should help with running acceptance tests in your own GKE instance. @@ -7,4 +9,33 @@ The Makefile at the top level of this repo contains a few target that should hel * Run `make test-provision` to provision the GKE cluster using terraform. * Run `make test-acceptance` to run the acceptance tests in this already provisioned cluster. * You can choose to only run certain tests by setting the ACCEPTANCE_TESTS variable and re-running the above target. -* Run `make test-destroy` when you have finished testing and want to tear-down and remove the cluster. \ No newline at end of file +* Run `make test-destroy` when you have finished testing and want to tear-down and remove the cluster. + +## Running chart verification tests + +If [chart-verifier](https://github.com/redhat-certification/chart-verifier) is built and available in your PATH, run: + + bats test/chart/verifier.bats + +Or if you'd rather use the latest chart-verifier docker container, set +USE_DOCKER: + + USE_DOCKER=true bats test/chart/verifier.bats + +## Generating the values json schema + +There is a make target for generating values.schema.json: + + make values-schema + +It relies on the helm [schema-gen plugin][schema-gen]. Note that some manual +editing will be required, since several properties accept multiple data types. + +[schema-gen]: https://github.com/karuppiah7890/helm-schema-gen + +## Helm test + +Vault Helm also contains a simple helm test under +[templates/tests/](../templates/tests/) that may be run against a helm release: + + helm test diff --git a/test/acceptance/csi-test/nginx.yaml b/test/acceptance/csi-test/nginx.yaml new file mode 100644 index 000000000..fed1137f7 --- /dev/null +++ b/test/acceptance/csi-test/nginx.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nginx +--- +kind: Pod +apiVersion: v1 +metadata: + name: nginx +spec: + terminationGracePeriodSeconds: 0 + serviceAccountName: nginx + containers: + - image: docker.mirror.hashicorp.services/nginx + name: nginx + volumeMounts: + - name: secrets-store-inline + mountPath: "/mnt/secrets-store" + readOnly: true + volumes: + - name: secrets-store-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "vault-kv" diff --git a/test/acceptance/csi-test/vault-kv-secretproviderclass.yaml b/test/acceptance/csi-test/vault-kv-secretproviderclass.yaml new file mode 100644 index 000000000..e793bde64 --- /dev/null +++ b/test/acceptance/csi-test/vault-kv-secretproviderclass.yaml @@ -0,0 +1,14 @@ +# The "Hello World" Vault SecretProviderClass +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: vault-kv +spec: + provider: vault + parameters: + roleName: "kv-role" + vaultAddress: http://vault:8200 + objects: | + - objectName: "bar" + secretPath: "secret/data/kv1" + secretKey: "bar1" diff --git a/test/acceptance/csi-test/vault-policy.hcl b/test/acceptance/csi-test/vault-policy.hcl new file mode 100644 index 000000000..48b670ea7 --- /dev/null +++ b/test/acceptance/csi-test/vault-policy.hcl @@ -0,0 +1,3 @@ +path "secret/data/kv1" { + capabilities = ["read"] +} \ No newline at end of file diff --git a/test/acceptance/csi.bats b/test/acceptance/csi.bats new file mode 100644 index 000000000..67be09d6d --- /dev/null +++ b/test/acceptance/csi.bats @@ -0,0 +1,59 @@ +#!/usr/bin/env bats + +load _helpers + +@test "csi: testing deployment" { + cd `chart_dir` + + kubectl delete namespace acceptance --ignore-not-found=true + kubectl create namespace acceptance + + # Install Secrets Store CSI driver + helm install secrets-store-csi-driver https://github.com/kubernetes-sigs/secrets-store-csi-driver/blob/master/charts/secrets-store-csi-driver-0.0.20.tgz?raw=true \ + --wait --timeout=5m \ + --namespace=acceptance \ + --set linux.image.pullPolicy="IfNotPresent" + # Install Vault and Vault provider + helm install vault \ + --wait --timeout=5m \ + --namespace=acceptance \ + --set="server.dev.enabled=true" \ + --set="csi.enabled=true" \ + --set="injector.enabled=false" . + kubectl --namespace=acceptance wait --for=condition=Ready --timeout=5m pod -l app.kubernetes.io/name=vault + kubectl --namespace=acceptance wait --for=condition=Ready --timeout=5m pod -l app.kubernetes.io/name=vault-csi-provider + + # Set up k8s auth and a kv secret. + cat ./test/acceptance/csi-test/vault-policy.hcl | kubectl --namespace=acceptance exec -i vault-0 -- vault policy write kv-policy - + kubectl --namespace=acceptance exec vault-0 -- vault auth enable kubernetes + kubectl --namespace=acceptance exec vault-0 -- sh -c 'vault write auth/kubernetes/config \ + token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ + kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \ + kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ + disable_iss_validation=true' + kubectl --namespace=acceptance exec vault-0 -- vault write auth/kubernetes/role/kv-role \ + bound_service_account_names=nginx \ + bound_service_account_namespaces=acceptance \ + policies=kv-policy \ + ttl=20m + kubectl --namespace=acceptance exec vault-0 -- vault kv put secret/kv1 bar1=hello1 + + kubectl --namespace=acceptance apply -f ./test/acceptance/csi-test/vault-kv-secretproviderclass.yaml + kubectl --namespace=acceptance apply -f ./test/acceptance/csi-test/nginx.yaml + kubectl --namespace=acceptance wait --for=condition=Ready --timeout=5m pod nginx + + result=$(kubectl --namespace=acceptance exec nginx -- cat /mnt/secrets-store/bar) + [[ "$result" == "hello1" ]] +} + +# Clean up +teardown() { + if [[ ${CLEANUP:-true} == "true" ]] + then + echo "helm/pvc teardown" + helm --namespace=acceptance delete vault + helm --namespace=acceptance delete secrets-store-csi-driver + kubectl delete --all pvc + kubectl delete namespace acceptance + fi +} diff --git a/test/acceptance/helm-test.bats b/test/acceptance/helm-test.bats new file mode 100644 index 000000000..c5f9553df --- /dev/null +++ b/test/acceptance/helm-test.bats @@ -0,0 +1,27 @@ +#!/usr/bin/env bats + +load _helpers + +@test "helm/test: running helm test" { + cd `chart_dir` + + kubectl delete namespace acceptance --ignore-not-found=true + kubectl create namespace acceptance + kubectl config set-context --current --namespace=acceptance + + helm install "$(name_prefix)" . + wait_for_running $(name_prefix)-0 + + helm test "$(name_prefix)" +} + +# Clean up +teardown() { + if [[ ${CLEANUP:-true} == "true" ]] + then + echo "helm/pvc teardown" + helm delete vault + kubectl delete --all pvc + kubectl delete namespace acceptance --ignore-not-found=true + fi +} diff --git a/test/acceptance/server-ha-enterprise-dr.bats b/test/acceptance/server-ha-enterprise-dr.bats index 3698f08c4..1445ffb83 100644 --- a/test/acceptance/server-ha-enterprise-dr.bats +++ b/test/acceptance/server-ha-enterprise-dr.bats @@ -7,10 +7,11 @@ load _helpers helm install "$(name_prefix)-east" \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.6.2_ent' \ + --set='server.image.tag=1.7.3_ent' \ --set='injector.enabled=false' \ --set='server.ha.enabled=true' \ - --set='server.ha.raft.enabled=true' . + --set='server.ha.raft.enabled=true' \ + --set='server.enterpriseLicense.secretName=vault-license' . wait_for_running "$(name_prefix)-east-0" # Sealed, not initialized @@ -76,9 +77,10 @@ load _helpers helm install "$(name_prefix)-west" \ --set='injector.enabled=false' \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.6.2_ent' \ + --set='server.image.tag=1.7.3_ent' \ --set='server.ha.enabled=true' \ - --set='server.ha.raft.enabled=true' . + --set='server.ha.raft.enabled=true' \ + --set='server.enterpriseLicense.secretName=vault-license' . wait_for_running "$(name_prefix)-west-0" # Sealed, not initialized @@ -153,6 +155,7 @@ setup() { kubectl delete namespace acceptance --ignore-not-found=true kubectl create namespace acceptance kubectl config set-context --current --namespace=acceptance + kubectl create secret generic vault-license --from-literal license=$VAULT_LICENSE_CI } #cleanup diff --git a/test/acceptance/server-ha-enterprise-perf.bats b/test/acceptance/server-ha-enterprise-perf.bats index 5fcfbcef2..98fc3e6d6 100644 --- a/test/acceptance/server-ha-enterprise-perf.bats +++ b/test/acceptance/server-ha-enterprise-perf.bats @@ -8,9 +8,10 @@ load _helpers helm install "$(name_prefix)-east" \ --set='injector.enabled=false' \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.6.2_ent' \ + --set='server.image.tag=1.7.3_ent' \ --set='server.ha.enabled=true' \ - --set='server.ha.raft.enabled=true' . + --set='server.ha.raft.enabled=true' \ + --set='server.enterpriseLicense.secretName=vault-license' . wait_for_running "$(name_prefix)-east-0" # Sealed, not initialized @@ -76,9 +77,10 @@ load _helpers helm install "$(name_prefix)-west" \ --set='injector.enabled=false' \ --set='server.image.repository=hashicorp/vault-enterprise' \ - --set='server.image.tag=1.6.2_ent' \ + --set='server.image.tag=1.7.3_ent' \ --set='server.ha.enabled=true' \ - --set='server.ha.raft.enabled=true' . + --set='server.ha.raft.enabled=true' \ + --set='server.enterpriseLicense.secretName=vault-license' . wait_for_running "$(name_prefix)-west-0" # Sealed, not initialized @@ -151,6 +153,7 @@ setup() { kubectl delete namespace acceptance --ignore-not-found=true kubectl create namespace acceptance kubectl config set-context --current --namespace=acceptance + kubectl create secret generic vault-license --from-literal license=$VAULT_LICENSE_CI } #cleanup diff --git a/test/chart/_helpers.bash b/test/chart/_helpers.bash new file mode 100644 index 000000000..fb9db31da --- /dev/null +++ b/test/chart/_helpers.bash @@ -0,0 +1,18 @@ +# chart_dir returns the directory for the chart +chart_dir() { + echo ${BATS_TEST_DIRNAME}/../.. +} + +# check_result checks if the specified test passed +# results schema example: +# { +# "check": "has-minkubeversion", +# "type": "Mandatory", +# "outcome": "PASS", +# "reason": "Minimum Kubernetes version specified" +# } +check_result() { + local -r var="$1" + local check=$(cat $VERIFY_OUTPUT | jq -r ".results[] | select(.check==\"${var}\").outcome") + [ "$check" = "PASS" ] +} diff --git a/test/chart/verifier.bats b/test/chart/verifier.bats new file mode 100644 index 000000000..e7ab5aa72 --- /dev/null +++ b/test/chart/verifier.bats @@ -0,0 +1,86 @@ +#!/usr/bin/env bats + +load _helpers + +setup_file() { + cd `chart_dir` + export VERIFY_OUTPUT="/$BATS_RUN_TMPDIR/verify.json" + export CHART_VOLUME=vault-helm-chart-src + # Note: currently `latest` is the only tag available in the chart-verifier repo. + local IMAGE="quay.io/redhat-certification/chart-verifier:latest" + # chart-verifier requires an openshift version if a cluster isn't available + local OPENSHIFT_VERSION="4.7" + local DISABLED_TESTS="chart-testing" + + local run_cmd="chart-verifier" + local chart_src="." + + if [ ! -e $USE_DOCKER ]; then + chart_src="/chart" + # Create a dummy container which will hold a volume with chart source + docker create -v $chart_src --name $CHART_VOLUME alpine:3 /bin/true + # Copy the chart source into this volume + docker cp . $CHART_VOLUME:$chart_src + # Make sure we have the latest version of chart-verifier + docker pull $IMAGE + # Start chart-verifier using this volume + run_cmd="docker run --rm --volumes-from $CHART_VOLUME $IMAGE" + fi + + $run_cmd verify $chart_src \ + --output json \ + --openshift-version $OPENSHIFT_VERSION \ + --disable $DISABLED_TESTS \ + --chart-values values.openshift.yaml 2>&1 | tee $VERIFY_OUTPUT +} + +teardown_file() { + if [ ! -e $USE_DOCKER ]; then + docker rm $CHART_VOLUME + fi +} + +@test "has-kubeversion" { + check_result has-kubeversion +} + +@test "is-helm-v3" { + check_result is-helm-v3 +} + +@test "not-contains-crds" { + check_result not-contains-crds +} + +@test "helm-lint" { + check_result helm-lint +} + +@test "not-contain-csi-objects" { + check_result not-contain-csi-objects +} + +@test "has-readme" { + check_result has-readme +} + +@test "contains-values" { + check_result contains-values +} + +@test "contains-values-schema" { + check_result contains-values-schema +} + +@test "contains-test" { + check_result contains-test +} + +@test "images-are-certified" { + check_result images-are-certified +} + +@test "chart-testing" { + skip "Skipping since this test requires a kubernetes/openshift cluster" + check_result chart-testing +} diff --git a/test/docker/Test.dockerfile b/test/docker/Test.dockerfile index 4b1c37579..98afeace2 100644 --- a/test/docker/Test.dockerfile +++ b/test/docker/Test.dockerfile @@ -9,7 +9,7 @@ FROM docker.mirror.hashicorp.services/alpine:latest WORKDIR /root -ENV BATS_VERSION "1.1.0" +ENV BATS_VERSION "1.3.0" ENV TERRAFORM_VERSION "0.12.10" # base packages diff --git a/test/terraform/main.tf b/test/terraform/main.tf index 1c3f035c1..3556c6fd8 100644 --- a/test/terraform/main.tf +++ b/test/terraform/main.tf @@ -8,7 +8,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = "${var.zone}" - version_prefix = "1.15." + version_prefix = "1.17." } data "google_service_account" "gcpapi" { diff --git a/test/unit/csi-clusterrole.bats b/test/unit/csi-clusterrole.bats new file mode 100644 index 000000000..68ea7ce78 --- /dev/null +++ b/test/unit/csi-clusterrole.bats @@ -0,0 +1,33 @@ +#!/usr/bin/env bats + +load _helpers + +@test "csi/ClusterRole: disabled by default" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/csi-clusterrole.yaml \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "csi/ClusterRole: enabled with csi.enabled" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-clusterrole.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +# ClusterRole name +@test "csi/ClusterRole: name" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-clusterrole.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.metadata.name' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-vault-csi-provider-clusterrole" ] +} \ No newline at end of file diff --git a/test/unit/csi-clusterrolebinding.bats b/test/unit/csi-clusterrolebinding.bats new file mode 100644 index 000000000..cff3a3699 --- /dev/null +++ b/test/unit/csi-clusterrolebinding.bats @@ -0,0 +1,44 @@ +#!/usr/bin/env bats + +load _helpers + +@test "csi/ClusterRoleBinding: disabled by default" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/csi-clusterrolebinding.yaml \ + . || echo "---")| tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "csi/ClusterRoleBinding: enabled with csi.enabled" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-clusterrolebinding.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +# ClusterRoleBinding cluster role ref name +@test "csi/ClusterRoleBinding: cluster role ref name" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-clusterrolebinding.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.roleRef.name' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-vault-csi-provider-clusterrole" ] +} + +# ClusterRoleBinding service account name +@test "csi/ClusterRoleBinding: service account name" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-clusterrolebinding.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.subjects[0].name' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-vault-csi-provider" ] +} \ No newline at end of file diff --git a/test/unit/csi-daemonset.bats b/test/unit/csi-daemonset.bats new file mode 100644 index 000000000..f0a62c2b2 --- /dev/null +++ b/test/unit/csi-daemonset.bats @@ -0,0 +1,416 @@ +#!/usr/bin/env bats + +load _helpers + +#-------------------------------------------------------------------- +# Daemonset + +# Enabled +@test "csi/daemonset: created only when enabled" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/csi-daemonset.yaml \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$( (helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "global.enabled=false" \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +# serviceAccountName reference name +@test "csi/daemonset: serviceAccountName reference name" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.serviceAccountName' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-vault-csi-provider" ] +} + +# Image +@test "csi/daemonset: image is configurable" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.image.repository=SomeOtherImage" \ + --set "csi.image.tag=0.0.1" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].image' | tee /dev/stderr) + [ "${actual}" = "SomeOtherImage:0.0.1" ] + + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.image.pullPolicy=SomePullPolicy" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].imagePullPolicy' | tee /dev/stderr) + [ "${actual}" = "SomePullPolicy" ] +} + +@test "csi/daemonset: Custom imagePullSecrets" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set 'global.imagePullSecrets[0].name=foo' \ + --set 'global.imagePullSecrets[1].name=bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.imagePullSecrets' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.[0].name' | tee /dev/stderr) + [ "${actual}" = "foo" ] + + local actual=$(echo $object | + yq -r '.[1].name' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +@test "csi/daemonset: default imagePullSecrets" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.imagePullSecrets' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +# Debug arg +@test "csi/daemonset: debug arg is configurable" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].args[1]' | tee /dev/stderr) + [ "${actual}" = "--debug=false" ] + + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.debug=true" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].args[1]' | tee /dev/stderr) + [ "${actual}" = "--debug=true" ] +} + +# Extra args +@test "csi/daemonset: extra args can be passed" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].args | length' | tee /dev/stderr) + [ "${actual}" = "2" ] + + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.extraArgs={--foo=bar,--bar baz,first}" \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0]') + local actual=$(echo $object | + yq -r '.args | length' | tee /dev/stderr) + [ "${actual}" = "5" ] + local actual=$(echo $object | + yq -r '.args[2]' | tee /dev/stderr) + [ "${actual}" = "--foo=bar" ] + local actual=$(echo $object | + yq -r '.args[3]' | tee /dev/stderr) + [ "${actual}" = "--bar baz" ] + local actual=$(echo $object | + yq -r '.args[4]' | tee /dev/stderr) + [ "${actual}" = "first" ] +} + +# updateStrategy +@test "csi/daemonset: updateStrategy is configurable" { + cd `chart_dir` + # Default + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.spec.updateStrategy.type' | tee /dev/stderr) + [ "${actual}" = "RollingUpdate" ] + + # OnDelete + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.daemonSet.updateStrategy.type=OnDelete" \ + . | tee /dev/stderr | + yq -r '.spec.updateStrategy.type' | tee /dev/stderr) + [ "${actual}" = "OnDelete" ] + + # Max unavailable + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set "csi.enabled=true" \ + --set "csi.daemonSet.updateStrategy.maxUnavailable=25%" \ + . | tee /dev/stderr | + yq -r '.spec.updateStrategy.rollingUpdate.maxUnavailable' | tee /dev/stderr) + [ "${actual}" = "25%" ] +} + +#-------------------------------------------------------------------- +# Extra annotations +@test "csi/daemonset: default csi.daemonSet.annotations" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "csi/daemonset: specify csi.daemonSet.annotations yaml" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.daemonSet.annotations.foo=bar' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +@test "csi/daemonset: specify csi.daemonSet.annotations yaml string" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.daemonSet.annotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +@test "csi/daemonset: default csi.pod.annotations" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "csi/daemonset: specify csi.pod.annotations yaml" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.pod.annotations.foo=bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +@test "csi/daemonset: specify csi.pod.annotations yaml string" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.pod.annotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + +@test "csi/daemonset: tolerations not set by default" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec | .tolerations? == null' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "csi/daemonset: tolerations can be set" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.pod.tolerations=foobar' \ + . | tee /dev/stderr | + yq '.spec.template.spec.tolerations == "foobar"' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# volumes + +@test "csi/daemonset: csi.volumes adds volume" { + cd `chart_dir` + + # Test that it defines it + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.volumes[0].name=plugins' \ + --set 'csi.volumes[0].emptyDir=\{\}' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.volumes[] | select(.name == "plugins")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.emptyDir' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +#-------------------------------------------------------------------- +# volumeMounts + +@test "csi/daemonset: csi.volumeMounts adds volume mounts" { + cd `chart_dir` + + # Test that it defines it + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.volumeMounts[0].name=plugins' \ + --set 'csi.volumeMounts[0].mountPath=/usr/local/libexec/vault' \ + --set 'csi.volumeMounts[0].readOnly=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "plugins")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.mountPath' | tee /dev/stderr) + [ "${actual}" = "/usr/local/libexec/vault" ] + + local actual=$(echo $object | + yq -r '.readOnly' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# Readiness/liveness probes + +@test "csi/daemonset: csi.livenessProbe is configurable" { + cd `chart_dir` + + # Test the defaults + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].livenessProbe' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.failureThreshold' | tee /dev/stderr) + [ "${actual}" = "2" ] + local actual=$(echo $object | + yq -r '.initialDelaySeconds' | tee /dev/stderr) + [ "${actual}" = "5" ] + local actual=$(echo $object | + yq -r '.periodSeconds' | tee /dev/stderr) + [ "${actual}" = "5" ] + local actual=$(echo $object | + yq -r '.successThreshold' | tee /dev/stderr) + [ "${actual}" = "1" ] + local actual=$(echo $object | + yq -r '.timeoutSeconds' | tee /dev/stderr) + [ "${actual}" = "3" ] + + # Test it is configurable + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.livenessProbe.failureThreshold=10' \ + --set 'csi.livenessProbe.initialDelaySeconds=11' \ + --set 'csi.livenessProbe.periodSeconds=12' \ + --set 'csi.livenessProbe.successThreshold=13' \ + --set 'csi.livenessProbe.timeoutSeconds=14' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].livenessProbe' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.failureThreshold' | tee /dev/stderr) + [ "${actual}" = "10" ] + local actual=$(echo $object | + yq -r '.initialDelaySeconds' | tee /dev/stderr) + [ "${actual}" = "11" ] + local actual=$(echo $object | + yq -r '.periodSeconds' | tee /dev/stderr) + [ "${actual}" = "12" ] + local actual=$(echo $object | + yq -r '.successThreshold' | tee /dev/stderr) + [ "${actual}" = "13" ] + local actual=$(echo $object | + yq -r '.timeoutSeconds' | tee /dev/stderr) + [ "${actual}" = "14" ] +} + +@test "csi/daemonset: csi.readinessProbe is configurable" { + cd `chart_dir` + + # Test the defaults + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].readinessProbe' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.failureThreshold' | tee /dev/stderr) + [ "${actual}" = "2" ] + local actual=$(echo $object | + yq -r '.initialDelaySeconds' | tee /dev/stderr) + [ "${actual}" = "5" ] + local actual=$(echo $object | + yq -r '.periodSeconds' | tee /dev/stderr) + [ "${actual}" = "5" ] + local actual=$(echo $object | + yq -r '.successThreshold' | tee /dev/stderr) + [ "${actual}" = "1" ] + local actual=$(echo $object | + yq -r '.timeoutSeconds' | tee /dev/stderr) + [ "${actual}" = "3" ] + + # Test it is configurable + local object=$(helm template \ + --show-only templates/csi-daemonset.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.readinessProbe.failureThreshold=10' \ + --set 'csi.readinessProbe.initialDelaySeconds=11' \ + --set 'csi.readinessProbe.periodSeconds=12' \ + --set 'csi.readinessProbe.successThreshold=13' \ + --set 'csi.readinessProbe.timeoutSeconds=14' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].readinessProbe' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.failureThreshold' | tee /dev/stderr) + [ "${actual}" = "10" ] + local actual=$(echo $object | + yq -r '.initialDelaySeconds' | tee /dev/stderr) + [ "${actual}" = "11" ] + local actual=$(echo $object | + yq -r '.periodSeconds' | tee /dev/stderr) + [ "${actual}" = "12" ] + local actual=$(echo $object | + yq -r '.successThreshold' | tee /dev/stderr) + [ "${actual}" = "13" ] + local actual=$(echo $object | + yq -r '.timeoutSeconds' | tee /dev/stderr) + [ "${actual}" = "14" ] +} diff --git a/test/unit/csi-serviceaccount.bats b/test/unit/csi-serviceaccount.bats new file mode 100644 index 000000000..22ba06df2 --- /dev/null +++ b/test/unit/csi-serviceaccount.bats @@ -0,0 +1,59 @@ +#!/usr/bin/env bats + +load _helpers + +@test "csi/ServiceAccount: disabled by default" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/csi-serviceaccount.yaml \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "csi/ServiceAccount: enable with csi.enabled" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-serviceaccount.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +# serviceAccountName reference name +@test "csi/daemonset: serviceAccountName name" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/csi-serviceaccount.yaml \ + --set "csi.enabled=true" \ + . | tee /dev/stderr | + yq -r '.metadata.name' | tee /dev/stderr) + [ "${actual}" = "RELEASE-NAME-vault-csi-provider" ] +} + +@test "csi/serviceAccount: specify annotations" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/server-serviceaccount.yaml \ + --set 'csi.enabled=true' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations["foo"]' | tee /dev/stderr) + [ "${actual}" = "null" ] + + local actual=$(helm template \ + --show-only templates/server-serviceaccount.yaml \ + --set 'csi.enabled=true' \ + --set 'csi.serviceAccount.annotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations["foo"]' | tee /dev/stderr) + [ "${actual}" = "null" ] + + local actual=$(helm template \ + --show-only templates/server-serviceaccount.yaml \ + --set 'csi.enabled=true' \ + --set 'server.serviceAccount.annotations.foo=bar' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations["foo"]' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} \ No newline at end of file diff --git a/test/unit/injector-deployment.bats b/test/unit/injector-deployment.bats index a1174808b..cd6f1ddd3 100755 --- a/test/unit/injector-deployment.bats +++ b/test/unit/injector-deployment.bats @@ -133,21 +133,13 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[5].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_TLS_CERT_FILE" ] - - local actual=$(echo $object | - yq -r '.[5].value' | tee /dev/stderr) - [ "${actual}" = "/etc/webhook/certs/test.crt" ] - - local actual=$(echo $object | - yq -r '.[6].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_TLS_KEY_FILE" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_TLS_CERT_FILE")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "/etc/webhook/certs/test.crt" ] - local actual=$(echo $object | - yq -r '.[6].value' | tee /dev/stderr) - [ "${actual}" = "/etc/webhook/certs/test.key" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_TLS_KEY_FILE")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "/etc/webhook/certs/test.key" ] } @test "injector/deployment: auto TLS by default" { @@ -163,13 +155,35 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[5].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_TLS_AUTO" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_TLS_AUTO")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "RELEASE-NAME-vault-agent-injector-cfg" ] - local actual=$(echo $object | - yq -r '.[6].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_TLS_AUTO_HOSTS" ] + # helm template does uses current context namespace and ignores namespace flags, so + # discover the targeted namespace so we can check the rendered value correctly. + local namespace=$(kubectl config view --minify --output 'jsonpath={..namespace}') + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_TLS_AUTO_HOSTS")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "RELEASE-NAME-vault-agent-injector-svc,RELEASE-NAME-vault-agent-injector-svc.${namespace:-default},RELEASE-NAME-vault-agent-injector-svc.${namespace:-default}.svc" ] +} + +@test "injector/deployment: manual TLS adds volume mount" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + --set 'injector.enabled=true' \ + --set 'injector.certs.secretName=vault-tls' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "webhook-certs")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.mountPath' | tee /dev/stderr) + [ "${actual}" = "/etc/webhook/certs" ] + + local actual=$(echo $object | + yq -r '.readOnly' | tee /dev/stderr) + [ "${actual}" = "true" ] } @test "injector/deployment: with externalVaultAddr" { @@ -180,13 +194,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[2].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_VAULT_ADDR" ] - - local actual=$(echo $object | - yq -r '.[2].value' | tee /dev/stderr) - [ "${actual}" = "http://vault-outside" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_VAULT_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "http://vault-outside" ] } @test "injector/deployment: without externalVaultAddr" { @@ -198,13 +208,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[2].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_VAULT_ADDR" ] - - local actual=$(echo $object | - yq -r '.[2].value' | tee /dev/stderr) - [ "${actual}" = "http://not-external-test-vault.default.svc:8200" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_VAULT_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "http://not-external-test-vault.default.svc:8200" ] } @test "injector/deployment: default authPath" { @@ -214,13 +220,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[3].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_VAULT_AUTH_PATH" ] - - local actual=$(echo $object | - yq -r '.[3].value' | tee /dev/stderr) - [ "${actual}" = "auth/kubernetes" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_VAULT_AUTH_PATH")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "auth/kubernetes" ] } @test "injector/deployment: custom authPath" { @@ -231,13 +233,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[3].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_VAULT_AUTH_PATH" ] - - local actual=$(echo $object | - yq -r '.[3].value' | tee /dev/stderr) - [ "${actual}" = "auth/k8s" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_VAULT_AUTH_PATH")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "auth/k8s" ] } @test "injector/deployment: default logLevel" { @@ -247,13 +245,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[1].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_LOG_LEVEL" ] - - local actual=$(echo $object | - yq -r '.[1].value' | tee /dev/stderr) - [ "${actual}" = "info" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_LOG_LEVEL")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "info" ] } @test "injector/deployment: custom logLevel" { @@ -264,13 +258,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[1].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_LOG_LEVEL" ] - - local actual=$(echo $object | - yq -r '.[1].value' | tee /dev/stderr) - [ "${actual}" = "foo" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_LOG_LEVEL")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "foo" ] } @test "injector/deployment: default logFormat" { @@ -280,13 +270,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[7].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_LOG_FORMAT" ] - - local actual=$(echo $object | - yq -r '.[7].value' | tee /dev/stderr) - [ "${actual}" = "standard" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_LOG_FORMAT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "standard" ] } @test "injector/deployment: custom logFormat" { @@ -297,13 +283,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[7].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_LOG_FORMAT" ] - - local actual=$(echo $object | - yq -r '.[7].value' | tee /dev/stderr) - [ "${actual}" = "json" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_LOG_FORMAT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "json" ] } @test "injector/deployment: default revoke on shutdown" { @@ -313,13 +295,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[8].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_REVOKE_ON_SHUTDOWN" ] - - local actual=$(echo $object | - yq -r '.[8].value' | tee /dev/stderr) - [ "${actual}" = "false" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_REVOKE_ON_SHUTDOWN")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "false" ] } @test "injector/deployment: custom revoke on shutdown" { @@ -330,13 +308,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[8].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_REVOKE_ON_SHUTDOWN" ] - - local actual=$(echo $object | - yq -r '.[8].value' | tee /dev/stderr) - [ "${actual}" = "true" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_REVOKE_ON_SHUTDOWN")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "true" ] } @test "injector/deployment: disable security context when openshift enabled" { @@ -347,9 +321,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[9].name' | tee /dev/stderr) - [ "${actual}" = "AGENT_INJECT_SET_SECURITY_CONTEXT" ] + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_SET_SECURITY_CONTEXT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "false" ] } #-------------------------------------------------------------------- @@ -365,29 +339,17 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[9].name' | tee /dev/stderr) - [ "${actual}" = "FOO" ] - - local actual=$(echo $object | - yq -r '.[9].value' | tee /dev/stderr) - [ "${actual}" = "bar" ] - - local actual=$(echo $object | - yq -r '.[10].name' | tee /dev/stderr) - [ "${actual}" = "FOOBAR" ] + local value=$(echo $object | + yq -r 'map(select(.name=="FOO")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "bar" ] - local actual=$(echo $object | - yq -r '.[10].value' | tee /dev/stderr) - [ "${actual}" = "foobar" ] + local value=$(echo $object | + yq -r 'map(select(.name=="FOOBAR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "foobar" ] - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "LOWER_CASE" ] - - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "sanitized" ] + local value=$(echo $object | + yq -r 'map(select(.name=="LOWER_CASE")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "sanitized" ] } #-------------------------------------------------------------------- @@ -422,6 +384,42 @@ load _helpers [ "${actual}" = "bar" ] } +#-------------------------------------------------------------------- +# agent port + +@test "injector/deployment: default agentPort" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.[0].name' | tee /dev/stderr) + [ "${actual}" = "AGENT_INJECT_LISTEN" ] + + local actual=$(echo $object | + yq -r '.[0].value' | tee /dev/stderr) + [ "${actual}" = ":8080" ] +} + +@test "injector/deployment: custom agentPort" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + --set 'injector.port=8443' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.[0].name' | tee /dev/stderr) + [ "${actual}" = "AGENT_INJECT_LISTEN" ] + + local actual=$(echo $object | + yq -r '.[0].value' | tee /dev/stderr) + [ "${actual}" = ":8443" ] +} + #-------------------------------------------------------------------- # affinity @@ -543,3 +541,102 @@ load _helpers yq -r '.spec.template.metadata.labels.foo' | tee /dev/stderr) [ "${actual}" = "bar" ] } + +#-------------------------------------------------------------------- +# hostNetwork + +@test "injector/deployment: injector.hostNetwork not set" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-deployment.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.hostNetwork' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "injector/deployment: injector.hostNetwork is set" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-deployment.yaml \ + --set 'injector.hostNetwork=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.hostNetwork' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "injector/deployment: agent default resources" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_CPU_LIMIT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "500m" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_CPU_REQUEST")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "250m" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_MEM_LIMIT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "128Mi" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_MEM_REQUEST")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "64Mi" ] +} + +@test "injector/deployment: can set agent default resources" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + --set 'injector.agentDefaults.cpuLimit=cpuLimit' \ + --set 'injector.agentDefaults.cpuRequest=cpuRequest' \ + --set 'injector.agentDefaults.memLimit=memLimit' \ + --set 'injector.agentDefaults.memRequest=memRequest' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_CPU_LIMIT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "cpuLimit" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_CPU_REQUEST")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "cpuRequest" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_MEM_LIMIT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "memLimit" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_MEM_REQUEST")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "memRequest" ] +} + +@test "injector/deployment: agent default template" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_DEFAULT_TEMPLATE")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "map" ] +} + +@test "injector/deployment: can set agent default template" { + cd `chart_dir` + local object=$(helm template \ + --show-only templates/injector-deployment.yaml \ + --set='injector.agentDefaults.template=json' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $object | + yq -r 'map(select(.name=="AGENT_INJECT_DEFAULT_TEMPLATE")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "json" ] +} diff --git a/test/unit/injector-mutating-webhook.bats b/test/unit/injector-mutating-webhook.bats index bb307f857..65f505bcf 100755 --- a/test/unit/injector-mutating-webhook.bats +++ b/test/unit/injector-mutating-webhook.bats @@ -76,6 +76,29 @@ load _helpers [ "${actual}" = "true" ] } +@test "injector/MutatingWebhookConfiguration: objectSelector empty by default" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-mutating-webhook.yaml \ + --set 'injector.enabled=true' \ + --namespace foo \ + . | tee /dev/stderr | + yq '.webhooks[0].objectSelector' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "injector/MutatingWebhookConfiguration: can set objectSelector" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-mutating-webhook.yaml \ + --set 'injector.enabled=true' \ + --set 'injector.objectSelector.matchLabels.injector=true' \ + . | tee /dev/stderr | + yq '.webhooks[0].objectSelector.matchLabels.injector' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + @test "injector/MutatingWebhookConfiguration: failurePolicy 'Ignore' by default" { cd `chart_dir` local actual=$(helm template \ diff --git a/test/unit/injector-service.bats b/test/unit/injector-service.bats index f9d872256..ad4800991 100755 --- a/test/unit/injector-service.bats +++ b/test/unit/injector-service.bats @@ -18,6 +18,25 @@ load _helpers [ "${actual}" = "true" ] } +@test "injector/Service: service with default port" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-service.yaml \ + . | tee /dev/stderr | + yq -r '.spec.ports[0].targetPort' | tee /dev/stderr) + [ "${actual}" = "8080" ] +} + +@test "injector/Service: service with custom port" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/injector-service.yaml \ + --set 'injector.port=8443' \ + . | tee /dev/stderr | + yq -r '.spec.ports[0].targetPort' | tee /dev/stderr) + [ "${actual}" = "8443" ] +} + @test "injector/Service: disable with global.enabled false" { cd `chart_dir` local actual=$( (helm template \ diff --git a/test/unit/schema.bats b/test/unit/schema.bats new file mode 100644 index 000000000..a42614bf6 --- /dev/null +++ b/test/unit/schema.bats @@ -0,0 +1,46 @@ +#!/usr/bin/env bats + +load _helpers + +# These tests are just to verify there is a schema file used in the chart. Since +# .enabled is defined as a boolean type for each of the top-level blocks in the +# schema, setting it as a string fails 'helm template'. +@test "schema: csi enabled datatype" { + cd `chart_dir` + run helm template . --set csi.enabled="nope" + [ "$status" -eq 1 ] + [ "${lines[2]}" = "- csi.enabled: Invalid type. Expected: boolean, given: string" ] + + run helm template . --set csi.enabled=true + [ "$status" -eq 0 ] +} + +@test "schema: injector enabled datatype" { + cd `chart_dir` + run helm template . --set injector.enabled="nope" + [ "$status" -eq 1 ] + [ "${lines[2]}" = "- injector.enabled: Invalid type. Expected: boolean, given: string" ] + + run helm template . --set injector.enabled=true + [ "$status" -eq 0 ] +} + +@test "schema: server enabled datatype" { + cd `chart_dir` + run helm template . --set server.enabled="nope" + [ "$status" -eq 1 ] + [ "${lines[2]}" = "- server.enabled: Invalid type. Expected: boolean, given: string" ] + + run helm template . --set server.enabled=true + [ "$status" -eq 0 ] +} + +@test "schema: ui enabled datatype" { + cd `chart_dir` + run helm template . --set ui.enabled="nope" + [ "$status" -eq 1 ] + [ "${lines[2]}" = "- ui.enabled: Invalid type. Expected: boolean, given: string" ] + + run helm template . --set ui.enabled=true + [ "$status" -eq 0 ] +} diff --git a/test/unit/server-dev-statefulset.bats b/test/unit/server-dev-statefulset.bats index 4e47fea69..3c5f9d8fb 100755 --- a/test/unit/server-dev-statefulset.bats +++ b/test/unit/server-dev-statefulset.bats @@ -246,13 +246,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_DEV_ROOT_TOKEN_ID" ] - - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "root" ] + local name=$(echo $object | + yq -r 'map(select(.name=="VAULT_DEV_ROOT_TOKEN_ID")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "root" ] } @test "server/dev-StatefulSet: set custom devRootToken" { @@ -264,13 +260,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_DEV_ROOT_TOKEN_ID" ] - - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "customtoken" ] + local name=$(echo $object | + yq -r 'map(select(.name=="VAULT_DEV_ROOT_TOKEN_ID")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "customtoken" ] } #-------------------------------------------------------------------- @@ -340,27 +332,21 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "ENV_FOO_0" ] - local actual=$(echo $object | - yq -r '.[11].valueFrom.secretKeyRef.name' | tee /dev/stderr) - [ "${actual}" = "secret_name_0" ] - local actual=$(echo $object | - yq -r '.[11].valueFrom.secretKeyRef.key' | tee /dev/stderr) - [ "${actual}" = "secret_key_0" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_0")) | .[] .valueFrom.secretKeyRef.name' | tee /dev/stderr) + [ "${value}" = "secret_name_0" ] - local actual=$(echo $object | - yq -r '.[12].name' | tee /dev/stderr) - [ "${actual}" = "ENV_FOO_1" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_0")) | .[] .valueFrom.secretKeyRef.key' | tee /dev/stderr) + [ "${value}" = "secret_key_0" ] - local actual=$(echo $object | - yq -r '.[12].valueFrom.secretKeyRef.name' | tee /dev/stderr) - [ "${actual}" = "secret_name_1" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_1")) | .[] .valueFrom.secretKeyRef.name' | tee /dev/stderr) + [ "${value}" = "secret_name_1" ] - local actual=$(echo $object | - yq -r '.[12].valueFrom.secretKeyRef.key' | tee /dev/stderr) - [ "${actual}" = "secret_key_1" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_1")) | .[] .valueFrom.secretKeyRef.key' | tee /dev/stderr) + [ "${value}" = "secret_key_1" ] } #-------------------------------------------------------------------- diff --git a/test/unit/server-ha-disruptionbudget.bats b/test/unit/server-ha-disruptionbudget.bats index f3c329ec6..6cf21f200 100755 --- a/test/unit/server-ha-disruptionbudget.bats +++ b/test/unit/server-ha-disruptionbudget.bats @@ -85,3 +85,15 @@ load _helpers yq '.spec.maxUnavailable' | tee /dev/stderr) [ "${actual}" = "2" ] } + +@test "server/DisruptionBudget: correct maxUnavailable with custom value" { + cd `chart_dir` + local actual=$(helm template \ + --show-only templates/server-disruptionbudget.yaml \ + --set 'server.ha.enabled=true' \ + --set 'server.ha.replicas=3' \ + --set 'server.ha.disruptionBudget.maxUnavailable=2' \ + . | tee /dev/stderr | + yq '.spec.maxUnavailable' | tee /dev/stderr) + [ "${actual}" = "2" ] +} \ No newline at end of file diff --git a/test/unit/server-ha-statefulset.bats b/test/unit/server-ha-statefulset.bats index 6df4dfe30..43e1acef2 100755 --- a/test/unit/server-ha-statefulset.bats +++ b/test/unit/server-ha-statefulset.bats @@ -70,14 +70,11 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[4].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_ADDR" ] - - local actual=$(echo $object | - yq -r '.[4].value' | tee /dev/stderr) - [ "${actual}" = "http://127.0.0.1:8200" ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "http://127.0.0.1:8200" ] } + @test "server/ha-StatefulSet: tls enabled" { cd `chart_dir` local object=$(helm template \ @@ -86,13 +83,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[4].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_ADDR" ] - - local actual=$(echo $object | - yq -r '.[4].value' | tee /dev/stderr) - [ "${actual}" = "https://127.0.0.1:8200" ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "https://127.0.0.1:8200" ] } #-------------------------------------------------------------------- @@ -348,21 +341,13 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "FOO" ] + local value=$(echo $object | + yq -r 'map(select(.name=="FOO")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "bar" ] - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "bar" ] - - local actual=$(echo $object | - yq -r '.[12].name' | tee /dev/stderr) - [ "${actual}" = "FOOBAR" ] - - local actual=$(echo $object | - yq -r '.[12].value' | tee /dev/stderr) - [ "${actual}" = "foobar" ] + local value=$(echo $object | + yq -r 'map(select(.name=="FOOBAR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "foobar" ] } #-------------------------------------------------------------------- @@ -382,25 +367,21 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "ENV_FOO_0" ] - local actual=$(echo $object | - yq -r '.[11].valueFrom.secretKeyRef.name' | tee /dev/stderr) - [ "${actual}" = "secret_name_0" ] - local actual=$(echo $object | - yq -r '.[11].valueFrom.secretKeyRef.key' | tee /dev/stderr) - [ "${actual}" = "secret_key_0" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_0")) | .[] .valueFrom.secretKeyRef.name' | tee /dev/stderr) + [ "${value}" = "secret_name_0" ] - local actual=$(echo $object | - yq -r '.[12].name' | tee /dev/stderr) - [ "${actual}" = "ENV_FOO_1" ] - local actual=$(echo $object | - yq -r '.[12].valueFrom.secretKeyRef.name' | tee /dev/stderr) - [ "${actual}" = "secret_name_1" ] - local actual=$(echo $object | - yq -r '.[12].valueFrom.secretKeyRef.key' | tee /dev/stderr) - [ "${actual}" = "secret_key_1" ] + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_0")) | .[] .valueFrom.secretKeyRef.key' | tee /dev/stderr) + [ "${value}" = "secret_key_0" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_1")) | .[] .valueFrom.secretKeyRef.name' | tee /dev/stderr) + [ "${value}" = "secret_name_1" ] + + local value=$(echo $object | + yq -r 'map(select(.name=="ENV_FOO_1")) | .[] .valueFrom.secretKeyRef.key' | tee /dev/stderr) + [ "${value}" = "secret_key_1" ] } #-------------------------------------------------------------------- @@ -414,16 +395,12 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[5].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_API_ADDR" ] - - local actual=$(echo $object | - yq -r '.[5].value' | tee /dev/stderr) - [ "${actual}" = 'http://$(POD_IP):8200' ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_API_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = 'http://$(POD_IP):8200' ] } -@test "server/ha-StatefulSet: api addr can be overriden" { +@test "server/ha-StatefulSet: api addr is configurable" { cd `chart_dir` local object=$(helm template \ --show-only templates/server-statefulset.yaml \ @@ -432,13 +409,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[5].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_API_ADDR" ] - - local actual=$(echo $object | - yq -r '.[5].value' | tee /dev/stderr) - [ "${actual}" = 'https://example.com:8200' ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_API_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "https://example.com:8200" ] } #-------------------------------------------------------------------- @@ -453,13 +426,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[9].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_CLUSTER_ADDR" ] - - local actual=$(echo $object | - yq -r '.[9].value' | tee /dev/stderr) - [ "${actual}" = 'https://$(HOSTNAME).RELEASE-NAME-vault-internal:8201' ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_CLUSTER_ADDR")) | .[] .value' | tee /dev/stderr) + [ "${value}" = 'https://$(HOSTNAME).RELEASE-NAME-vault-internal:8201' ] } #-------------------------------------------------------------------- @@ -475,13 +444,9 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[10].name' | tee /dev/stderr) - [ "${actual}" = "VAULT_RAFT_NODE_ID" ] - - local actual=$(echo $object | - yq -r '.[10].valueFrom.fieldRef.fieldPath' | tee /dev/stderr) - [ "${actual}" = 'metadata.name' ] + local value=$(echo $object | + yq -r 'map(select(.name=="VAULT_RAFT_NODE_ID")) | .[] .valueFrom.fieldRef.fieldPath' | tee /dev/stderr) + [ "${value}" = "metadata.name" ] } #-------------------------------------------------------------------- diff --git a/test/unit/server-ingress.bats b/test/unit/server-ingress.bats index 5af493847..bf191c3a2 100755 --- a/test/unit/server-ingress.bats +++ b/test/unit/server-ingress.bats @@ -57,6 +57,43 @@ load _helpers } +@test "server/ingress: extra paths prepend host configuration" { + cd `chart_dir` + + local actual=$(helm template \ + --show-only templates/server-ingress.yaml \ + --set 'server.ingress.enabled=true' \ + --set 'server.ingress.hosts[0].host=test.com' \ + --set 'server.ingress.hosts[0].paths[0]=/' \ + --set 'server.ingress.extraPaths[0].path=/annotation-service' \ + --set 'server.ingress.extraPaths[0].backend.serviceName=ssl-redirect' \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[0].backend.serviceName' | tee /dev/stderr) + [ "${actual}" = 'ssl-redirect' ] + + local actual=$(helm template \ + --show-only templates/server-ingress.yaml \ + --set 'server.ingress.enabled=true' \ + --set 'server.ingress.hosts[0].host=test.com' \ + --set 'server.ingress.hosts[0].paths[0]=/' \ + --set 'server.ingress.extraPaths[0].path=/annotation-service' \ + --set 'server.ingress.extraPaths[0].backend.serviceName=ssl-redirect' \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[0].path' | tee /dev/stderr) + [ "${actual}" = '/annotation-service' ] + + local actual=$(helm template \ + --show-only templates/server-ingress.yaml \ + --set 'server.ingress.enabled=true' \ + --set 'server.ingress.hosts[0].host=test.com' \ + --set 'server.ingress.hosts[0].paths[0]=/' \ + --set 'server.ingress.extraPaths[0].path=/annotation-service' \ + --set 'server.ingress.extraPaths[0].backend.serviceName=ssl-redirect' \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[1].path' | tee /dev/stderr) + [ "${actual}" = '/' ] +} + @test "server/ingress: labels gets added to object" { cd `chart_dir` diff --git a/test/unit/server-statefulset.bats b/test/unit/server-statefulset.bats index 7a0533cd9..d7edb969d 100755 --- a/test/unit/server-statefulset.bats +++ b/test/unit/server-statefulset.bats @@ -2,6 +2,41 @@ load _helpers +#-------------------------------------------------------------------- +# disable / enable server deployment + +@test "server/StatefulSet: disabled server.enabled" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/server-statefulset.yaml \ + --set 'server.enabled=false' \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: disabled server.enabled random string" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/server-statefulset.yaml \ + --set 'server.enabled=blabla' \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: enabled server.enabled explicit true" { + cd `chart_dir` + local actual=$( (helm template \ + --show-only templates/server-statefulset.yaml \ + --set 'server.enabled=true' \ + . || echo "---") | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- + @test "server/standalone-StatefulSet: default server.standalone.enabled" { cd `chart_dir` local actual=$(helm template \ @@ -413,6 +448,62 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# log level + +@test "server/standalone-StatefulSet: default log level to empty" { + cd `chart_dir` + local objects=$(helm template \ + --show-only templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $objects | + yq -r 'map(select(.name=="VAULT_LOG_LEVEL")) | .[] .name' | tee /dev/stderr) + [ "${value}" = "" ] +} + +@test "server/standalone-StatefulSet: log level can be changed" { + cd `chart_dir` + local objects=$(helm template \ + --show-only templates/server-statefulset.yaml \ + --set='server.logLevel=debug' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $objects | + yq -r 'map(select(.name=="VAULT_LOG_LEVEL")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "debug" ] +} + +#-------------------------------------------------------------------- +# log format + +@test "server/standalone-StatefulSet: default log format to empty" { + cd `chart_dir` + local objects=$(helm template \ + --show-only templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $objects | + yq -r 'map(select(.name=="VAULT_LOG_FORMAT")) | .[] .name' | tee /dev/stderr) + [ "${value}" = "" ] +} + +@test "server/standalone-StatefulSet: can set log format" { + cd `chart_dir` + local objects=$(helm template \ + --show-only templates/server-statefulset.yaml \ + --set='server.logFormat=json' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) + + local value=$(echo $objects | + yq -r 'map(select(.name=="VAULT_LOG_FORMAT")) | .[] .value' | tee /dev/stderr) + [ "${value}" = "json" ] +} + #-------------------------------------------------------------------- # extraEnvironmentVars @@ -426,21 +517,13 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "FOO" ] + local name=$(echo $object | + yq -r 'map(select(.name=="FOO")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "bar" ] - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "bar" ] - - local actual=$(echo $object | - yq -r '.[12].name' | tee /dev/stderr) - [ "${actual}" = "FOOBAR" ] - - local actual=$(echo $object | - yq -r '.[12].value' | tee /dev/stderr) - [ "${actual}" = "foobar" ] + local name=$(echo $object | + yq -r 'map(select(.name=="FOOBAR")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "foobar" ] local object=$(helm template \ --show-only templates/server-statefulset.yaml \ @@ -449,21 +532,13 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env' | tee /dev/stderr) - local actual=$(echo $object | - yq -r '.[11].name' | tee /dev/stderr) - [ "${actual}" = "FOO" ] - - local actual=$(echo $object | - yq -r '.[11].value' | tee /dev/stderr) - [ "${actual}" = "bar" ] - - local actual=$(echo $object | - yq -r '.[12].name' | tee /dev/stderr) - [ "${actual}" = "FOOBAR" ] + local name=$(echo $object | + yq -r 'map(select(.name=="FOO")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "bar" ] - local actual=$(echo $object | - yq -r '.[12].value' | tee /dev/stderr) - [ "${actual}" = "foobar" ] + local name=$(echo $object | + yq -r 'map(select(.name=="FOOBAR")) | .[] .value' | tee /dev/stderr) + [ "${name}" = "foobar" ] } #-------------------------------------------------------------------- @@ -1491,3 +1566,59 @@ load _helpers } + +#-------------------------------------------------------------------- +# enterprise license autoload support +@test "server/StatefulSet: adds volume for license secret when enterprise license secret name and key are provided" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.enterpriseLicense.secretName=foo' \ + --set 'server.enterpriseLicense.secretKey=bar' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.volumes[] | select(.name == "vault-license")' | tee /dev/stderr) + [ "${actual}" = '{"name":"vault-license","secret":{"secretName":"foo","defaultMode":288}}' ] +} + +@test "server/StatefulSet: adds volume mount for license secret when enterprise license secret name and key are provided" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.enterpriseLicense.secretName=foo' \ + --set 'server.enterpriseLicense.secretKey=bar' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "vault-license")' | tee /dev/stderr) + [ "${actual}" = '{"name":"vault-license","mountPath":"/vault/license","readOnly":true}' ] +} + +@test "server/StatefulSet: adds env var for license path when enterprise license secret name and key are provided" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.enterpriseLicense.secretName=foo' \ + --set 'server.enterpriseLicense.secretKey=bar' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "VAULT_LICENSE_PATH")' | tee /dev/stderr) + [ "${actual}" = '{"name":"VAULT_LICENSE_PATH","value":"/vault/license/bar"}' ] +} + +@test "server/StatefulSet: blank secretName does not set env var" { + cd `chart_dir` + + # setting secretName=null + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.enterpriseLicense.secretName=null' \ + --set 'server.enterpriseLicense.secretKey=bar' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "VAULT_LICENSE_PATH")' | tee /dev/stderr) + [ "${actual}" = '' ] + + # omitting secretName + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.enterpriseLicense.secretKey=bar' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "VAULT_LICENSE_PATH")' | tee /dev/stderr) + [ "${actual}" = '' ] +} diff --git a/test/unit/ui-service.bats b/test/unit/ui-service.bats index 499f7326c..9dade3db3 100755 --- a/test/unit/ui-service.bats +++ b/test/unit/ui-service.bats @@ -300,3 +300,26 @@ load _helpers yq -r '.spec.selector["vault-active"]' | tee /dev/stderr) [ "${actual}" = 'true' ] } + +@test "ui/Service: default is no nodePort" { + cd `chart_dir` + + local actual=$(helm template \ + --show-only templates/ui-service.yaml \ + --set 'ui.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.ports[0].nodePort' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "ui/Service: can set nodePort" { + cd `chart_dir` + + local actual=$(helm template \ + --show-only templates/ui-service.yaml \ + --set 'ui.enabled=true' \ + --set 'ui.serviceNodePort=123' \ + . | tee /dev/stderr | + yq -r '.spec.ports[0].nodePort' | tee /dev/stderr) + [ "${actual}" = "123" ] +} diff --git a/values.openshift.yaml b/values.openshift.yaml new file mode 100644 index 000000000..96198fe9b --- /dev/null +++ b/values.openshift.yaml @@ -0,0 +1,18 @@ +# These overrides are appropriate defaults for deploying this chart on OpenShift + +global: + openshift: true + +injector: + image: + repository: "registry.connect.redhat.com/hashicorp/vault-k8s" + tag: "0.10.2-ubi" + + agentImage: + repository: "registry.connect.redhat.com/hashicorp/vault" + tag: "1.7.3-ubi" + +server: + image: + repository: "registry.connect.redhat.com/hashicorp/vault" + tag: "1.7.3-ubi" diff --git a/values.schema.json b/values.schema.json new file mode 100644 index 000000000..db3b80679 --- /dev/null +++ b/values.schema.json @@ -0,0 +1,806 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "csi": { + "type": "object", + "properties": { + "daemonSet": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "updateStrategy": { + "type": "object", + "properties": { + "maxUnavailable": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + } + }, + "debug": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "pod": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "tolerations": { + "type": ["null", "string"] + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "resources": { + "type": "object" + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "volumeMounts": { + "type": [ + "null", + "array" + ] + }, + "volumes": { + "type": [ + "null", + "array" + ] + } + } + }, + "global": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "imagePullSecrets": { + "type": "array" + }, + "openshift": { + "type": "boolean" + }, + "psp": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enable": { + "type": "boolean" + } + } + }, + "tlsDisable": { + "type": "boolean" + } + } + }, + "injector": { + "type": "object", + "properties": { + "affinity": { + "type": "string" + }, + "agentDefaults": { + "type": "object", + "properties": { + "cpuLimit": { + "type": "string" + }, + "cpuRequest": { + "type": "string" + }, + "memLimit": { + "type": "string" + }, + "memRequest": { + "type": "string" + }, + "template": { + "type": "string" + } + } + }, + "agentImage": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "authPath": { + "type": "string" + }, + "certs": { + "type": "object", + "properties": { + "caBundle": { + "type": "string" + }, + "certName": { + "type": "string" + }, + "keyName": { + "type": "string" + }, + "secretName": { + "type": [ + "null", + "string" + ] + } + } + }, + "enabled": { + "type": "boolean" + }, + "externalVaultAddr": { + "type": "string" + }, + "extraEnvironmentVars": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "failurePolicy": { + "type": "string" + }, + "hostNetwork": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "leaderElector": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ttl": { + "type": "string" + } + } + }, + "logFormat": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "namespaceSelector": { + "type": "object" + }, + "nodeSelector": { + "type": ["null", "string"] + }, + "objectSelector": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "revokeOnShutdown": { + "type": "boolean" + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "tolerations": { + "type": [ + "null", + "string" + ] + } + } + }, + "server": { + "type": "object", + "properties": { + "affinity": { + "type": "string" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "auditStorage": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": [ + "null", + "string" + ] + } + } + }, + "authDelegator": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "dataStorage": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": [ + "null", + "string" + ] + } + } + }, + "dev": { + "type": "object", + "properties": { + "devRootToken": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "enabled": { + "type": "boolean" + }, + "enterpriseLicense": { + "type": "object", + "properties": { + "secretKey": { + "type": "string" + }, + "secretName": { + "type": "string" + } + } + }, + "extraArgs": { + "type": "string" + }, + "extraContainers": { + "type": [ + "null", + "array" + ] + }, + "extraEnvironmentVars": { + "type": "object" + }, + "extraInitContainers": { + "type": [ + "null", + "array" + ] + }, + "extraLabels": { + "type": "object" + }, + "extraSecretEnvironmentVars": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "ha": { + "type": "object", + "properties": { + "apiAddr": { + "type": [ + "null", + "string" + ] + }, + "config": { + "type": "string" + }, + "disruptionBudget": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxUnavailable": { + "type": [ + "null", + "integer" + ] + } + } + }, + "enabled": { + "type": "boolean" + }, + "raft": { + "type": "object", + "properties": { + "config": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "setNodeId": { + "type": "boolean" + } + } + }, + "replicas": { + "type": "integer" + } + } + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "extraPaths": { + "type": "array" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array" + } + } + } + }, + "labels": { + "type": "object" + }, + "tls": { + "type": "array" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "logFormat": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "networkPolicy": { + "type": "object", + "properties": { + "egress": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + }, + "nodeSelector": { + "type": [ + "null", + "string" + ] + }, + "postStart": { + "type": "array" + }, + "preStopSleepSeconds": { + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "resources": { + "type": "object" + }, + "route": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "labels": { + "type": "object" + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "port": { + "type": "integer" + }, + "targetPort": { + "type": "integer" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "standalone": { + "type": "object", + "properties": { + "config": { + "type": "string" + }, + "enabled": { + "type": [ + "string", + "boolean" + ] + } + } + }, + "statefulSet": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "tolerations": { + "type": [ + "null", + "string" + ] + }, + "updateStrategyType": { + "type": "string" + }, + "volumeMounts": { + "type": [ + "null", + "array" + ] + }, + "volumes": { + "type": [ + "null", + "array" + ] + } + } + }, + "ui": { + "type": "object", + "properties": { + "activeVaultPodOnly": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "externalPort": { + "type": "integer" + }, + "publishNotReadyAddresses": { + "type": "boolean" + }, + "serviceNodePort": { + "type": [ + "null", + "integer" + ] + }, + "serviceType": { + "type": "string" + }, + "targetPort": { + "type": "integer" + } + } + } + } +} diff --git a/values.yaml b/values.yaml index f00818c5d..a46a82868 100644 --- a/values.yaml +++ b/values.yaml @@ -29,6 +29,9 @@ injector: replicas: 1 + # Configures the port the injector should listen on + port: 8080 + # If multiple replicas are specified, by default a leader-elector side-car # will be created so that only one injector attempts to create TLS certificates. leaderElector: @@ -49,7 +52,7 @@ injector: # image sets the repo and tag of the vault-k8s image to use for the injector. image: repository: "hashicorp/vault-k8s" - tag: "0.8.0" + tag: "0.10.2" pullPolicy: IfNotPresent # agentImage sets the repo and tag of the Vault image to use for the Vault Agent @@ -57,12 +60,26 @@ injector: # required. agentImage: repository: "vault" - tag: "1.6.2" + tag: "1.7.3" + + # The default values for the injected Vault Agent containers. + agentDefaults: + # For more information on configuring resources, see the K8s documentation: + # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + cpuLimit: "500m" + cpuRequest: "250m" + memLimit: "128Mi" + memRequest: "64Mi" + + # Default template type for secrets when no custom template is specified. + # Possible values include: "json" and "map". + template: "map" # Mount Path of the Vault Kubernetes Auth Method. authPath: "auth/kubernetes" - # Configures the log verbosity of the injector. Supported log levels: Trace, Debug, Error, Warn, Info + # Configures the log verbosity of the injector. + # Supported log levels include: trace, debug, info, warn, error logLevel: "info" # Configures the log format of the injector. Supported log formats: "standard", "json". @@ -80,6 +97,15 @@ injector: # matchLabels: # sidecar-injector: enabled namespaceSelector: {} + # objectSelector is the selector for restricting the webhook to only + # specific labels. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-objectselector + # for more details. + # Example: + # objectSelector: + # matchLabels: + # vault-sidecar-injector: enabled + objectSelector: {} # Configures failurePolicy of the webhook. The "unspecified" default behaviour deoends on the # API Version of the WebHook. @@ -159,19 +185,38 @@ injector: # This should be a YAML map of the labels to apply to the injector extraLabels: {} + # Should the injector pods run on the host network (useful when using + # an alternate CNI in EKS) + hostNetwork: false + # Injector service specific config service: # Extra annotations to attach to the injector service annotations: {} server: + # If not set to true, Vault server will not be installed. See vault.mode in _helpers.tpl for implementation details + enabled: true + + # [Enterprise Only] This value refers to a Kubernetes secret that you have + # created that contains your enterprise license. If you are not using an + # enterprise image or if you plan to introduce the license key via another + # route, then leave secretName blank ("") or set it to null. + # Requires Vault Enterprise 1.8 or later. + enterpriseLicense: + # The name of the Kubernetes secret that holds the enterprise license. The + # secret must be in the same namespace that Vault is installed into. + secretName: "" + # The key within the Kubernetes secret that holds the enterprise license. + secretKey: "license" + # Resource requests, limits, etc. for the server cluster placement. This # should map directly to the value of the resources field for a PodSpec. # By default no direct resource request is made. image: repository: "vault" - tag: "1.6.2" + tag: "1.7.9" # Overrides the default Image Pull Policy pullPolicy: IfNotPresent @@ -179,6 +224,14 @@ server: # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies updateStrategyType: "OnDelete" + # Configure the logging verbosity for the Vault server. + # Supported log levels include: trace, debug, info, warn, error + logLevel: "" + + # Configure the logging format for the Vault server. + # Supported log formats include: standard, json + logFormat: "" + resources: {} # resources: # requests: @@ -205,7 +258,12 @@ server: hosts: - host: chart-example.local paths: [] - + ## Extra paths to prepend to the host configuration. This is useful when working with annotation based services. + extraPaths: [] + # - path: /* + # backend: + # serviceName: ssl-redirect + # servicePort: use-annotation tls: [] # - secretName: chart-example-tls # hosts: @@ -310,6 +368,7 @@ server: # secretName: vault # secretKey: AWS_SECRET_ACCESS_KEY + # Deprecated: please use 'volumes' instead. # extraVolumes is a list of extra volumes to mount. These will be exposed # to Vault in the path `/vault/userconfig//`. The value below is # an array of objects, examples are shown below. @@ -599,6 +658,8 @@ server: # YAML or a YAML-formatted multi-line templated string map of the # annotations to apply to the serviceAccount. annotations: {} + # A boolean flag to setup logrotate as a side car continer + logrotate: null # Settings for the statefulSet used to run Vault. statefulSet: @@ -623,6 +684,7 @@ ui: serviceType: "ClusterIP" serviceNodePort: null externalPort: 8200 + targetPort: 8200 # loadBalancerSourceRanges: # - 10.0.0.0/16 @@ -634,3 +696,103 @@ ui: # This can either be YAML or a YAML-formatted multi-line templated string map # of the annotations to apply to the ui service annotations: {} + +# secrets-store-csi-driver-provider-vault +csi: + # True if you want to install a secrets-store-csi-driver-provider-vault daemonset. + # + # Requires installing the secrets-store-csi-driver separately, see: + # https://github.com/kubernetes-sigs/secrets-store-csi-driver#install-the-secrets-store-csi-driver + # + # With the driver and provider installed, you can mount Vault secrets into volumes + # similar to the Vault Agent injector, and you can also sync those secrets into + # Kubernetes secrets. + enabled: false + + image: + repository: "hashicorp/vault-csi-provider" + tag: "0.3.0" + pullPolicy: IfNotPresent + + # volumes is a list of volumes made available to all containers. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumes: null + # - name: tls + # secret: + # secretName: vault-tls + + # volumeMounts is a list of volumeMounts for the main server container. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumeMounts: null + # - name: tls + # mountPath: "/vault/tls" + # readOnly: true + + resources: {} + # resources: + # requests: + # cpu: 50m + # memory: 128Mi + # limits: + # cpu: 50m + # memory: 128Mi + + # Settings for the daemonSet used to run the provider. + daemonSet: + updateStrategy: + type: RollingUpdate + maxUnavailable: "" + # Extra annotations for the daemonSet. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the daemonSet. + annotations: {} + + pod: + # Extra annotations for the provider pods. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the pod. + annotations: {} + + # Toleration Settings for provider pods + # This should be a multi-line string matching the Toleration array + # in a PodSpec. + tolerations: null + + serviceAccount: + # Extra annotations for the serviceAccount definition. This can either be + # YAML or a YAML-formatted multi-line templated string map of the + # annotations to apply to the serviceAccount. + annotations: {} + + # Used to configure readinessProbe for the pods. + readinessProbe: + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + # Used to configure livenessProbe for the pods. + livenessProbe: + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + + # Enables debug logging. + debug: false + + # Pass arbitrary additional arguments to vault-csi-provider. + extraArgs: []