2025-11-09 12:07:04 +00:00
|
|
|
---
|
|
|
|
|
sidebar_position: 10
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# Architecture
|
|
|
|
|
|
|
|
|
|
We begin the guide with a high-level overview of the architecture of the CDR Link deployment framework.
|
|
|
|
|
|
|
|
|
|
## Introduction
|
|
|
|
|
|
|
|
|
|
We deploy each CDR Link instance on a single
|
|
|
|
|
[Red Had Enterprise Linux](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux)
|
|
|
|
|
9 (or compatible) host using
|
|
|
|
|
[rootless Podman](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md).
|
|
|
|
|
Each component of Link is a container instance with the containers managed via systemd using
|
|
|
|
|
[Podman Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html).
|
|
|
|
|
Components communicate via isolated networks that are also configured via Quadlet, and make use of the
|
|
|
|
|
[slirp4netns](https://github.com/rootless-containers/slirp4netns) user-mode networking for unprivileged
|
|
|
|
|
network namespaces.
|
|
|
|
|
|
|
|
|
|
Both
|
|
|
|
|
[discretionary access controls](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_basic_system_settings/managing-file-system-permissions_configuring-basic-system-settings)
|
2025-11-09 14:39:28 +00:00
|
|
|
and
|
|
|
|
|
[SELinux](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html-single/using_selinux/index)
|
|
|
|
|
are used to prevent lateral movement between containers should a container be compromised, with particular
|
2025-11-09 12:07:04 +00:00
|
|
|
attention given to the messaging channels WhatsApp and Signal.
|
|
|
|
|
No container runs its application as the inside "root" user, which is an unprivileged user on the host.
|
|
|
|
|
|
|
|
|
|
The `/home` mount point on the host is encrypted using
|
|
|
|
|
[LUKS](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/managing_storage_devices/encrypting-block-devices-using-luks_managing-storage-devices)
|
|
|
|
|
with a per instance key to protect all user data at rest.
|
|
|
|
|
Further, we use separate partitions for critical audit logging to ensure that a resource exhaustion attack cannot
|
|
|
|
|
prevent later investigation, and automatically shut down instances where there is no space available for audit logging.
|
|
|
|
|
|
|
|
|
|
## Components
|
|
|
|
|
|
|
|
|
|
The following diagram shows the dependency relationships between the components of CDR Link.
|
2025-11-09 14:39:28 +00:00
|
|
|
If you use our [Ansible role](./deploy.md) for deployment then these will be automatically configured.
|
2025-11-09 12:07:04 +00:00
|
|
|
The Link stack containers are
|
|
|
|
|
[OCI](https://opencontainers.org/) compliant containers and you can run these with alternatives
|
|
|
|
|
such as [Docker Compose](https://docs.docker.com/compose/) however we would not be able to provide support for this
|
|
|
|
|
setup.
|
|
|
|
|
Our former Docker Compose deployment framework has been deprecated and we intend to migrate all partners to our new
|
|
|
|
|
rootless Podman setup for the improved reliability, performance, and security.
|
|
|
|
|
|
|
|
|
|
:::info
|
|
|
|
|
While the following diagram refers to `.service` units, these are the units generated by Podman Quadlet.
|
|
|
|
|
The service definitions are in `.container` units within the Quadlet directory at `$HOME/.config/containers/systemd`.
|
|
|
|
|
:::
|
|
|
|
|
```mermaid
|
|
|
|
|
flowchart TD
|
|
|
|
|
bridge-worker.service --> bridge-postgresql.service
|
2025-11-09 14:39:28 +00:00
|
|
|
bridge-worker.service -.-> bridge-whatsapp.service
|
|
|
|
|
bridge-worker.service -.-> signal-cli-rest-api.service
|
2025-11-09 12:07:04 +00:00
|
|
|
|
|
|
|
|
link.service --> bridge-postgresql.service
|
|
|
|
|
link.service --> bridge-worker.service
|
|
|
|
|
|
|
|
|
|
opensearch-dashboards.service --> zammad-opensearch.service
|
|
|
|
|
|
|
|
|
|
zammad-nginx.service --> zammad-railsserver.service
|
|
|
|
|
zammad-nginx.service --> link.service
|
|
|
|
|
|
|
|
|
|
zammad-storage.target{zammad-storage.target}
|
|
|
|
|
zammad-storage.target --> zammad-postgresql.service
|
|
|
|
|
zammad-storage.target --> zammad-redis.service
|
|
|
|
|
zammad-storage.target --> zammad-memcached.service
|
|
|
|
|
zammad-storage.target --> zammad-opensearch.service
|
|
|
|
|
|
|
|
|
|
zammad-railsserver.service -.-> zammad-init.service
|
|
|
|
|
|
|
|
|
|
zammad-init.service --> zammad-storage.target
|
|
|
|
|
zammad-railsserver.service --> zammad-storage.target
|
|
|
|
|
zammad-scheduler.service --> zammad-storage.target
|
|
|
|
|
zammad-websocket.service --> zammad-storage.target
|
|
|
|
|
|
|
|
|
|
link.target{link.target}
|
|
|
|
|
link.target --> opensearch-dashboards.service
|
|
|
|
|
link.target --> zammad-nginx.service
|
|
|
|
|
link.target --> zammad-scheduler.service
|
|
|
|
|
link.target --> zammad-websocket.service
|
2025-11-09 15:45:14 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
All of the containers are built from the same [source repository](https://gitlab.com/digiresilience/link/link-stack)
|
|
|
|
|
and published in a public registry:
|
|
|
|
|
|
2025-11-12 12:05:12 +00:00
|
|
|
| Container Name | Image |
|
|
|
|
|
|-----------------------|-----------------------------------------------------------------------------------|
|
2025-11-09 15:45:14 +00:00
|
|
|
| bridge-postgresql | `registry.gitlab.com/digiresilience/link/link-stack/postgresql:latest` |
|
|
|
|
|
| bridge-whatsapp | `registry.gitlab.com/digiresilience/link/link-stack/bridge-whatsapp:latest` |
|
|
|
|
|
| bridge-worker | `registry.gitlab.com/digiresilience/link/link-stack/bridge-worker:latest` |
|
|
|
|
|
| link | `registry.gitlab.com/digiresilience/link/link-stack/link:latest` |
|
|
|
|
|
| opensearch-dashboards | `registry.gitlab.com/digiresilience/link/link-stack/opensearch-dashboards:latest` |
|
|
|
|
|
| signal-cli-rest-api | `registry.gitlab.com/digiresilience/link/link-stack/signal-cli-rest-api:latest` |
|
|
|
|
|
| zammad-init | `registry.gitlab.com/digiresilience/link/link-stack/zammad:latest` |
|
|
|
|
|
| zammad-memcached | `registry.gitlab.com/digiresilience/link/link-stack/memcached:latest` |
|
|
|
|
|
| zammad-nginx | `registry.gitlab.com/digiresilience/link/link-stack/zammad:latest` |
|
2025-11-12 12:05:12 +00:00
|
|
|
| zammad-opensearch | `registry.gitlab.com/digiresilience/link/link-stack/opensearch:latest` |
|
2025-11-09 15:45:14 +00:00
|
|
|
| zammad-postgresql | `registry.gitlab.com/digiresilience/link/link-stack/postgresql:latest` |
|
|
|
|
|
| zammad-railsserver | `registry.gitlab.com/digiresilience/link/link-stack/zammad:latest` |
|
|
|
|
|
| zammad-redis | `registry.gitlab.com/digiresilience/link/link-stack/redis:latest` |
|
|
|
|
|
| zammad-scheduler | `registry.gitlab.com/digiresilience/link/link-stack/zammad:latest` |
|
|
|
|
|
| zammad-websocket | `registry.gitlab.com/digiresilience/link/link-stack/zammad:latest` |
|