LINUXOR.SK ... open source notes ...

Email 14 - Accounts, clients and operations

category: solutionz · date: 2019-12-31 · updated: 2026-10-02 · author: LALA

Email Solution · Previous: Webmail

The last part is about living with the system: what has to be done in Active Directory before a device can send its first alert, what is typed into that device, how the servers are watched and logged, in which order a site was built, and what was left unfinished. It closes with the list of contradictions I found when I read my own documents again.

How an account gets mail

Nothing about a mail user is stored on the mail servers. An account exists in Active Directory, and membership in groups decides what it may do. The lookups behind this are in Active Directory integration; here is the procedure as an operator sees it.

First the account. A device, a server or an application that sends mail gets its own account, named after the service with the suffix _mail: gitlab_mail for GitLab, sensu_mail for the monitoring. A person who only reads mail in the webmail has a normal user account.

Kind of accountCreated underUsed for
Device or software componentOU=msx_SVC,OU=Users_SVC,DC=ad,DC=example,DC=netSMTP login of the device
UserOU=Users_STD,DC=ad,DC=example,DC=netWebmail, to read mail; the design does not authorize these accounts to send

The login name is the user principal name, account@ad.example.net in site 1 and account@ad-dc2.example.net in site 2, and it is also the mail address. There is nothing else to set: the address is the account.

Then the groups. Each permission has one group per organisation, so that it stays visible who let whom in, and one role group that contains them. Postfix and Dovecot ask only for the role group and follow the nesting.

To allowAdd the account to one ofRole group that the servers check
Activating the address: sending to addresses of the own mail domainsSMTP_ORG, SMTP_PARTNER1, SMTP_PARTNER2SMTP_ACCESS
Sending to external domainsESMTP_ORG, ESMTP_PARTNER1, ESMTP_PARTNER2ESMTP_ACCESS
Access to the webmailIMAP_ORG, IMAP_PARTNER1, IMAP_PARTNER2IMAP_ACCESS

The per-organisation groups live in OU=RBAC_GROUPS,OU=RBAC, the role groups in OU=RBAC_ROLES,OU=RBAC. These paths, like the two in the first table, are the notation of the design: the archived lookup files of site 2 search under DC=ad-dc2,DC=example,DC=net and name the role groups in OU=APPS,OU=RBAC_ROLES,OU=RBAC; see Active Directory integration. A device account that is in one SMTP_ group and nothing else is meant to alert the operators' mailboxes and not to send a single message to the internet. A notification that must reach a partner's mailbox outside needs the ESMTP_ group too, and then the content filter decides whether it leaves encrypted; see Automatic email encryption. Distribution lists are groups as well, under OU=DISTRIBUTION_GROUPS.

A change of membership needs nothing on the mail servers. There is no map to rebuild and no service to reload, because every check is an LDAP query at the time of the connection.

Client configuration

Clients are given the virtual address of the internal pair. The design does not forbid a node's own address: it says SMTP can also be used on the addresses that are not the virtual one, and its firewall rule for clients lists both nodes beside the virtual address. The design gives two ways in and calls the first one preferred.

ParameterSMTPS, preferredSMTP with TLS
PortTCP 465TCP 25
Connection securitySSL/TLS from the first byteSTARTTLS
Authentication methodsPLAIN, LOGINPLAIN, LOGIN
User namethe account's addressthe account's address
Passwordthe account's password in Active Directorythe account's password in Active Directory
Sender addressthe account's addressthe account's address

The sender address is meant to be the account's own address. The design intended Postfix to compare the two and reject a message whose MAIL FROM belongs to somebody else. As archived, the order of the sender restrictions defeats that check: the group lookup permits every member of SMTP_ACCESS before the comparison is reached, so an authenticated account can use the address of any other account in that group. See Internal servers: Postfix.

The values that differ per site are these.

ParameterSite 1 (DC1)Site 2 (DC2)
SMTP server, namedc1-s-xcmsx001.adm.example.netdc2-s-xcmsx001.adm.example.net
SMTP server, IPv410.11.19.3310.12.19.33
SMTP server, IPv62001:db8:a1:b6f::f:12001:db8:a2:b6f::f:1
User name and sender addressaccount@ad.example.netaccount@ad-dc2.example.net

Two remarks on this table. The client tables of the design give 10.12.16.33 as the IPv4 address for site 2; the Keepalived configuration, the install notes and the design's own chapter on the virtual address all say 10.12.19.33, and I take the client table for a typing error. And the site 1 values carry a note in the design that they apply only after the new concept is implemented there: in October 2019 site 1 still ran the first concept, where clients were given the name of the single internal server. Its address was 10.11.19.33, the one the design then assigns to the virtual address, so a client configured by address would not have noticed the change.

