# Installation environment setup

This section outlines the critical preparatory and planning steps you need to provision your environment for a successful production installation. This involves two main streams of work:

1. Infrastructure planning: Provisioning all required external services (database, message queue, HSM, blockchain nodes, etc.). This is the longest and most critical part of the process.
2. Asset Preparation: Setting up your deployment tools and obtaining the Helm charts and container images for installation.


## Preparing the deployment workstation

The deployment workstation serves as the "control plane" for your installation and upgrade operations. You typically use a secured Linux machine (or VM). This machine must have network access to your Kubernetes cluster's API server and to Ripple's container registry.

This workstation requires three key tools:

* **Helm:** The package manager for Kubernetes. You use Helm to manage the application's release. Define *what* you need (which Docker images, what configuration) in the `production.yaml` file.
* **kubectl:** The command-line tool for interacting directly with your Kubernetes cluster's API server.
* **cosign:** The tool used to verify the cryptographic signatures of the container images.


**Tool versions:** Ensure you have compatible versions of these tools installed. Consult with your Ripple contact for the minimum required versions for your Ripple Custody release.

### Understanding the tools

* **Kubernetes (K8s):** This is your container orchestration platform. It runs "Pods," which are made up of one or more Docker containers.
* **Helm:** A templating solution. You provide it with a `production.yaml` file (your inputs), and it generates the complex Kubernetes manifests needed to deploy all the Pods and services.


## Infrastructure prerequisite planning

In an on-premises production deployment, you must provision all major infrastructure components *before* you can run the Helm chart. The installation process focuses on configuring connections to these pre-existing services.

You must plan, procure, and provision the following 6 items:

| # | Prerequisite | Details & Key Considerations | Required outputs | Planning document |
|  --- | --- | --- | --- | --- |
| 1 | Database (DB) | A high-availability PostgreSQL-compatible database. You manage its performance, redundancy, and backup. You must create a dedicated user, password, and database. | Hostname, Port, DB Name, Username, Password. | [Database checklist](/products/custody/v1.34/deployment/planning/database) |
| 2 | Message Queue (MQ) | A high-availability RabbitMQ-compatible message broker. This is essential for the platform's asynchronous services. | Hostname, Port, Username, Password, vHost. | [Message queue checklist](/products/custody/v1.34/deployment/planning/messaging) |
| 3 | Hardware Security Module (HSM) | This has the longest lead time. The notary and vault require a network-attached HSM (e.g., Thales Luna, Entrust). You handle procurement, racking, and network setup. | HSM Partition(s) IP, Port, and user PIN(s). | [KMS Integration](/products/custody/v1.34/how-to/integrate-kms/luna) |
| 4 | Blockchain nodes | You must provide endpoint access for each ledger you intend to support. This can be self-hosted nodes or a third-party provider (e.g., QuickNode). | RPC/WS URL and any required API keys for each ledger. | [Blockchain nodes checklist](/products/custody/v1.34/deployment/planning/blockchain-nodes) |
| 5 | Network (DNS/TLS) | You manage all networking. This includes: (1) Private DNS: Creating internal DNS records (A-records) for all services (e.g., custody.my-bank.com, api.custody.my-bank.com, auth.custody.my-bank.com). (2) TLS Certificates: Providing valid, trusted TLS certificates for all public-facing endpoints. | DNS Records and TLS Certificates/Keys. | [Network checklist](/products/custody/v1.34/deployment/planning/networking) |
| 6 | Secrets management | (Recommended) An external secrets manager (e.g., HashiCorp Vault, Conjur) to store and inject sensitive credentials (like DB/MQ passwords) into the cluster at runtime. | Connection details and access credentials. | [Secrets management checklist](/products/custody/v1.34/deployment/planning/secrets) |


You cannot proceed to Phase 3 (Installation) until you have provisioned all of these items and documented their connection details.

## Obtaining container images

Ripple Custody container images are hosted in Ripple's OCI container registry (`metaco.azurecr.io`). All images are digitally signed, allowing you to verify their authenticity and integrity before deployment.

### Primary method: Direct connection to Ripple's registry

This is the standard method for accessing Ripple Custody container images. Your Kubernetes cluster pulls images directly from Ripple's registry.

1. **Receive credentials:** Ripple's security team securely shares credentials for our OCI container registry: `metaco.azurecr.io`.
2. **Authenticate Docker:** On your deployment workstation, log in to the registry:

```bash
docker login metaco.azurecr.io
# Enter provided username and password
```
3. **Configure Kubernetes:** Create a Kubernetes secret so your cluster can pull the images:

```bash
kubectl create secret docker-registry metaco-creds \
  --namespace custody-core \
  --docker-server=metaco.azurecr.io \
  --docker-username=[Service-Principal-ID] \
  --docker-password=[Service-Principal-Secret]
```
4. **Configure production.yaml:** Reference the Ripple registry and pull secret into your configuration:

```yaml
harmonize:
  repository:
    base: "metaco.azurecr.io/custody"
    pullSecrets:
      - "metaco-creds"
```


### Advanced option: mirroring to a private registry

Some organizations require hosting container images in their own internal registry. Common reasons include:

* **Air-gapped environments:** Your production cluster has no external internet access.
* **Additional scanning:** Your security team requires running internal vulnerability scans before deployment.
* **Compliance requirements:** Regulatory policies mandate internal hosting of all production images.


If you need to mirror images to a private registry, follow this process:

1. **Get image list:** Your CPE provides a complete list of container images and tags required for your specific release version.
The image list typically includes 20-30 images covering all components: API, web UI, notary, vault, indexers, and supporting services. Each image has a specific version tag (e.g., `v1.28.0`).
2. **Authenticate to both registries:**
On your deployment workstation, log in to both the source (Ripple) and destination (your private) registries:

```bash
# Log in to Ripple's registry
docker login metaco.azurecr.io

# Log in to your private registry
docker login my-artifactory.my-bank.com
```
3. **Pull, verify, re-tag, and push:**
For each image in the provided list, perform the following steps:
**Example for the vault image:**

```bash
# Define image names
# Note: Component versions are independent of the Custody release version.
# Check the release notes for the correct component versions.
export SOURCE_IMAGE="metaco.azurecr.io/harmonize/vault-releases:1.28.1"
export TARGET_IMAGE="my-artifactory.my-bank.com/harmonize/vault-releases:1.28.1"

# Step 3a: Pull the image from Ripple
docker pull $SOURCE_IMAGE

# Step 3b: Verify the image signature (see next section)
cosign verify --key ripple-custody.pub --insecure-ignore-tlog=true $SOURCE_IMAGE

# Step 3c: Re-tag the image to point to your private registry
docker tag $SOURCE_IMAGE $TARGET_IMAGE

# Step 3d: Push the newly tagged image to your private registry
docker push $TARGET_IMAGE
```
4. **Repeat:** Repeat this process for all images in the release list.
5. **Configure production.yaml:** After mirroring all images to your internal registry, update your configuration to use your private registry:

```yaml
harmonize:
  repository:
    base: "my-artifactory.my-bank.com/harmonize"
    pullSecrets:
      - "my-artifactory-creds"
```


## Verifying image signatures (critical)

Image signing guarantees the authenticity and integrity of a container image. It provides the only way to prove that the image you deploy matches the exact, unmodified image Ripple published. This protects you from a "man-in-the-middle" (MITM) attack where an attacker could replace genuine images with malicious ones.

For all production deployments, you **must** verify the image signatures *before* deploying them.

### How it works

