Compare commits

...

4 commits

Author SHA1 Message Date
irl
e79576cd73 feat(podman_link): configure xfs quotas for channel container data directories
Some checks failed
Ansible Lint Check / lint (push) Failing after 52s
2025-12-04 17:26:56 +00:00
irl
d6bc8a48a8 feat(podman_link): enable opensearch-dashboards
Fixes: #5
2025-12-04 17:26:12 +00:00
irl
b6ddf7bcac feat(podman_link): exclude more attachment types when indexing opensearch
Ref: #8
2025-12-03 16:07:57 +00:00
irl
65fcca88f5 feat(podman_link): split up container networks for isolation
Fixes: #4
2025-12-03 16:07:57 +00:00
19 changed files with 145 additions and 25 deletions

View file

@ -68,6 +68,18 @@
notify: notify:
- Restart Link - Restart Link
# Opensearch Dashboards runs with UID/GID 1000 inside the container
- name: Podman CDR Link | PATCH | Install Opensearch Dashboards configuration
ansible.builtin.template:
src: home/opensearch-dashboards.yml
dest: "/home/{{ podman_link_podman_rootless_user }}/opensearch-dashboards.yml"
mode: "0400"
owner: "{{ _podman_link_user_subuid_start + 999 }}"
group: "{{ _podman_link_user_subgid_start + 999 }}"
become: true
notify:
- Restart Link
# Zammad runs with UID/GID 1000 inside the container # Zammad runs with UID/GID 1000 inside the container
- name: Podman CDR Link | PATCH | Install Zammad database configuration file - name: Podman CDR Link | PATCH | Install Zammad database configuration file
ansible.builtin.template: ansible.builtin.template:
@ -96,16 +108,6 @@
- zammad-data - zammad-data
- zammad-config-nginx - zammad-config-nginx
# Bridge/Link runs with UID/GID 1000 inside the container (because it's based on the node container)
- name: Podman CDR Link | PATCH | Create data directory for bridge-whatsapp
ansible.builtin.file:
path: "/home/{{ podman_link_podman_rootless_user }}/bridge-whatsapp-data"
owner: "{{ _podman_link_user_subuid_start + 999 }}"
group: "{{ _podman_link_user_subgid_start + 999 }}"
mode: "0700"
state: "directory"
become: true
# Postgres/Redis runs with UID/GID 999 inside the container # Postgres/Redis runs with UID/GID 999 inside the container
# Postgres seems to want to set group permissions on the data directory, which is probably fine # Postgres seems to want to set group permissions on the data directory, which is probably fine
- name: Podman CDR Link | PATCH | Create data directory for PostgreSQL and Redis - name: Podman CDR Link | PATCH | Create data directory for PostgreSQL and Redis
@ -121,6 +123,16 @@
- redis-data - redis-data
- postgresql-data - postgresql-data
# Bridge/Link runs with UID/GID 1000 inside the container (because it's based on the node container)
- name: Podman CDR Link | PATCH | Create data directory for bridge-whatsapp
ansible.builtin.file:
path: "/home/{{ podman_link_podman_rootless_user }}/bridge-whatsapp-data"
owner: "{{ _podman_link_user_subuid_start + 999 }}"
group: "{{ _podman_link_user_subgid_start + 999 }}"
mode: "0700"
state: "directory"
become: true
# We set the UID/GID to 1002 inside the signal-cli-rest-api container with environment variables # We set the UID/GID to 1002 inside the signal-cli-rest-api container with environment variables
- name: Podman CDR Link | PATCH | Create data directory for signal-cli-rest-api - name: Podman CDR Link | PATCH | Create data directory for signal-cli-rest-api
ansible.builtin.file: ansible.builtin.file:
@ -131,6 +143,44 @@
state: "directory" state: "directory"
become: true become: true
- name: Podman CDR Link | PATCH | Ensure a project is created for Signal and WhatsApp containers
ansible.builtin.lineinfile:
path: /etc/projid
line: "{{ item.name }}:{{ item.project_id }}"
owner: root
group: root
mode: "0644"
create: true
become: true
with_items:
- {"project_id": 11, "name": "signal"}
- {"project_id": 12, "name": "whatsapp"}
- name: Podman CDR Link | PATCH | Ensure a project is mapped for Signal and WhatsApp container data directories
ansible.builtin.lineinfile:
path: /etc/projects
line: "{{ item.project_id }}:{{ item.path }}"
owner: root
group: root
mode: "0644"
create: true
become: true
with_items:
- {"project_id": 11, "path": "/home/{{ podman_link_podman_rootless_user }}/signal-cli-rest-api-data"}
- {"project_id": 12, "path": "/home/{{ podman_link_podman_rootless_user }}/bridge-whatsapp-data"}
- name: Podman CDR Link | PATCH | Set project quotas of 3G each for Signal and WhatsApp container data directories
community.general.xfs_quota:
type: project
mountpoint: /home
name: "{{ item }}"
bsoft: 3g
bhard: 3g
state: present
with_items:
- signal
- whatsapp
- name: Podman CDR Link | PATCH | Install shared environment files - name: Podman CDR Link | PATCH | Install shared environment files
ansible.builtin.template: ansible.builtin.template:
src: "home/config/containers/systemd/{{ item }}" src: "home/config/containers/systemd/{{ item }}"
@ -177,8 +227,10 @@
owner: "{{ podman_link_podman_rootless_user }}" owner: "{{ podman_link_podman_rootless_user }}"
mode: "0400" mode: "0400"
with_items: with_items:
- channels.network
- frontend.network - frontend.network
- link.network - link.network
- zammad.network
become: true become: true
notify: notify:
- Restart Link - Restart Link
@ -315,6 +367,29 @@
become_user: "{{ podman_link_podman_rootless_user }}" become_user: "{{ podman_link_podman_rootless_user }}"
changed_when: false changed_when: false
- name: Podman CDR Link | AUDIT | Check if specified attachment types are excluded from Opensearch indexing
containers.podman.podman_container_exec:
name: zammad-railsserver
argv:
- rails
- r
- "print Setting.get('es_attachment_ignore')"
become: true
become_user: "{{ podman_link_podman_rootless_user }}"
register: _podman_link_zammad_es_ssl_verify
changed_when: false
- name: Podman CDR Link | PATCH | Configure Zammad to exclude specified attachment types from Opensearch indexing
containers.podman.podman_container_exec:
name: zammad-railsserver
argv:
- rails
- r
- "Setting.set('es_attachment_ignore', %w[.png .jpg .jpeg .mpeg .mpg .mov .bin .exe .box .mbox .avi .mp4 .mp3 unknown-filename unknown .webp .m4v .mkv ])"
become: true
become_user: "{{ podman_link_podman_rootless_user }}"
when: (_podman_link_zammad_es_ssl_verify.stdout | trim)[-199:] != "[\".png\", \".jpg\", \".jpeg\", \".mpeg\", \".mpg\", \".mov\", \".bin\", \".exe\", \".box\", \".mbox\", \".avi\", \".mp4\", \".mp3\", \"unknown-filename\", \"unknown\", \".webp\", \".m4v\", \".mkv\"]"
- name: Podman CDR Link | AUDIT | Check if Zammad wants to verify SSL connections to Opensearch - name: Podman CDR Link | AUDIT | Check if Zammad wants to verify SSL connections to Opensearch
containers.podman.podman_container_exec: containers.podman.podman_container_exec:
name: zammad-railsserver name: zammad-railsserver

