Files
mcias/internal/policy/defaults.go
Kyle Isom 25417b24f4 Add FIDO2/WebAuthn passkey authentication
Phase 14: Full WebAuthn support for passwordless passkey login and
hardware security key 2FA.

- go-webauthn/webauthn v0.16.1 dependency
- WebAuthnConfig with RPID/RPOrigin/DisplayName validation
- Migration 000009: webauthn_credentials table
- DB CRUD with ownership checks and admin operations
- internal/webauthn adapter: encrypt/decrypt at rest with AES-256-GCM
- REST: register begin/finish, login begin/finish, list, delete
- Web UI: profile enrollment, login passkey button, admin management
- gRPC: ListWebAuthnCredentials, RemoveWebAuthnCredential RPCs
- mciasdb: webauthn list/delete/reset subcommands
- OpenAPI: 6 new endpoints, WebAuthnCredentialInfo schema
- Policy: self-service enrollment rule, admin remove via wildcard
- Tests: DB CRUD, adapter round-trip, interface compliance
- Docs: ARCHITECTURE.md §22, PROJECT_PLAN.md Phase 14

Security: Credential IDs and public keys encrypted at rest with
AES-256-GCM via vault master key. Challenge ceremonies use 128-bit
nonces with 120s TTL in sync.Map. Sign counter validated on each
assertion to detect cloned authenticators. Password re-auth required
for registration (SEC-01 pattern). No credential material in API
responses or logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 16:12:59 -07:00

106 lines
4.3 KiB
Go

package policy
// defaultRules are the compiled-in authorization rules. They cannot be
// modified or deleted via the API. They reproduce the previous binary
// admin/non-admin behavior exactly when no operator rules exist, so wiring
// the policy engine alongside RequireRole("admin") produces identical results.
//
// All defaults use Priority 0 so they are evaluated before any operator rule
// (which defaults to Priority 100). Within priority 0, deny-wins still applies,
// but the defaults contain no Deny rules — they only grant the minimum required
// for self-service and admin operations.
//
// Security rationale for each rule is documented inline.
var defaultRules = []Rule{
{
// Admin wildcard: an account bearing the "admin" role is permitted to
// perform any action on any resource. This mirrors the previous
// RequireRole("admin") check and is the root of all administrative trust.
ID: -1,
Description: "Admin wildcard: admin role allows all actions",
Priority: 0,
Roles: []string{"admin"},
Effect: Allow,
},
{
// Self-service logout and token renewal: any authenticated principal may
// revoke or renew their own token. No resource scoping is needed because
// the handler independently verifies that the JTI belongs to the caller.
ID: -2,
Description: "Self-service: any principal may logout or renew their own token",
Priority: 0,
Actions: []Action{ActionLogout, ActionRenewToken},
Effect: Allow,
},
{
// Self-service TOTP enrollment: any authenticated human account may
// initiate and confirm their own TOTP enrollment. The handler verifies
// the subject matches before writing.
ID: -3,
Description: "Self-service: any principal may enroll their own TOTP",
Priority: 0,
Actions: []Action{ActionEnrollTOTP},
Effect: Allow,
},
{
// Self-service password change: any authenticated human account may
// change their own password. The handler derives the target exclusively
// from the JWT subject (claims.Subject) and requires the current
// password, so a non-admin caller can only affect their own account.
ID: -7,
Description: "Self-service: any human account may change their own password",
Priority: 0,
AccountTypes: []string{"human"},
Actions: []Action{ActionChangePassword},
Effect: Allow,
},
{
// System accounts reading their own pgcreds: a service that has already
// authenticated (e.g. via its bearer service token) may retrieve its own
// Postgres credentials without admin privilege. OwnerMatchesSubject
// ensures the service can only reach its own row — not another service's.
ID: -4,
Description: "System accounts may read their own pg_credentials",
Priority: 0,
AccountTypes: []string{"system"},
Actions: []Action{ActionReadPGCreds},
ResourceType: ResourcePGCreds,
OwnerMatchesSubject: true,
Effect: Allow,
},
{
// System accounts issuing or renewing their own service token: a system
// account may rotate its own bearer token. OwnerMatchesSubject ensures
// it cannot issue tokens for other accounts.
ID: -5,
Description: "System accounts may issue or renew their own service token",
Priority: 0,
AccountTypes: []string{"system"},
Actions: []Action{ActionIssueToken, ActionRenewToken},
ResourceType: ResourceToken,
OwnerMatchesSubject: true,
Effect: Allow,
},
{
// Self-service WebAuthn enrollment: any authenticated human account may
// register and manage their own passkeys/security keys. The handler
// verifies the subject matches before writing. Mirrors TOTP rule -3.
ID: -8,
Description: "Self-service: any principal may enroll their own WebAuthn credentials",
Priority: 0,
Actions: []Action{ActionEnrollWebAuthn},
Effect: Allow,
},
{
// Public endpoints: token validation and login do not require
// authentication. The middleware exempts them from RequireAuth entirely;
// this rule exists so that if a policy check is accidentally applied to
// these paths, it does not block them.
ID: -6,
Description: "Public: token validation and login are always permitted",
Priority: 0,
Actions: []Action{ActionValidateToken, ActionLogin},
Effect: Allow,
},
}