# Access Control Policy
**Document ID**: KD-POL-002
**Version**: 1.1
**Owner**: Chief Technology Officer
**Approved By**: CEO, Arivaran
**Effective Date**: 2026-03-19
**Last Updated**: 2026-09-30 (§3.1.3 restated as the multi-factor authentication posture actually delivered, per ticket #20984; an accuracy correction, not a change of control objective)
**Next Review Date**: 2027-03-30
**Review Cycle**: Semi-annual
**Classification**: Internal
> ⚠ **Review status.** The semi-annual review due 2026-09-19 was not recorded.
> The 2026-09-30 #20984 pass re-examined §3.1.3 against delivered state only, so
> every other section has not been reviewed since the 2026-03-19 effective date.
> The Next Review Date above runs from that pass; it does not assert that a full
> review took place.
## 1. Purpose
This policy defines the logical access control requirements for KuiperDesk infrastructure and services. KuiperDesk operates a multi-tenant backup platform where unauthorized access to any tenant's data represents a critical business and regulatory risk. Access controls must enforce least privilege, ensure individual accountability, and provide a complete audit trail of all authentication and authorization events.
## 2. Scope
This policy covers:
- Administrative access to RKE2 cluster nodes (VPS-3, product hub clusters EU1: kd-prod-b / US1: kd-prod-a) via SSH
- Kubernetes API access (kubectl, Helm, CI/CD service accounts)
- Application-level access to Keycloak, Forgejo, Mailcow, Nextcloud, and monitoring services
- Agent-to-service authentication (aaagent connecting to aaHashSvc/aaTwinSvc)
- Dashboard access (aaDash) by tenant administrators and end users
- PKI and secrets management access (OpenBao, cert-manager)
- CI/CD pipeline credentials and deployment permissions
## 3. Policy Statements
### 3.1 Identity and Authentication
3.1.1. **Individual Accounts**: Every human user who accesses KuiperDesk systems shall have a unique, individual account. Shared accounts are prohibited for interactive access. This applies to SSH, Keycloak, Forgejo, and all administrative interfaces.
3.1.2. **Centralized Identity**: Keycloak is the authoritative identity provider for all web-based services. All services that support OIDC (Forgejo, Nextcloud, Grafana, Harbor) shall use Keycloak as their authentication backend. Local accounts on these services are prohibited except for break-glass emergency access.
3.1.3. **Multi-Factor Authentication**: MFA shall be enforced for all Arivaran personnel accounts with administrative privileges. For customer accounts (aaDash), MFA (an authenticator app or a passkey) shall be available to every account and is not required at sign-in by default. A tenant administrator may require an authenticator app of every member of the tenant through the tenant's sign-in policy, where the tenant has its own sign-in realm. A fresh second factor (step-up) shall be required before a privileged administrative action in aaDash: a billing change, API key issuance, granting an administrator role, changing sign-in or authentication settings, changing where the tenant's data is stored, and issuing an enrollment key once the tenant holds data. A text-message (SMS) code shall not be accepted as a second factor.
3.1.4. **Agent Authentication (mTLS)**: The aaagent Windows client authenticates to backend gRPC services (aaHashSvc, aaTwinSvc) using mutual TLS. Client certificates are issued by the OpenBao intermediate CA with a 90-day validity period and automatic renewal. Private keys are stored in the Windows NCrypt key storage provider backed by the endpoint's TPM 2.0 where available. Endpoints without TPM shall use software-backed NCrypt storage with the key marked non-exportable.
3.1.5. **Dashboard Authentication (JWT)**: The aaDash web application authenticates users via Keycloak OIDC. Access tokens are JWTs with a maximum lifetime of 15 minutes. Refresh tokens have a maximum lifetime of 8 hours and are rotated on each use.
3.1.6. **SSH Access**: SSH to infrastructure nodes uses Ed25519 keys only. Password authentication is disabled. SSH keys are registered to individual administrators. The authorized_keys file is managed via Ansible and audited quarterly.
3.1.7. **Password Requirements**: Where passwords are used (Keycloak accounts, break-glass accounts), they must be a minimum of 14 characters with no composition rules (length-based policy per NIST 800-63B). Passwords are checked against known-breach databases via Keycloak's password policy plugin.
### 3.2 Authorization and Least Privilege
3.2.1. **RBAC via Keycloak Organizations**: Tenant isolation is enforced through Keycloak Organizations. Each tenant is a Keycloak Organization with scoped roles. JWT claims include the organization ID, which backend services use to filter data access. Users cannot access data outside their assigned organization.
3.2.2. **Kubernetes RBAC**: Kubernetes API access is controlled via RBAC. The CI/CD service account (Forgejo Actions runner) has permissions scoped to deployment-related operations in specific namespaces. No service account shall have cluster-admin privileges except the break-glass account.
3.2.3. **Administrative Tiers**: Infrastructure access follows a tiered model:
| Tier | Access Level | Personnel | Authentication |
|------|-------------|-----------|----------------|
| Tier 0 | RKE2 node SSH, etcd, OpenBao root | CTO only | SSH key + auditd |
| Tier 1 | Kubernetes admin, Helm deploys, Keycloak admin | Infrastructure engineers | Keycloak + kubeconfig |
| Tier 2 | Service admin (Forgejo, Grafana, Harbor) | Engineering team | Keycloak OIDC |
| Tier 3 | Tenant admin (aaDash) | Customer administrators | Keycloak OIDC + Org scope |
| Tier 4 | End user (aaagent, aaDash read-only) | Customer end users | mTLS (agent) / OIDC (dash) |
3.2.4. **Service Account Scoping**: Kubernetes service accounts for workloads (aaHashSvc, aaTwinSvc) are scoped to the minimum RBAC permissions required. Each service runs in its own namespace with NetworkPolicy restricting egress to only its required dependencies (e.g., aaHashSvc can reach its PostgreSQL database but not aaTwinSvc's PostgreSQL database).
3.2.5. **Break-Glass Access**: A single break-glass Keycloak local admin account exists for scenarios where OIDC is unavailable. The password is stored in an offline sealed envelope held by the CTO. Each use must be logged, justified in writing, and reported at the next risk review.
### 3.3 Access Provisioning and Deprovisioning
3.3.1. **Onboarding**: New personnel access is provisioned via a documented onboarding checklist. Access is granted based on role, not individual request. The checklist includes: Keycloak account creation, SSH key registration (if Tier 0/1), Forgejo team assignment, and Grafana role assignment.
3.3.2. **Role Changes**: When personnel change roles, access is reviewed and adjusted within 2 business days. Previous role access that is no longer required is revoked.
3.3.3. **Offboarding**: When personnel leave the organization, all access is revoked within 24 hours:
- Keycloak account disabled (not deleted, for audit trail)
- SSH key removed from authorized_keys via Ansible playbook
- Kubeconfig revoked (certificate-based auth: revoke via CRL)
- Forgejo/Grafana sessions invalidated
- Admin satgw-tunnel access revoked
3.3.4. **Agent Deprovisioning**: When a customer endpoint is decommissioned, the agent's mTLS certificate is revoked by adding it to the CRL distributed via OpenBao. aaHashSvc rejects connections from revoked certificates.
### 3.4 Access Reviews
3.4.1. Quarterly access reviews shall be conducted covering:
- All Keycloak user accounts and their organization/role assignments
- SSH authorized_keys on all infrastructure nodes
- Kubernetes RBAC bindings
- CI/CD service account permissions
- OpenBao policy assignments
3.4.2. Access reviews are documented with the reviewer name, date, accounts reviewed, and any actions taken (access removed, roles adjusted). Review artifacts are retained as SOC 2 evidence.
3.4.3. Inactive accounts (no login for 90 days) are flagged during access reviews and disabled unless a justified exception is documented.
### 3.5 Audit Logging
3.5.1. **auditd**: All SSH sessions on infrastructure nodes are logged via auditd with rules capturing: login/logout events, command execution (execve), file access to sensitive paths (/etc/shadow, /etc/ssh, /var/lib/rancher), and privilege escalation (sudo).
3.5.2. **Keycloak Audit**: All authentication events (success and failure), account modifications, role changes, and organization changes are logged by Keycloak and forwarded to Loki.
3.5.3. **Kubernetes Audit**: The RKE2 API server audit policy logs all authentication decisions, RBAC denials, secret access, and resource modifications at the RequestResponse level for write operations and Metadata level for read operations.
3.5.4. **Log Retention**: Access-related audit logs are retained for a minimum of 12 months in Loki. Logs are immutable once written (append-only storage).
3.5.5. **Alerting**: The following events generate immediate alerts via AlertManager:
- 5 or more failed login attempts to any service within 10 minutes
- SSH login from an IP outside the approved admin / satgw-tunnel range
- Use of the break-glass account
- RBAC denial for cluster-admin operations
- Certificate revocation events
## 4. Roles and Responsibilities
| Role | Responsibility |
|------|---------------|
| CTO | Approve access tier assignments. Hold break-glass credentials. Conduct Tier 0 access reviews. |
| Infrastructure Engineers | Execute provisioning/deprovisioning. Maintain Ansible access playbooks. Conduct Tier 1-2 access reviews. |
| Tenant Administrators | Manage user access within their Keycloak Organization. |
## 5. Compliance Mapping
| Policy Statement | SOC 2 Criteria | ISO 27001:2022 |
|-----------------|----------------|----------------|
| 3.1 Identity and Authentication | CC6.1, CC6.2 | A.8.2, A.8.5 |
| 3.2 Authorization and Least Privilege | CC6.3, CC6.6 | A.8.3, A.8.4 |
| 3.3 Provisioning/Deprovisioning | CC6.2, CC6.5 | A.6.1, A.6.5 |
| 3.4 Access Reviews | CC6.2, CC6.3 | A.8.2 |
| 3.5 Audit Logging | CC6.8, CC7.1, CC7.2 | A.8.15 |
## 6. Exceptions
Exceptions to this policy follow the process defined in KD-POL-001 Section 7. Access control exceptions require a documented compensating control and are limited to a maximum duration of 90 days.
## 7. Enforcement
Unauthorized access attempts are treated as security incidents under KD-POL-003. Personnel who intentionally bypass access controls are subject to immediate disciplinary action.
## 8. Revision History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2026-03-19 | CTO | Initial release |
| 1.1 | 2026-09-30 | Engineering (#20984) | §3.1.3: customer-account MFA restated as delivered (available to every account, enforceable per tenant by its administrator, step-up before privileged actions, no SMS second factor); the 2026-09-19 all-accounts enforcement date withdrawn |