View file

@ -7,7 +7,7 @@ Environment=BRIDGE_FRONTEND_URL=http://link:3000
ExposeHostPort=5000 ExposeHostPort=5000
Image=registry.gitlab.com/digiresilience/link/link-stack/bridge-whatsapp:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/bridge-whatsapp:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/bridge-whatsapp-data:/home/node/baileys:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/bridge-whatsapp-data:/home/node/baileys:rw,Z
Network=link.network Network=channels.network
[Service] [Service]
Restart=always Restart=always

View file

@ -9,6 +9,8 @@ ContainerName=bridge-worker
EnvironmentFile=common-bridge.env EnvironmentFile=common-bridge.env
Image=registry.gitlab.com/digiresilience/link/link-stack/bridge-worker:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/bridge-worker:{{ podman_link_stack_version }}
Network=link.network Network=link.network
Network=channels.network
Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -0,0 +1,2 @@
[Network]
NetworkName=channels

View file

@ -10,3 +10,4 @@ ELASTICSEARCH_USER=admin
ELASTICSEARCH_PASS={{ podman_link_opensearch_password }} ELASTICSEARCH_PASS={{ podman_link_opensearch_password }}
ELASTICSEARCH_SCHEMA=https ELASTICSEARCH_SCHEMA=https
ELASTICSEARCH_REINDEX=false ELASTICSEARCH_REINDEX=false
TZ=Etc/UTC

