> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/security-architecture.md).

# Security architecture

[Architecture overview](/decentralization-manager/concepts-and-development/architecture-overview.md) · [Audit and design acknowledgements](/decentralization-manager/operations-and-reference/audit-and-design-acknowledgements.md)

## Security model

Decentralization Manager combines several security layers. The layers are host controls, operator authentication, Canton authorization, encrypted peer communication, protected local state, supply-chain controls and on-ledger governance. No single layer secures the whole deployment.

Each organization operates its own Decentralization Manager node. The organization controls its accounts, identity provider, Canton credentials, local storage, network exposure, peer records and upgrades. On-ledger governance limits application actions. It does not protect a compromised host or incorrect off-ledger input.

## Trust boundaries

{% code expandable="true" %}

```mermaid
flowchart LR
  A["Operator browser"] -->|"HTTPS and OIDC token"| B
  W["Wallet or tenant client"] -->|"Tenant API key"| B
  S["Metrics scraper"] -->|"No authentication"| M
  G["Peer Decentralization Manager node"] <-->|"Noise transport, allowlisted keys"| P
  subgraph DM["Decentralization Manager node"]
    B["HTTP API and web UI"]
    M["Metrics listener"]
    P["Noise peer listener"]
    D["Noise key, database, and DARs"]
  end
  B -->|"Token validation"| C["Identity provider"]
  B -->|"Privileged connection"| E["Canton Admin API"]
  B -->|"Party credentials"| F["Canton Ledger API"]
  B -->|"kms:Sign, KMS-backed participants only"| K["AWS KMS"]
  E --> H["Canton participant"]
  F --> H
  H --> I["Canton Network"]
```

{% endcode %}

Treat every arrow as a separate boundary. Each boundary needs its own authentication, authorization, encryption, validation, logging and failure handling.

### Inbound surfaces

| Surface                                                                                       | Default port                  | Authentication                                                                                        | Hardening                                                                                                                        |
| --------------------------------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| HTTP API and web UI                                                                           | `8080` (`DECPM_PORT`)         | OIDC bearer token from Keycloak or Auth0. Privileged routes also need the role in `DECPM_ADMIN_ROLE`. | Set `DECPM_ADMIN_ROLE`. If it is unset, every authenticated caller acts as an admin. Put TLS in front of the port.               |
| Public paths: `/`, `/index.html`, static assets, `/auth-config`, `/healthz`, `/.well-known/*` | `8080`                        | None                                                                                                  | These paths return the web UI, the public login settings and a liveness response.                                                |
| First `PUT /party-config` on a new node                                                       | `8080`                        | None, while the node stores no party credentials                                                      | Configure the first party right after the first start. Keep the HTTP port on a trusted network until then.                       |
| Tenant API, `/v0/tenant/*`                                                                    | `8080`                        | Bearer key from `DECPM_TENANT_API_KEYS`. The key bypasses the operator token and the admin role.      | Leave the variable unset unless the node hosts external parties or adds hosts to a local party. Keep the keys in a secret store. |
| Noise peer listener                                                                           | `9000` (`DECPM_NOISE_PORT`)   | Allowlisted secp256k1 peer keys. Each peer pair derives a pre-shared key through ECDH.                | Verify peer records out of band. Expose only this port to peers.                                                                 |
| Metrics listener, `/metrics`                                                                  | `9464` (`DECPM_METRICS_PORT`) | None                                                                                                  | Keep the port inside the private network. Set `DECPM_METRICS_PORT=0` if no collector reads it.                                   |

{% hint style="warning" %}
**Unauthenticated first configuration.** A node with no stored party credentials accepts the first `PUT /party-config` without a token. The node runs one such request at a time. It rejects a concurrent request with HTTP 409. After the first party credentials exist, the route needs a valid token. It also needs the admin role when `DECPM_ADMIN_ROLE` is set. Complete the first configuration before you expose the HTTP port.
{% endhint %}

{% hint style="danger" %}
**Insecure mode.** `DECPM_INSECURE=true` turns off inbound authentication. In this mode, the tenant API accepts requests without a key. The node also serves the Swagger UI. The node starts in insecure mode only on DevNet. When `DECPM_CANTON_NETWORK` is unset, the network defaults to `devnet`.
{% endhint %}