The design does not say why SMTPS is the preferred one. The two ports are not equal on the server side, and not in the way the word "preferred" suggests: the listener on 465 carries its own, shorter recipient check. That is the first item under known issues below, and the server side of both ports is in Internal servers: Postfix.

Clients with neither authentication nor TLS

Requirement FR4 says that some clients, mostly specialised hardware appliances, support neither SMTP authentication nor TLS, and that the server "will be ready for such clients in the form of setting exceptions". I checked what the configuration really does with such a client. The relevant lines of main.cf on the internal pair:

ini
mynetworks = 10.12.19.34/32, 10.12.19.35/32, 10.12.19.43/32
smtpd_client_restrictions=
        permit_sasl_authenticated,
        permit_mynetworks,
        reject
smtpd_tls_security_level = encrypt
smtpd_tls_auth_only = yes

The mechanism for an exception is mynetworks: an address listed there passes the client, sender and recipient restrictions without logging in, as long as the mail is for the own domain. For external recipients a sender address of the own domain still has to be in ESMTP_ACCESS, because both check_sender_access lines of the recipient restrictions stand before permit_mynetworks. As archived, the list holds three addresses and all three are mail servers, the two relays and the mailbox server. No appliance is in it. A client that does not authenticate and is not in the list is rejected.

And the list alone would not be enough. smtpd_tls_security_level = encrypt makes TLS mandatory on port 25 for everybody, listed or not, so a client that cannot do STARTTLS is refused at MAIL FROM. A real exception for a client without TLS would have needed a second listener in master.cf with the security level lowered to may and access limited to named addresses. The Source material holds no such listener and no record of an appliance that needed one. So the honest statement is: FR4 was provided for in the design, the exception for authentication is one line away, the exception for TLS was not built. The whole file is a Config document: Postfix main.cf, internal servers.

Monitoring

The email servers sit in the same infrastructure services as every other server of the management infrastructure. The design has one diagram for that, redrawn here for site 2.

mermaid
flowchart LR
  adm["Administrators and operators"] -- "SSH, TCP 22" --> sshd
  subgraph vm["Email server, virtual machine"]
    sshd["sshd"]
    sssd["sssd"]
    res["DNS resolver"]
    ntpd["ntpd"]
    aud["auditd"]
    rsys["rsyslogd"]
    sen["sensu-client"]
    etck["etckeeper"]
  end
  aud --> rsys
  sssd -- "AD, LDAP" --> ad["Active Directory, DC2-A-VCAD001 and 002"]
  res -- "DNS, 53" --> ibx["Infoblox, site 1"]
  ntpd -- "NTP, 123" --> ibx
  rsys -- "syslog, TCP and UDP 514" --> sys["Central syslog, DC2-S-XCSYS001"]
  sen -- "Sensu messages, TCP 5672" --> rmq["RabbitMQ, DC2-A and DC2-B-VCRMQ001"]
  sen -- "metrics, TCP 80" --> gra["Graphite, DC2-S-XCGRA001"]
  vm -- "ICMP" --> sns["Sensu servers"]
  etck -- "git over SSH, TCP 22" --> git["GitLab"]

Monitoring is Sensu. A client on each server runs the checks and publishes the results to RabbitMQ; the machine pings the Sensu servers, which is the direction the design gives for ICMP; metrics go to Graphite. Every server gets the base template.

LevelCheckCondition
SystemProcesses sshd, sssd, ntpd, qemu-ga, rsyslogd, auditd, crondMust be running
SystemAll standard mount pointsUsage below the threshold

On top of the template each role has its own short list.

RoleServers in site 2Additional checks
Internal pairDC2-A-VCMSX001, DC2-B-VCMSX001Processes postfix and dovecot must be running
Mailbox and webmailDC2-A-VCMSX002Processes postfix, dovecot, httpd, mariadb must be running; usage of /data below the threshold
RelaysDC2-A-VCMSR001, DC2-B-VCMSR001Process postfix must be running

The site 1 servers have the same lists. The design gives no thresholds and no check definitions, only these tables.

Every check here asks whether a process exists. None asks whether mail gets through: no check of the queue length, no test message from end to end, no look at the expiry date of a certificate, and nothing watches which node holds the virtual address or whether the two key synchronization services are alive. The monitoring system itself sends its alerts through this mail system, with the account sensu_mail, which is on the list of senders whose mail is never encrypted. When the mail system is the thing that is broken, the alert about it travels through the broken thing.

