Sync chart from pieced-threema-gateway 0.1.1

This commit is contained in:
2026-05-16 20:52:10 +00:00
commit 1d88033575
8 changed files with 380 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
apiVersion: v2
name: pieced-threema-gateway
description: PieCed IT central Threema Gateway relay
type: application
version: 0.1.1
appVersion: "0.1.1"

View File

@@ -0,0 +1,20 @@
{{- if .Values.postgres.enabled }}
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pieced-threema-gateway-db
namespace: {{ .Values.namespace }}
spec:
instances: {{ .Values.postgres.instances }}
bootstrap:
initdb:
database: relay
owner: relay
storage:
size: {{ .Values.postgres.storage.size }}
storageClass: {{ .Values.postgres.storage.storageClass }}
resources:
{{- toYaml .Values.postgres.resources | nindent 4 }}
monitoring:
enablePodMonitor: true
{{- end }}

View File

@@ -0,0 +1,80 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: pieced-threema-gateway
namespace: {{ .Values.namespace }}
labels:
app.kubernetes.io/name: pieced-threema-gateway
app.kubernetes.io/managed-by: helm
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app.kubernetes.io/name: pieced-threema-gateway
template:
metadata:
labels:
app.kubernetes.io/name: pieced-threema-gateway
spec:
serviceAccountName: pieced-threema-gateway
containers:
- name: relay
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8080
- name: metrics
containerPort: 9090
env:
- name: LISTEN_HOST
value: "0.0.0.0"
- name: LISTEN_PORT
value: "8080"
- name: METRICS_PORT
value: "9090"
- name: LOG_LEVEL
value: {{ .Values.logLevel | quote }}
- name: OPENCLAW_URL_TEMPLATE
value: {{ .Values.openclawUrlTemplate | quote }}
- name: FORWARD_TIMEOUT_MS
value: {{ .Values.forwardTimeoutMs | quote }}
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: pieced-threema-gateway-db-app
key: uri
- name: THREEMA_API_IDENTITY
valueFrom:
secretKeyRef:
name: threema-credentials
key: api-identity
- name: THREEMA_API_SECRET
valueFrom:
secretKeyRef:
name: threema-credentials
key: api-secret
- name: THREEMA_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: threema-credentials
key: private-key
- name: ADMIN_TOKEN
valueFrom:
secretKeyRef:
name: threema-admin-token
key: token
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /readyz
port: http
initialDelaySeconds: 3
periodSeconds: 10
resources:
{{- toYaml .Values.resources | nindent 12 }}

View File

@@ -0,0 +1,45 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: threema-credentials
namespace: {{ .Values.namespace }}
spec:
refreshInterval: 1h
secretStoreRef:
name: openbao-backend
kind: ClusterSecretStore
target:
name: threema-credentials
creationPolicy: Owner
data:
- secretKey: api-identity
remoteRef:
key: {{ .Values.secrets.threemaPath }}
property: api-identity
- secretKey: api-secret
remoteRef:
key: {{ .Values.secrets.threemaPath }}
property: api-secret
- secretKey: private-key
remoteRef:
key: {{ .Values.secrets.threemaPath }}
property: private-key
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: threema-admin-token
namespace: {{ .Values.namespace }}
spec:
refreshInterval: 1h
secretStoreRef:
name: openbao-backend
kind: ClusterSecretStore
target:
name: threema-admin-token
creationPolicy: Owner
data:
- secretKey: token
remoteRef:
key: {{ .Values.secrets.adminTokenPath }}
property: token

View File

@@ -0,0 +1,37 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: pieced-threema-gateway
namespace: {{ .Values.namespace }}
annotations:
{{- if .Values.ingress.tls.enabled }}
cert-manager.io/cluster-issuer: {{ .Values.ingress.tls.issuer | quote }}
{{- end }}
# Threema's outbound webhook IPs are publicly documented as the
# standard Threema infrastructure. Lock down if you want to be strict;
# otherwise leave open since the MAC check is the real security gate.
nginx.ingress.kubernetes.io/proxy-body-size: "128k"
nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
spec:
ingressClassName: {{ .Values.ingress.className }}
{{- if .Values.ingress.tls.enabled }}
tls:
- hosts:
- {{ .Values.ingress.host }}
secretName: {{ .Values.ingress.tls.secretName }}
{{- end }}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
# Threema's CDN only ever hits /webhooks/threema. Don't expose
# /admin or /api from the internet — those go cluster-internal only.
- path: /webhooks/threema
pathType: Exact
backend:
service:
name: pieced-threema-gateway
port:
number: {{ .Values.service.port }}
{{- end }}

View File