The metrics listener has no authentication. It binds to `DECPM_HOST`, the same address as the HTTP API. Metric labels include party IDs. The [Monitoring and logging](/decentralization-manager/operations-and-reference/monitoring-and-logging.md) page describes the metrics.

## Protected local state

The data directory holds the Noise key file `data/noise.key`, the SQLite database and the DAR files. The database path defaults to `data/decpm.db`. The database stores the party credentials, the workflow payloads and each party's public key bundle.

`DECPM_DB_ENCRYPTION_KEY` encrypts these database values with AES-256-GCM. Decentralization Manager derives the encryption key from the passphrase with SHA-256. When the variable is unset, the database stores the party credentials in plaintext.

* Use a long random passphrase, and keep it in a secret store.
* Back up the passphrase with the database. Decentralization Manager cannot read values that a different passphrase encrypted.
* Protect the data volume. The passphrase does not encrypt the Noise key file.

## Daml key custody

Each member of a Decentralized Party holds two keys on its participant. The namespace key signs topology transactions. The Daml key signs ledger transactions for the party, for example the governance contract deployment.

The participant signs topology transactions itself. Canton has no API that signs a ledger transaction with a vault key. Decentralization Manager therefore signs the ledger transactions itself. The crypto provider of the participant decides how Decentralization Manager signs:

| Participant crypto provider | Location of the Daml private key                | How Decentralization Manager signs                                                                                                                                                                                    |
| --------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| JCE                         | The participant's vault. The key is exportable. | It exports the key over the Admin API with `VaultService.ExportKeyPair` each time it signs. It signs in memory with Ed25519 and then wipes the key bytes. It never stores the private key in its database or on disk. |
| AWS KMS                     | AWS KMS. The key cannot leave AWS KMS.          | It calls the AWS KMS `Sign` API with the key ID that the participant reports. The Decentralization Manager IAM role needs `kms:Sign` on the key.                                                                      |

Decentralization Manager selects the path from the key metadata. A key with a KMS key ID uses AWS KMS. A key without one uses the export path. Before each submission, Decentralization Manager verifies every signature against the public key that the participant registered.

{% hint style="warning" %}
On a JCE participant, any caller with Admin API access can export the party's Daml private key. Restrict the Admin API to the Decentralization Manager host. A KMS-backed participant keeps the key in AWS KMS. IAM then controls who can sign.
{% endhint %}

### KMS key ID validation

Decentralization Manager accepts only a bare AWS KMS key ID in the participant's key metadata. A bare key ID is a UUID, or `mrk-` followed by 32 hexadecimal digits. Decentralization Manager rejects an ARN, an alias or a malformed ID before it calls `Sign`. The error is `Invalid kms_key_id`.

AWS resolves a bare key ID in the account and region of the Decentralization Manager credentials. Key metadata therefore cannot redirect signing to a key in another account. [Sign with AWS KMS](/decentralization-manager/operations-and-reference/sign-with-aws-kms.md) describes the IAM setup.

## Coordinator and peer trust

A coordinator orders the workflow steps, collects the signatures and submits the result. It also builds the payloads: topology proposals, DAR files and prepared ledger submissions. A peer does not trust the content of these payloads. The Noise channel proves the identity of the coordinator, not the intent of the peer operator.

The peer operator accepts an invitation once per workflow run. The invitation names the party, the members, the threshold and the participant that joins or leaves. It also names the DAR files and their hashes. Before a peer signs or installs anything, it checks the payload against the accepted invitation:

* The command belongs to the accepted workflow kind.
* Each topology proposal targets the accepted party, member set and threshold. It also keeps the namespace of this node among the owners.
* For kick, add-party and change-threshold, each proposal must make exactly the expected change to the current on-chain state.
* The peer recomputes the hash of each prepared ledger submission. The submission must act as the accepted party and match the accepted contract creates.
* Each DAR file must match the accepted file name and SHA-256 hash.

