Privileged-access review#
Every quarter, someone reads the list of who can do what and confirms each line is still right. This is the control that catches what automation cannot: a person who changed role but kept infra, a contractor whose engagement ended without anyone removing the line, a token created for a migration and never revoked. It is deliberately small — one issue, one hour, one merge request.
Cadence and ownership#
- When: the first day of January, April, July and October, 09:00 Bucharest. The pipeline schedule Quarterly privileged-access review opens the issue (
scripts/access-review-issue.sh); nothing is reviewed automatically, the issue is the prompt and the record. - Who: a member of
infrawho is not the only one on the list being reviewed, if such a person exists; otherwise the infra lead, and the review says so. - Due: 14 days after the issue is opened. An open review issue past its due date is a finding in itself.
What is in scope#
Everything a person or a token can hold that is not derived from the directory alone:
| surface | source of truth | how to compare |
|---|---|---|
| people and their roles | the directory (https://id.profuse.ro) | the table in the issue; ask each manager "still here, still this role?" |
| contractors | cloudflare/accounts/profuse/contractors.auto.tfvars | every until date in the future |
| Access policies naming an e-mail directly | cloudflare/accounts/profuse/*.tf | each is a standing exception; keep with a reason or move to a group |
sv1 local accounts, sudo, docker group | getent group infra sudo docker, /etc/passwd | only directory accounts plus the documented local ones (deploy, root) |
| PostgreSQL human roles | \du on prod and staging | every human role is in the directory; pg-directory-sync journal clean |
| mailcow admins and password-backed mailboxes | mailcow UI → Configuration → Admins; Mailboxes with authsource ≠ generic-oidc | service accounts only (id@, gitlab@, zabbix@) |
| Cloudflare account members and API tokens | dashboard → Manage Account → Members / API Tokens | each still needed; a token unused for 90 days is revoked |
| GitLab access tokens, deploy tokens, CI variables | project/group settings → Access tokens, CI/CD → Variables | each still needed; credential variables protected + masked |
| authentik API tokens and the break-glass admin | Directory → Tokens; akadmin | tokens each tied to a running thing; akadmin has a passkey and its password is in the vault |
How to do it#
- Open the issue the schedule created (label
access-review). If the schedule did not fire, run the job by hand: CI/CD → Schedules → ▶, orbash scripts/access-review-issue.shlocally. - Walk the checklist. For every line that is not right, write what you found under the line.
- Fix through the repository where the repository is the source of truth: one merge request titled access review Qn YYYY that edits
contractors.auto.tfvarsor the policies, applied through the pipeline. A person's roles are corrected in the directory's interface, and every other clean-up (revoking a token, deleting a stray local user) is listed in the issue with the date it was done. - Close the issue with the merge request linked, or with "no change" and the date. The closed issues are the audit trail; nothing else needs to be kept.
What the review does not do#
It does not replace offboarding (docs/offboarding.md, same day) and it does not grant access — joining is still a line in the people file. It only proves, four times a year, that the two files and the world agree.