chasquid role: enhance mail server configuration

- Install dovecot packages (dovecot-core, dovecot-imapd) alongside chasquid
- Create support user with secure home directory and nologin shell
- Add chasquid user to mail group for proper permissions
- Set cap_net_bind_service capability on chasquid binary
- Disable socket-based activation services (socket, smtp, submission, submission_tls)
- Disable IPv6 system-wide via sysctl
- Add custom systemd service template with security hardening:
  * Standalone mode (Type=simple)
  * CAP_NET_BIND_SERVICE for port binding
  * ProtectSystem, ProtectHome, PrivateTmp, NoNewPrivileges
  * Automatic restart on failure
- Convert systemd service to Jinja2 template for variable support
- Add email test configuration variables (domain, SMTP settings, test recipients)
- Add swaks email test task with variable-based configuration
- Create reboot handler for IPv6 changes
- Add reload systemd daemon handler

Security:
- Binary capabilities instead of running as root
- Comprehensive systemd security features
- NoNewPrivileges to prevent escalation
- Private temporary directory

Testing:
- Automated swaks email sending test
- Display DNS records with DKIM key information
- Configurable email credentials via variables

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Haitao Pan 2025-11-10 20:49:22 +08:00
parent 136b205e01
commit f92eb3cfb7
4 changed files with 225 additions and 0 deletions

View File

@ -0,0 +1,19 @@
---
- name: Restart chasquid
systemd:
name: chasquid
state: restarted
- name: Reload chasquid
systemd:
name: chasquid
state: reloaded
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Reboot system
reboot:
reboot_timeout: 600
msg: "Rebooting system after IPv6 configuration changes"

View File

@ -0,0 +1,166 @@
---
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install required packages
apt:
name:
- chasquid
- swaks
- dovecot-core
- dovecot-imapd
- openssl
state: present
- name: Create support user
user:
name: support
home: /home/support
shell: /usr/sbin/nologin
system: yes
createhome: yes
- name: Add chasquid user to mail group
user:
name: chasquid
groups: mail
append: yes
- name: Set capability on chasquid binary
command: setcap 'cap_net_bind_service=+ep' /usr/bin/chasquid
args:
creates: /usr/bin/chasquid
- name: Disable chasquid socket services
systemd:
name: "{{ item }}"
state: stopped
enabled: no
loop:
- chasquid.socket
- chasquid-smtp.socket
- chasquid-submission.socket
- chasquid-submission_tls.socket
- name: Disable IPv6 globally
sysctl:
name: "{{ item.name }}"
value: 1
sysctl_file: /etc/sysctl.conf
state: present
reload: yes
loop:
- { name: 'net.ipv6.conf.all.disable_ipv6' }
- { name: 'net.ipv6.conf.default.disable_ipv6' }
notify: Reboot system
- name: Create necessary directories
file:
path: "{{ item }}"
state: directory
mode: '0755'
owner: chasquid
group: chasquid
loop:
- "{{ CONFIG_DIR }}/domains/{{ DOMAIN }}/certs"
- "{{ DATA_DIR }}"
- "/var/mail"
- name: Generate DKIM key
openssl_privatekey:
path: "{{ DKIM_KEY }}"
size: 1024
type: RSA
notify: Restart chasquid
- name: Extract DKIM public key
command: "openssl rsa -in {{ DKIM_KEY }} -pubout"
register: dkim_pub_result
changed_when: false
- name: Save DKIM public key
copy:
content: "{{ dkim_pub_result.stdout }}"
dest: "{{ DKIM_PUB }}"
mode: '0644'
owner: chasquid
group: chasquid
notify: Restart chasquid
- name: Create chasquid configuration
template:
src: chasquid.conf.j2
dest: "{{ CONFIG_DIR }}/chasquid.conf"
mode: '0644'
owner: chasquid
group: chasquid
notify: Restart chasquid
- name: Copy TLS certificates
copy:
src: "{{ CERT_PEM }}"
dest: "{{ CONFIG_DIR }}/domains/{{ DOMAIN }}/certs/fullchain.pem"
remote_src: yes
mode: '0640'
owner: root
group: chasquid
notify: Restart chasquid
ignore_errors: "{{ ignore_cert_missing | default(false) }}"
- name: Copy TLS private key
copy:
src: "{{ CERT_KEY }}"
dest: "{{ CONFIG_DIR }}/domains/{{ DOMAIN }}/certs/key.pem"
remote_src: yes
mode: '0640'
owner: root
group: chasquid
notify: Restart chasquid
ignore_errors: "{{ ignore_cert_missing | default(false) }}"
- name: Add chasquid user
command: "printf '%s\n%s\n' {{ USER_PASSWORD }} {{ USER_PASSWORD }} | chasquid-util user-add {{ USER }}@{{ DOMAIN }}"
args:
creates: "{{ CONFIG_DIR }}/users/{{ DOMAIN }}/{{ USER }}"
notify: Restart chasquid
- name: Create custom chasquid systemd service file
template:
src: chasquid.service.j2
dest: /etc/systemd/system/chasquid.service
mode: '0644'
owner: root
group: root
notify:
- Reload systemd daemon
- Restart chasquid
- name: Enable and start chasquid service
systemd:
name: chasquid
state: started
enabled: yes
daemon_reload: yes
- name: Display DNS records information
debug:
msg: |
🔧 DNS records for {{ DOMAIN }} ({{ IP }})
A smtp.{{ DOMAIN }} {{ IP }}
MX {{ DOMAIN }} smtp.{{ DOMAIN }}
TXT {{ DOMAIN }} "v=spf1 include:smtp.{{ DOMAIN }} ~all"
TXT default._domainkey.{{ DOMAIN }} "v=DKIM1; k=rsa; p=<Check {{ DKIM_PUB }} for the public key>"
TXT _dmarc.{{ DOMAIN }} "v=DMARC1; p=quarantine; rua=mailto:dmarc@{{ DOMAIN }}"
- name: Test email sending with swaks
command: "swaks --server {{ SMTP_SERVER }} --port {{ SMTP_PORT }} --tls --auth PLAIN --auth-user {{ EMAIL_USER }} --auth-password {{ EMAIL_PASSWORD }} --from {{ EMAIL_FROM }} --to {{ EMAIL_TO }}"
register: swaks_result
changed_when: false
failed_when: false
- name: Display test result
debug:
var: swaks_result

View File

@ -0,0 +1,16 @@
hostname: "{{ HOSTNAME }}"
max_data_size_mb: 50
submission_address: ":587"
submission_over_tls_address: ":465"
monitoring_address: "127.0.0.1:1099"
data_dir: "{{ DATA_DIR }}"
suffix_separators: "+"
dovecot_auth: true
domain {
name: "{{ DOMAIN }}"
dkim_key: "{{ DKIM_KEY }}"
maildir_base: "/var/mail"
}
smtp_address: []

View File

@ -0,0 +1,24 @@
[Unit]
Description=Chasquid SMTP Server (standalone)
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/chasquid -config_dir {{ CONFIG_DIR }}
Restart=always
RestartSec=5
User=chasquid
Group=chasquid
# 允许绑定低端口
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# 安全限制
ProtectSystem=full
ProtectHome=yes
PrivateTmp=yes
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target