updated podman_services role and initial work on mailcow service

This commit is contained in:
Mike Kell 2025-04-20 14:33:13 +00:00
parent 6c9f41c26c
commit e1e3eacbed
16 changed files with 204 additions and 184 deletions

View File

@ -15,9 +15,11 @@ wazuh_port: 55000
# 📦 Container Images # 📦 Container Images
nextcloud_aio_image: nextcloud/all-in-one:latest nextcloud_aio_image: nextcloud/all-in-one:latest
keycloak_image: quay.io/keycloak/keycloak:24.0.2 keycloak_image: quay.io/keycloak/keycloak:24.0.2
mailcow_image: mailcow/mailcow-dockerized:latest
# 🗂️ Data Directories # 🗂️ Data Directories
nextcloud_data_dir: /srv/nextcloud nextcloud_data_dir: /srv/nextcloud
mailcow_data_dir: /opt/mailcow
backup_base_dir: /srv/backups backup_base_dir: /srv/backups
logs_dir: /var/log/open-cmmc logs_dir: /var/log/open-cmmc
@ -37,3 +39,13 @@ hostname: open-cmmc-gateway
# 📜 Default Realm for Keycloak # 📜 Default Realm for Keycloak
keycloak_realm: OpenCMMC keycloak_realm: OpenCMMC
# 📧 Mailcow Settings
mailcow_hostname: mail
mailcow_domain: "{{ domain_name }}"
mailcow_fqdn: "{{ mailcow_hostname }}.{{ mailcow_domain }}"
mailcow_timezone: America/New_York
mailcow_admin_user: admin
mailcow_admin_password: change_me_securely
mailcow_letsencrypt_email: it@example.com
mailcow_use_letsencrypt: "n"

View File

@ -1,3 +0,0 @@
# Ansible Role: keycloak_init
This role initializes a Keycloak instance with a predefined realm, groups, and clients for the OpenCMMC Stack.

View File

@ -1,6 +0,0 @@
---
- name: Register SAML client for Nextcloud
shell: '/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC -s clientId=nextcloud-aio -s protocol=saml -s enabled=true'
- name: Register OIDC client for Mailcow
shell: '/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC -s clientId=mailcow -s protocol=openid-connect -s enabled=true'

View File

@ -1,9 +0,0 @@
---
- name: Create Keycloak Groups
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_CUI'
- name: Create FCI Group
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_FCI'
- name: Create Proprietary Group
shell: '/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name=Access_Proprietary'

View File

@ -1,80 +0,0 @@
---
- name: Check if Keycloak is already installed
stat:
path: /opt/keycloak/bin/kcadm.sh
register: keycloak_installed
- name: Download Keycloak if not already present
unarchive:
src: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/keycloak-{{ keycloak_version }}.tar.gz"
dest: /opt/
remote_src: yes
when: not keycloak_installed.stat.exists
- name: Rename keycloak directory
command: mv /opt/keycloak-{{ keycloak_version }} /opt/keycloak
args:
creates: /opt/keycloak/bin/kcadm.sh
when: not keycloak_installed.stat.exists
- name: Set executable permissions on kcadm.sh
file:
path: /opt/keycloak/bin/kcadm.sh
mode: '0755'
when: not keycloak_installed.stat.exists
- name: Log in to Keycloak Admin CLI
command: >
/opt/keycloak/bin/kcadm.sh config credentials
--server http://localhost:8080
--realm master
--user {{ keycloak_admin_user }}
--password {{ keycloak_admin_password }}
environment:
KC_HOME: /opt/keycloak
register: kcadm_login
changed_when: false
- name: Create OpenCMMC realm
command: >
/opt/keycloak/bin/kcadm.sh create realms
-s realm=OpenCMMC -s enabled=true
environment:
KC_HOME: /opt/keycloak
when: kcadm_login is succeeded
- name: Create groups
loop:
- Access_CUI
- Access_FCI
- Access_Proprietary
command: >
/opt/keycloak/bin/kcadm.sh create groups -r OpenCMMC -s name={{ item }}
environment:
KC_HOME: /opt/keycloak
when: kcadm_login is succeeded
- name: Create OIDC client for Mailcow
command: >
/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC
-s clientId=mailcow
-s enabled=true
-s protocol=openid-connect
-s publicClient=false
-s 'redirectUris=["https://mail.yourdomain.com/*"]'
environment:
KC_HOME: /opt/keycloak
when: kcadm_login is succeeded
- name: Create SAML client for Nextcloud
command: >
/opt/keycloak/bin/kcadm.sh create clients -r OpenCMMC
-s clientId=nextcloud
-s enabled=true
-s protocol=saml
-s 'redirectUris=["https://nextcloud.yourdomain.com/*"]'
-s 'attributes.saml.assertion.signature=true'
-s 'attributes.saml.force.post.binding=true'
environment:
KC_HOME: /opt/keycloak
when: kcadm_login is succeeded

