Icinga Web 2 now ships a PasswordPolicyHook that gives administrators and module developers full control over what constitutes a valid password. Instead of hard-coding a single rule set for every deployment, the hook makes password validation an extension point: any module can register a policy, admins select the active one from the configuration UI, and Icinga Web 2 enforces it everywhere a local password is set or changed.
This matters because password rules are not one-size-fits-all. A deployment following BSI guidance may prefer long passphrases over character composition rules. One subject to PCI-DSS may be required to enforce composition rules. The hook lets each deployment pick the right policy instead of compromising on a single built-in one.
What ships by default
Two policies are registered out of the box:
None: accepts any non-empty password without any further checks.
Common: enforces a baseline composition rule set:
- Minimum 12 characters
- At least one number
- At least one special character
- At least one uppercase letter
- At least one lowercase letter
The active policy is selected under Configuration → Security → Password Policy. The dropdown lists every registered hook by display name.
What experts like BSI recommends for secure passwords
The German Federal Office for Information Security (BSI) publishes guidelines for creating secure passwords that are worth taking as a baseline. The key points:
- Length is the primary lever. The BSI describes two equivalent paths to a strong password: short and complex (8-12 characters using all character types) or long and simple (20-25 characters using only two character types, such as a sequence of words). Both are acceptable as length compensates for reduced character variety.
- Use all available character types when short. Uppercase and lowercase letters, digits, and special characters including spaces all expand the character space. If you are enforcing a short minimum, requiring variety matters. If you allow long passwords, it matters less.
- Avoid predictable patterns. Dictionary words, names, dates of birth, keyboard walks (asdfgh), numeric sequences (1234), and simply appending a digit to a weak base word are all ineffective regardless of how many character types they use.
- Don’t reuse passwords. Each account should have a distinct password. A password manager is the practical solution for most users.
- MFA supplements passwords. Hardware-based second factors offer the highest level of security. Passwords alone are not sufficient for high-value accounts. Icinga Web recently added native TOTP support.
The built-in Common policy maps to the BSI’s short-and-complex path. It is a reasonable baseline for organizations subject to compliance frameworks (PCI-DSS, some ISO 27001 controls) that mandate composition requirements. If your deployment would rather follow the long-and-simple path, the hook lets you install a policy that reflects that instead.
How to write a custom password policy
Since password requirements vary by organization, administrators are expected to write their own policies. A policy is a PHP class inside an Icinga Web module that extends PasswordPolicyHook. It provides a display name shown in the configuration dropdown and a machine-readable name used to persist the selection. An optional description is rendered on the password change form, so users know what is expected before they submit. The core of the policy is a validate method that receives the new password and returns a list of violation messages, or an empty list if the password is accepted. Once registered, the policy appears immediately in the dropdown under Configuration → Security → Password Policy.
The validate method also receives the old password when available, which allows policies that reject reuse.
Ideas for possible password policies
Each of these approaches catches a different class of weak password. None of them is complete on its own.
Entropy
Shannon entropy measures how evenly characters are distributed across a password. A password of a single repeated character scores 0 bits. A long, varied password approaches 7-8 bits per character. A policy can reject passwords whose entropy falls below a configurable threshold. The appeal is that it is language-agnostic and requires no external data. The limitation is that it does not detect keyboard walks or dictionary words with character substitutions: qwertyuiop scores reasonably well.
Blacklist / dictionary check
A blacklist policy maintains a set of forbidden passwords: the top 10,000 most common passwords, company or product names, or previous known bad choices specific to your organization. Lookups are fast and require no network access, making it a good complement to entropy: the blacklist catches obvious bad choices that score well on entropy (Icinga2024! is varied enough to pass but would appear in any targeted wordlist), while entropy catches low-variety passwords that are not common enough to be listed.
Reuse history
A reuse history policy rejects passwords that the user has already used before, beyond just the immediately preceding one. This closes the common pattern of cycling through a small set of passwords to satisfy rotation requirements.
Implementing this requires the module to maintain its own storage: a per-user list of previous password hashes. Icinga Web does not expose the password history, so the module must record each accepted password at change time and query that store on validation. This means the policy only covers passwords changed after the module was installed. It has no visibility into the history before that point.
Historic password hashes must be secured with the same care as any current password. Storing more entries increases both the usefulness of the policy and the value of the data to an attacker, so the retention length is a deliberate tradeoff.
HaveIBeenPwned
NIST explicitly recommends verifiers to check new passwords against breach corpora. The HaveIBeenPwned Passwords API is the practical way to do this: it exposes a database of over 800 million passwords from known breaches. A policy can query it using k-anonymity: only the first 5 hex characters of the SHA-1 hash of the password are sent over the network. The API returns all hashes sharing that prefix and the exact match is performed locally, so the plaintext password never leaves the server. When the API is unreachable, the policy should fail open so that a network hiccup does not prevent a user from changing their password.
What is next
The PasswordPolicyHook reference is on icinga.com/docs, that’s where to start if you’re writing a policy. The ideas above (entropy, blacklists, reuse history, HaveIBeenPwned) are starting points, not a spec to follow exactly: combine them, drop what doesn’t fit your compliance requirements, or write something none of us thought of. If you build one worth sharing, the Icinga community is the place to show it off.