These checks limit what a coordinator can get a signature for. They do not make the coordinator trustworthy. The [architecture document](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ARCHITECTURE.md#coordinator--peer-trust-model) lists the known gaps:

* During onboarding, a peer cannot verify the namespaces and signing keys of the other members.
* An add-party namespace change does not tie the added owner to the new member.
* A kick does not tie the removed owner and key to the member that leaves.
* A legacy `PartyToKeyMapping` does not limit how many keys a proposal removes.
* A peer that accepts a contracts invitation authorizes the contract creates that the invitation states. Review them before you accept.
* An older coordinator can send an invitation without DAR hashes. The peer then checks the file names only and logs a warning.

## Reward delegation authority

A reward delegation lets any one listed assigner reassign the unassigned reward coupons of a Decentralized Party. The assigner needs no vote. The delegation contract fixes the beneficiary split. An assigner therefore controls the timing of an assignment, not its destination. Only a governance vote can replace or revoke the delegation.

Decentralization Manager also checks the identity of the delegation and the coupons:

* Before each assignment, it reads the template of the delegation from the ledger. It refuses the delegation unless the template is `Governance.Rewards.CouponReassignmentDelegation:CouponReassignmentDelegation` in the configured `governance-rewards-automation-v1` package.
* It compares the full party ID of this node's member with the assigner list.
* It assigns only `Splice.Amulet:RewardCouponV2` coupons from the DSO that the delegation names.

[Reward automation](/decentralization-manager/operations-and-reference/reward-automation.md) describes all the checks.

## Governance limits

Governance authorizes application actions on Canton. It does not prove that every input, package, host or external system is safe. Members must review the proposal, the referenced contracts, the package versions and the expected effects before they confirm.

`GovernanceRules_ConfirmAction` accepts a confirmation only while the live rules list the proposer as a member or an additional proposer. Decentralization Manager flags a proposal whose proposer the rules no longer list:

* The card in **Approvals** shows **Proposer not authorized** and hides **Confirm**.
* **Cancel proposal**, **Revoke** and **Execute** stay available. Only the proposer can cancel the proposal.
* If the node cannot read the rules contract or the proposer, the card keeps **Confirm**. The ledger then decides.

Do not treat a fixed approval count as a universal product property. `GovernanceRules` permits a 1-of-1 configuration for bootstrap and development. [Audit and design acknowledgements](/decentralization-manager/operations-and-reference/audit-and-design-acknowledgements.md) explains this decision.

## Control ownership

<table data-search="false"><thead><tr><th>Boundary</th><th>Primary controls</th><th>Canonical procedure</th></tr></thead><tbody><tr><td>Operator access</td><td>OIDC, PKCE, admin role, session and account controls</td><td><a href="/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md">Authentication and operator roles</a></td></tr><tr><td>Canton connections</td><td>Separate Admin and Ledger credentials, least privilege, restricted network paths, TLS or mTLS</td><td><a href="/decentralization-manager/get-started/production-deployment.md">Production deployment</a></td></tr><tr><td>Daml key signing</td><td>Admin API restriction, AWS KMS key policy, <code>kms:Sign</code> scope</td><td><a href="/decentralization-manager/operations-and-reference/sign-with-aws-kms.md">Sign with AWS KMS</a></td></tr><tr><td>Peer communication</td><td>Persistent Noise identity, encrypted transport, allowlisted keys, out-of-band verification</td><td><a href="/decentralization-manager/get-started/connect-peers.md">Connect peers</a></td></tr><tr><td>Tenant API</td><td>Tenant API keys, secret storage, network restriction</td><td><a href="/decentralization-manager/operations-and-reference/decentralize-an-external-party.md">Decentralize an external party</a></td></tr><tr><td>Metrics</td><td>Private network for the metrics port, or <code>DECPM_METRICS_PORT=0</code></td><td><a href="/decentralization-manager/operations-and-reference/monitoring-and-logging.md">Monitoring and logging</a></td></tr><tr><td>Persistent data</td><td>Restricted storage, <code>DECPM_DB_ENCRYPTION_KEY</code>, protected backups, consistent recovery</td><td><a href="/decentralization-manager/operations-and-reference/backup-recovery-and-upgrades.md">Backup, recovery, and upgrades</a></td></tr><tr><td>DAR supply chain</td><td>Approved source, version pinning, hashes, review and package comparison</td><td><a href="/decentralization-manager/operations-and-reference/package-and-contract-operations.md">Package and contract operations</a></td></tr><tr><td>Governance</td><td>On-ledger proposals, confirmations, active rules, execution, expiry and result verification</td><td><a href="/decentralization-manager/concepts-and-development/governance-lifecycle.md">Governance lifecycle</a></td></tr><tr><td>Reward automation</td><td>Fixed split, assigner list, delegation and coupon identity checks</td><td><a href="/decentralization-manager/operations-and-reference/reward-automation.md">Reward automation</a></td></tr><tr><td>Release compatibility</td><td>Approved versions, peer protocol, migrations, known issues and support status</td><td><a href="/decentralization-manager/operations-and-reference/compatibility-releases-and-troubleshooting.md">Compatibility, releases, and troubleshooting</a></td></tr></tbody></table>

## Threat model and residual risks

* **Compromised operator account:** can call the routes and use the Canton rights that the account has.
* **Compromised host:** can expose local credentials, falsify the UI, interrupt workflows or misuse the assigned Canton rights. On a JCE participant, it can also export the party's Daml private key.
* **Leaked tenant API key:** gives access to every `/v0/tenant/*` endpoint on the node without an operator token.
* **Exposed metrics port:** discloses party IDs and operational counters to any caller.
* **Unset database encryption key:** leaves the party credentials readable to anyone who can read the database file.
* **Wrong peer record:** creates encrypted trust with the wrong endpoint. Encryption does not replace identity verification.
* **Lost or replaced Noise identity:** changes how peers recognize the node. The replacement needs coordination with every peer.
* **Malicious or incompatible DAR:** can affect application behavior, even after a successful distribution.
* **Mixed peer versions:** can interrupt coordination when the peer protocol changes.
* **Compromised coordinator:** can get signatures only for payloads that pass the peer checks. The known gaps above still apply.
* **Coordinator failure:** can stop workflow progress. It does not invalidate the existing Decentralized Party.
* **Compromised reward assigner:** can assign coupons early or late, but only to the approved split.
* **Inconsistent restore:** can keep only part of the identity, credential, package or workflow state.
* **Sensitive logs or support exports:** can leak credentials or confidential identifiers. Sanitize them before you share them.

## Audit and disclosure

Quantstamp reviewed the governance Daml packages. [Audit and design acknowledgements](/decentralization-manager/operations-and-reference/audit-and-design-acknowledgements.md) lists the reviewed revisions, the scope, the findings and the design acknowledgements. An audit is point-in-time evidence. It is not a guarantee for every deployment or later release.

Report a vulnerability through a private channel. Do not use public issues, discussions or pull requests.

* **GitHub private vulnerability reporting (preferred):** open the **Security** tab of the repository and select **Report a vulnerability**.
* **Email:** `eng@bitsafe.finance`.

The project applies security fixes to the latest release and to the `main` branch.

## Technical sources

* [Security policy](https://github.com/DLC-link/decentralization-manager/blob/main/docs/SECURITY.md)
* [Architecture](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ARCHITECTURE.md)
* [Deployment guide](https://github.com/DLC-link/decentralization-manager/blob/main/docs/DEPLOYMENT_GUIDE.md)
* [Signing with AWS KMS party keys](https://github.com/DLC-link/decentralization-manager/blob/main/docs/KMS_SIGNING.md)
* [Audit design acknowledgements](https://github.com/DLC-link/decentralization-manager/blob/main/docs/audit-acknowledgements.md)
* [Authentication middleware](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/middleware/auth.rs)
* [Database encryption](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/db/crypto.rs)
* [Signing backends](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/signing/mod.rs)
* [Reward automation](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/reward_automation.rs)

## Next step

👉 **Apply the controls:** [Production deployment](/decentralization-manager/get-started/production-deployment.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/security-architecture.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