View File

@ -1,5 +0,0 @@
---
- name: Create Keycloak Realm
shell: '/opt/keycloak/bin/kcadm.sh create realms -s realm=OpenCMMC -s enabled=true'
args:
creates: /opt/keycloak/data/realms/OpenCMMC

View File

@ -1,10 +0,0 @@
---
- name: Ensure kcadm.sh is present
stat:
path: /opt/keycloak/bin/kcadm.sh
register: kcadm_path
- name: Install unzip (required for kcadm)
apt:
name: unzip
state: present

View File

@ -0,0 +1,20 @@
# 🐮 Mailcow Sample Environment File
# Host Settings
HOSTNAME=mail
DOMAINNAME=example.cmmc.local
MAILCOW_HOSTNAME=mail.example.cmmc.local
# Admin Interface
MAILCOW_ADMIN_USER=admin
MAILCOW_ADMIN_PASSWORD=change_me_securely
# Timezone
TZ=America/New_York
# DNS Resolver
RESOLVER=9.9.9.9
# Let's Encrypt (n = disabled, y = enabled)
SKIP_LETS_ENCRYPT=y
LETS_ENCRYPT_EMAIL=it@example.com

View File

@ -0,0 +1,52 @@
version: '3.7'
services:
redis:
image: redis:alpine
restart: always
volumes:
- redis-data:/data:Z
mysql:
image: mariadb:10.5
restart: always
environment:
- MYSQL_ROOT_PASSWORD=mailcowrootpass
- MYSQL_DATABASE=mailcow
- MYSQL_USER=mailcow
- MYSQL_PASSWORD=mailcowpass
volumes:
- mysql-data:/var/lib/mysql:Z
dovecot:
image: mailcow/dovecot:latest
restart: always
volumes:
- vmail-data:/var/vmail:Z
- rspamd-data:/var/lib/rspamd:Z
environment:
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
postfix:
image: mailcow/postfix:latest
restart: always
environment:
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
nginx:
image: mailcow/nginx:latest
restart: always
ports:
- "8081:80"
- "8443:443"
volumes:
- nginx-certs:/etc/ssl/mail:Z
environment:
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
volumes:
redis-data:
mysql-data:
vmail-data:
rspamd-data:
nginx-certs:

View File

@ -1,38 +0,0 @@
---
- name: Deploy keycloak container with Podman
containers.podman.podman_container:
name: keycloak
image: "{{ keycloak_image }}"
state: started
restart_policy: always
volumes:
- "{{ keycloak_data_dir }}:/data:z"
env:
CONFIG_PATH: "/data/config"
- name: Ensure systemd service is enabled for keycloak
copy:
dest: "/etc/systemd/system/podman-keycloak.service"
content: |
[Unit]
Description=Podman container for keycloak
Wants=network.target
After=network.target
[Service]
ExecStart=/usr/bin/podman start -a keycloak
ExecStop=/usr/bin/podman stop -t 10 keycloak
Restart=always
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: "0644"
- name: Reload systemd and enable service for keycloak
systemd:
daemon_reload: yes
name: podman-keycloak.service
enabled: yes
state: started

View File

