mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-05-07 12:00:48 +02:00
Merge 834a194816 into f21a3adae2
This commit is contained in:
commit
90f83ecf50
14 changed files with 1508 additions and 0 deletions
12
helm/vaultwarden/.helmignore
Normal file
12
helm/vaultwarden/.helmignore
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Patterns to ignore when building packages.
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
.git
|
||||
.gitignore
|
||||
.project
|
||||
.idea
|
||||
*.tmproj
|
||||
.vscode
|
||||
18
helm/vaultwarden/Chart.yaml
Normal file
18
helm/vaultwarden/Chart.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
apiVersion: v2
|
||||
name: vaultwarden
|
||||
description: Vaultwarden - unofficial Bitwarden-compatible server written in Rust
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.35.3"
|
||||
home: https://github.com/dani-garcia/vaultwarden
|
||||
icon: https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/resources/vaultwarden-icon.svg
|
||||
sources:
|
||||
- https://github.com/dani-garcia/vaultwarden
|
||||
keywords:
|
||||
- vaultwarden
|
||||
- bitwarden
|
||||
- password-manager
|
||||
- secrets
|
||||
maintainers:
|
||||
- name: dani-garcia
|
||||
url: https://github.com/dani-garcia
|
||||
437
helm/vaultwarden/README.md
Normal file
437
helm/vaultwarden/README.md
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
# Vaultwarden Helm Chart
|
||||
|
||||
Official Helm chart for [Vaultwarden](https://github.com/dani-garcia/vaultwarden) — an unofficial Bitwarden-compatible server written in Rust.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
helm install vaultwarden ./helm/vaultwarden \
|
||||
--set vaultwarden.domain=https://vault.example.com
|
||||
```
|
||||
|
||||
This deploys vaultwarden with **SQLite** (the default). Data is persisted in a 5Gi PVC.
|
||||
|
||||
> **For production deployments, we recommend PostgreSQL.** See [Production Setup with PostgreSQL](#production-setup-with-postgresql) below.
|
||||
|
||||
## Production Setup with PostgreSQL
|
||||
|
||||
```yaml
|
||||
# values-production.yaml
|
||||
vaultwarden:
|
||||
domain: https://vault.example.com
|
||||
signupsAllowed: false
|
||||
admin:
|
||||
enabled: true
|
||||
existingSecret: vaultwarden-admin
|
||||
existingSecretKey: admin-token
|
||||
|
||||
database:
|
||||
type: postgresql
|
||||
existingSecret: vaultwarden-db-credentials
|
||||
existingSecretKey: database-url
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
cert-manager.io/private-key-algorithm: ECDSA
|
||||
cert-manager.io/private-key-size: "384"
|
||||
cert-manager.io/private-key-rotation-policy: Always
|
||||
hosts:
|
||||
- host: vault.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: vault-tls
|
||||
hosts:
|
||||
- vault.example.com
|
||||
|
||||
persistence:
|
||||
storageClassName: longhorn # or your preferred storage class
|
||||
size: 10Gi
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 1Gi
|
||||
```
|
||||
|
||||
```bash
|
||||
helm install vaultwarden ./helm/vaultwarden -f values-production.yaml
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Image
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `image.repository` | Container image repository | `vaultwarden/server` |
|
||||
| `image.tag` | Image tag (defaults to `appVersion`) | `""` |
|
||||
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
||||
| `replicaCount` | Number of replicas (keep at 1 for SQLite) | `1` |
|
||||
|
||||
### Vaultwarden
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.domain` | **(required)** Public URL of your instance | `""` |
|
||||
| `vaultwarden.signupsAllowed` | Allow new user registrations | `false` |
|
||||
| `vaultwarden.rocketPort` | HTTP server port | `8080` |
|
||||
| `vaultwarden.websocket.enabled` | Enable websocket notifications | `true` |
|
||||
| `vaultwarden.logging.level` | Log level (trace/debug/info/warn/error/off) | `info` |
|
||||
| `vaultwarden.icons.service` | Icon service (internal/bitwarden/duckduckgo/google) | `internal` |
|
||||
|
||||
### Admin Panel
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.admin.enabled` | Enable the admin panel at `/admin` | `false` |
|
||||
| `vaultwarden.admin.token` | Admin token (argon2 hash recommended) | `""` |
|
||||
| `vaultwarden.admin.existingSecret` | Existing secret name for admin token | `""` |
|
||||
| `vaultwarden.admin.existingSecretKey` | Key in existing secret | `admin-token` |
|
||||
|
||||
### Database
|
||||
|
||||
The chart supports two ways to configure the database connection for PostgreSQL/MySQL:
|
||||
|
||||
**Option 1: Full connection URL** — provide a complete `DATABASE_URL` via a secret:
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `database.type` | Database backend: `sqlite`, `postgresql`, or `mysql` | `sqlite` |
|
||||
| `database.url` | Full connection URL (inline, not recommended) | `""` |
|
||||
| `database.existingSecret` | Secret containing the full database URL | `""` |
|
||||
| `database.existingSecretKey` | Key in existing secret | `database-url` |
|
||||
|
||||
```yaml
|
||||
database:
|
||||
type: postgresql
|
||||
existingSecret: my-db-url-secret
|
||||
existingSecretKey: database-url
|
||||
```
|
||||
|
||||
**Option 2: Compose from parts** (recommended for Postgres operators) — the chart reads username and password from a credentials secret and assembles the `DATABASE_URL` automatically. This is ideal for Zalando Postgres Operator, CloudNativePG, or any operator that creates per-user credential secrets:
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `database.host` | Database hostname (triggers compose mode) | `""` |
|
||||
| `database.port` | Database port | `5432` |
|
||||
| `database.dbName` | Database name | `vaultwarden` |
|
||||
| `database.credentialsSecret` | Secret with `username` and `password` keys | `""` |
|
||||
| `database.credentialsSecretUsernameKey` | Key for username | `username` |
|
||||
| `database.credentialsSecretPasswordKey` | Key for password | `password` |
|
||||
|
||||
```yaml
|
||||
# Example: Zalando Postgres Operator
|
||||
database:
|
||||
type: postgresql
|
||||
host: vaultwarden-db.postgres-cluster
|
||||
port: 5432
|
||||
dbName: vaultwarden
|
||||
credentialsSecret: vaultwarden.user.vaultwarden-db.credentials.postgresql.acid.zalan.do
|
||||
```
|
||||
|
||||
This renders as:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: _DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: vaultwarden.user.vaultwarden-db.credentials.postgresql.acid.zalan.do
|
||||
key: username
|
||||
- name: _DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: vaultwarden.user.vaultwarden-db.credentials.postgresql.acid.zalan.do
|
||||
key: password
|
||||
- name: DATABASE_URL
|
||||
value: postgresql://$(_DB_USER):$(_DB_PASSWORD)@vaultwarden-db.postgres-cluster:5432/vaultwarden
|
||||
```
|
||||
|
||||
**Common settings:**
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `database.maxConnections` | Max database connections | `10` |
|
||||
| `database.wal` | Enable WAL mode (SQLite only) | `true` |
|
||||
|
||||
### SMTP (Email)
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.smtp.host` | SMTP server hostname | `""` |
|
||||
| `vaultwarden.smtp.from` | Sender email address | `""` |
|
||||
| `vaultwarden.smtp.port` | SMTP port | `587` |
|
||||
| `vaultwarden.smtp.security` | Security mode (starttls/force_tls/off) | `starttls` |
|
||||
| `vaultwarden.smtp.username` | SMTP username | `""` |
|
||||
| `vaultwarden.smtp.password` | SMTP password | `""` |
|
||||
| `vaultwarden.smtp.existingSecret` | Existing secret for SMTP credentials | `""` |
|
||||
| `vaultwarden.smtp.existingSecretUsernameKey` | Key in existing secret for username | `smtp-username` |
|
||||
| `vaultwarden.smtp.existingSecretPasswordKey` | Key in existing secret for password | `smtp-password` |
|
||||
|
||||
### SSO (OpenID Connect)
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.sso.enabled` | Enable SSO authentication | `false` |
|
||||
| `vaultwarden.sso.only` | Require SSO (disable password login) | `false` |
|
||||
| `vaultwarden.sso.authority` | OIDC authority URL | `""` |
|
||||
| `vaultwarden.sso.clientId` | OIDC client ID | `""` |
|
||||
| `vaultwarden.sso.clientSecret` | OIDC client secret | `""` |
|
||||
| `vaultwarden.sso.existingSecret` | Existing secret for SSO credentials | `""` |
|
||||
| `vaultwarden.sso.existingSecretClientIdKey` | Key in existing secret for client ID | `sso-client-id` |
|
||||
| `vaultwarden.sso.existingSecretClientSecretKey` | Key in existing secret for client secret | `sso-client-secret` |
|
||||
|
||||
### Push Notifications
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.push.enabled` | Enable push notifications | `false` |
|
||||
| `vaultwarden.push.installationId` | Installation ID from bitwarden.com/host | `""` |
|
||||
| `vaultwarden.push.installationKey` | Installation key from bitwarden.com/host | `""` |
|
||||
| `vaultwarden.push.existingSecret` | Existing secret for push credentials | `""` |
|
||||
| `vaultwarden.push.relayUri` | Push relay URI | `""` |
|
||||
| `vaultwarden.push.identityUri` | Push identity URI | `""` |
|
||||
|
||||
### Yubico OTP
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `vaultwarden.yubico.enabled` | Enable Yubico OTP | `false` |
|
||||
| `vaultwarden.yubico.clientId` | Yubico client ID | `""` |
|
||||
| `vaultwarden.yubico.secretKey` | Yubico secret key | `""` |
|
||||
| `vaultwarden.yubico.existingSecret` | Existing secret for Yubico credentials | `""` |
|
||||
|
||||
### Service
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `service.type` | Service type (`ClusterIP`, `NodePort`, `LoadBalancer`) | `ClusterIP` |
|
||||
| `service.port` | Service port | `8080` |
|
||||
| `service.nodePort` | Node port (when type is `NodePort`) | `""` |
|
||||
| `service.loadBalancerIP` | Load balancer IP (when type is `LoadBalancer`) | `""` |
|
||||
| `service.externalTrafficPolicy` | External traffic policy (`Local` or `Cluster`) | `""` |
|
||||
| `service.annotations` | Service annotations (e.g. for external-dns) | `{}` |
|
||||
| `service.labels` | Additional service labels | `{}` |
|
||||
|
||||
### Ingress
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `ingress.enabled` | Enable ingress | `false` |
|
||||
| `ingress.className` | Ingress class name (e.g. `nginx`, `traefik`, `haproxy`) | `""` |
|
||||
| `ingress.annotations` | Ingress annotations (e.g. cert-manager, rate-limiting) | `{}` |
|
||||
| `ingress.labels` | Additional ingress labels | `{}` |
|
||||
| `ingress.hosts` | Ingress host rules | see `values.yaml` |
|
||||
| `ingress.tls` | Ingress TLS configuration | `[]` |
|
||||
|
||||
Example with full ingress configuration:
|
||||
|
||||
```yaml
|
||||
ingress:
|
||||
enabled: true
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
cert-manager.io/private-key-algorithm: ECDSA
|
||||
cert-manager.io/private-key-size: "384"
|
||||
cert-manager.io/private-key-rotation-policy: Always
|
||||
hosts:
|
||||
- host: vault.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: vault-tls
|
||||
hosts:
|
||||
- vault.example.com
|
||||
```
|
||||
|
||||
### Persistence
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `persistence.enabled` | Enable persistent storage | `true` |
|
||||
| `persistence.storageClassName` | Storage class name (see below) | `nil` |
|
||||
| `persistence.accessModes` | PVC access modes | `[ReadWriteOnce]` |
|
||||
| `persistence.size` | Storage size | `5Gi` |
|
||||
| `persistence.existingClaim` | Use an existing PVC | `""` |
|
||||
| `persistence.annotations` | Additional PVC annotations | `{}` |
|
||||
| `persistence.labels` | Additional PVC labels | `{}` |
|
||||
|
||||
**Storage class behavior:**
|
||||
|
||||
| Value | Behavior |
|
||||
|-------|----------|
|
||||
| `nil` (unset) | Uses the cluster default storage class |
|
||||
| `"-"` | Disables dynamic provisioning (`storageClassName: ""`) |
|
||||
| `"longhorn"` | Uses the specified storage class |
|
||||
|
||||
**High availability (multiple replicas):** Running `replicaCount > 1` requires PostgreSQL (SQLite does not support concurrent access) and a storage class that supports `ReadWriteMany` (RWX) access mode, such as NFS, CephFS, or a cloud-native RWX provider (e.g. AWS EFS, Azure Files, GCP Filestore). Update your persistence accordingly:
|
||||
|
||||
```yaml
|
||||
replicaCount: 2
|
||||
|
||||
database:
|
||||
type: postgresql
|
||||
host: my-cluster.postgres
|
||||
credentialsSecret: my-pg-credentials
|
||||
|
||||
persistence:
|
||||
storageClassName: efs-sc # or any RWX-capable storage class
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
```
|
||||
|
||||
### Security Context
|
||||
|
||||
The chart runs vaultwarden as a non-root user (UID 1000) by default with a read-only root filesystem. The `ROCKET_PORT` is set to `8080` to avoid requiring privileged ports.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `podSecurityContext.runAsUser` | Pod user ID | `1000` |
|
||||
| `podSecurityContext.runAsGroup` | Pod group ID | `1000` |
|
||||
| `podSecurityContext.runAsNonRoot` | Enforce non-root | `true` |
|
||||
| `podSecurityContext.fsGroup` | Pod filesystem group | `1000` |
|
||||
| `podSecurityContext.seccompProfile.type` | Seccomp profile | `RuntimeDefault` |
|
||||
| `securityContext.readOnlyRootFilesystem` | Read-only root FS | `true` |
|
||||
| `securityContext.allowPrivilegeEscalation` | Prevent privilege escalation | `false` |
|
||||
| `securityContext.capabilities.drop` | Dropped capabilities | `["ALL"]` |
|
||||
|
||||
### Scheduling
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `nodeSelector` | Node selector constraints | `{}` |
|
||||
| `tolerations` | Pod tolerations | `[]` |
|
||||
| `affinity` | Affinity rules | `{}` |
|
||||
| `topologySpreadConstraints` | Topology spread constraints | `[]` |
|
||||
| `priorityClassName` | Priority class for pod scheduling | `""` |
|
||||
|
||||
### Other
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `serviceAccount.create` | Create a service account | `true` |
|
||||
| `serviceAccount.annotations` | Service account annotations | `{}` |
|
||||
| `serviceAccount.automountServiceAccountToken` | Automount SA token | `false` |
|
||||
| `resources` | CPU/memory resources | see `values.yaml` |
|
||||
| `revisionHistoryLimit` | Deployment revision history limit | `3` |
|
||||
| `terminationGracePeriodSeconds` | Termination grace period | `30` |
|
||||
| `startupProbe` | Startup probe config (for slow starts) | `{}` |
|
||||
| `initContainers` | Init containers | `[]` |
|
||||
| `extraVolumes` | Additional volumes | `[]` |
|
||||
| `extraVolumeMounts` | Additional volume mounts | `[]` |
|
||||
| `podAnnotations` | Pod annotations | `{}` |
|
||||
| `podLabels` | Additional pod labels | `{}` |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The chart provides three layers for setting environment variables, from simplest to most flexible:
|
||||
|
||||
**`env`** — plain key-value map for any vaultwarden env var:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
SIGNUPS_ALLOWED: "true"
|
||||
INVITATION_ORG_NAME: "My Org"
|
||||
SENDS_ALLOWED: "true"
|
||||
```
|
||||
|
||||
**`secretEnv`** — shorthand for sourcing env vars from Kubernetes secrets:
|
||||
|
||||
```yaml
|
||||
secretEnv:
|
||||
ADMIN_TOKEN:
|
||||
secretName: my-admin-secret
|
||||
secretKey: admin-token
|
||||
DATABASE_URL:
|
||||
secretName: my-db-secret
|
||||
secretKey: database-url
|
||||
```
|
||||
|
||||
**`extraEnv`** — raw Kubernetes env spec for complex cases (fieldRef, resourceFieldRef, etc.):
|
||||
|
||||
```yaml
|
||||
extraEnv:
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
```
|
||||
|
||||
These layers are additive and render in order: structured values (from `vaultwarden.*`), then `env`, then `secretEnv`, then `extraEnv`. Later values override earlier ones for the same env var name.
|
||||
|
||||
## Using Existing Secrets
|
||||
|
||||
For production deployments, use `existingSecret` references instead of putting credentials in `values.yaml`. All sensitive values support `existingSecret`:
|
||||
|
||||
```bash
|
||||
# Create secrets before installing the chart
|
||||
kubectl create secret generic vaultwarden-admin \
|
||||
--from-literal=admin-token='$argon2id$...'
|
||||
|
||||
kubectl create secret generic vaultwarden-db \
|
||||
--from-literal=database-url='postgresql://user:pass@host:5432/vaultwarden'
|
||||
|
||||
kubectl create secret generic vaultwarden-smtp \
|
||||
--from-literal=smtp-username='user@example.com' \
|
||||
--from-literal=smtp-password='password'
|
||||
|
||||
kubectl create secret generic vaultwarden-sso \
|
||||
--from-literal=sso-client-id='vaultwarden' \
|
||||
--from-literal=sso-client-secret='secret'
|
||||
|
||||
kubectl create secret generic vaultwarden-push \
|
||||
--from-literal=push-installation-id='...' \
|
||||
--from-literal=push-installation-key='...'
|
||||
```
|
||||
|
||||
Then reference them in your values:
|
||||
|
||||
```yaml
|
||||
vaultwarden:
|
||||
admin:
|
||||
enabled: true
|
||||
existingSecret: vaultwarden-admin
|
||||
smtp:
|
||||
host: smtp.example.com
|
||||
from: vault@example.com
|
||||
existingSecret: vaultwarden-smtp
|
||||
sso:
|
||||
enabled: true
|
||||
authority: https://auth.example.com/realms/main
|
||||
existingSecret: vaultwarden-sso
|
||||
push:
|
||||
enabled: true
|
||||
existingSecret: vaultwarden-push
|
||||
database:
|
||||
type: postgresql
|
||||
existingSecret: vaultwarden-db
|
||||
```
|
||||
|
||||
## Mounting Custom CA Certificates
|
||||
|
||||
To trust custom CA certificates (e.g. for LDAP or SSO with self-signed certs):
|
||||
|
||||
```yaml
|
||||
extraVolumes:
|
||||
- name: custom-certs
|
||||
secret:
|
||||
secretName: ca-bundle
|
||||
|
||||
extraVolumeMounts:
|
||||
- name: custom-certs
|
||||
mountPath: /etc/ssl/certs/custom
|
||||
readOnly: true
|
||||
|
||||
extraEnv:
|
||||
- name: SSL_CERT_DIR
|
||||
value: /etc/ssl/certs:/etc/ssl/certs/custom
|
||||
```
|
||||
52
helm/vaultwarden/templates/NOTES.txt
Normal file
52
helm/vaultwarden/templates/NOTES.txt
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
Vaultwarden has been deployed successfully!
|
||||
|
||||
{{- if .Values.ingress.enabled }}
|
||||
|
||||
Your vaultwarden instance is available at:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
https://{{ .host }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
|
||||
To access vaultwarden, run:
|
||||
kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "vaultwarden.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
|
||||
|
||||
Then open http://localhost:{{ .Values.service.port }} in your browser.
|
||||
{{- end }}
|
||||
|
||||
{{- if not .Values.vaultwarden.domain }}
|
||||
|
||||
WARNING: vaultwarden.domain is not set. You must set this to the URL
|
||||
where vaultwarden will be accessible (e.g. https://vault.example.com).
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.vaultwarden.admin.enabled }}
|
||||
|
||||
Admin panel is enabled at /admin
|
||||
{{- if not .Values.vaultwarden.admin.existingSecret }}
|
||||
Make sure to use an existingSecret for the admin token in production.
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if eq .Values.database.type "sqlite" }}
|
||||
|
||||
NOTE: You are using SQLite (default). For production deployments with
|
||||
multiple users, consider switching to PostgreSQL:
|
||||
database.type=postgresql
|
||||
database.host=<your-postgres-host>
|
||||
database.credentialsSecret=<your-credentials-secret>
|
||||
{{- end }}
|
||||
|
||||
{{- if and (gt (int .Values.replicaCount) 1) (eq .Values.database.type "sqlite") }}
|
||||
|
||||
WARNING: replicaCount > 1 is not supported with SQLite. Use PostgreSQL
|
||||
for multi-replica deployments.
|
||||
{{- end }}
|
||||
|
||||
{{- if and (gt (int .Values.replicaCount) 1) .Values.persistence.enabled }}
|
||||
|
||||
NOTE: Running multiple replicas with persistence requires a storage class
|
||||
that supports ReadWriteMany (RWX) access mode, such as NFS, CephFS, or
|
||||
a cloud-native RWX provider. Ensure persistence.accessModes includes
|
||||
ReadWriteMany.
|
||||
{{- end }}
|
||||
133
helm/vaultwarden/templates/_helpers.tpl
Normal file
133
helm/vaultwarden/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "vaultwarden.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "vaultwarden.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "vaultwarden.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels.
|
||||
*/}}
|
||||
{{- define "vaultwarden.labels" -}}
|
||||
helm.sh/chart: {{ include "vaultwarden.chart" . }}
|
||||
{{ include "vaultwarden.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels.
|
||||
*/}}
|
||||
{{- define "vaultwarden.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "vaultwarden.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use.
|
||||
*/}}
|
||||
{{- define "vaultwarden.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "vaultwarden.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the appropriate image tag.
|
||||
*/}}
|
||||
{{- define "vaultwarden.imageTag" -}}
|
||||
{{- default .Chart.AppVersion .Values.image.tag }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for admin token.
|
||||
*/}}
|
||||
{{- define "vaultwarden.adminSecretName" -}}
|
||||
{{- if .Values.vaultwarden.admin.existingSecret }}
|
||||
{{- .Values.vaultwarden.admin.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-admin" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for SMTP credentials.
|
||||
*/}}
|
||||
{{- define "vaultwarden.smtpSecretName" -}}
|
||||
{{- if .Values.vaultwarden.smtp.existingSecret }}
|
||||
{{- .Values.vaultwarden.smtp.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-smtp" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for SSO credentials.
|
||||
*/}}
|
||||
{{- define "vaultwarden.ssoSecretName" -}}
|
||||
{{- if .Values.vaultwarden.sso.existingSecret }}
|
||||
{{- .Values.vaultwarden.sso.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-sso" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for push notification credentials.
|
||||
*/}}
|
||||
{{- define "vaultwarden.pushSecretName" -}}
|
||||
{{- if .Values.vaultwarden.push.existingSecret }}
|
||||
{{- .Values.vaultwarden.push.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-push" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for Yubico credentials.
|
||||
*/}}
|
||||
{{- define "vaultwarden.yubicoSecretName" -}}
|
||||
{{- if .Values.vaultwarden.yubico.existingSecret }}
|
||||
{{- .Values.vaultwarden.yubico.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-yubico" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Return the secret name for database URL.
|
||||
*/}}
|
||||
{{- define "vaultwarden.databaseSecretName" -}}
|
||||
{{- if .Values.database.existingSecret }}
|
||||
{{- .Values.database.existingSecret }}
|
||||
{{- else }}
|
||||
{{- printf "%s-database" (include "vaultwarden.fullname" .) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
40
helm/vaultwarden/templates/configmap.yaml
Normal file
40
helm/vaultwarden/templates/configmap.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
data:
|
||||
ROCKET_PORT: {{ .Values.vaultwarden.rocketPort | quote }}
|
||||
SIGNUPS_ALLOWED: {{ .Values.vaultwarden.signupsAllowed | quote }}
|
||||
ENABLE_WEBSOCKET: {{ .Values.vaultwarden.websocket.enabled | quote }}
|
||||
LOG_LEVEL: {{ .Values.vaultwarden.logging.level | quote }}
|
||||
ICON_SERVICE: {{ .Values.vaultwarden.icons.service | quote }}
|
||||
{{- if .Values.vaultwarden.domain }}
|
||||
DOMAIN: {{ .Values.vaultwarden.domain | quote }}
|
||||
{{- end }}
|
||||
{{- if eq .Values.database.type "sqlite" }}
|
||||
ENABLE_DB_WAL: {{ .Values.database.wal | quote }}
|
||||
{{- end }}
|
||||
DATABASE_MAX_CONNS: {{ .Values.database.maxConnections | quote }}
|
||||
{{- if .Values.vaultwarden.smtp.host }}
|
||||
SMTP_HOST: {{ .Values.vaultwarden.smtp.host | quote }}
|
||||
SMTP_FROM: {{ .Values.vaultwarden.smtp.from | quote }}
|
||||
SMTP_PORT: {{ .Values.vaultwarden.smtp.port | quote }}
|
||||
SMTP_SECURITY: {{ .Values.vaultwarden.smtp.security | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.vaultwarden.sso.enabled }}
|
||||
SSO_ENABLED: "true"
|
||||
SSO_ONLY: {{ .Values.vaultwarden.sso.only | quote }}
|
||||
SSO_AUTHORITY: {{ .Values.vaultwarden.sso.authority | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.vaultwarden.push.enabled }}
|
||||
PUSH_ENABLED: "true"
|
||||
{{- if .Values.vaultwarden.push.relayUri }}
|
||||
PUSH_RELAY_URI: {{ .Values.vaultwarden.push.relayUri | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.vaultwarden.push.identityUri }}
|
||||
PUSH_IDENTITY_URI: {{ .Values.vaultwarden.push.identityUri | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
228
helm/vaultwarden/templates/deployment.yaml
Normal file
228
helm/vaultwarden/templates/deployment.yaml
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
{{- /* Validation */}}
|
||||
{{- if and .Values.vaultwarden.admin.enabled (not .Values.vaultwarden.admin.token) (not .Values.vaultwarden.admin.existingSecret) }}
|
||||
{{- fail "vaultwarden.admin.enabled is true but neither admin.token nor admin.existingSecret is set" }}
|
||||
{{- end }}
|
||||
{{- if and (ne .Values.database.type "sqlite") .Values.database.host (not .Values.database.credentialsSecret) }}
|
||||
{{- fail "database.host is set but database.credentialsSecret is not — provide the secret containing database credentials" }}
|
||||
{{- end }}
|
||||
{{- if and (ne .Values.database.type "sqlite") (not .Values.database.host) (not .Values.database.url) (not .Values.database.existingSecret) }}
|
||||
{{- fail "database.type is not sqlite but no database connection is configured — set database.host (with credentialsSecret), database.url, or database.existingSecret" }}
|
||||
{{- end }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- if .Values.revisionHistoryLimit }}
|
||||
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
||||
{{- end }}
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "vaultwarden.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "vaultwarden.serviceAccountName" . }}
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.priorityClassName }}
|
||||
priorityClassName: {{ .Values.priorityClassName }}
|
||||
{{- end }}
|
||||
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
|
||||
{{- with .Values.initContainers }}
|
||||
initContainers:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: vaultwarden
|
||||
image: "{{ .Values.image.repository }}:{{ include "vaultwarden.imageTag" . }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.vaultwarden.rocketPort }}
|
||||
name: http
|
||||
protocol: TCP
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
env:
|
||||
{{- /* Admin token */}}
|
||||
{{- if .Values.vaultwarden.admin.enabled }}
|
||||
- name: ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.adminSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.admin.existingSecretKey | default "admin-token" }}
|
||||
{{- end }}
|
||||
{{- /* SMTP credentials */}}
|
||||
{{- if and .Values.vaultwarden.smtp.host (or .Values.vaultwarden.smtp.username .Values.vaultwarden.smtp.existingSecret) }}
|
||||
- name: SMTP_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.smtpSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.smtp.existingSecretUsernameKey | default "smtp-username" }}
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.smtpSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.smtp.existingSecretPasswordKey | default "smtp-password" }}
|
||||
{{- end }}
|
||||
{{- /* SSO credentials */}}
|
||||
{{- if .Values.vaultwarden.sso.enabled }}
|
||||
- name: SSO_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.ssoSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.sso.existingSecretClientIdKey | default "sso-client-id" }}
|
||||
- name: SSO_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.ssoSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.sso.existingSecretClientSecretKey | default "sso-client-secret" }}
|
||||
{{- end }}
|
||||
{{- /* Database URL — Option 2: compose from parts */}}
|
||||
{{- if and (ne .Values.database.type "sqlite") .Values.database.host }}
|
||||
- name: _DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ required "database.credentialsSecret is required when database.host is set" .Values.database.credentialsSecret }}
|
||||
key: {{ .Values.database.credentialsSecretUsernameKey | default "username" }}
|
||||
- name: _DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.database.credentialsSecret }}
|
||||
key: {{ .Values.database.credentialsSecretPasswordKey | default "password" }}
|
||||
- name: DATABASE_URL
|
||||
value: {{ .Values.database.type }}://$(_DB_USER):$(_DB_PASSWORD)@{{ .Values.database.host }}:{{ .Values.database.port }}/{{ .Values.database.dbName }}
|
||||
{{- /* Database URL — Option 1: full URL from secret */}}
|
||||
{{- else if ne .Values.database.type "sqlite" }}
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.databaseSecretName" . }}
|
||||
key: {{ .Values.database.existingSecretKey | default "database-url" }}
|
||||
{{- end }}
|
||||
{{- /* Push notifications */}}
|
||||
{{- if .Values.vaultwarden.push.enabled }}
|
||||
- name: PUSH_INSTALLATION_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.pushSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.push.existingSecretInstallationIdKey | default "push-installation-id" }}
|
||||
- name: PUSH_INSTALLATION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.pushSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.push.existingSecretInstallationKeyKey | default "push-installation-key" }}
|
||||
{{- end }}
|
||||
{{- /* Yubico */}}
|
||||
{{- if .Values.vaultwarden.yubico.enabled }}
|
||||
- name: YUBICO_CLIENT_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.yubicoSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.yubico.existingSecretClientIdKey | default "yubico-client-id" }}
|
||||
- name: YUBICO_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "vaultwarden.yubicoSecretName" . }}
|
||||
key: {{ .Values.vaultwarden.yubico.existingSecretSecretKeyKey | default "yubico-secret-key" }}
|
||||
{{- end }}
|
||||
{{- /* Plain env vars from env map */}}
|
||||
{{- range $name, $value := .Values.env }}
|
||||
- name: {{ $name }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- /* Secret env vars from secretEnv map */}}
|
||||
{{- range $name, $ref := .Values.secretEnv }}
|
||||
- name: {{ $name }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $ref.secretName }}
|
||||
key: {{ $ref.secretKey }}
|
||||
{{- end }}
|
||||
{{- /* Raw extra env vars */}}
|
||||
{{- with .Values.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: data
|
||||
{{- if .Values.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim | default (include "vaultwarden.fullname" .) }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 64Mi
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
45
helm/vaultwarden/templates/ingress.yaml
Normal file
45
helm/vaultwarden/templates/ingress.yaml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "vaultwarden.fullname" $ }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
33
helm/vaultwarden/templates/pvc.yaml
Normal file
33
helm/vaultwarden/templates/pvc.yaml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
{{- with .Values.persistence.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
{{- with .Values.persistence.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- range .Values.persistence.accessModes }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- $sc := .Values.persistence.storageClassName }}
|
||||
{{- if not (kindIs "invalid" $sc) }}
|
||||
{{- if eq (toString $sc) "-" }}
|
||||
storageClassName: ""
|
||||
{{- else if $sc }}
|
||||
storageClassName: {{ $sc | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size }}
|
||||
{{- end }}
|
||||
81
helm/vaultwarden/templates/secret.yaml
Normal file
81
helm/vaultwarden/templates/secret.yaml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
{{- if and .Values.vaultwarden.admin.enabled .Values.vaultwarden.admin.token (not .Values.vaultwarden.admin.existingSecret) -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-admin
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
admin-token: {{ .Values.vaultwarden.admin.token | quote }}
|
||||
{{- end }}
|
||||
{{- if and .Values.vaultwarden.smtp.host .Values.vaultwarden.smtp.username (not .Values.vaultwarden.smtp.existingSecret) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-smtp
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
smtp-username: {{ .Values.vaultwarden.smtp.username | quote }}
|
||||
smtp-password: {{ .Values.vaultwarden.smtp.password | quote }}
|
||||
{{- end }}
|
||||
{{- if and .Values.vaultwarden.sso.enabled .Values.vaultwarden.sso.clientId (not .Values.vaultwarden.sso.existingSecret) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-sso
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
sso-client-id: {{ .Values.vaultwarden.sso.clientId | quote }}
|
||||
sso-client-secret: {{ .Values.vaultwarden.sso.clientSecret | quote }}
|
||||
{{- end }}
|
||||
{{- if and .Values.vaultwarden.push.enabled .Values.vaultwarden.push.installationId (not .Values.vaultwarden.push.existingSecret) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-push
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
push-installation-id: {{ .Values.vaultwarden.push.installationId | quote }}
|
||||
push-installation-key: {{ .Values.vaultwarden.push.installationKey | quote }}
|
||||
{{- end }}
|
||||
{{- if and .Values.vaultwarden.yubico.enabled .Values.vaultwarden.yubico.clientId (not .Values.vaultwarden.yubico.existingSecret) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-yubico
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
yubico-client-id: {{ .Values.vaultwarden.yubico.clientId | quote }}
|
||||
yubico-secret-key: {{ .Values.vaultwarden.yubico.secretKey | quote }}
|
||||
{{- end }}
|
||||
{{- if and (ne .Values.database.type "sqlite") .Values.database.url (not .Values.database.existingSecret) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}-database
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
database-url: {{ .Values.database.url | quote }}
|
||||
{{- end }}
|
||||
32
helm/vaultwarden/templates/service.yaml
Normal file
32
helm/vaultwarden/templates/service.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
{{- with .Values.service.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.externalTrafficPolicy }}
|
||||
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
|
||||
nodePort: {{ .Values.service.nodePort }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "vaultwarden.selectorLabels" . | nindent 4 }}
|
||||
14
helm/vaultwarden/templates/serviceaccount.yaml
Normal file
14
helm/vaultwarden/templates/serviceaccount.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "vaultwarden.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
|
||||
{{- end }}
|
||||
16
helm/vaultwarden/templates/tests/test-connection.yaml
Normal file
16
helm/vaultwarden/templates/tests/test-connection.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "vaultwarden.fullname" . }}-test-connection"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "vaultwarden.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox:stable
|
||||
command: ['wget']
|
||||
args: ['{{ include "vaultwarden.fullname" . }}:{{ .Values.service.port }}/alive', '-q', '-O', '-']
|
||||
restartPolicy: Never
|
||||
367
helm/vaultwarden/values.yaml
Normal file
367
helm/vaultwarden/values.yaml
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
# -- Number of replicas. Keep at 1 when using SQLite.
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
# -- Container image repository
|
||||
repository: vaultwarden/server
|
||||
# -- Image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
# -- Overrides the image tag (default: appVersion from Chart.yaml)
|
||||
tag: ""
|
||||
|
||||
# -- Image pull secrets
|
||||
imagePullSecrets: []
|
||||
# -- Override the release name
|
||||
nameOverride: ""
|
||||
# -- Override the full release name
|
||||
fullnameOverride: ""
|
||||
|
||||
# =============================================================================
|
||||
# Vaultwarden configuration
|
||||
# =============================================================================
|
||||
vaultwarden:
|
||||
# -- (required) The domain URL for your vaultwarden instance (e.g. https://vault.example.com)
|
||||
domain: ""
|
||||
# -- Allow new user signups
|
||||
signupsAllowed: false
|
||||
# -- Rocket server port. Set to non-privileged port for non-root operation.
|
||||
rocketPort: 8080
|
||||
# -- Enable websocket notifications
|
||||
websocket:
|
||||
enabled: true
|
||||
|
||||
# -- Logging configuration
|
||||
logging:
|
||||
# -- Log level (trace, debug, info, warn, error, off)
|
||||
level: "info"
|
||||
|
||||
# -- Icon service configuration
|
||||
icons:
|
||||
# -- Icon service to use (internal, bitwarden, duckduckgo, google)
|
||||
service: "internal"
|
||||
|
||||
# -- Admin panel configuration
|
||||
admin:
|
||||
# -- Enable the admin panel (/admin)
|
||||
enabled: false
|
||||
# -- Admin token (argon2 hash recommended). Ignored if existingSecret is set.
|
||||
token: ""
|
||||
# -- Use an existing secret for the admin token
|
||||
existingSecret: ""
|
||||
# -- Key within the existing secret that holds the admin token
|
||||
existingSecretKey: "admin-token"
|
||||
|
||||
# -- SMTP email configuration
|
||||
smtp:
|
||||
# -- SMTP server hostname
|
||||
host: ""
|
||||
# -- Email address used as the sender
|
||||
from: ""
|
||||
# -- SMTP server port
|
||||
port: 587
|
||||
# -- SMTP security mode (starttls, force_tls, off)
|
||||
security: "starttls"
|
||||
# -- SMTP username. Ignored if existingSecret is set.
|
||||
username: ""
|
||||
# -- SMTP password. Ignored if existingSecret is set.
|
||||
password: ""
|
||||
# -- Use an existing secret for SMTP credentials
|
||||
existingSecret: ""
|
||||
# -- Key in existing secret for SMTP username
|
||||
existingSecretUsernameKey: "smtp-username"
|
||||
# -- Key in existing secret for SMTP password
|
||||
existingSecretPasswordKey: "smtp-password"
|
||||
|
||||
# -- SSO/OpenID Connect configuration
|
||||
sso:
|
||||
# -- Enable SSO authentication
|
||||
enabled: false
|
||||
# -- Require SSO for all logins (disable password login)
|
||||
only: false
|
||||
# -- OpenID Connect authority URL
|
||||
authority: ""
|
||||
# -- OIDC client ID. Ignored if existingSecret is set.
|
||||
clientId: ""
|
||||
# -- OIDC client secret. Ignored if existingSecret is set.
|
||||
clientSecret: ""
|
||||
# -- Use an existing secret for SSO credentials
|
||||
existingSecret: ""
|
||||
# -- Key in existing secret for client ID
|
||||
existingSecretClientIdKey: "sso-client-id"
|
||||
# -- Key in existing secret for client secret
|
||||
existingSecretClientSecretKey: "sso-client-secret"
|
||||
|
||||
# -- Push notifications configuration (requires https://bitwarden.com/host keys)
|
||||
push:
|
||||
# -- Enable push notifications
|
||||
enabled: false
|
||||
# -- Installation ID from https://bitwarden.com/host. Ignored if existingSecret is set.
|
||||
installationId: ""
|
||||
# -- Installation key from https://bitwarden.com/host. Ignored if existingSecret is set.
|
||||
installationKey: ""
|
||||
# -- Use an existing secret for push notification credentials
|
||||
existingSecret: ""
|
||||
# -- Key in existing secret for installation ID
|
||||
existingSecretInstallationIdKey: "push-installation-id"
|
||||
# -- Key in existing secret for installation key
|
||||
existingSecretInstallationKeyKey: "push-installation-key"
|
||||
# -- Relay URI (default uses Bitwarden US server)
|
||||
relayUri: ""
|
||||
# -- Identity URI (default uses Bitwarden US server)
|
||||
identityUri: ""
|
||||
|
||||
# -- Yubico OTP configuration
|
||||
yubico:
|
||||
# -- Enable Yubico OTP support
|
||||
enabled: false
|
||||
# -- Yubico client ID. Ignored if existingSecret is set.
|
||||
clientId: ""
|
||||
# -- Yubico secret key. Ignored if existingSecret is set.
|
||||
secretKey: ""
|
||||
# -- Use an existing secret for Yubico credentials
|
||||
existingSecret: ""
|
||||
# -- Key in existing secret for client ID
|
||||
existingSecretClientIdKey: "yubico-client-id"
|
||||
# -- Key in existing secret for secret key
|
||||
existingSecretSecretKeyKey: "yubico-secret-key"
|
||||
|
||||
# =============================================================================
|
||||
# Database configuration
|
||||
# =============================================================================
|
||||
database:
|
||||
# -- Database backend: sqlite, postgresql, or mysql
|
||||
type: "sqlite"
|
||||
|
||||
# --- Option 1: Full connection URL ---
|
||||
# -- Full database connection URL.
|
||||
# Examples:
|
||||
# postgresql://user:password@host:5432/vaultwarden
|
||||
# mysql://user:password@host:3306/vaultwarden
|
||||
url: ""
|
||||
# -- Use an existing secret containing the full database URL
|
||||
existingSecret: ""
|
||||
# -- Key within the existing secret for the database URL
|
||||
existingSecretKey: "database-url"
|
||||
|
||||
# --- Option 2: Compose from parts (recommended for Postgres operators) ---
|
||||
# When `host` is set, the chart composes DATABASE_URL from individual fields.
|
||||
# Username and password are read from a Kubernetes secret via secretKeyRef.
|
||||
# This is ideal for Zalando Postgres Operator, CloudNativePG, etc.
|
||||
# -- Database hostname (e.g. my-cluster.postgres-namespace)
|
||||
host: ""
|
||||
# -- Database port
|
||||
port: 5432
|
||||
# -- Database name
|
||||
dbName: "vaultwarden"
|
||||
# -- Secret containing database user credentials (must have username and password keys)
|
||||
credentialsSecret: ""
|
||||
# -- Key in credentialsSecret for the username
|
||||
credentialsSecretUsernameKey: "username"
|
||||
# -- Key in credentialsSecret for the password
|
||||
credentialsSecretPasswordKey: "password"
|
||||
|
||||
# --- Common settings ---
|
||||
# -- Maximum number of database connections
|
||||
maxConnections: 10
|
||||
# -- Enable WAL mode for SQLite (improves performance)
|
||||
wal: true
|
||||
|
||||
# =============================================================================
|
||||
# Kubernetes resources
|
||||
# =============================================================================
|
||||
serviceAccount:
|
||||
# -- Create a service account
|
||||
create: true
|
||||
# -- Annotations for the service account
|
||||
annotations: {}
|
||||
# -- Override the service account name
|
||||
name: ""
|
||||
# -- Automount the service account token
|
||||
automountServiceAccountToken: false
|
||||
|
||||
# -- Pod-level security context
|
||||
podSecurityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
fsGroup: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
# -- Container-level security context
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
readOnlyRootFilesystem: true
|
||||
|
||||
service:
|
||||
# -- Service type (ClusterIP, NodePort, LoadBalancer)
|
||||
type: ClusterIP
|
||||
# -- Service port
|
||||
port: 8080
|
||||
# -- Node port (only used when type is NodePort)
|
||||
nodePort: ""
|
||||
# -- Load balancer IP (only used when type is LoadBalancer)
|
||||
loadBalancerIP: ""
|
||||
# -- External traffic policy (Local or Cluster, only used when type is NodePort or LoadBalancer)
|
||||
externalTrafficPolicy: ""
|
||||
# -- Additional service annotations (e.g. for external-dns, service meshes)
|
||||
annotations: {}
|
||||
# -- Additional service labels
|
||||
labels: {}
|
||||
|
||||
ingress:
|
||||
# -- Enable ingress
|
||||
enabled: false
|
||||
# -- Ingress class name (e.g. nginx, traefik, haproxy)
|
||||
className: ""
|
||||
# -- Ingress annotations (e.g. cert-manager, auth, rate-limiting)
|
||||
annotations: {}
|
||||
# cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
# cert-manager.io/private-key-algorithm: ECDSA
|
||||
# cert-manager.io/private-key-size: "384"
|
||||
# cert-manager.io/private-key-rotation-policy: Always
|
||||
# nginx.ingress.kubernetes.io/proxy-body-size: 128m
|
||||
# -- Additional ingress labels
|
||||
labels: {}
|
||||
# -- Ingress hosts
|
||||
hosts:
|
||||
- host: vault.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
# -- Ingress TLS configuration
|
||||
tls: []
|
||||
# - secretName: vault-tls
|
||||
# hosts:
|
||||
# - vault.example.com
|
||||
|
||||
persistence:
|
||||
# -- Enable persistent storage for /data
|
||||
enabled: true
|
||||
# -- Storage class name.
|
||||
# Set to "-" to disable dynamic provisioning.
|
||||
# Leave unset or null for the cluster default storage class.
|
||||
# @default -- `nil` (cluster default)
|
||||
storageClassName:
|
||||
# -- Access modes
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
# -- Storage size
|
||||
size: 5Gi
|
||||
# -- Use an existing PVC instead of creating one
|
||||
existingClaim: ""
|
||||
# -- Additional PVC annotations
|
||||
annotations: {}
|
||||
# -- Additional PVC labels
|
||||
labels: {}
|
||||
|
||||
# -- Resource requests and limits
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 1Gi
|
||||
|
||||
# -- Liveness probe configuration
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /alive
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
# -- Readiness probe configuration
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /alive
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
|
||||
# -- Startup probe configuration (useful for slow-starting instances with large databases)
|
||||
startupProbe: {}
|
||||
# httpGet:
|
||||
# path: /alive
|
||||
# port: http
|
||||
# failureThreshold: 30
|
||||
# periodSeconds: 5
|
||||
|
||||
# -- Deployment revision history limit
|
||||
revisionHistoryLimit: 3
|
||||
|
||||
# -- Pod annotations
|
||||
podAnnotations: {}
|
||||
|
||||
# -- Pod labels
|
||||
podLabels: {}
|
||||
|
||||
# -- Priority class name for pod scheduling
|
||||
priorityClassName: ""
|
||||
|
||||
# -- Termination grace period in seconds
|
||||
terminationGracePeriodSeconds: 30
|
||||
|
||||
# -- Node selector
|
||||
nodeSelector: {}
|
||||
|
||||
# -- Tolerations
|
||||
tolerations: []
|
||||
|
||||
# -- Affinity rules
|
||||
affinity: {}
|
||||
|
||||
# -- Topology spread constraints for pod scheduling
|
||||
topologySpreadConstraints: []
|
||||
# - maxSkew: 1
|
||||
# topologyKey: kubernetes.io/hostname
|
||||
# whenUnsatisfiable: DoNotSchedule
|
||||
# labelSelector:
|
||||
# matchLabels: ...
|
||||
|
||||
# -- Init containers
|
||||
initContainers: []
|
||||
|
||||
# -- Additional environment variables (plain key-value).
|
||||
# Use this to set any vaultwarden env var not covered by the structured values above.
|
||||
# These are added to the container env directly.
|
||||
env: {}
|
||||
# SIGNUPS_ALLOWED: "false"
|
||||
# INVITATION_ORG_NAME: "My Org"
|
||||
# SENDS_ALLOWED: "true"
|
||||
# EMERGENCY_ACCESS_ALLOWED: "true"
|
||||
|
||||
# -- Environment variables sourced from Kubernetes secrets (secretKeyRef shorthand).
|
||||
# Each key is the env var name, value specifies the secret and key to read from.
|
||||
secretEnv: {}
|
||||
# ADMIN_TOKEN:
|
||||
# secretName: my-admin-secret
|
||||
# secretKey: admin-token
|
||||
# DATABASE_URL:
|
||||
# secretName: my-db-secret
|
||||
# secretKey: database-url
|
||||
# SMTP_PASSWORD:
|
||||
# secretName: my-smtp-secret
|
||||
# secretKey: password
|
||||
|
||||
# -- Additional environment variables (raw Kubernetes env spec).
|
||||
# Use this for complex env definitions like fieldRef, resourceFieldRef, etc.
|
||||
extraEnv: []
|
||||
# - name: POD_IP
|
||||
# valueFrom:
|
||||
# fieldRef:
|
||||
# fieldPath: status.podIP
|
||||
|
||||
# -- Additional volume mounts for the vaultwarden container
|
||||
extraVolumeMounts: []
|
||||
# - name: custom-certs
|
||||
# mountPath: /etc/ssl/custom
|
||||
# readOnly: true
|
||||
|
||||
# -- Additional volumes
|
||||
extraVolumes: []
|
||||
# - name: custom-certs
|
||||
# secret:
|
||||
# secretName: custom-ca-certs
|
||||
Loading…
Reference in a new issue