Setting the authentication policy
Settings → Platform security is where the panel says what it expects of a login: which second factor, how long a password has to be, and when somebody is left outside for a while after too many failed attempts. This page walks through the f
Written for: Administrator
Settings → Platform security is where the panel says what it expects of a login: which second factor, how long a password has to be, and when somebody is left outside for a while after too many failed attempts. This page walks through the four blocks, and says for each what it cannot do and why.
Everything here is administrator work. A reseller does not see the tab — the API refuses it, and a tab that answers 403 is worse than no tab.
Authentication policy: three stances per level
The table at the top has one row per factor × level. The factors are an authenticator app and a passkey; the levels are Global admin, Server-admin, Reseller and Customer. Each row is in one of three stances:
| Stance | What it means |
|---|---|
| Off | The panel never asks for it. Anybody who wants it may always have one — "off" never takes anything away. |
| Available | Encouraged, with a standing notice in the panel, but nobody is stopped. |
| Enforced | Required. Whoever does not have it lands on the enrolment screen when signing in, and can reach nothing else. |
The grace period
Move a level to Enforced and the panel asks for a grace period in days. It works the way Google Workspace's does:
- the panel remembers the day you decided;
- everybody who already had a login on that day gets as many days as you enter, counted from that day. During it they see a notice with the date on it;
- after that it is no longer a notice but a wall: signing in ends on the enrolment screen.
A login created after your decision gets no grace at all. It never knew a world without the rule, and a fortnight's reprieve would mean the rule takes effect two weeks after the last person who wants to work around it has signed up.
The Effect now column on the right translates the rule into what happens today: never asked for, encouraged, required from 19-08-2026, or signing in asks for enrolment first.
What you cannot set, and why
Global admin and Server-admin have no dropdown for the authenticator app: they show the word Enforced and an information icon. Those two levels can change other people's servers, so a second factor is fixed for them — and there is no grace period either, because a week in which the strongest login on the platform is a password is a week too many.
This is not a screen rule. The panel applies it when it reads the setting, so a row written by hand into the database comes back out as Enforced:
ssh root@panel1.corecp.dev
sudo -u postgres psql -d corecp_panel -c \
"UPDATE setting SET value = '{\"totp\":{\"admin\":{\"stance\":\"off\"}}}'::jsonb
WHERE key = 'security.auth_policy'"
curl -s -b jar http://127.0.0.1:8080/api/v1/security/policy | jq '.factors[0]'
# { "factor": "totp", "level": "admin", "stance": "enforced", "floor": "enforced", … }The passkey fallback
Below the table there is one switch: A code from an app still works beside a passkey. Off by default. While it is off, the §B6 rule applies: whoever has registered a passkey on a hostname must use it there — a code from an app is refused.
Turning it on is a real weakening. A passkey that a code can bypass no longer protects against phishing, because a fake site then only has to ask for the code. corecp-panel doctor reports it for as long as it is on.
Password policy
Length only. No forced renewal, no rules about capitals or punctuation: NIST SP 800-63B rev.4 (2025) advises against both, because they push people towards Summer2026! instead of towards something long.
- Minimum per level. 15 characters by default, and 20 for Global admin and Server-admin. You cannot go below 15: that is the floor the standard names, and the panel refuses it.
- Maximum. At least 64, so a passphrase fits. Higher is allowed; lower is not.
- Only when a password is set. Raise the minimum and everybody's existing password stays valid. The new number applies at the next change or for a new account. Otherwise moving a slider would be an outage with a security justification stapled to it.
The breach check
The switch Refuse known breached passwords asks Have I Been Pwned. What leaves your server is five characters:
- the panel computes the SHA-1 of the password;
- it sends the first five characters of that hash — for
password123that isCBFDA— to the range API; - it gets back every hash starting with those five (about eight hundred) and compares locally.
So the service learns that somebody on this panel checked a password whose hash begins with five particular characters. That is roughly one in a million passwords, and it is not a fact about a person. You can see it in the log:
ssh root@panel1.corecp.dev 'journalctl -u corecp-panel -n 200 | grep breached-password'
# Aug 16 11:04:12 panel1 corecp-panel[8812]: breached-password check prefix=CBFDAThere is nothing there but prefix=, and that is deliberate: that line is the proof that nothing else goes out.
If the service is unreachable, the password goes through. With a warning in the log, but it goes through. That is a decision and not an oversight: a third party that is down must not stop anybody who wants to change their password — which is exactly when you need it most.
The connection uses the same outbound guard as the rest of the panel: https only, no redirects, and a check on the real IP address immediately before connecting. The panel will not connect to an address inside your own network.
Lockout after failed attempts
Three numbers, saved together:
- Attempts — how many failed sign-ins lock a login (3-50);
- Window — how long a failed attempt counts (1-1440 minutes);
- Duration — how long the lock stays on (1-240 minutes).
The window is new in 0.17.16 and fixes a genuinely annoying case: without one the counter only fell back on a successful sign-in, so five typos spread over a year locked an account exactly as hard as five guesses in ten seconds. Now a failure older than the window expires.
There is deliberately no permanent lockout. Anyone who knows an email address could trigger one, and then the security control is the outage.
If a blue note says "These values still come from panel.yaml", nobody has saved them here yet and the panel is using the numbers from the configuration file. Save once and the panel takes them over.
Locked-out logins
Below that is who the panel is currently refusing, with the number of failed attempts, when the last one was, and how long the lock has left. Unlock sets the counter to zero and takes the lock off. It asks for confirmation — it is an action on somebody else's account — and the owner of the address gets an email about it, even if they have switched every notification off.
Only live locks are listed. A lock that has already expired is not: an unlock button beside it would be a button that does nothing.
From the command line:
ssh root@panel1.corecp.dev
corecp-panel audit list --action security.unlock --limit 10Set in panel.yaml
At the bottom is a block of security values the panel does use but cannot change itself: how long a session lives, the hard ceiling on it, the rate limits towards the servers, the mass-operation threshold, and the proxies whose X-Forwarded-For the panel believes.
They are there on purpose. A settings screen that shows six of the nine knobs teaches an administrator that the other three do not exist. They are read-only, with the sentence saying they live in /etc/corecp-panel/panel.yaml and take effect after a restart — and there is no button that pretends otherwise:
ssh root@panel1.corecp.dev
sed -n '/^security:/,/^[a-z]/p' /etc/corecp-panel/panel.yaml
systemctl restart corecp-panelSince 0.18.0 the sentence beside each value is in your language. Those sentences are written by the panel server, which does not know what language you have set — so it sends each one as a key with the English sentence beside it: the panel translates it, and a command-line client gets the sentence it always got. Until 0.18.0 there were seven English sentences on a Dutch screen here.
ssh root@panel1.corecp.dev
curl -s -b jar http://127.0.0.1:8080/api/v1/security/policy | jq '.file_only[0]'
# { "key": "session_ttl", "value": "12h0m0s",
# "what": "how long a session lives without being used",
# "what_msg": { "key": "policy.fileOnly.sessionTTL", "text": "how long a session lives without being used" } }Withdrawn certificates
This screen is about people signing in. Machines do not sign in: every server in the fleet proves who it is with a certificate from this panel's certificate authority, valid for ninety days and renewed automatically.
If a key leaves the building — hardware replaced, a machine stolen, a backup in the wrong place — you withdraw that certificate. Security → Withdrawn certificates shows what the fleet refuses: which machine, why, when and by whom. Usually it is empty, and that is the healthy state.
Withdrawing happens on the server's own page, under Danger zone → Retire this server. Two things happen at once: the certificate authority stops renewing the certificate, and every server that answers is told to refuse it. Machines that were down get the list later — the panel repeats it every quarter of an hour, and the button on this screen does it straight away.
If a withdrawn certificate turns up again afterwards, the server remembers it and you hear about it. That is exactly the kind of message you do not want to miss: somebody is using a key that was decided against.
See Managing a server for the button itself.
The authority itself, and when it expires
At the bottom of this screen, under Break glass, there are a few facts about the panel. Two of them are about certificates and they are worth keeping apart:
| Certificate | the certificate the panel identifies itself to the servers with. It renews itself; a failed renewal is a week's work. |
| Fleet authority | the authority every server was joined against. If it expires, no node certificate can be renewed and no new join can be verified — and replacing it means re-joining every machine. |
The second row is new. It is shown to administrators only: it is a property of the control plane, and the rest of the panel does not get the date. Not seeing it is the answer rather than a fault.
The panel warns a long way out — amber a year ahead, red three months ahead — and that finding is read under Servers → Monitoring, in the This panel block. See What the panel knows about itself.
Everything is recorded
Every change on this page is a line in the audit log, with what changed and from what to what:
ssh root@panel1.corecp.dev
corecp-panel audit list --action security.policy.factor --limit 5And every change asks for a fresh factor. Even if you have been signed in for an hour: the panel puts up a window asking once more for your passkey or your code, and then performs the action. You do not have to configure anything for that.
What you set here is about everybody on this panel. What you have — your own passkeys, your own second factor, your own sessions — is under Securing your account.