View file

@ -7,8 +7,8 @@ PartOf=zammad-nginx.service
ContainerName=link ContainerName=link
Environment=ZAMMAD_VIRTUAL_HOST={{ podman_link_web_hostname }} Environment=ZAMMAD_VIRTUAL_HOST={{ podman_link_web_hostname }}
Environment=SETUP_MODE={{ podman_link_setup_mode }} Environment=SETUP_MODE={{ podman_link_setup_mode }}
Environment=LEAFCUTTER_ENABLED={{ podman_link_leafcutter_enabled }} Environment=LEAFCUTTER_ENABLED=false
Environment=LEAFCUTTER_DEFAULT_DASHBOARD_URL={{ podman_link_dashboard_url }} Environment=LEAFCUTTER_DEFAULT_DASHBOARD_URL=""
Environment=ZAMMAD_API_TOKEN={{ podman_link_zammad_api_token }} Environment=ZAMMAD_API_TOKEN={{ podman_link_zammad_api_token }}
Environment=LINK_URL=https://localhost:3000/link Environment=LINK_URL=https://localhost:3000/link
Environment=ZAMMAD_URL=http://zammad-nginx:8080 Environment=ZAMMAD_URL=http://zammad-nginx:8080
@ -16,6 +16,8 @@ EnvironmentFile=common-bridge.env
ExposeHostPort=3000 ExposeHostPort=3000
Image=registry.gitlab.com/digiresilience/link/link-stack/link:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/link:{{ podman_link_stack_version }}
Network=link.network Network=link.network
Network=channels.network
Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -9,8 +9,8 @@ ContainerName=opensearch-dashboards
#Environment=OPENSEARCH_PASSWORD={{ podman_link_opensearch_password }} #Environment=OPENSEARCH_PASSWORD={{ podman_link_opensearch_password }}
Image=registry.gitlab.com/digiresilience/link/link-stack/opensearch-dashboards:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/opensearch-dashboards:{{ podman_link_stack_version }}
PublishPort=127.0.0.1:5601:5601 PublishPort=127.0.0.1:5601:5601
#Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-dashboards-config.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml:ro,Z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -10,7 +10,7 @@ Environment=SIGNAL_CLI_GID=1002
ExposeHostPort=8081 ExposeHostPort=8081
Image=registry.gitlab.com/digiresilience/link/link-stack/signal-cli-rest-api:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/signal-cli-rest-api:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/signal-cli-rest-api-data:/home/.local/share/signal-cli:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/signal-cli-rest-api-data:/home/.local/share/signal-cli:rw,Z
Network=link.network Network=channels.network
[Service] [Service]
Restart=always Restart=always

View file

@ -10,7 +10,7 @@ Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_s
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-config-nginx:/etc/nginx/sites-enabled:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-config-nginx:/etc/nginx/sites-enabled:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:ro,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:ro,z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=on-failure Restart=on-failure

View file

@ -5,7 +5,7 @@ PartOf=zammad-storage.target
ContainerName=zammad-memcached ContainerName=zammad-memcached
Exec=memcached -m 256M Exec=memcached -m 256M
Image=registry.gitlab.com/digiresilience/link/link-stack/memcached:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/memcached:{{ podman_link_stack_version }}
Network=link.network Network=zammad.network
ExposeHostPort=11211 ExposeHostPort=11211
[Service] [Service]