@ -1,38 +1,39 @@
--- ---
- name: Deploy mailcow container with Podman - name: Ensure mailcow service directory exists
containers.podman.podman_container: file:
name: mailcow path: "{{ service.compose_dir }}"
image: "{{ mailcow_image }}" state: directory
state: started mode: "0755"
restart_policy: always owner: "{{ service.user | default('root') }}"
volumes: group: "{{ service.group | default('root') }}"
- "{{ mailcow_data_dir }}:/data:z"
env:
CONFIG_PATH: "/data/config"
- name: Ensure systemd service is enabled for mailcow - name: Deploy mailcow .env file from template
template:
src: mailcow/env.j2
dest: "{{ service.compose_dir }}/.env"
owner: "{{ service.user | default('root') }}"
group: "{{ service.group | default('root') }}"
mode: "0600"
- name: Copy mailcow podman-compose.yml
copy: copy:
dest: "/etc/systemd/system/podman-mailcow.service" src: mailcow/podman-compose.yml
content: | dest: "{{ service.compose_dir }}/podman-compose.yml"
[Unit] owner: "{{ service.user | default('root') }}"
Description=Podman container for mailcow group: "{{ service.group | default('root') }}"
Wants=network.target
After=network.target
[Service]
ExecStart=/usr/bin/podman start -a mailcow
ExecStop=/usr/bin/podman stop -t 10 mailcow
Restart=always
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: "0644" mode: "0644"
- name: Reload systemd and enable service for mailcow - name: Copy mailcow systemd unit file
template:
src: mailcow/mailcow.service.j2
dest: /etc/systemd/system/podman-mailcow.service
mode: "0644"
- name: Reload systemd daemon
command: systemctl daemon-reexec
- name: Enable and start mailcow container service
systemd: systemd:
daemon_reload: yes
name: podman-mailcow.service name: podman-mailcow.service
enabled: yes enabled: true
state: started state: started

View File

@ -1,11 +1,24 @@
--- ---
- name: Ensure Podman is installed - name: Ensure Podman and dependencies are installed
apt: apt:
name: podman name:
- podman
- uidmap
- slirp4netns
- fuse-overlayfs
state: present state: present
become: true become: true
- name: Pull and run Podman services - name: Confirm Podman version
command: podman --version
register: podman_version
changed_when: false
- name: Debug Podman version for audit
debug:
msg: "Podman version is {{ podman_version.stdout }}"
- name: Iterate over defined Podman services
include_tasks: run_service.yml include_tasks: run_service.yml
loop: "{{ podman_services }}" loop: "{{ podman_services }}"
loop_control: loop_control:

View File

@ -2,6 +2,11 @@
- name: Pull image for {{ service.name }} - name: Pull image for {{ service.name }}
containers.podman.podman_image: containers.podman.podman_image:
name: "{{ service.image }}" name: "{{ service.image }}"
register: pulled_image
- name: Debug pulled image result for {{ service.name }}
debug:
msg: "Image {{ service.image }} pulled: {{ pulled_image }}"
- name: Create data directory for {{ service.name }} - name: Create data directory for {{ service.name }}
file: file:
@ -21,3 +26,8 @@
env: "{{ service.env | default({}) }}" env: "{{ service.env | default({}) }}"
volumes: "{{ service.volumes | default([]) }}" volumes: "{{ service.volumes | default([]) }}"
user: "{{ service.user | default(omit) }}" user: "{{ service.user | default(omit) }}"
register: podman_run
- name: Debug container run status for {{ service.name }}
debug:
var: podman_run

View File

@ -0,0 +1,20 @@
# 🐮 Mailcow Environment File (Generated by Ansible)
# Host Settings
HOSTNAME={{ mailcow_hostname }}
DOMAINNAME={{ mailcow_domain }}
MAILCOW_HOSTNAME={{ mailcow_fqdn }}
# Admin Interface
MAILCOW_ADMIN_USER={{ mailcow_admin_user }}
MAILCOW_ADMIN_PASSWORD={{ mailcow_admin_password }}
# Timezone
TZ={{ mailcow_timezone }}
# DNS Resolver
RESOLVER=9.9.9.9
# Let's Encrypt
SKIP_LETS_ENCRYPT={{ 'n' if mailcow_use_letsencrypt == 'y' else 'y' }}
LETS_ENCRYPT_EMAIL={{ mailcow_letsencrypt_email }}

View File

@ -0,0 +1,15 @@
[Unit]
Description=Mailcow Podman Compose Service
Wants=network.target
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory={{ service.compose_dir }}
ExecStart=/usr/bin/podman-compose -f {{ service.compose_dir }}/podman-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f {{ service.compose_dir }}/podman-compose.yml down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,28 @@
version: "3.8"
services:
mailcow:
image: mailcow/mailcow-dockerized:latest
container_name: mailcow
env_file:
- .env
restart: always
ports:
- "25:25"
- "80:80"
- "443:443"
- "587:587"
- "993:993"
volumes:
- mailcow_data:/var/lib/mailcow
- mailcow_conf:/etc/mailcow
networks:
- mailcow_net
volumes:
mailcow_data:
mailcow_conf:
networks:
mailcow_net:
driver: bridge