From d50219d8b966af0aafdf96172eddc38fb9a3a624 Mon Sep 17 00:00:00 2001 From: Rich Braun Date: Wed, 31 Jul 2024 08:24:36 -0700 Subject: [PATCH] SYS-624 helm chart for vaultwarden password manager --- README.md | 1 + k8s/helm/vaultwarden/.helmignore | 2 + k8s/helm/vaultwarden/Chart.yaml | 13 +++ k8s/helm/vaultwarden/templates/NOTES.txt | 28 ++++++ k8s/helm/vaultwarden/templates/app.yaml | 11 +++ .../templates/tests/test-connection.yaml | 17 ++++ k8s/helm/vaultwarden/values.yaml | 86 +++++++++++++++++++ 7 files changed, 158 insertions(+) create mode 100644 k8s/helm/vaultwarden/.helmignore create mode 100644 k8s/helm/vaultwarden/Chart.yaml create mode 100644 k8s/helm/vaultwarden/templates/NOTES.txt create mode 100644 k8s/helm/vaultwarden/templates/app.yaml create mode 100644 k8s/helm/vaultwarden/templates/tests/test-connection.yaml create mode 100644 k8s/helm/vaultwarden/values.yaml diff --git a/README.md b/README.md index 336761e7..04b67f86 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ The cluster-deployment tools here include helm charts and ansible playbooks to s * Non-default namespace with its own service account (full permissions within namespace, limited read-only in kube-system namespaces) * Keycloak for OpenID / OAuth2 user authentication / authorization +* Vaultwarden, a self-hosted Bitwarden-compatible password manager * Helm3 * Mozilla [sops](https://github.com/mozilla/sops/blob/master/README.rst) with encryption (to keep credentials in local git repo) * Encryption for internal etcd diff --git a/k8s/helm/vaultwarden/.helmignore b/k8s/helm/vaultwarden/.helmignore new file mode 100644 index 00000000..839de881 --- /dev/null +++ b/k8s/helm/vaultwarden/.helmignore @@ -0,0 +1,2 @@ +*~ +.git diff --git a/k8s/helm/vaultwarden/Chart.yaml b/k8s/helm/vaultwarden/Chart.yaml new file mode 100644 index 00000000..b2b30b34 --- /dev/null +++ b/k8s/helm/vaultwarden/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +name: vaultwarden +description: Self-hosted bitwarden vault service +home: https://github.com/instantlinux/docker-tools +sources: +- https://github.com/instantlinux/docker-tools +type: application +version: 0.1.0 +appVersion: "1.31.0-alpine" +dependencies: +- name: chartlib + version: 0.1.8 + repository: https://instantlinux.github.io/docker-tools diff --git a/k8s/helm/vaultwarden/templates/NOTES.txt b/k8s/helm/vaultwarden/templates/NOTES.txt new file mode 100644 index 00000000..62ea3f4b --- /dev/null +++ b/k8s/helm/vaultwarden/templates/NOTES.txt @@ -0,0 +1,28 @@ +{{- if hasKey .Values "service" }} +{{- if or .Values.service.enabled (not (hasKey .Values.service "enabled")) }} +1. Get the application URL by running these commands: +{{- if hasKey .Values "ingress" }} +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "local.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "local.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "local.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "local.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/k8s/helm/vaultwarden/templates/app.yaml b/k8s/helm/vaultwarden/templates/app.yaml new file mode 100644 index 00000000..5b83e9c4 --- /dev/null +++ b/k8s/helm/vaultwarden/templates/app.yaml @@ -0,0 +1,11 @@ +{{- include "chartlib.deployment" . }} +--- +{{- include "chartlib.hpa" . }} +--- +{{- include "chartlib.ingress" . }} +--- +{{- include "chartlib.ingresstotp" . }} +--- +{{- include "chartlib.service" . }} +--- +{{- include "chartlib.serviceaccount" . }} diff --git a/k8s/helm/vaultwarden/templates/tests/test-connection.yaml b/k8s/helm/vaultwarden/templates/tests/test-connection.yaml new file mode 100644 index 00000000..ae159a4f --- /dev/null +++ b/k8s/helm/vaultwarden/templates/tests/test-connection.yaml @@ -0,0 +1,17 @@ +{{- if hasKey .Values "service" }} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "local.fullname" . }}-test-connection" + labels: + {{- include "local.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "local.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never +{{- end }} diff --git a/k8s/helm/vaultwarden/values.yaml b/k8s/helm/vaultwarden/values.yaml new file mode 100644 index 00000000..98327537 --- /dev/null +++ b/k8s/helm/vaultwarden/values.yaml @@ -0,0 +1,86 @@ +# Default values for vaultwarden. +tlsHostname: vaultwarden.example.com +domain: example.com +deployment: + containerPorts: + - containerPort: 80 + - containerPort: 3012 + env: + emergency_access_allowed: "true" + invitation_expiration_hours: 36 + invitations_allowed: "false" + signups_allowed: "true" + signups_verify: "true" + smtp_from: admin@example.com + smtp_host: smtp + smtp_port: 587 + smtp_security: starttls + tz: UTC + xenv: + - name: ADMIN_TOKEN + valueFrom: + secretKeyRef: + key: admin-token + name: vaultwarden + - name: DATABASE_URL + # in form mysql://username:secret@db00:3306/vaultwarden + valueFrom: + secretKeyRef: + key: database-url + name: vaultwarden + nodeSelector: + service.vaultwarden: allow + resources: + limits: + cpu: 2 + memory: 2048Mi + requests: + cpu: 200m + memory: 1280Mi + strategy: + type: Recreate + terminationGracePeriodSeconds: 120 +livenessProbe: + httpGet: + path: /alive + port: 80 + initialDelaySeconds: 5 +readinessProbe: + httpGet: + path: /alive + port: 80 + initialDelaySeconds: 5 + +volumeMounts: +- mountPath: /data + name: vaultwarden +volumes: +- name: vaultwarden + hostPath: { path: /var/lib/docker/k8s-volumes/share/vaultwarden } + +image: + repository: vaultwarden/server + pullPolicy: IfNotPresent + # tag: default + +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: false +service: + type: ClusterIP + ports: + - { port: 80, targetPort: 80, name: http } + - { port: 3012, targetPort: 3012, name: websocket } + +ingress: + enabled: true + className: "" + annotations: + kubernetes.io/ingress.class: nginx + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/enable-access-log: "false" + +autoscaling: + enabled: false