Security and Vault Architecture
Security Goals
Eco Manager manages sensitive technical operational data. Security must be designed into the product from the start.
Core goals:
- secure authentication,
- role and capability-based authorization,
- controlled secret handling,
- tenant-level encryption boundaries,
- immutable audit records,
- separation of secret values from metadata,
- minimal credential exposure,
- future support for RLS.
Authentication
Primary user authentication should use Microsoft Entra ID through OIDC.
The backend should treat identity provider claims as authentication input, not as the full authorization model.
Application-specific roles, capabilities, and entity-scoped access should be stored and evaluated by Eco Manager.
Authorisation
Authorisation should combine:
- user identity,
- role,
- capability,
- entity scope,
- hierarchy scope,
- graph relationships,
- Vault-specific rules.
Example capabilities:
entity.read
entity.create
entity.update
entity.delete
admin.entity_type.update
admin.template.update
admin.bulk_update
vault.secret.create
vault.secret.reveal
vault.secret.copy
vault.secret.rotate
remote.session.start
audit.readRoot Entity Scope
Users should be scoped to one or more root entities. A root entity is usually a tenant, customer, organisation, or internal operational boundary.
A user can only read, edit, delete, tag, move, or reveal data when the target entity is inside at least one authorised root entity tree.
Conceptually:
user.allowedRootEntityIds = [customer-a-root, customer-b-root]
target entity is editable only when:
target.path <@ allowed_root.pathThis rule should become a reusable authorisation utility used throughout the app for:
- entities,
- assets,
- properties,
- tags,
- credentials,
- secret metadata,
- secret reveal/copy operations,
- remote sessions,
- audit queries,
- Admin Studio operations,
- future RLS policies.
Example service-level helper:
assertEntityInUserScope({
userId,
targetEntityId,
capability: "entity.update",
})The helper should resolve the target entity path, resolve the user's allowed root paths, and require at least one matching root path before allowing the operation.
This same concept can later be enforced in PostgreSQL RLS as a defense-in-depth layer.
Vault Boundary
Secrets must not be edited through general entity property CRUD.
The Vault is the sole authority for:
- creating secrets,
- updating secrets,
- rotating secrets,
- revealing secrets,
- copying secrets,
- deleting secrets.
Directory and Admin Studio views may show secret metadata, such as:
- credential name,
- credential type,
- last rotated date,
- owner entity,
- access policy,
- status.
They must not expose decrypted secret values except through explicit Vault reveal/copy flows.
Secret Storage
Secret values should be encrypted before being written to the database.
Recommended baseline:
- AES-256-GCM encryption,
- unique nonce per encrypted value,
- authenticated metadata where appropriate,
- key version tracking,
- physical separation of secret ciphertext from general entity properties.
Tenant-level key management should allow per-tenant isolation, key rotation, and emergency revocation without exposing plaintext outside authorised tenant scope.
Tenant-Level Encryption Keys
Eco Manager should use tenant-level encryption boundaries so that sensitive values belonging to one customer, organisation, or root entity cannot be decrypted by another tenant.
The recommended logical model is:
Root entity / tenant
owns encryption key material
protects Vault secrets and sensitive properties within that treeThe application should treat the root entity as the encryption scope. Encrypted values should reference a tenant/root key identifier and should only be decrypted after authorisation confirms that the caller is allowed to operate within that root entity tree.
Recommended envelope-encryption model:
Tenant Root Key / KEK
encrypts Data Encryption Keys / DEKs
encrypt individual secret versions or sensitive property valuesMinimum metadata to track per encrypted value:
- tenant/root entity id,
- key id,
- key version,
- algorithm,
- nonce / IV,
- ciphertext,
- authentication tag,
- authenticated context / AAD,
- created by,
- created at.
The authenticated context should include stable identifiers such as:
tenant_root_entity_id
entity_id
secret_id or property_value_id
secret_version_id
key_versionThis prevents ciphertext from being copied between tenants or entities without detection.
Operational rule:
A user should never be able to decrypt sensitive values unless they are authorized for the value's root entity scope and have the required Vault capability.
For Alpha, the key-management implementation can be pragmatic. For production, the design should allow migration to an external KMS, HSM, cloud KMS, or customer-managed-key model without changing the Vault contract.
Secret Versioning
Every secret change should create a new version.
Secret version records should include:
- secret id,
- version number,
- ciphertext,
- nonce,
- key version,
- created by,
- created at,
- reason or change note where appropriate.
Audit Events
The audit log should record sensitive operations immutably.
Examples:
secret.created
secret.revealed
secret.copied
secret.rotated
secret.deleted
entity.created
entity.updated
entity.deleted
entity.restored
relationship.created
relationship.deleted
admin.entity_type.updated
admin.template.updated
admin.bulk_update.performed
remote_session.started
remote_session.endedAudit records should answer:
- who performed the action,
- what action occurred,
- which entity or secret was affected,
- when it happened,
- from which context,
- whether it succeeded or failed.
RLS Direction
The entity hierarchy supports future row-level security.
A tenant, customer, organisation, or operational scope can be represented by a root entity path.
Example concept:
path <@ current_setting('app.root_entity_path')::ltreeFor users with access to multiple roots, the application can set an array of allowed root paths or use a session-scoped authorization table.
RLS should not be rushed into Alpha unless needed. The application service authorization model should be clear first. RLS can then be added as a defense-in-depth layer.