--- 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) 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 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. If you use our [Ansible role](./deploy.md) for deployment then these will be automatically configured. 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 bridge-worker.service -.-> bridge-whatsapp.service bridge-worker.service -.-> signal-cli-rest-api.service 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 ``` All of the containers are built from the same [source repository](https://gitlab.com/digiresilience/link/link-stack) and published in a public registry: | Container Name | Image | |-----------------------|------------------------------------------------------------------------------------| | 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` | | zammad-opensearch | `registry.gitlab.com/digiresilience/link/link-stack/opensearch:3.2.0b2` | | 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` |