The process uses asymmetric (public/private) key cryptography and the industry-standard [Cosign](https://docs.sigstore.dev/cosign/overview/) tool from Sigstore.

1. **Ripple (Sign):** During our release pipeline, we cryptographically sign every container image using a private key stored securely in AWS KMS. We store this signature in our OCI registry (`metaco.azurecr.io`) alongside the image.
2. **You (Verify):** You use Ripple's corresponding public key and the `cosign` tool to verify the signature. This verification proves two things:
  * **Authenticity:** Only Ripple's private key could have created the signature.
  * **Integrity:** No one has tampered with the image since Ripple signed it.


### Verification process

Image signing is available starting with Ripple Custody **v1.30.0**. Earlier versions do not have signed images.

#### 1. Obtain the public key

Ripple provides a single public key that is valid for verifying all Ripple Custody container images across all releases. This key is backed by a code signing certificate issued by an intermediate certificate authority (CA), which chains up to the Ripple root CA. This provides a complete chain of trust for verification.

**Obtaining the key:**

1. **Email:** Securely emailed to your organization's technical contacts during onboarding
2. **CPE:** Available from your Ripple Customer Platform Engineer on request


The public key file is typically named `ripple-custody.pub`.

#### 2. Run the verification command

After pulling an image to your local workstation, use the `cosign verify` command:


```bash
# Example: Verifying the vault image
# Note: Component versions are independent of the Custody release version.
# Check the release notes for the correct component versions.
cosign verify \
  --key ripple-custody.pub \
  --insecure-ignore-tlog=true \
  metaco.azurecr.io/harmonize/vault-releases:1.28.1
```

**About `--insecure-ignore-tlog=true`:** This flag is required because Ripple does not currently publish signatures to the public Sigstore transparency log. The signature is still cryptographically verified against Ripple's public key, ensuring authenticity and integrity. This flag only skips the transparency log lookup.

**Expected output on successful verification:**


```text
Verification for metaco.azurecr.io/harmonize/vault-releases:1.28.1 --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
[
  {
    "critical": {
      "identity": {
        "docker-reference": "metaco.azurecr.io/harmonize/vault-releases"
      },
      "image": {
        "docker-manifest-digest": "sha256:..."
      },
      "type": "https://sigstore.dev/cosign/sign/v1"
    },
    "optional": {
      "commit": "",
      "time": "2026-01-09T15:10:25Z"
    }
  }
]
```

A successful verification confirms the image is authentic and safe to deploy. The `optional` metadata includes the signing timestamp for audit purposes.

**If the verification fails, DO NOT DEPLOY THE IMAGE.** A failed verification indicates that either the image did not come from Ripple or someone tampered with it. Contact [Ripple support](/products/custody/v1.34/support/get-support) immediately.

#### 3. Verify all images

You must perform this verification for every image before deployment. If you are mirroring to a private registry, verify each image after pulling and before pushing to your internal registry.

### Container images reference

The following table lists the container images included in Ripple Custody. The list of images is dynamic and may change between versions as new ledgers, crypto backends, or components are added or deprecated.

Component versioning
Each Ripple Custody component is versioned independently and may **not** match the Ripple Custody release version number. For example, Ripple Custody v1.30.3 may use `vault-releases:1.28.1`. Check with your CPE for the correct component versions for your deployment.

Verify all images you deploy. The specific images required for your deployment depend on your configuration (enabled ledgers, KMS type, etc.).

| Category | Image |
|  --- | --- |
| **Core services** | `harmonize/gateway``harmonize/event-processing``harmonize/ledger-accounting``harmonize/approval-bridge``harmonize/approval-notary``harmonize/state-review-tool``harmonize/replicator` |
| **API & frontend** | `harmonize/api-management``harmonize/graph-api``harmonize/frontend``harmonize/frontend-v2``harmonize/oauth``harmonize/notification``harmonize/keycloak` |
| **Vault & KMS** | `harmonize/vault-releases``harmonize/vault-cold-bridge``harmonize/kms-luna``harmonize/kms-blocksafe``harmonize/kms-ibm``harmonize/kms-rust-mpc``harmonize/kms-rust-primus``harmonize/kms-rust-soft``harmonize/kms-rust-soft-aws-wrap``harmonize/kms-soft``harmonize/kms-soft-gcp-wrap``harmonize/kms-andro``harmonize/kms-mock``harmonize/mpc-core` |
| **Blockchain indexers** | `harmonize/eth-indexer``harmonize/nbxplorer``harmonize/algorand-indexer``harmonize/cardano-indexer``harmonize/hedera-indexer``harmonize/stellar-indexer``harmonize/substrate-indexer``harmonize/tezos-indexer` |
| **Shared indexer** | `harmonize/shared-indexer_events-api``harmonize/shared-indexer_evm-adapter``harmonize/shared-indexer_evm-api``harmonize/shared-indexer_generic-indexer``harmonize/shared-indexer_processor``harmonize/shared-indexer_solana-adapter``harmonize/shared-indexer_solana-api``harmonize/shared-indexer_stellar-adapter``harmonize/shared-indexer_stellar-api``harmonize/shared-indexer_tron-adapter``harmonize/shared-indexer_tron-api``harmonize/shared-indexer_xrpl-api``harmonize/shared-indexer_xrpl-indexer` |
| **Extensions** | `harmonize/flows``harmonize/core-extensions``harmonize/compliance``harmonize/virtual-accounting``harmonize/eod-reconciliation``harmonize/coinbase-adapter``harmonize/web3-connector` |
| **Data services** | `harmonize/eds-api-service``harmonize/eds-event-processing` |
| **Infrastructure** | `harmonize/amqp` |


## Summary

At the end of this phase, you should have:

- All infrastructure prerequisites provisioned and connection details documented
- Deployment workstation configured with Helm, kubectl, and cosign
- Access to Ripple's container registry (or images mirrored to your private registry)
- All images verified using cosign and Ripple's public key
- `production.yaml` file created with initial configuration


You are now ready to proceed to [Phase 3: Installation & Initialization](/products/custody/v1.34/deployment/install/installation).