Access Control Policy¶
Effective Date: 2026-03-02 Last Review: 2026-03-02 Next Review: 2026-09-02 Owner: Greg Felice, Project Lead
1. Purpose¶
This policy defines how access to tomo infrastructure, services, and data is granted, managed, reviewed, and revoked.
2. Scope¶
Applies to all systems in the tomo ecosystem:
- PostgreSQL databases (development and hosted service)
- Server infrastructure (dweezil, cloud VMs)
- CI/CD pipelines (Forgejo, Woodpecker)
- Monitoring (Grafana, Prometheus, postgres-exporter)
- Docker Hub (image publishing)
- PyPI (package publishing)
- DNS and domain management
- Authentik SSO
3. Principles¶
- Least privilege — Users receive the minimum permissions required for their role
- Named accounts — No shared accounts; every credential maps to an individual
- Defense in depth — Multiple authentication factors where supported
- Timely revocation — Access removed within 24 hours of role change
4. Authentication Requirements¶
4.1 SSH Access¶
| Requirement | Standard |
|---|---|
| Method | Key-based only (password auth disabled) |
| Key type | Ed25519 or RSA 4096-bit minimum |
| Passphrase | Required on private keys |
| Agent forwarding | Disabled by default |
4.2 Database Access¶
| Requirement | Standard |
|---|---|
| Auth method | scram-sha-256 (no trust or md5) |
| Password complexity | Minimum 16 characters, generated randomly |
| Connection encryption | TLS required (sslmode=require minimum) |
| Superuser access | Infrastructure owner only, not used for application queries |
4.3 Web Services (Forgejo, Grafana, Admin Panels)¶
| Requirement | Standard |
|---|---|
| SSO | Authentik OIDC/SAML |
| MFA | Required (TOTP or WebAuthn) |
| Session timeout | 8 hours idle, 24 hours maximum |
| Password policy | 16+ characters, no reuse of last 10 |
4.4 API Access (Hosted Service)¶
| Requirement | Standard |
|---|---|
| Method | API key (initial), OAuth2 (future) |
| Key rotation | Every 90 days |
| Scope | Per-database, minimum required permissions |
| Rate limiting | Enforced per key |
5. Authorization Model¶
5.1 PostgreSQL Roles¶
| Role | Permissions | Use Case |
|---|---|---|
tomo_admin |
Superuser equivalent, extension management | Infrastructure owner only |
tomo_app |
CRUD on application schemas, LOAD 'age' | Application service accounts |
tomo_readonly |
SELECT only on specified schemas | Monitoring, reporting |
tomo_tenant_{id} |
Full access to own database only | Hosted service tenants |
Role hierarchy:
Tenant roles are isolated — no cross-database access.
5.2 Infrastructure Roles¶
| Role | Access | Holders |
|---|---|---|
| Infrastructure Owner | Root/sudo on all servers, all database roles | Project Lead |
| CI Service Account | Deploy, publish packages, push images | Woodpecker CI |
| Monitoring | Read-only database metrics, log access | Grafana/Prometheus |
5.3 Repository Roles¶
| Role | Permissions | Holders |
|---|---|---|
| Owner | Full admin, merge to main, tag releases | Project Lead |
| Maintainer | PR review and merge, CI management | Trusted contributors |
| Contributor | Fork, submit PRs, open issues | Public |
6. Access Lifecycle¶
6.1 Granting Access¶
- Request: Documented request (issue or direct communication)
- Approval: Project Lead approves based on role and need
- Provisioning: Create named account with minimum required permissions
- Confirmation: Verify access works, document in asset inventory
6.2 Modifying Access¶
- Role changes require documented approval
- Privilege escalation requires explicit justification
- Temporary elevated access has a defined expiration (maximum 7 days)
6.3 Revoking Access¶
Triggers for immediate revocation:
- Contributor leaves the project
- Role change that reduces required access
- Security incident involving the account
- Account compromise (suspected or confirmed)
Timeline: Within 24 hours of trigger event.
Revocation checklist:
- [ ] SSH keys removed from
authorized_keys - [ ] Database roles dropped or password rotated
- [ ] Authentik account deactivated
- [ ] API keys revoked
- [ ] CI/CD secrets rotated if shared
- [ ] Reviewed recent activity for anomalies
7. Access Reviews¶
7.1 Schedule¶
| Review Type | Frequency | Scope |
|---|---|---|
| Quarterly access review | Every 3 months | All accounts, roles, and permissions |
| Annual privilege audit | Yearly | Superuser/admin accounts, service accounts |
| Event-triggered review | As needed | After incidents, org changes, infrastructure changes |
7.2 Process¶
- Export current access lists (PG roles, SSH keys, Authentik users, API keys)
- Compare against approved access register
- Identify and remove stale/unauthorized access
- Document findings and actions
- Store review record in
docs/security/access-reviews/YYYY-QN.md
8. Service Accounts¶
| Account | Purpose | Key Rotation | Owner |
|---|---|---|---|
| Woodpecker CI | Build, test, publish | 90 days | Infrastructure Owner |
| Grafana postgres-exporter | Database metrics collection | 90 days | Infrastructure Owner |
| Docker Hub publish | Push container images | 90 days | Infrastructure Owner |
| PyPI publish | Push Python packages | 90 days (Forgejo token) | Infrastructure Owner |
Service accounts:
- Must not have interactive login capability
- Must use minimum required permissions
- Must have credentials stored in CI secrets or secrets manager (never in code)
- Must be included in quarterly access reviews
9. Emergency Access¶
In case of emergency (incident response, critical production issue):
- Emergency access may be granted without prior approval
- Must be documented within 24 hours after the fact
- Emergency credentials must be rotated within 48 hours
- Post-incident review must evaluate whether emergency access was appropriate
10. Compliance Mapping¶
| SOC 2 Criteria | Control |
|---|---|
| CC6.1 | Logical access security over infrastructure and systems |
| CC6.2 | User authentication and authorization |
| CC6.3 | Access provisioning and management |
| CC6.6 | Access review and revocation |