View file

@ -11,7 +11,7 @@ ExposeHostPort=8080
Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-config-nginx:/etc/nginx/sites-enabled:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-config-nginx:/etc/nginx/sites-enabled:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:ro,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:ro,z
Network=link.network Network=zammad.network
Network=frontend.network Network=frontend.network
[Service] [Service]

View file

@ -20,7 +20,7 @@ PublishPort=127.0.0.1:9200:9200
PublishPort=127.0.0.1:9600:9600 PublishPort=127.0.0.1:9600:9600
Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-data:/usr/share/opensearch/data:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-data:/usr/share/opensearch/data:rw,Z
Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-config.yml:/usr/share/opensearch/config/opensearch-security/config.yml:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/opensearch-config.yml:/usr/share/opensearch/config/opensearch-security/config.yml:rw,Z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -12,7 +12,7 @@ Image=registry.gitlab.com/digiresilience/link/link-stack/postgresql:{{ podman_li
Volume=/home/{{ podman_link_podman_rootless_user }}/postgresql-data:/var/lib/postgresql/data:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/postgresql-data:/var/lib/postgresql/data:rw,Z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-data:/opt/zammad:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-data:/opt/zammad:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-backup:/var/tmp/zammad:ro,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-backup:/var/tmp/zammad:ro,z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -12,7 +12,7 @@ Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_s
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-database.yml:/opt/zammad/config/database.yml:ro,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-database.yml:/opt/zammad/config/database.yml:ro,z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -6,7 +6,7 @@ ContainerName=zammad-redis
Environment=REDIS_PASSWORD={{ podman_link_zammad_redis_password }} Environment=REDIS_PASSWORD={{ podman_link_zammad_redis_password }}
Image=registry.gitlab.com/digiresilience/link/link-stack/redis:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/redis:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/redis-data:/data:rw,Z Volume=/home/{{ podman_link_podman_rootless_user }}/redis-data:/data:rw,Z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -9,7 +9,7 @@ Exec=zammad-scheduler
Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -9,7 +9,7 @@ Exec=zammad-websocket
Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }} Image=registry.gitlab.com/digiresilience/link/link-stack/zammad:{{ podman_link_stack_version }}
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-var:/opt/zammad/var:rw,z
Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z Volume=/home/{{ podman_link_podman_rootless_user }}/zammad-storage:/opt/zammad/storage:rw,z
Network=link.network Network=zammad.network
[Service] [Service]
Restart=always Restart=always

View file

@ -0,0 +1,2 @@
[Network]
NetworkName=zammad

View file

@ -0,0 +1,36 @@
---
opensearch.hosts: [https://zammad-opensearch:9200]
opensearch.ssl.verificationMode: none
opensearch.requestHeadersAllowlist:
- "securitytenant"
- "Authorization"
- "x-forwarded-for"
- "x-forwarded-user"
- "x-forwarded-roles"
opensearch_security.auth.type: "proxy"
opensearch_security.proxycache.user_header: "x-forwarded-user"
opensearch_security.proxycache.roles_header: "x-forwarded-roles"
opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.enable_global: true
opensearch_security.multitenancy.tenants.enable_private: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.cookie.secure: false
server.basePath: "/link/dashboards"
server.rewriteBasePath: false
opensearch.username: "admin"
opensearch.password: "{{ podman_link_opensearch_password }}"
server.host: "0.0.0.0"
# New config that adds to or overrides existing one:
#
# server.port: 5601
# server.name: "nextgen-dashboards"
# opensearch.hosts: ["https://aberdeen-opensearch:9200"]
# opensearch.ssl.verificationMode: certificate
# opensearch.ssl.certificateAuthorities:
# ["/usr/share/opensearch-dashboards/config/certs/ca.pem"]
# opensearch.requestHeadersAllowlist: ["securitytenant", "Authorization"]
# opensearch_security.readonly_mode.roles: ["kibana_read_only"]