Installing authnd
The repository carries the two files a systemd host needs:
packaging/sysusers.d/authnd.conf (the account) and
packaging/systemd/authnd.service (the unit). This page explains both and
the steps around them. go-pkgx’s versioned services are meant to do this for
you later; they do not exist yet.
The release binary
Each tag publishes authnd-<os>-<arch> for linux, darwin and windows on amd64
and arm64 (.exe on windows), built with CGO_ENABLED=0, a SHA256SUMS
manifest, and a build provenance attestation for every binary.
version=v0.11.1
arch=amd64 # or arm64
base=https://github.com/go-authn/authnd/releases/download/$version
curl -fsSLO "$base/authnd-linux-$arch"
curl -fsSLO "$base/SHA256SUMS"
sha256sum -c SHA256SUMS --ignore-missing # the bytes the release published
gh attestation verify "authnd-linux-$arch" --repo go-authn/authnd # built by the release workflow, at that tagStop if either check fails. The release workflow refuses to publish a binary that does not report exactly the tag it is published under, so the version is something to compare:
$ authnd --version
authnd version v0.11.1Building only what you want
The server is always there; two build tags leave out where people can come
from. -tags nosql drops the three database drivers (PostgreSQL through pgx,
MySQL/MariaDB, SQLite through modernc.org/sqlite) and the users "sql" block;
-tags noldap drops the LDAP client and the users "ldap" block. A
configuration naming a block the binary was built without is told so —
this binary was built without SQL support (-tags nosql) — rather than that
the block does not exist. The release binaries are built without tags.
The account
#Type Name ID Description Home Shell
u authnd - "authnd LDAP directory and Kerberos KDC" /var/lib/authnd -A static account from sysusers.d, not DynamicUser=. The files authnd
reads — password files, a DSN, a keytab, a TLS key — are secrets given to the
authnd group ahead of time, and a password change
writes back into them. A dynamic uid does not exist until the service starts,
and a file it wrote would belong to a number that later means somebody else.
The two files come from the packaging/ directory of the release tag, the
same version as the binary: copy that directory beside the binary, from a
checkout of the tag or, for v0.11.1, from
https://github.com/go-authn/authnd/tree/v0.11.1/packaging.
sudo install -m 0755 "authnd-linux-$arch" /usr/local/bin/authnd
sudo install -m 0644 packaging/sysusers.d/authnd.conf /usr/lib/sysusers.d/authnd.conf
sudo systemd-sysusers /usr/lib/sysusers.d/authnd.conf
sudo install -m 0644 packaging/systemd/authnd.service /etc/systemd/system/authnd.service
sudo systemd-analyze verify /etc/systemd/system/authnd.service
sudo systemctl daemon-reloadWhat the unit grants, and why
[Service]
Type=exec
ExecStart=/usr/local/bin/authnd --config /etc/authnd
Restart=on-failure
RestartSec=5s
User=authnd
Group=authnd
UMask=0077
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
StateDirectory=authnd
StateDirectoryMode=0700
ProtectSystem=strictThe rest of the unit is the usual hardening (ProtectHome, PrivateTmp,
PrivateDevices, ProtectProc=invisible, the kernel and cgroup protections,
MemoryDenyWriteExecute, SystemCallFilter=@system-service,
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX). Three things it
leaves out are deliberate:
ExecReload= | authnd has no reload. It reads its configuration, certificate and keytab once; see running it |
PrivateUsers= | inside a user namespace CAP_NET_BIND_SERVICE no longer applies to the host’s network, and the bind to 389 is refused |
ProcSubset=pid | it hides /proc/sys, where Go reads net/core/somaxconn, and every listener’s backlog falls to Go’s fallback of 128 |
IPAddressAllow=/IPAddressDeny= are not set either: which networks may ask
a directory is the site’s to say, in a drop-in:
sudo systemctl edit authnd[Service]
IPAddressDeny=any
IPAddressAllow=localhost 10.0.0.0/8The one capability is for the privileged ports: LDAP 389, LDAPS 636, and
Kerberos 88 over UDP and TCP. A PostgreSQL or MariaDB on the same machine is
reached through its socket, which a read-only file system allows. The state
directory, /var/lib/authnd, is there for a SQLite database; authnd keeps no
state of its own — the second-factor lockout counts live in memory and are
reset at every restart.
The configuration directory
sudo install -d -o root -g authnd -m 0750 /etc/authndEvery file inside it root:authnd, mode 0640. Secrets go in files named by
*_file keys rather than inline: a file has permissions, and a configuration
someone pastes does not. With ProtectSystem=strict the service cannot write
under /etc, which is right for the configuration and wrong for the
passwords people change themselves — give those a directory of their own:
sudo install -d -o authnd -g authnd -m 0700 /etc/authnd/passwords
sudo systemctl edit authnd[Service]
ReadWritePaths=/etc/authnd/passwordsWhy that directory and not the file is explained in changing a password.
| key | default | |
|---|---|---|
base_dn | — (required) | the root of the tree, e.g. dc=example,dc=org; a value with no = is refused |
listen | 127.0.0.1:3893 | one address. Loopback by default: a directory that appears on every interface the moment it starts is a decision somebody should make on purpose. A site that needs LDAP and LDAPS runs two instances |
reader "<dn>" | none | a service account that may search; see who may read |
cert_file, key_file, starttls, publish_nt_hash, samba | off | TLS |
user, group, users | — | the people; at least one user or users block |
kerberos | none | a realm |
mfa | none | a second factor |
oidc | none | a token at the bind |
A relative path in the configuration is resolved against the directory the
process runs in, not the configuration file’s; the unit runs from /, so
write paths absolute.
Before every start:
sudo -u authnd authnd check /etc/authnd
sudo systemctl enable --now authnd
journalctl -u authndcheck is described on its own page;
running it as authnd also proves the account can read every file.
Upgrade, roll back, remove
Check the configuration with the new binary before it replaces the old
one, and keep the old one. The new binary is installed beside the old one
first: that makes it executable, and puts it where the authnd account can
run it.
sudo install -m 0755 "authnd-linux-$arch" /usr/local/bin/authnd.new
sudo -u authnd /usr/local/bin/authnd.new check /etc/authnd
sudo cp /usr/local/bin/authnd /usr/local/bin/authnd.previous
sudo mv /usr/local/bin/authnd.new /usr/local/bin/authnd
sudo systemctl restart authnd
authnd --versionCompare packaging/ at the new tag with what is installed (v0.11.1’s is
v0.10.2’s, unchanged). Rolling back is the same install from
authnd.previous, and a restart.
From v0.10.x to v0.11.0 the check above is the step that matters: a
configuration with publish_nt_hash = true and no
samba block is refused
there rather than at the restart, and the lines after its tables say who is
no longer a posixAccount and which groups are no longer posixGroups
(the entries).
To remove it:
sudo systemctl disable --now authnd
sudo rm /etc/systemd/system/authnd.service
sudo rm -r /etc/systemd/system/authnd.service.d # if a drop-in was added
sudo systemctl daemon-reload
sudo rm /usr/local/bin/authnd /usr/local/bin/authnd.previous /usr/lib/sysusers.d/authnd.conf/etc/authnd, /var/lib/authnd and the authnd account are left in place:
the first two hold people’s credentials, and a uid that is reused can be
given somebody else’s files. Remove them deliberately.
Created on by tannevaled
Modified on by tannevaled