Logging

WhatWhere it is writtenRotation
Postfix, all serverssyslog, facility mail; the SMTPS listener logs as postfix/smtpsby the system
Dovecotsyslog, facility mailby the system
Roundcubesyslog, facility mail, identity roundcubeby the system
Content filterits own file, /var/spool/postfix/bash-postfix-encrypt-filter/log/bash-postfix-encrypt-filter.logdaily, seven kept, copytruncate
Operating system auditauditdby the system

rsyslogd forwards everything that reaches syslog to the central syslog server of the site, dc2-s-xcsys001.adm.example.net in site 2 and dc1-s-xcsys001.adm.example.net in site 1. The forwarding rule is part of the operating system template and is not in the archived configuration trees.

The filter is the exception. It is a shell script and writes its own log, one line per step with the mail ID in front, so that the path of one message through the filter can be followed with grep: entered the filter, sender or recipient on an exception list, certificate or key found, encrypted, handed back. That file stays on the node. It is not in syslog and therefore not on the central server, and since either node of the pair may have handled a message, a search means looking on both. The rotation is a Config document: logrotate rule for the filter. copytruncate is there because the script appends to the file by name on every run and nothing could be told to reopen it. For logrotate to be allowed into the Postfix spool at all, SELinux needed a file context and a local module; see Virtual machines and OS build.

Besides the log, the filter keeps a copy of every message, the original and the encrypted one, in its archive directory for one day. I read this as a troubleshooting aid, the Source material does not say what it was for; it also means that clear text of mail that left encrypted lies on the internal servers for a day. The script is in bash-postfix-encrypt-filter.sh.

Configuration tracking

etckeeper is on every server as part of the base build: /etc is a git repository, changes are committed, and the diagram of the design shows the repository pushed to the GitLab of the management infrastructure. The email system used it and did not configure it; the Source material has no etckeeper settings. What it did not cover is everything outside /etc: the filter script and the two synchronization scripts in /usr/local/bin, the exception lists and the recipients' keys under /var/spool/postfix. The design names a GitLab project of its own for the source code of the filter. Where the exception lists were kept besides the servers, the Source material does not say.

The order of installation

Chapter 7 of the design, "Installation notes", is four references to text files and one empty heading, that of the second relay, for site 2, and five times the sentence that the notes "will be added after implementation of new email concept" for site 1. The archive holds five files of notes, one per server of site 2. They are grouped by topic and not strictly by time (the certificate, which Postfix on the internal servers cannot start without, is the second to last section in each; the notes of the relays say their certificate is generated and currently not used), so the order below is the order of the notes with that caveat.

StepInternal pairMailbox and webmailRelays
1Install Postfix and Dovecot, stop them, set the stock configuration asideThe sameInstall Postfix, stop it, set the stock configuration aside
2vmail account, Dovecot configuration/data/vmail, its SELinux label, vmail account, DovecotPostfix: main.cf, transport to the mailbox server, header_checks
3Postfix: virtual address, relay hosts, transportPostfix: relay through the pair, delivery to DovecotStart Postfix
4Content filter: packages, account, script, directories, exception lists, master.cf, log rotationfirewalld: SSH, SMTP, 465, HTTPS, IMAPfirewalld: SSH, SMTP
5Key synchronization: rsync, inotify-tools, SSH keys, two systemd unitsSELinux: two modules, one booleanCertificate request
6firewalld: SSH, SMTP, 465Apache and PHP, MariaDB, Roundcube installerRepositories
7Keepalived: non-local bind, reboot, configurationCertificate request
8SELinux: file context, three modulesRepositories
9Certificate request with the name of the virtual address
10Repositories

The notes do not record the order between the servers. The dependencies give one: the relays and the mailbox server first, because the internal pair needs somewhere to send; node A of the pair before node B; the SSH keys of the synchronization last, since each node needs the other's public key. The notes for node A and node B are the same file with a handful of differences: names, addresses, Keepalived state and priority, peer.

Known issues and limitations

Both design documents of the first concept end with a chapter of this name, and in both it is one sentence: "No known issues or limitations have been found." The final design has no such chapter. Reading everything again for this write-up, I found the following. Each item is in the Source material; none of them is in its list of issues.

What I would do differently

The list above is what was wrong then. This one is what has changed since, checked against current upstream documentation in October 2026.

← solutionz