Variables
Variable Names
Variable names must be prefixed with the name of the role that owns the variable.
The role name may be prefixed with an underscore (_) to define internal variables.
Passwords
Every secret in the framework lives in a variable whose name ends in
_password (for example podman_link_opensearch_zammad_password).
Set these in the vault, never in defaults or plain inventory. Each one belongs
to a service account: list it in the service account inventory with its named
owner.
Passwords must be generated, not chosen, and meet the criteria:
Length: at least 40 characters.
Characters: letters and digits only (
A-Z,a-z,0-9).Rotation: generate a new value each time. Never reuse an old one.
Values pass through several layers that give special characters a meaning, and a character that’s harmless in one can break or silently change the password in another:
Jinja2: Ansible templates variable values, so
{{ }}and{% %}are evaluated, and anything between{#and#}is silently removed.systemd:
%is a unit file specifier and$is expanded inExecStart, which is where quadlets passEnvironment=values.Shell and env files: quotes, backslashes,
#,$and whitespace are interpreted, stripped or kept literally, depending on the tool.
Some symbols would be safe in some places, but letters and digits are safe everywhere.
If you need more complexity, make the password longer rather than adding symbols. Each extra alphanumeric character adds roughly 6 bits of entropy, and 40 characters give about 238 bits.
To generate one:
python3 -c 'import secrets, string; a = string.ascii_letters + string.digits; print("".join(secrets.choice(a) for _ in range(48)))'
Roles MUST replace or remove every default account and password that an application ships with.
Controls
CIS Controls v8
5.2, Use Unique Passwords: at least 14 characters without MFA.
4.7, Manage Default Accounts on Enterprise Assets and Software.
Cyber Essentials
User access control: at least 12 characters for password-only accounts (or 8 with automatic blocking of common passwords).
Secure configuration: change default passwords and remove unnecessary accounts.
OCI Container images
Every container image the framework runs is set in a role default whose name
ends in _image, on one line, in this form:
<repository>:<tag>@sha256:<digest>
for example:
podman_link_redis_image: docker.io/library/redis:8.8.0@sha256:234c902a…
Pin the digest. A tag can be moved to different contents; a digest can’t. The digest identifies exactly which image was approved.
Never specify an image anywhere else. Quadlet templates use
Image={{ *_image }}. Renovate only manages images defined as*_imagedefaults.Renovate manages these values. Don’t edit tags or digests by hand, except in an emergency (below). Renovate opens a merge request for each update. Images released together, such as the CDR Link stack, are updated together.
New releases wait 3 days (
minimumReleaseAge) before Renovate proposes them. This protects against compromised releases that are caught and pulled shortly after publication.
Emergency security updates. When a fix for a critical or high
vulnerability is released, don’t wait for the 3-day delay. Update the
*_image value to the fixed digest by pull request straight away, or approve
the update from Renovate’s dependency dashboard.
Critical and high fixes must reach production within 14 days of release.
Controls
CIS Controls v8
7.4, Perform Automated Application Patch Management.
16.4, Establish and Manage an Inventory of Third-Party Software Components.
Cyber Essentials
Security update management: high and critical updates within 14 days of release, and only supported software.