@@ -0,0 +1,87 @@
{{- if .Values.networkPolicy.enabled }}
# =============================================================================
# Ingress: who can talk to the relay
# =============================================================================
# Three sources:
# 1. The cluster Ingress controller (nginx-ingress) — for Threema webhooks
# hitting us through the LB.
# 2. The portal namespace — calls /admin and reads /metrics.
# 3. Tenant namespaces (managed by pieced-operator) — call /api/send.
#
# Egress:
# - DNS (kube-system)
# - Threema Gateway: msgapi.threema.ch:443 (FQDN-pinned)
# - Postgres in same namespace
# - HTTPS to tenant OpenClaw services in tenant namespaces (port 18789)
# =============================================================================
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: pieced-threema-gateway
namespace: {{ .Values.namespace }}
spec:
endpointSelector:
matchLabels:
app.kubernetes.io/name: pieced-threema-gateway
ingress:
# nginx-ingress
- fromEndpoints:
- matchLabels:
"k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": "ingress-nginx"
toPorts:
- ports:
- port: "8080"
protocol: TCP
# Portal
- fromEndpoints:
- matchLabels:
"k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": {{ .Values.networkPolicy.portalNamespace | quote }}
toPorts:
- ports:
- port: "8080"
protocol: TCP
- port: "9090"
protocol: TCP
# Tenant namespaces (pieced-operator-managed)
- fromEndpoints:
- matchLabels:
{{ .Values.networkPolicy.tenantNamespaceLabel | quote }}: {{ .Values.networkPolicy.tenantNamespaceLabelValue | quote }}
toPorts:
- ports:
- port: "8080"
protocol: TCP
egress:
# DNS
- toEndpoints:
- matchLabels:
"k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name": "kube-system"
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCP
# Threema Gateway public API
- toFQDNs:
- matchName: "msgapi.threema.ch"
toPorts:
- ports:
- port: "443"
protocol: TCP
# Postgres (same namespace)
- toEndpoints:
- matchLabels:
"cnpg.io/cluster": "pieced-threema-gateway-db"
toPorts:
- ports:
- port: "5432"
protocol: TCP
# Tenant OpenClaw services — port 18789, any tenant namespace
- toEndpoints:
- matchLabels:
{{ .Values.networkPolicy.tenantNamespaceLabel | quote }}: {{ .Values.networkPolicy.tenantNamespaceLabelValue | quote }}
toPorts:
- ports:
- port: "18789"
protocol: TCP
{{- end }}

View File

@@ -0,0 +1,26 @@
apiVersion: v1
kind: Service
metadata:
name: pieced-threema-gateway
namespace: {{ .Values.namespace }}
labels:
app.kubernetes.io/name: pieced-threema-gateway
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: pieced-threema-gateway
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: 8080
protocol: TCP
- name: metrics
port: {{ .Values.service.metricsPort }}
targetPort: 9090
protocol: TCP
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: pieced-threema-gateway
namespace: {{ .Values.namespace }}

View File

@@ -0,0 +1,79 @@
# =============================================================================
# pieced-threema-gateway Helm values
# =============================================================================
namespace: threema-gateway
image:
repository: git.c5ai.ch/pieced/pieced-threema-gateway
tag: "0.1.1"
pullPolicy: IfNotPresent
replicas: 1
service:
port: 8080
metricsPort: 9090
# Internet-facing ingress so Threema's CDN can POST webhooks.
# DNS must resolve threemaGw.host to your cluster's LB IP.
ingress:
enabled: true
className: nginx
host: threema-gw.pieced.ch
tls:
enabled: true
# cert-manager ClusterIssuer name — matches the rest of pieced-gitops
issuer: letsencrypt-production
secretName: threema-gw-tls
# CloudNativePG cluster created in-chart, mirrors portal-db pattern.
postgres:
enabled: true
instances: 1
storage:
size: 5Gi
storageClass: longhorn-luks2
resources:
requests:
cpu: 100m
memory: 256Mi
# Secrets sourced from OpenBao via External Secrets Operator.
# Paths use the same convention as apps/portal/external-secrets.yaml:
# full key path starting with the KV v2 mount name (`secret/`), no
# `/data/` segment — ESO with the openbao-backend ClusterSecretStore
# rewrites that automatically for KV v2 paths.
secrets:
# Threema Gateway credentials — PieCed-wide, one identity for the platform.
threemaPath: secret/threema-gateway/credentials
# Admin token shared with pieced-portal.
adminTokenPath: secret/threema-gateway/admin
# Template for inbound delivery to tenant OpenClaw instances. Verify your
# OpenClaw operator's Service naming before deploy.
openclawUrlTemplate: http://openclaw.tenant-{tenant}.svc.cluster.local:18789/webhooks/threema-relay
forwardTimeoutMs: 8000
logLevel: info
# Resources for the relay pod
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# CiliumNetworkPolicy — restricts who can talk in and out.
networkPolicy:
enabled: true
# Tenant namespaces are matched by label set by the operator.
# Cedric's pieced-operator sets pieced.ch/managed-by=pieced-operator
# on every tenant namespace it provisions.
tenantNamespaceLabel: "k8s:io.cilium.k8s.namespace.labels.pieced.ch/managed-by"
tenantNamespaceLabelValue: "pieced-operator"
# The portal pod runs in this namespace (per apps/portal in pieced-gitops).
portalNamespace: pieced-system