Skip to content

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:

text
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.read

Root 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:

text
user.allowedRootEntityIds = [customer-a-root, customer-b-root]

target entity is editable only when:
    target.path <@ allowed_root.path

This 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:

ts
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:

text
Root entity / tenant
    owns encryption key material
        protects Vault secrets and sensitive properties within that tree

The 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:

text
Tenant Root Key / KEK
    encrypts Data Encryption Keys / DEKs
        encrypt individual secret versions or sensitive property values

Minimum 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:

text
tenant_root_entity_id
entity_id
secret_id or property_value_id
secret_version_id
key_version

This 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:

text
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.ended

Audit 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:

sql
path <@ current_setting('app.root_entity_path')::ltree

For 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.