Matrix-Synapse chart: security hardening, naming scheme, configurable probes
- Values-driven securityContext for the Synapse pod/container with hardened defaults: runAsNonRoot as uid/gid 1000 (matching the image's previous gosu drop target), readOnlyRootFilesystem, allowPrivilegeEscalation false, all capabilities dropped; /tmp mounted as emptyDir. The now-ineffective UID/GID env vars are removed (the securityContext controls the user). - Naming scheme: delegation Deployment renamed to ...-delegation-nginx-deployment, ConfigMap to ...-delegation-nginx-configmap (references and service selector updated). - matrix.configSecretRef moved to secrets.configSecretRef (repo standard). - Probes for Synapse and the delegation nginx are values-configurable; defaults are the previous hardcoded settings. - Flexible ingress standard: ingress.className (default nginx) and ingress.annotations merged with the cert-manager annotation. - Additive matrix.env block rendered through tpl (value/secretKeyRef/ configMapKeyRef forms). - CI fixtures: secret ref moved, seed job image synced to appVersion. - Chart 4.2.1+upv1.159.0 -> 5.0.0+upv1.159.0 (major; app version unchanged).
This commit is contained in:
10 files changed
+144
-73
No files matched your search
@@ -40,7 +40,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: generate
|
- name: generate
|
||||||
# Same image the chart deploys (appVersion of matrix-synapse).
|
# Same image the chart deploys (appVersion of matrix-synapse).
|
||||||
image: ghcr.io/element-hq/synapse:v1.149.1
|
image: ghcr.io/element-hq/synapse:v1.159.0
|
||||||
args: ["generate"]
|
args: ["generate"]
|
||||||
env:
|
env:
|
||||||
- name: SYNAPSE_SERVER_NAME
|
- name: SYNAPSE_SERVER_NAME
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
secrets:
|
||||||
|
configSecretRef: op://ci/matrix-synapse-config
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
serverName: synapse.ci.local
|
serverName: synapse.ci.local
|
||||||
configSecretRef: op://ci/matrix-synapse-config
|
|
||||||
delegation:
|
delegation:
|
||||||
enabled: true
|
enabled: true
|
||||||
serverUrl: ci.local
|
serverUrl: ci.local
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: matrix-synapse
|
|||||||
description: A Helm chart to deploy a Matrix Synapse server on Kubernetes
|
description: A Helm chart to deploy a Matrix Synapse server on Kubernetes
|
||||||
icon: https://raw.githubusercontent.com/element-hq/synapse/develop/docs/favicon.png
|
icon: https://raw.githubusercontent.com/element-hq/synapse/develop/docs/favicon.png
|
||||||
type: application
|
type: application
|
||||||
version: 4.2.1+upv1.159.0
|
version: 5.0.0+upv1.159.0
|
||||||
appVersion: "v1.159.0"
|
appVersion: "v1.159.0"
|
||||||
maintainers:
|
maintainers:
|
||||||
- name: jklein
|
- name: jklein
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-config
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-configmap
|
||||||
data:
|
data:
|
||||||
nginx.conf: |
|
nginx.conf: |
|
||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-deployment
|
||||||
labels:
|
labels:
|
||||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-deployment
|
||||||
spec:
|
spec:
|
||||||
replicas: {{ include "matrix-synapse.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.matrix.delegation.replicas) }}
|
replicas: {{ include "matrix-synapse.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.matrix.delegation.replicas) }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-deployment
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-deployment
|
||||||
spec:
|
spec:
|
||||||
automountServiceAccountToken: false
|
automountServiceAccountToken: false
|
||||||
securityContext:
|
securityContext:
|
||||||
@@ -38,36 +38,17 @@ spec:
|
|||||||
resources:
|
resources:
|
||||||
{{- include "matrix-synapse.resources" .Values.matrix.delegation.resources | nindent 12 }}
|
{{- include "matrix-synapse.resources" .Values.matrix.delegation.resources | nindent 12 }}
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.delegation.readinessProbe | nindent 12 }}
|
||||||
path: /.well-known/matrix/server
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 3
|
|
||||||
failureThreshold: 3
|
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.delegation.livenessProbe | nindent 12 }}
|
||||||
path: /.well-known/matrix/server
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 3
|
|
||||||
failureThreshold: 3
|
|
||||||
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
|
||||||
startupProbe:
|
startupProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.delegation.startupProbe | nindent 12 }}
|
||||||
path: /.well-known/matrix/server
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 5
|
|
||||||
timeoutSeconds: 3
|
|
||||||
failureThreshold: 30
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: tmp
|
- name: tmp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
- name: nginx-config
|
- name: nginx-config
|
||||||
configMap:
|
configMap:
|
||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-config
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-configmap
|
||||||
items:
|
items:
|
||||||
- key: nginx.conf
|
- key: nginx.conf
|
||||||
path: nginx.conf
|
path: nginx.conf
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ metadata:
|
|||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-service
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-service
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-delegation-nginx-deployment
|
||||||
ports:
|
ports:
|
||||||
- protocol: TCP
|
- protocol: TCP
|
||||||
port: 80
|
port: 80
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ kind: OnePasswordItem
|
|||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-config-secret
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-config-secret
|
||||||
spec:
|
spec:
|
||||||
itemPath: {{ required "You must provide a configSecret Reference" .Values.matrix.configSecretRef }}
|
itemPath: {{ required "You must provide a configSecret Reference" .Values.secrets.configSecretRef }}
|
||||||
@@ -4,8 +4,11 @@ metadata:
|
|||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer }}
|
cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
rules:
|
rules:
|
||||||
- host: {{ required "A Domain/Host must be provided" .Values.ingress.domain }}
|
- host: {{ required "A Domain/Host must be provided" .Values.ingress.domain }}
|
||||||
http:
|
http:
|
||||||
|
|||||||
@@ -18,52 +18,49 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
automountServiceAccountToken: false
|
automountServiceAccountToken: false
|
||||||
securityContext:
|
securityContext:
|
||||||
fsGroup: 1000
|
{{- toYaml .Values.matrix.securityContext.pod | nindent 8 }}
|
||||||
fsGroupChangePolicy: Always
|
|
||||||
containers:
|
containers:
|
||||||
- name: "{{ .Release.Name }}-{{ .Chart.Name }}-container"
|
- name: "{{ .Release.Name }}-{{ .Chart.Name }}-container"
|
||||||
image: "ghcr.io/element-hq/synapse:{{ .Chart.AppVersion }}"
|
image: "ghcr.io/element-hq/synapse:{{ .Chart.AppVersion }}"
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.matrix.securityContext.container | nindent 12 }}
|
||||||
env:
|
env:
|
||||||
- name: SYNAPSE_SERVER_NAME
|
- name: SYNAPSE_SERVER_NAME
|
||||||
value: "{{ required "You must provide a Server-Name" .Values.matrix.serverName }}"
|
value: "{{ required "You must provide a Server-Name" .Values.matrix.serverName }}"
|
||||||
- name: SYNAPSE_REPORT_STATS
|
- name: SYNAPSE_REPORT_STATS
|
||||||
value: "no"
|
value: "no"
|
||||||
- name: UID
|
|
||||||
value: "1000"
|
|
||||||
- name: GID
|
|
||||||
value: "1000"
|
|
||||||
- name: TZ
|
- name: TZ
|
||||||
value: "{{ .Values.matrix.timezone }}"
|
value: "{{ .Values.matrix.timezone }}"
|
||||||
|
{{- range $value := .Values.matrix.env }}
|
||||||
|
{{- if $value.value }}
|
||||||
|
- name: {{ $value.name }}
|
||||||
|
value: {{ tpl $value.value $ }}
|
||||||
|
{{- else if $value.valueFrom }}
|
||||||
|
{{- if $value.valueFrom.secretKeyRef }}
|
||||||
|
- name: {{ $value.name }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ tpl $value.valueFrom.secretKeyRef.name $ }}
|
||||||
|
key: {{ tpl $value.valueFrom.secretKeyRef.key $ }}
|
||||||
|
{{- else if $value.valueFrom.configMapKeyRef }}
|
||||||
|
- name: {{ $value.name }}
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ }}
|
||||||
|
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
containerPort: 8008
|
containerPort: 8008
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.readinessProbe | nindent 12 }}
|
||||||
path: /health
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.livenessProbe | nindent 12 }}
|
||||||
path: /health
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
# The startup probe gates liveness/readiness. Synapse can take a
|
|
||||||
# while to start (migrations, cache warmup): budget 10s * 30 = 300s.
|
|
||||||
startupProbe:
|
startupProbe:
|
||||||
httpGet:
|
{{- toYaml .Values.matrix.startupProbe | nindent 12 }}
|
||||||
path: /health
|
|
||||||
port: http
|
|
||||||
scheme: HTTP
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 30
|
|
||||||
resources:
|
resources:
|
||||||
{{- include "matrix-synapse.resources" .Values.matrix.resources | nindent 12 }}
|
{{- include "matrix-synapse.resources" .Values.matrix.resources | nindent 12 }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
@@ -76,7 +73,13 @@ spec:
|
|||||||
- name: matrix-synapse-config-secret
|
- name: matrix-synapse-config-secret
|
||||||
mountPath: /data/homeserver.yaml
|
mountPath: /data/homeserver.yaml
|
||||||
subPath: homeserver.yaml
|
subPath: homeserver.yaml
|
||||||
|
# Scratch space so the read-only root filesystem never blocks
|
||||||
|
# temp-file writes (e.g. URL-preview downloads).
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
volumes:
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
- name: matrix-synapse-volume
|
- name: matrix-synapse-volume
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ .Release.Name }}-{{ .Chart.Name }}-pvc
|
claimName: {{ .Release.Name }}-{{ .Chart.Name }}-pvc
|
||||||
|
|||||||
+92
-10
@@ -4,13 +4,75 @@
|
|||||||
# Services stay in place; scaleDown: false brings the workloads back up.
|
# Services stay in place; scaleDown: false brings the workloads back up.
|
||||||
scaleDown: false
|
scaleDown: false
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
configSecretRef: null
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
# Replica count for this workload; 0 is allowed and scales it down.
|
# Replica count for this workload; 0 is allowed and scales it down.
|
||||||
# The chart-global scaleDown flag takes precedence.
|
# The chart-global scaleDown flag takes precedence.
|
||||||
replicas: 1
|
replicas: 1
|
||||||
serverName: null
|
serverName: null
|
||||||
timezone: UTC
|
timezone: UTC
|
||||||
configSecretRef: null
|
# The upstream image (ghcr.io/element-hq/synapse) only drops privileges
|
||||||
|
# itself (via gosu, driven by UID/GID env vars) when started as root; with
|
||||||
|
# an explicit non-root runAsUser it skips that step and runs directly as
|
||||||
|
# that user. Synapse writes to /data and /media_store (both on the PVC) and
|
||||||
|
# to /tmp (mounted as an emptyDir by the chart), so the root filesystem
|
||||||
|
# stays read-only. The uid/gid 1000 matches the previous gosu default, so
|
||||||
|
# existing PVC data stays accessible.
|
||||||
|
securityContext:
|
||||||
|
pod:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
fsGroupChangePolicy: Always
|
||||||
|
container:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
# The startup probe gates liveness/readiness. Synapse can take a
|
||||||
|
# while to start (migrations, cache warmup): budget 10s * 30 = 300s.
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 30
|
||||||
|
# Extra environment variables, appended to the ones the chart always sets.
|
||||||
|
# Values are rendered through tpl; value, secretKeyRef and configMapKeyRef
|
||||||
|
# forms are supported.
|
||||||
|
env: []
|
||||||
|
resources:
|
||||||
|
# Limits are optional: memory and ephemeral-storage limits default to
|
||||||
|
# limitFactor x the request, an explicitly set limit always wins, and a
|
||||||
|
# CPU limit is only set when configured explicitly under "limits".
|
||||||
|
limitFactor: 3
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1"
|
||||||
|
ephemeralStorage: "1Gi"
|
||||||
delegation:
|
delegation:
|
||||||
# Replica count for this workload; 0 is allowed and scales it down.
|
# Replica count for this workload; 0 is allowed and scales it down.
|
||||||
# The chart-global scaleDown flag takes precedence.
|
# The chart-global scaleDown flag takes precedence.
|
||||||
@@ -37,6 +99,31 @@ matrix:
|
|||||||
capabilities:
|
capabilities:
|
||||||
drop:
|
drop:
|
||||||
- ALL
|
- ALL
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /.well-known/matrix/server
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /.well-known/matrix/server
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
# The startup probe gates liveness/readiness. Startup budget = 5s * 30 = 150s.
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /.well-known/matrix/server
|
||||||
|
port: http
|
||||||
|
scheme: HTTP
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 30
|
||||||
resources:
|
resources:
|
||||||
# Limits are optional: memory and ephemeral-storage limits default to
|
# Limits are optional: memory and ephemeral-storage limits default to
|
||||||
# limitFactor x the request, an explicitly set limit always wins, and a
|
# limitFactor x the request, an explicitly set limit always wins, and a
|
||||||
@@ -46,15 +133,6 @@ matrix:
|
|||||||
memory: "64Mi"
|
memory: "64Mi"
|
||||||
cpu: "125m"
|
cpu: "125m"
|
||||||
ephemeralStorage: "50Mi"
|
ephemeralStorage: "50Mi"
|
||||||
resources:
|
|
||||||
# Limits are optional: memory and ephemeral-storage limits default to
|
|
||||||
# limitFactor x the request, an explicitly set limit always wins, and a
|
|
||||||
# CPU limit is only set when configured explicitly under "limits".
|
|
||||||
limitFactor: 3
|
|
||||||
requests:
|
|
||||||
memory: "1Gi"
|
|
||||||
cpu: "1"
|
|
||||||
ephemeralStorage: "1Gi"
|
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
amount: 10Gi
|
amount: 10Gi
|
||||||
@@ -63,3 +141,7 @@ storage:
|
|||||||
ingress:
|
ingress:
|
||||||
domain: null
|
domain: null
|
||||||
clusterIssuer: null
|
clusterIssuer: null
|
||||||
|
className: nginx
|
||||||
|
# Extra annotations for the Ingress; merged with the cert-manager
|
||||||
|
# cluster-issuer annotation the chart always sets.
|
||||||
|
annotations: {}
|
||||||
Reference in new issue
Block a user