diff --git a/dsf-podman-dev-setup/README.md b/dsf-podman-dev-setup/README.md new file mode 100644 index 000000000..41bca1b09 --- /dev/null +++ b/dsf-podman-dev-setup/README.md @@ -0,0 +1,290 @@ +# DSF Kube + +A rootless Podman setup for the Data Sharing Framework (DSF), designed as an intermediate step towards Kubernetes. It uses native Quadlet integration into systemd and Kubernetes-compatible YAML manifests. + +## Improvements over the original Docker Compose setup + +- Explicit registry prefix (e.g. `docker.io`) to avoid ambiguity +- More descriptive image tags (e.g. `postgres:18.3-alpine3.23`) +- Rootless Podman with user namespace isolation +- Engine-managed volumes instead of bind-mounts +- Fixed sysctl settings for the proxy container +- Official enterprise Linux support (SLES, RHEL, Ubuntu) +- Native init system integration via Quadlet instead of a central daemon + +## Additional requirements compared to the original setup + +- Podman >= 5.0 (Ubuntu 24+, SLES 16, RHEL 9+) +- `passt` (any version) +- Rootless service account with configured SubUIDs and SubGIDs + +## Preparation + +### Install dependencies + +```bash +# Ubuntu +apt install podman passt + +# SLES +zypper install podman passt + +# Alma Linux / RHEL +dnf install podman passt +``` + +### Allow unprivileged ports (required for the FHIR proxy on port 443) + +```bash +echo "net.ipv4.ip_unprivileged_port_start=80" > /etc/sysctl.d/99-user_priv_ports.conf +sysctl --system +``` + +### Create a service account + +To use a separate partition for application data, mount that partition on `/home` before creating the user. + +```bash +useradd -r -m -s /bin/bash podman + +# Add to systemd-journal group for log access +usermod -a -G systemd-journal podman + +# Configure SubUIDs and SubGIDs (adjust ranges for additional accounts) +usermod --add-subgids 100000-165536 --add-subuids 100000-165536 podman + +# Enable persistent user session (services survive logout) +loginctl enable-linger podman + +# Configure XDG_RUNTIME_DIR for rootless podman and systemd --user +cat >> /home/podman/.bashrc << 'EOF' +export XDG_RUNTIME_DIR=/run/user/$(id -u) +EOF + +# Switch into the service account context +sudo --login -u podman +``` + +--- + +## FHIR-Deployment + +### Secrets und Zertifikate + +Edit the certificate YAML files and insert the PEM contents: + +```bash +# Server certificate (Certificate A): SSL cert, key and chain +vi ./dsf-fhir/dsf-ssl-cert.yaml + +# Client certificate (Certificate B): used by the FHIR app to authenticate +vi ./dsf-fhir/dsf-client-cert.yaml +``` + +Generate and apply database passwords: + +```bash +# For using own passwords encode them as base64 and set them as env +export DB_LIQUIBASE_PASSWORD=$(openssl rand -base64 30 | tr -d '\n') +export DB_USER_PASSWORD=$(openssl rand -base64 16 | tr -d '\n') +export DB_USER_PERMANENT_DELETE_PASSWORD=$(openssl rand -base64 16 | tr -d '\n') + +envsubst < dsf-fhir/dsf-fhir-passwords.yaml.tpl > dsf-fhir-passwords.yaml +podman kube play dsf-fhir-passwords.yaml +rm dsf-fhir-passwords.yaml +``` + +### Install Quadlet units and create directories + +```bash +# Install Quadlet units +podman quadlet install ./dsf-fhir + +# Install systemd target +install -m 640 ./dsf-fhir.target ~/.config/systemd/user/dsf-fhir.target +``` + +### Configuration + +Edit the Kubernetes YAML and set the required environment variables: + +| Variable | Description | +| --------------------------------------------------- | --------------------------------------------------------------------- | +| `DEV_DSF_FHIR_SERVER_BASE_URL` | External FQDN of the FHIR server, e.g. `https://dsf.example.com/fhir` | +| `DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE` | Organization identifier, e.g. `dsf.example.com` | +| `DEV_DSF_FHIR_SERVER_ROLECONFIG` | Role configuration for browser and API access | +| `HTTPS_SERVER_NAME_PORT` | FQDN and port of the FHIR server, e.g. `dsf.example.com:443` | + +See the [FHIR server configuration reference](https://dsf.dev/operations/latest/fhir/configuration) for all available parameters. + +### Start and stop + +```bash +# Start +systemctl --user daemon-reload +systemctl --user enable --now dsf-fhir.target + +# Restart (e.g. after configuration changes or certificate renewal) +systemctl --user restart dsf-fhir.target + +# Stop +systemctl --user disable --now dsf-fhir.target +``` + +### Verify startup + +Check the logs for successful startup: + +```bash +journalctl --user -u dsf-app.service -f +``` + +Expected on successful startup: +- FHIR server is reachable and responding on port 443 +- Proxy presents the correct server certificate (Certificate A) + +Test TLS from a remote host: + +```bash +openssl s_client -connect dsf.example.com:443 +# Expected: server certificate shown, connection ends with: +# tlsv13 alert certificate required +``` + +--- + +## BPE Server Deployment + +### Secrets and certificates + +Edit the certificate YAML file: + +```bash +# Client certificate (Certificate B): same certificate as used by the FHIR server +vi ./dsf-bpe/dsf-client-cert.yaml +``` + +Generate and apply database passwords: + +```bash +# For using own passwords encode them as base64 and set them as env +export DB_LIQUIBASE_PASSWORD=$(openssl rand -base64 30 | tr -d '\n') +export DB_USER_PASSWORD=$(openssl rand -base64 16 | tr -d '\n') +export DB_USER_CAMUNDA=$(openssl rand -base64 16 | tr -d '\n') + +envsubst < dsf-bpe/dsf-bpe-passwords.yaml.tpl > dsf-bpe-passwords.yaml +podman kube play dsf-bpe-passwords.yaml +rm dsf-bpe-passwords.yaml +``` + +### Install Quadlet units and create directories + +```bash +# Install Quadlet units +podman quadlet install ./dsf-bpe + +# Install systemd target +install -m 640 ./dsf-bpe.target ~/.config/systemd/user/dsf-bpe.target + +# Create process plugin directory +mkdir -p ~/.config/dsf-bpe/process +podman unshare chown root:2202 ~/.config/dsf-bpe/process +podman unshare chmod 650 ~/.config/dsf-bpe/process +``` + +### Configuration + +Edit the Kubernetes YAML and set the required environment variables: + +| Variable | Description | +| ---------------------------------- | --------------------------------------------------------------------------------- | +| `DEV_DSF_BPE_FHIR_SERVER_BASE_URL` | Base URL of the corresponding FHIR server, e.g. `https://dsf.example.com/fhir` | +| `DEV_DSF_BPE_PROCESS_EXCLUDED` | Pipe-separated list of process IDs to exclude, e.g. `dsfdev_updateAllowList\|1.0` | + +See the [BPE server configuration reference](https://dsf.dev/operations/latest/bpe/configuration) for all available parameters. + +### Start and stop + +```bash +# Start +systemctl --user daemon-reload +systemctl --user enable --now dsf-bpe.target + +# Restart (e.g. after configuration changes or plugin updates) +systemctl --user restart dsf-bpe.target + +# Stop +systemctl --user disable --now dsf-bpe.target +``` + +### Verify startup + +```bash +journalctl --user -u dsf-bpe-app.service -f +``` + +Expected on successful startup: +- BPE downloaded Task resources from the DSF FHIR server +- BPE downloaded a Subscription resource from the DSF FHIR server +- BPE established a WebSocket connection to the DSF FHIR server + +If TLS issues occur, test the connection manually: + +```bash +podman run -it --rm alpine/openssl s_client dsf.example.com:443 +# Expected: server certificate shown, ends with tlsv13 alert certificate required +``` + +--- + +## Certificate renewal + +Both FHIR and BPE use certificate YAML files (`dsf-ssl-cert.yaml`, `dsf-client-cert.yaml`) that can be updated in place. After updating the PEM contents, restart the affected service: + +```bash +# FHIR proxy (server certificate) +systemctl --user restart dsf-proxy.service + +# FHIR app or BPE app (client certificate) +systemctl --user restart dsf-app.service +systemctl --user restart dsf-bpe-app.service +``` + +--- + +## Roadmap + +1. **Multiline config as mounted YAML** — Load Spring Boot configuration as a mounted `config.yaml` instead of environment variables for better readability of multiline values such as role configurations: + ```yaml + - name: spring-application-config + mountPath: /config + ``` + +2. **Unified naming** — Avoid duplicate names between BPE and FHIR to support single-instance dev setups. + +3. **Migrate to Deployments** — Replace `kind: Pod` with `kind: Deployment` (replicas: 1) for a smoother migration path to Kubernetes. + +4. **One secret per password** — Currently all DB passwords are bundled in a single Kubernetes Secret. Splitting them improves least-privilege access. + +5. **Unprivileged proxy port** — Find a solution that avoids the `net.ipv4.ip_unprivileged_port_start=80` sysctl requirement, e.g. by using a higher container port with host port mapping or a setcap-based approach. + +--- + +### Kubernetes Migration Notes + +The Kubernetes YAML files under `dsf-fhir` and `dsf-bpe` can be used as a starting point for a Kubernetes deployment with minor additions: + +- Add `namespace` to each resource +- Replace ConfigMap-based private keys with proper `kind: Secret` resources +- Replace `hostPort` with a proper `Service` of type `LoadBalancer` or `NodePort` +- Consider a sidecar or init container approach for process plugins +- Instead of deploying plugins as jar files via bind-mount, publish them as OCI images and mount them into the container. + +### Notes on certificate handling + +In this setup, certificate keys are provided as ConfigMaps. This has the following advantages in the Podman/Quadlet context: + +- Editable as plain text (PEM format) +- Reusable across multiple pods via the `--configmap` option in `podman kube play` + +In a production Kubernetes deployment, private keys should be stored as `kind: Secret` instead of ConfigMap to benefit from Kubernetes secret management, RBAC, and optional encryption at rest. diff --git a/dsf-podman-dev-setup/dsf-bpe-passwords.yaml.tpl b/dsf-podman-dev-setup/dsf-bpe-passwords.yaml.tpl new file mode 100644 index 000000000..4e1b12258 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe-passwords.yaml.tpl @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: dsf-bpe-passwords +stringData: + db_liquibase.password: "${DB_LIQUIBASE_PASSWORD}" + db_user.password: "${DB_USER_PASSWORD}" + db_user_camunda.password: "${DB_USER_CAMUNDA}" \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-bpe.target b/dsf-podman-dev-setup/dsf-bpe.target new file mode 100644 index 000000000..8e27441bb --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe.target @@ -0,0 +1,7 @@ +[Unit] +Description=DSF FHIR Server +Wants=dsf-bpe-app.service +After=dsf-bpe-app.service + +[Install] +WantedBy=default.target diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-backend.network b/dsf-podman-dev-setup/dsf-bpe/dsf-backend.network new file mode 100644 index 000000000..dc672fa89 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-backend.network @@ -0,0 +1,2 @@ +[Network] +NetworkName=dsf-backend \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.kube b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.kube new file mode 100644 index 000000000..9297ce780 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.kube @@ -0,0 +1,16 @@ +[Unit] +Description=DSF BPE Application +PartOf=dsf-bpe.target +After=dsf-bpe-db.service +Wants=dsf-db.service + +[Kube] +Yaml=%h/.config/containers/systemd/dsf-bpe-app.yaml +ConfigMap=%h/.config/containers/systemd/dsf-client-cert.yaml +Network=dsf-bpe-backend.network + +[Service] +Restart=on-failure + +[Install] +WantedBy=dsf-bpe.target \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.yaml b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.yaml new file mode 100644 index 000000000..062eed9b9 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-app.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: dsf-bpe-cache + annotations: + volume.podman.io/uid: "0" + volume.podman.io/gid: "2202" + volume.podman.io/mount-options: "uid=0,gid=2202,mode=0770" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: dsf-bpe-config +data: + TZ: "Europe/Berlin" + DEV_DSF_BPE_DB_URL: "jdbc:postgresql://dsf-bpe-db/bpe" + DEV_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE: "/run/secrets/db/db_liquibase.password" + DEV_DSF_BPE_DB_USER_PASSWORD_FILE: "/run/secrets/db/db_user.password" + DEV_DSF_BPE_DB_USER_ENGINE_PASSWORD_FILE: "/run/secrets/db/db_user_camunda.password" + DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE: "/run/secrets/cert/client_certificate.pem" + DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: "/run/secrets/cert/client_certificate_private_key.pem" + DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: "/run/secrets/cert/client_certificate_private_key.pem.password" + # TODO specify the base url of this DSF FHIR server + DEV_DSF_BPE_FHIR_SERVER_BASE_URL: "https://dsf.todo.organization.com/fhir" + # DEV_DSF_BPE_PROCESS_EXCLUDED: | + # dsfdev_updateAllowList|1.0 +--- +apiVersion: v1 +kind: Pod +metadata: + name: dsf-bpe-app + labels: + app: dsf-bpe-app +spec: + restartPolicy: OnFailure + containers: + - name: dsf-bpe-app + image: ghcr.io/datasharingframework/bpe:2.1.0 + envFrom: + - configMapRef: + name: dsf-bpe-config + volumeMounts: + - name: db-passwords + mountPath: /run/secrets/db + readOnly: true + - name: client-cert + mountPath: /run/secrets/cert + readOnly: true + - name: bpe-process + mountPath: /opt/bpe/process + readOnly: true + - name: bpe-cache + mountPath: /opt/bpe/cache + volumes: + - name: bpe-process + hostPath: + path: /home/podman/.config/dsf-bpe/process + type: Directory + - name: db-passwords + secret: + secretName: dsf-bpe-passwords + - name: client-cert + configMap: + name: dsf-client-cert + - name: bpe-cache + persistentVolumeClaim: + claimName: dsf-bpe-cache diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.kube b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.kube new file mode 100644 index 000000000..1ff6aefb3 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.kube @@ -0,0 +1,13 @@ +[Unit] +Description=DSF BPE Database +PartOf=dsf-bpe.target + +[Kube] +Yaml=%h/.config/containers/systemd/dsf-bpe-db.yaml +Network=dsf-backend.network + +[Service] +Restart=on-failure + +[Install] +WantedBy=dsf-bpe.target diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.yaml b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.yaml new file mode 100644 index 000000000..8a0fe07eb --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-bpe-db.yaml @@ -0,0 +1,63 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: dsf-bpe-db-data + annotations: + volume.podman.io/driver: local + volume.podman.io/uid: "70" + volume.podman.io/gid: "70" + volume.podman.io/mount-options: "uid=70,gid=70,mode=0770" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: Pod +metadata: + name: dsf-bpe-db + labels: + app: dsf-bpe-db +spec: + restartPolicy: OnFailure + containers: + - name: dsf-bpe-db + image: docker.io/library/postgres:18.4-alpine3.23 + env: + - name: TZ + value: Europe/Berlin + - name: POSTGRES_USER + value: liquibase_user + - name: POSTGRES_DB + value: bpe + - name: POSTGRES_PASSWORD_FILE + value: /run/secrets/db_liquibase.password + livenessProbe: + exec: + command: + - pg_isready + - -U + - liquibase_user + - -d + - bpe + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 5 + volumeMounts: + - name: db-data + mountPath: /var/lib/postgresql + - name: db-passwords + mountPath: /run/secrets/db_liquibase.password + subPath: db_liquibase.password + readOnly: true + volumes: + - name: db-data + persistentVolumeClaim: + claimName: dsf-bpe-db-data + - name: db-passwords + secret: + secretName: dsf-bpe-passwords diff --git a/dsf-podman-dev-setup/dsf-bpe/dsf-client-cert.yaml b/dsf-podman-dev-setup/dsf-bpe/dsf-client-cert.yaml new file mode 100644 index 000000000..edbaad91e --- /dev/null +++ b/dsf-podman-dev-setup/dsf-bpe/dsf-client-cert.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: dsf-client-cert +data: + client_certificate.pem: | + -----BEGIN CERTIFICATE----- + MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw + ... + -----END CERTIFICATE----- + client_certificate_private_key.pem: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + client_certificate_private_key.pem.password: "dein-passwort" diff --git a/dsf-podman-dev-setup/dsf-fhir-passwords.yaml.tpl b/dsf-podman-dev-setup/dsf-fhir-passwords.yaml.tpl new file mode 100644 index 000000000..40afe8167 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir-passwords.yaml.tpl @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: dsf-fhir-passwords +stringData: + db_liquibase.password: "${DB_LIQUIBASE_PASSWORD}" + db_user.password: "${DB_USER_PASSWORD}" + db_user_permanent_delete.password: "${DB_USER_PERMANENT_DELETE_PASSWORD}" \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir.target b/dsf-podman-dev-setup/dsf-fhir.target new file mode 100644 index 000000000..2903ded98 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir.target @@ -0,0 +1,7 @@ +[Unit] +Description=DSF FHIR Server +Wants=dsf-proxy.service +After=dsf-proxy.service + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-app.kube b/dsf-podman-dev-setup/dsf-fhir/dsf-app.kube new file mode 100644 index 000000000..0af71d7b9 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-app.kube @@ -0,0 +1,16 @@ +[Unit] +Description=DSF FHIR App +After=dsf-db.service +Wants=dsf-db.service +PartOf=dsf-fhir.target + +[Kube] +Yaml=%h/.config/containers/systemd/dsf-app.yaml +ConfigMap=%h/.config/containers/systemd/dsf-client-cert.yaml +Network=dsf-backend.network + +[Service] +Restart=on-failure + +[Install] +WantedBy=dsf-fhir.target \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-app.yaml b/dsf-podman-dev-setup/dsf-fhir/dsf-app.yaml new file mode 100644 index 000000000..3cdb46e8c --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-app.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: dsf-fhir-config +data: + TZ: "Europe/Berlin" + DEV_DSF_FHIR_DB_URL: "jdbc:postgresql://dsf-db/fhir" + DEV_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE: "/run/secrets/db/db_liquibase.password" + DEV_DSF_FHIR_DB_USER_PASSWORD_FILE: "/run/secrets/db/db_user.password" + DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE: "/run/secrets/db/db_user_permanent_delete.password" + DEV_DSF_FHIR_CLIENT_CERTIFICATE: "/run/secrets/cert/client_certificate.pem" + DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY: "/run/secrets/cert/client_certificate_private_key.pem" + DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: "/run/secrets/cert/client_certificate_private_key.pem.password" + DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: "todo.organization.com" + # TODO specify the base url of this DSF FHIR server + DEV_DSF_FHIR_SERVER_BASE_URL: "https://dsf.todo.organization.com/fhir" + # TODO specify the SHA-512 thumbprint of the Client-Certificate as lower case HEX (Regex: ^[a-f0-9]{128}$) + # certtool --fingerprint --hash=sha512 --infile=client_certificate.pem + # or simply get it from allowlist management tool + DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: "" + # TODO specify role configuration to allow access to the UI via web-browser or REST API for specific users, see documentation at dsf.dev + DEV_DSF_FHIR_SERVER_ROLECONFIG: | + "" +--- +apiVersion: v1 +kind: Pod +metadata: + name: dsf-app + labels: + app: dsf-app-pod +spec: + restartPolicy: OnFailure + containers: + - name: dsf-app + image: ghcr.io/datasharingframework/fhir:2.1.0 + envFrom: + - configMapRef: + name: dsf-fhir-config + volumeMounts: + - name: db-passwords + mountPath: /run/secrets/db + readOnly: true + - name: client-cert + mountPath: /run/secrets/cert + readOnly: true + + volumes: + - name: db-passwords + secret: + secretName: dsf-fhir-passwords + - name: client-cert + configMap: + name: dsf-client-cert diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-backend.network b/dsf-podman-dev-setup/dsf-fhir/dsf-backend.network new file mode 100644 index 000000000..dc672fa89 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-backend.network @@ -0,0 +1,2 @@ +[Network] +NetworkName=dsf-backend \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-client-cert.yaml b/dsf-podman-dev-setup/dsf-fhir/dsf-client-cert.yaml new file mode 100644 index 000000000..edbaad91e --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-client-cert.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: dsf-client-cert +data: + client_certificate.pem: | + -----BEGIN CERTIFICATE----- + MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw + ... + -----END CERTIFICATE----- + client_certificate_private_key.pem: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + client_certificate_private_key.pem.password: "dein-passwort" diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-db.kube b/dsf-podman-dev-setup/dsf-fhir/dsf-db.kube new file mode 100644 index 000000000..460405bfa --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-db.kube @@ -0,0 +1,13 @@ +[Unit] +Description=DSF FHIR DB +PartOf=dsf-fhir.target + +[Kube] +Yaml=%h/.config/containers/systemd/dsf-db.yaml +Network=dsf-backend.network + +[Service] +Restart=on-failure + +[Install] +WantedBy=dsf-fhir.target diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-db.yaml b/dsf-podman-dev-setup/dsf-fhir/dsf-db.yaml new file mode 100644 index 000000000..35030b000 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-db.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: dsf-db-data + annotations: + volume.podman.io/driver: local + volume.podman.io/gid: "70" + volume.podman.io/uid: "70" + volume.podman.io/mount-options: "uid=70,gid=70,mode=0770" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: dsf-db + name: dsf-db +spec: + containers: + - image: docker.io/library/postgres:18.4-alpine3.23 + name: dsf-db + livenessProbe: + exec: + command: + - pg_isready + - -U + - liquibase_user + - -d + - fhir + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 5 + env: + - name: POSTGRES_DB + value: fhir + - name: POSTGRES_PASSWORD_FILE + value: /run/secrets/db_liquibase.password + - name: POSTGRES_USER + value: liquibase_user + - name: TZ + value: Europe/Berlin + volumeMounts: + - mountPath: /var/lib/postgresql + name: postgres-data-pvc + - name: db-passwords + mountPath: /run/secrets/db_liquibase.password + subPath: db_liquibase.password + readOnly: true + volumes: + - name: postgres-data-pvc + persistentVolumeClaim: + claimName: dsf-db-data + - name: db-passwords + secret: + secretName: dsf-fhir-passwords \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-frontend.network b/dsf-podman-dev-setup/dsf-fhir/dsf-frontend.network new file mode 100644 index 000000000..8bf0a4829 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-frontend.network @@ -0,0 +1,2 @@ +[Network] +NetworkName=dsf-frontend \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.kube b/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.kube new file mode 100644 index 000000000..d0227e3d8 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.kube @@ -0,0 +1,16 @@ +[Unit] +Description=DSF FHIR Proxy +PartOf=dsf-fhir.target +After=dsf-app.service + +[Kube] +Yaml=%h/.config/containers/systemd/dsf-proxy.yaml +ConfigMap=%h/.config/containers/systemd/dsf-ssl-cert.yaml +Network=dsf-frontend.network +Network=dsf-backend.network + +[Service] +Restart=on-failure + +[Install] +WantedBy=dsf-fhir.target \ No newline at end of file diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.yaml b/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.yaml new file mode 100644 index 000000000..1e7bad633 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-proxy.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: v1 +kind: Pod +metadata: + name: dsf-proxy + labels: + app: dsf-proxy +spec: + restartPolicy: OnFailure + securityContext: + sysctls: + - name: net.ipv4.ip_unprivileged_port_start + value: "80" + containers: + - name: dsf-proxy + image: ghcr.io/datasharingframework/fhir_proxy:2.1.0 + env: + - name: TZ + value: Europe/Berlin + - name: APP_SERVER_IP + value: dsf-app + - name: HTTPS_SERVER_NAME_PORT + value: "dsf.todo.organization.com:443" + - name: SSL_CERTIFICATE_FILE + value: /run/secrets/ssl_certificate_file.pem + - name: SSL_CERTIFICATE_KEY_FILE + value: /run/secrets/ssl_certificate_key_file.pem + - name: SSL_CERTIFICATE_CHAIN_FILE + value: /run/secrets/ssl_certificate_chain_file.pem + ports: + - containerPort: 443 + hostPort: 443 + volumeMounts: + - name: ssl-cert + mountPath: /run/secrets + readOnly: true + volumes: + - name: ssl-cert + configMap: + name: dsf-ssl-cert diff --git a/dsf-podman-dev-setup/dsf-fhir/dsf-ssl-cert.yaml b/dsf-podman-dev-setup/dsf-fhir/dsf-ssl-cert.yaml new file mode 100644 index 000000000..0c0500497 --- /dev/null +++ b/dsf-podman-dev-setup/dsf-fhir/dsf-ssl-cert.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: dsf-ssl-cert +data: + ssl_certificate_file.pem: | + -----BEGIN CERTIFICATE----- + MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw + ... + -----END CERTIFICATE----- + ssl_certificate_chain_file.pem: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + ssl_certificate_key_file.pem: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE-----