Compare commits

...

7 Commits

13 changed files with 184 additions and 72 deletions

View File

@ -2,7 +2,7 @@ apiVersion: v2
name: donetick
description: Donetick helm chart for Kubernetes
type: application
version: 1.0.2
version: 1.0.4
appVersion: "v0.1.60"
maintainers:
- name: Richard Tomik

View File

@ -107,11 +107,18 @@ config:
type: "postgres"
host: "postgresql.database.svc.cluster.local"
port: 5432
user: "donetick"
name: "donetick"
# Use existing secret for database credentials
existingSecret: "donetick-db-secret"
passwordKey: "postgresql-password"
# Use existing secret for postgres credentials
database:
type: "postgres"
host: "postgresql.database.svc.cluster.local"
port: 5432
name: "donetick"
secrets:
existingSecret: "donetick-postgres-secret"
userKey: "username"
passwordKey: "password"
# Use existing secret for JWT
jwt:
@ -179,9 +186,10 @@ ingress:
Create the required secrets:
```bash
# Database secret
kubectl create secret generic donetick-db-secret \
--from-literal=postgresql-password='your-secure-db-password'
# Postgres secret
kubectl create secret generic donetick-postgres-secret \
--from-literal=username='donetick' \
--from-literal=password='your-secure-db-password'
# JWT secret
kubectl create secret generic donetick-jwt-secret \
@ -234,12 +242,9 @@ helm uninstall donetick
| `config.oauth2.existingSecret` | Name of existing secret for OAuth2 credentials | `""` |
| `config.oauth2.clientIdKey` | Key in the existing secret for OAuth2 client ID | `"client-id"` |
| `config.oauth2.clientSecretKey` | Key in the existing secret for OAuth2 client secret | `"client-secret"` |
| `config.database.existingSecret` | Name of existing secret for database credentials | `""` |
| `config.database.hostKey` | Key in the existing secret for database host | `"db-host"` |
| `config.database.portKey` | Key in the existing secret for database port | `"db-port"` |
| `config.database.userKey` | Key in the existing secret for database user | `"db-user"` |
| `config.database.passwordKey` | Key in the existing secret for database password | `"db-password"` |
| `config.database.nameKey` | Key in the existing secret for database name | `"db-name"` |
| `config.database.secrets.existingSecret` | Name of existing secret for postgres credentials | `""` |
| `config.database.secrets.userKey` | Key in the existing secret for postgres username | `"username"` |
| `config.database.secrets.passwordKey` | Key in the existing secret for postgres password | `"password"` |
### Deployment parameters

View File

@ -22,15 +22,18 @@ data:
{{- if .Values.config.database.migration_retry }}
migration_retry: {{ .Values.config.database.migration_retry }}
{{- end }}
migration_timeout: {{ .Values.config.database.migration_timeout | default "300s" | quote }}
{{- if eq .Values.config.database.type "postgres" }}
{{- if not .Values.config.database.existingSecret }}
host: {{ .Values.config.database.host | quote }}
port: {{ .Values.config.database.port }}
name: {{ .Values.config.database.name | quote }}
{{- if not .Values.config.database.secrets.existingSecret }}
user: {{ .Values.config.database.user | quote }}
password: {{ .Values.config.database.password | quote }}
name: {{ .Values.config.database.name | quote }}
{{- else }}
# Database credentials will be injected via environment variables from Secret
# Reference environment variables for database credentials
user: "$DT_DATABASE_USER"
password: "$DT_DATABASE_PASSWORD"
{{- end }}
{{- end }}
jwt:

View File

@ -88,15 +88,44 @@ spec:
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- if or .Values.config.jwt.existingSecret .Values.config.oauth2.existingSecret .Values.config.database.existingSecret }}
# Secret-based environment variables
# Database configuration environment variables
{{- if eq .Values.config.database.type "postgres" }}
- name: DT_DATABASE_TYPE
value: "postgres"
- name: DT_DATABASE_HOST
value: {{ .Values.config.database.host | quote }}
- name: DT_DATABASE_PORT
value: {{ .Values.config.database.port | quote }}
- name: DT_DATABASE_NAME
value: {{ .Values.config.database.name | quote }}
{{- if .Values.config.database.secrets.existingSecret }}
- name: DT_DATABASE_USER
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.secrets.existingSecret }}
key: {{ .Values.config.database.secrets.userKey }}
- name: DT_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.secrets.existingSecret }}
key: {{ .Values.config.database.secrets.passwordKey }}
{{- end }}
{{- else }}
- name: DT_DATABASE_TYPE
value: {{ .Values.config.database.type | quote }}
{{- end }}
# JWT configuration
{{- if .Values.config.jwt.existingSecret }}
- name: DT_JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.config.jwt.existingSecret }}
key: {{ .Values.config.jwt.secretKey }}
{{- else }}
- name: DT_JWT_SECRET
value: {{ .Values.config.jwt.secret | quote }}
{{- end }}
# OAuth2 configuration
{{- if .Values.config.oauth2.existingSecret }}
- name: DT_OAUTH2_CLIENT_ID
valueFrom:
@ -109,34 +138,6 @@ spec:
name: {{ .Values.config.oauth2.existingSecret }}
key: {{ .Values.config.oauth2.clientSecretKey }}
{{- end }}
{{- if and .Values.config.database.existingSecret (eq .Values.config.database.type "postgres") }}
- name: DT_DB_HOST
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.existingSecret }}
key: {{ .Values.config.database.hostKey }}
- name: DT_DB_PORT
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.existingSecret }}
key: {{ .Values.config.database.portKey }}
- name: DT_DB_USER
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.existingSecret }}
key: {{ .Values.config.database.userKey }}
- name: DT_DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.existingSecret }}
key: {{ .Values.config.database.passwordKey }}
- name: DT_DB_NAME
valueFrom:
secretKeyRef:
name: {{ .Values.config.database.existingSecret }}
key: {{ .Values.config.database.nameKey }}
{{- end }}
{{- end }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}

View File

@ -1,4 +1,4 @@
{{- if or (not .Values.config.jwt.existingSecret) (and (not .Values.config.oauth2.existingSecret) (or .Values.config.oauth2.client_id .Values.config.oauth2.client_secret)) (and (eq .Values.config.database.type "postgres") (not .Values.config.database.existingSecret)) }}
{{- if or (not .Values.config.jwt.existingSecret) (and (not .Values.config.oauth2.existingSecret) (or .Values.config.oauth2.client_id .Values.config.oauth2.client_secret)) (and (eq .Values.config.database.type "postgres") (not .Values.config.database.secrets.existingSecret)) }}
apiVersion: v1
kind: Secret
metadata:
@ -10,8 +10,8 @@ data:
{{- if not .Values.config.jwt.existingSecret }}
{{ .Values.config.jwt.secretKey }}: {{ .Values.config.jwt.secret | b64enc }}
{{- end }}
{{- if and (eq .Values.config.database.type "postgres") (not .Values.config.database.existingSecret) }}
{{ .Values.config.database.passwordKey }}: {{ .Values.config.database.password | b64enc }}
{{- if and (eq .Values.config.database.type "postgres") (not .Values.config.database.secrets.existingSecret) }}
{{ .Values.config.database.secrets.passwordKey }}: {{ .Values.config.database.password | b64enc }}
{{- end }}
{{- if and (not .Values.config.oauth2.existingSecret) .Values.config.oauth2.client_id }}
{{ .Values.config.oauth2.clientIdKey }}: {{ .Values.config.oauth2.client_id | b64enc }}

View File

@ -107,10 +107,10 @@ resources: {}
probes:
startup:
enabled: true
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 30
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 15
failureThreshold: 80
successThreshold: 1
path: /health
liveness:
@ -157,21 +157,18 @@ config:
# Migration options
migration_skip: false # Set to true to skip database migrations
migration_retry: 3 # Number of retries for failed migrations
# These are only required for postgres - direct configuration
migration_timeout: "600s" # Timeout for database migrations (default: 10 minutes)
# These are only required for postgres
host: ""
port: 5432
user: ""
password: ""
name: ""
# Secret configuration for database credentials
existingSecret: "" # Name of existing Kubernetes secret
hostKey: "db-host" # Key in the secret for database host
portKey: "db-port" # Key in the secret for database port
userKey: "db-user" # Key in the secret for database user
passwordKey: "db-password" # Key in the secret for database password
nameKey: "db-name" # Key in the secret for database name
# Secret configuration for postgres credentials
secrets:
existingSecret: "" # Name of existing Kubernetes secret containing postgres credentials
userKey: "username" # Key in the secret for database username
passwordKey: "password" # Key in the secret for database password
# Security settings
# For production, use a generated secret and store in a Kubernetes Secret

View File

@ -18,4 +18,10 @@ spec:
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- end }}
{{- if .Values.persistence.selector }}
{{- with .Values.persistence.selector }}
selector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -2,7 +2,7 @@ apiVersion: v2
name: paperless-ngx
description: Paperless-ngx helm chart for Kubernetes
type: application
version: 0.0.1
version: 0.0.2
appVersion: "latest"
maintainers:
- name: Richard Tomik

View File

@ -32,6 +32,13 @@ Paperless-ngx requires PostgreSQL 11+ as its database backend. Ensure you have:
Redis is required for background task processing. Ensure you have:
- A Redis server accessible from the cluster
- Connection details configured in values.yaml
- Optional: Redis authentication credentials (username/password)
- Optional: Redis key prefix for sharing one Redis server among multiple Paperless instances
The chart supports all Redis authentication methods:
- No authentication: `redis://host:port/database`
- Password only (requirepass): `redis://:password@host:port/database`
- Username and password (Redis 6.0+ ACL): `redis://username:password@host:port/database`
## Installing the Chart
@ -86,6 +93,11 @@ The following table lists the configurable parameters and their default values.
| `redis.external.host` | External Redis host | `redis.default.svc.cluster.local` |
| `redis.external.port` | External Redis port | `6379` |
| `redis.external.database` | External Redis database number | `0` |
| `redis.external.username` | Redis username (Redis 6.0+ with ACL) | `""` |
| `redis.external.password` | Redis password (leave empty if no auth required) | `""` |
| `redis.external.existingSecret` | Existing secret with Redis credentials | `""` |
| `redis.external.passwordKey` | Key in existing secret for Redis password | `redis-password` |
| `redis.external.prefix` | Prefix for Redis keys/channels (for multi-instance) | `""` |
### Security Configuration
@ -166,14 +178,27 @@ config:
existingSecret: "paperless-admin-secrets"
postgresql:
# External PostgreSQL connection details
external:
host: "postgresql.database.svc.cluster.local"
existingSecret: "paperless-db-secrets"
enabled: true
host: "postgres-cluster-pooler.dbs.svc.cluster.local"
port: 5432
database: "paperless"
username: "paperless"
# Use existingSecret for credentials
existingSecret: "paperless-db-credentials"
passwordKey: "password"
redis:
external:
host: "redis.cache.svc.cluster.local"
port: 6379
database: 0
# Use existingSecret for Redis credentials
existingSecret: "paperless-redis-credentials"
passwordKey: "password"
# Optional: Use prefix to share Redis among multiple instances
prefix: "paperless-prod"
ingress:
enabled: true
@ -193,13 +218,63 @@ ingress:
helm install paperless-ngx . -f values-production.yaml
```
### Redis Authentication Examples
#### Redis with Password Only (requirepass)
```bash
helm install paperless-ngx . \
--set redis.external.host=redis.example.com \
--set redis.external.password=myredispassword
```
Or with existing secret:
```yaml
redis:
external:
host: "redis.example.com"
existingSecret: "redis-auth-secret"
passwordKey: "redis-password"
```
#### Redis with Username and Password (Redis 6.0+ ACL)
```bash
helm install paperless-ngx . \
--set redis.external.host=redis.example.com \
--set redis.external.username=paperless-user \
--set redis.external.password=myredispassword
```
#### Multiple Paperless Instances on One Redis Server
Use the `prefix` parameter to avoid key collisions:
```yaml
# Instance 1
redis:
external:
host: "shared-redis.example.com"
password: "sharedpassword"
prefix: "paperless-prod"
# Instance 2
redis:
external:
host: "shared-redis.example.com"
password: "sharedpassword"
prefix: "paperless-staging"
```
## Security Considerations
1. **Use external secrets** for production deployments to store sensitive data like database passwords and the Django secret key.
1. **Use external secrets** for production deployments to store sensitive data like database passwords, Redis passwords, and the Django secret key.
2. **Set a proper PAPERLESS_URL** when exposing the application externally.
3. **Configure ALLOWED_HOSTS** to restrict which hosts can access the application.
4. **Use HTTPS** when exposing the application to the internet.
5. **Container Security**: The container runs as root initially to allow s6-overlay to set up the runtime environment, then drops privileges to UID 1000. This is required for the Paperless-ngx Docker image to function properly.
5. **Secure Redis**: Always use authentication (password or username/password) for Redis in production environments. Use `existingSecret` instead of plain text passwords.
6. **Container Security**: The container runs as root initially to allow s6-overlay to set up the runtime environment, then drops privileges to UID 1000. This is required for the Paperless-ngx Docker image to function properly.
## Volumes and Data

View File

@ -90,10 +90,20 @@ Redis port
{{/*
Redis URL
Constructs the Redis URL with optional authentication.
Format: redis://[username]:[password]@host:port/database
*/}}
{{- define "paperless-ngx.redis.url" -}}
{{- $host := include "paperless-ngx.redis.host" . }}
{{- $port := include "paperless-ngx.redis.port" . }}
{{- $database := .Values.redis.external.database | toString }}
{{- $username := .Values.redis.external.username | default "" }}
{{- $password := .Values.redis.external.password | default "" }}
{{- if and $username $password }}
{{- printf "redis://%s:%s@%s:%s/%s" $username $password $host $port $database }}
{{- else if $password }}
{{- printf "redis://:%s@%s:%s/%s" $password $host $port $database }}
{{- else }}
{{- printf "redis://%s:%s/%s" $host $port $database }}
{{- end }}
{{- end }}

View File

@ -69,6 +69,10 @@ spec:
# Required services
- name: PAPERLESS_REDIS
value: {{ include "paperless-ngx.redis.url" . | quote }}
{{- if .Values.redis.external.prefix }}
- name: PAPERLESS_REDIS_PREFIX
value: {{ .Values.redis.external.prefix | quote }}
{{- end }}
- name: PAPERLESS_DBHOST
value: {{ include "paperless-ngx.postgresql.host" . | quote }}
- name: PAPERLESS_DBPORT

View File

@ -5,6 +5,9 @@
{{- if not .Values.postgresql.external.existingSecret -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if and .Values.redis.external.password (not .Values.redis.external.existingSecret) -}}
{{- $needsSecret = true -}}
{{- end -}}
{{- if and .Values.config.admin.user (not .Values.config.admin.existingSecret) -}}
{{- $needsSecret = true -}}
{{- end -}}
@ -27,6 +30,9 @@ data:
{{- if not .Values.postgresql.external.existingSecret }}
{{ .Values.postgresql.external.passwordKey | default "postgresql-password" }}: {{ .Values.postgresql.external.password | default "paperless" | b64enc }}
{{- end }}
{{- if and .Values.redis.external.password (not .Values.redis.external.existingSecret) }}
{{ .Values.redis.external.passwordKey | default "redis-password" }}: {{ .Values.redis.external.password | b64enc }}
{{- end }}
{{- if and .Values.config.admin.user (not .Values.config.admin.existingSecret) }}
{{ .Values.config.admin.userKey | default "admin-user" }}: {{ .Values.config.admin.user | b64enc }}
{{ .Values.config.admin.passwordKey | default "admin-password" }}: {{ .Values.config.admin.password | default "changeme" | b64enc }}

View File

@ -158,11 +158,16 @@ redis:
host: "redis.default.svc.cluster.local"
port: 6379
database: 0
# Authentication (leave empty if Redis has no auth)
username: "" # Optional: Redis username (Redis 6.0+)
# Use existingSecret for credentials if Redis has auth
existingSecret: ""
passwordKey: "redis-password"
# Or set password directly (leave empty if no auth)
password: ""
# Optional: Prefix for Redis keys and channels
# Useful for sharing one Redis server among multiple Paperless instances
prefix: ""
## Paperless-ngx Configuration
config: