Security hardening reference¶
This page is the reference for MAAS security-hardening configuration:
the activation model, the maas config-hardening command, the hardening
parameters and their stores, the password policy enforced in hardening mode,
and the violation codes reported at startup.
For step-by-step setup, see Activate MAAS hardening. For the concepts behind hardening, see Security hardening.
Activation model¶
Hardening state is resolved once per process at startup and never blocks a controller from starting.
|
Host in FIPS mode |
Result |
|---|---|---|
|
yes |
hardening active |
|
no |
hardening inactive |
|
yes or no |
hardening active |
|
no |
hardening inactive |
|
yes |
hardening active (FIPS overrides |
FIPS mode is detected from /proc/sys/crypto/fips_enabled. On a FIPS host,
hardening is always active; off cannot disable it.
maas config-hardening¶
usage: maas config-hardening {set,get,list,validate,enable,disable} ...
Manage MAAS hardening configuration parameters.
subcommands:
set <key> <value> Set a hardening parameter. hardening_enabled (DB-backed)
and conf-backed keys (api_bind, database_sslmode, etc.)
can be set; fips_enabled cannot (see below).
get <key> Get a hardening parameter value and its source store.
list List all hardening parameters with values and stores.
validate Run hardening validation; print violations; exit
non-zero if any exist.
enable Set hardening_enabled=on. A pure database operation;
it does not touch regiond.conf. Every bind key is
left unset so MAAS can derive or discover an
address at startup.
disable Set hardening_enabled=off; refused on FIPS hosts.
get, list, and validate are the inspection commands. validate reads the
region’s current configuration, runs every check, prints violations, and exits
non-zero when any exist — use it as on-demand audit evidence. It does not start
or restart services.
set accepts any known hardening key except fips_enabled (see below).
hardening_enabled is written to the DB Config store; keys backed by
regiond.conf (api_bind, database_sslmode, and so on) are written to
regiond.conf on the local host. The set command handles YAML quoting
automatically.
enable is a convenience shortcut for
maas config-hardening set hardening_enabled on: it writes only the DB
Config store. No bind key is seeded. See
Bind and address parameters for the
full derivation rule.
Parameters and stores¶
Key |
Store |
Default |
Purpose |
|---|---|---|---|
|
DB Config |
|
|
|
|
empty |
Path to a DH parameters PEM file. When present, it must be at least 2048 bits. |
|
|
|
PostgreSQL client SSL mode. Under hardening, use |
|
|
empty |
Path to the PostgreSQL client certificate. Required when |
|
|
empty |
Path to the PostgreSQL client private key. Required when |
|
|
empty |
Path to the CA certificate used to verify the PostgreSQL server. Required when |
TLS certificate / key |
secret store |
not set |
Public-API HTTPS certificate and key. Managed by |
fips_enabled (DB Config, not user-settable) is a read-only, auto-detected
drift flag: the first controller in the fleet to observe kernel FIPS mode
active writes true, holding every other controller in the fleet to the
same requirement thereafter. It cannot be set via config-hardening set
(see Violation codes) but is visible with get/list.
Bind and address parameters¶
The remaining parameters configure where a service listens. Under
hardening, a wildcard bind (0.0.0.0/::) is a violation; when left
unset, api_bind, agent_api_bind, and http_proxy_bind each derive a
specific address per family from maas_url at startup;
temporal_bind, rpc_bind, and syslog_bind derive a single address
matching whichever family maas_url resolves to. prometheus_bind
instead defaults to loopback (127.0.0.1) when left unset, since it’s
scraped locally rather than reached via maas_url. All are per-host,
stored in regiond.conf unless noted.
api_bind— public API bind address(es); comma-separated list, may mix IPv4 and IPv6. Left unset: auto-derived frommaas_urlas described above; otherwise binds all interfaces. Any family missing from an explicit value is still auto-derived.api_int_bind— internal (rack-facing) plain HTTP listener bind address(es), used whenever TLS is enabled; comma-separated list, may mix IPv4 and IPv6. Not derived frommaas_url— binds all interfaces when unset, which is flagged under hardening.prometheus_bind— single IPv4 address for the Prometheus metrics endpoint. Left unset: binds to127.0.0.1when hardening is active, unlike the other keys here, since it’s scraped locally by a co-located agent (e.g. grafana-agent) rather than reached viamaas_url.temporal_bind— single address for the Temporal services. Left unset: derived frommaas_urlat startup, on every install mode (region, rack+region, all-in-one).temporal_server(rackd.conf; not a hardening key) — single address the MAAS Agent dials to reach Temporal. Left unset: derived frommaas_url, the same astemporal_bind.rpc_bind— region RPC service bind address(es); comma-separated list, may mix IPv4 and IPv6. Left unset: derived frommaas_url(the same address rack controllers already use to reach the region), falling back to binding and advertising every interface only ifmaas_urlcan’t be resolved. When set, rack controllers dial exactly the configured address(es).agent_api_bind— internal API server bind address(es), dialed bymaas-agenton rack controllers (port 5242); comma-separated list, may mix IPv4 and IPv6. Same derivation asrpc_bind, per family.syslog_bind(regiond.conf/rackd.conf) — syslog service bind address(es); comma-separated list. Left unset: derived frommaas_url(the same address enrolled machines and rack controllers already reach MAAS on), the same asrpc_bind/temporal_bind.dns_bind— snap installs only. DNS (BIND9) bind address(es); comma-separated list, may mix IPv4 and IPv6, rendered into BIND9’s separatelisten-on/listen-on-v6directives. Not derived frommaas_url: DNS must serve every managed subnet, not just the interface that reaches the API, so an explicit address per family is always required under hardening. Not available (nor validated) on Debian package installs, where MAAS does not own the basenamed.conf.options.http_proxy_bind(regiond.conf/rackd.conf) — HTTP proxy (squid) bind address(es); comma-separated list, may mix IPv4 and IPv6. Left unset: binds all interfaces outside hardening, or each family derives its own address frommaas_urlwhen hardening is active, the same asrpc_bind/syslog_bind.
regiond.conf is at /var/snap/maas/current/regiond.conf for snap installs and /etc/maas/regiond.conf for Debian package installs.
regiond.conf is YAML. String values that YAML would otherwise coerce must be
quoted when editing the file directly — for example hardening_enabled: "on"
(unquoted on parses as a boolean). The maas config-hardening set command
handles quoting automatically and is the recommended way to set all parameters.
Rack controller hardening¶
maas config-hardening manages the region’s regiond.conf. A rack
controller has its own bind keys in rackd.conf and its own CLI,
maas-rack config-hardening, run locally on the rack:
usage: maas-rack config-hardening {list,get,set,validate} ...
subcommands:
list List all rack hardening parameters.
get <key> Get a rack hardening parameter value.
set <key> <value>
Set a rack hardening parameter value.
validate Run hardening validation against rackd.conf; print
violations; exit non-zero if any exist.
Keys: hardening_enabled, api_bind, rpc_bind, tftp_bind,
syslog_bind, http_proxy_bind, and (snap installs only) dns_bind.
api_bind and http_proxy_bind each derive a specific address per
family from maas_url when left unset, the same as their region
counterparts; syslog_bind derives a single address matching
whichever family maas_url resolves to. rpc_bind, tftp_bind, and
dns_bind have no such derivation: leaving rpc_bind unset binds all
interfaces and is flagged under hardening; tftp_bind and dns_bind
must serve every managed subnet rather than just the interface that
reaches the API, so each takes a comma-separated list — one address
per subnet/family — and is flagged under hardening when left unset.
maas-rack config-hardening validate checks only bind-wildcard rules —
the rack has no TLS certificate, DH parameters, or database to validate;
those checks are region-only. It does not post notifications to the
region database (see Security hardening
for the region/rack notification scope).
Violation codes¶
When hardening is active, startup validation posts each unmet prerequisite as a
non-dismissable admin notification and maas config-hardening validate prints
it. A violation clears automatically once the underlying setting is corrected.
Code |
Trigger |
Resolution |
|---|---|---|
|
No public-API TLS certificate configured |
|
|
No public-API TLS private key configured |
|
|
Certificate and key are not a matching pair |
Re-run |
|
Certificate’s key is DSA, an RSA key under 2048 bits, or the certificate is signed with SHA-1/MD5 (only checked when FIPS mode is active on the host) |
Re-run |
|
Certificate or key is not valid PEM |
Re-run |
|
|
See commands below. |
|
|
See commands below. |
|
A bind key’s value is not a valid IP address (see Bind and address parameters for the full key list) |
|
|
A bind key is set to an all-interfaces address ( |
|
|
|
See commands below. |
|
Another controller in the fleet has FIPS mode active ( |
Enable FIPS mode on this host’s kernel to match the rest of the fleet. |
Resolving WEAK_DH_PARAMS or DH_PARAMS_PARSE_ERROR: generate a new DH
parameters file and set the path:
openssl dhparam -out /var/snap/maas/current/certs/dhparam.pem 2048
sudo maas config-hardening set api_tls_dhparam /var/snap/maas/current/certs/dhparam.pem
Resolving INSECURE_DB_SSLMODE: set the SSL mode and supply the client
certificate, key, and CA certificate:
sudo maas config-hardening set database_sslmode verify-full
sudo maas config-hardening set database_sslcert /var/snap/maas/current/certs/db-client.pem
sudo maas config-hardening set database_sslkey /var/snap/maas/current/certs/db-client.key
sudo maas config-hardening set database_sslrootcert /var/snap/maas/current/certs/db-ca.pem
Not flagged when database_host is a filesystem path (e.g. the socket
directory used by maas-test-db): connections over a Unix domain socket
never negotiate TLS, so database_sslmode is not applicable.
Password policy¶
When hardening is active, MAAS enforces password complexity on every password
set through the CLI (maas createadmin, maas changepassword) and the web UI.
The same policy applies independently on any FIPS host, regardless of the
hardening_enabled setting.
A compliant password must satisfy all four rules:
Rule |
Requirement |
|---|---|
Length |
At least 14 characters |
Uppercase |
At least one uppercase letter (A–Z) |
Digit |
At least one digit (0–9) |
Special character |
At least one character that is not a letter or digit — including |
All four rules are evaluated together. When a password fails, the error message lists every unmet rule in a single response.
The policy is not configurable. It cannot be relaxed or disabled while hardening is active or FIPS mode is on.
Startup log events¶
Structured JSON events. View them with journalctl -o json.
Event |
Level |
Meaning |
|---|---|---|
|
INFO |
FIPS state read at startup ( |
|
INFO |
Resolved hardening state ( |
|
ERROR |
A prerequisite is unmet ( |
|
INFO |
An admin notification was posted for a violation ( |
Content Security Policy (CSP)¶
When hardening is active, the region controller’s nginx configuration emits a
strict Content-Security-Policy header on every response:
default-src 'self';
script-src 'self' 'sha256-…';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
frame-ancestors 'none'
The script-src directive includes a single SHA-256 hash that whitelists
one static inline <script> block required by the documentation theme.
Inline scripts are otherwise forbidden by script-src 'self'.
The CSP header is defined in the region controller’s nginx configuration template inside a hardening-only conditional block. It is only emitted when hardening is active.
Other directives¶
Directive |
Value |
Rationale |
|---|---|---|
|
|
Deny by default; every resource type must be same-origin unless overridden below. |
|
|
Sphinx and Furo emit inline |
|
|
|
|
|
Fonts must be same-origin. The Ubuntu fonts referenced by the theme are vendored under |
|
|
|
|
|
Prevents MAAS pages from being embedded in any frame (clickjacking defence). |