Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ The repository includes several ready-to-use examples to help you get started wi
| [`basic-example-metrics`](./examples/basic-example-metrics/) | Setup with Prometheus and Grafana metrics |
| [`vault-secret-signer`](./examples/vault-secret-signer/) | Using HashiCorp Vault for key management |
| [`vault-transit-signer`](./examples/vault-transit-signer/) | Using Vault Transit for secure signing |
| [`stellar-vault-transit-signer`](./examples/stellar-vault-transit-signer/) | Using Vault Transit for Stellar secure signing |
| [`evm-azure-key-vault-signer`](./examples/evm-azure-key-vault-signer/) | Using Azure Key Vault for EVM secure signing |
| [`evm-turnkey-signer`](./examples/evm-turnkey-signer/) | Using Turnkey Signer for EVM secure signing |
| [`solana-turnkey-signer`](./examples/solana-turnkey-signer/) | Using Turnkey Signer for Solana secure signing |
Expand Down
17 changes: 14 additions & 3 deletions docs/configuration/signers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The following table shows which signer types are compatible with each network ty
| --- | --- | --- | --- |
| `local` | ✅ Supported | ✅ Supported | ✅ Supported |
| `vault` | ✅ Supported | ✅ Supported | ❌ Not supported |
| `vault_transit` | ❌ Not supported | ✅ Supported | ❌ Not supported |
| `vault_transit` | ❌ Not supported | ✅ Supported | ✅ Supported |
| `turnkey` | ✅ Supported | ✅ Supported | ✅ Supported |
| `google_cloud_kms` | ✅ Supported | ✅ Supported | ✅ Supported |
| `aws_kms` | ✅ Supported | ✅ Supported | ✅ Supported |
Expand All @@ -62,7 +62,7 @@ The following table shows which signer types are compatible with each network ty

* ***EVM Networks***: Use secp256k1 cryptography. Most signers support EVM networks with proper key generation.
* ***Solana Networks***: Use ed25519 cryptography. Ensure your signer supports ed25519 key generation and signing.
* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Supported by local, AWS KMS, Google Cloud KMS, and Turnkey signers.
* ***Stellar Networks***: Use ed25519 cryptography with specific Stellar requirements. Supported by local, Vault Transit, AWS KMS, Google Cloud KMS, and Turnkey signers.
* ***AWS KMS***: Supports secp256k1 (EVM) and ed25519 (Solana, Stellar) key types.
* ***Azure Key Vault***: Supports EVM networks with secp256k1 keys stored in Azure Key Vault.
* ***Google Cloud KMS***: Supports secp256k1 (EVM) and ed25519 (Solana, Stellar) key types.
Expand Down Expand Up @@ -179,7 +179,12 @@ Configuration fields:
| key_name | String | The name of the cryptographic key within Vault’s Transit engine that is used for signing operations |
| mount_point | String | The mount point for the Transit secrets engine in Vault. Defaults to `transit` if not explicitly specified. Optional. |
| namespace | String | The Vault namespace for API calls. This is used only in Vault Enterprise environments. Optional. |
| pubkey | String | Public key of the cryptographic key within Vault’s Transit engine that is used for signing operations |
| pubkey | String | Public key of the cryptographic key within Vault’s Transit engine that is used for signing operations. For Solana and Stellar, provide the raw Ed25519 public key encoded in standard base64 as returned by Vault Transit |

Vault Transit-specific requirements:
* Supported for Solana and Stellar networks
* Use an Ed25519 key in Vault Transit
* Grant the configured AppRole permission to sign with the Transit key

## Turnkey Signer Configuration

Expand Down Expand Up @@ -442,4 +447,10 @@ Configuration fields:
* Check AppRole credentials and permissions
* Ensure the secret/transit engine is properly mounted and configured

***Vault Transit signing failures***

* Confirm the Transit key is an Ed25519 key and the configured `pubkey` matches the key exported by Vault
* Verify the AppRole policy allows `update` on the Transit signing path for the configured key
* Check that the Transit mount point is correct if you are not using the default `transit`

For additional troubleshooting help, check the application logs and refer to the specific cloud provider or service documentation.
1 change: 1 addition & 0 deletions docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ For quick setup with various configurations, check the [examples directory](http
* `basic-example-metrics`: Setup with Prometheus and Grafana metrics
* `vault-secret-signer`: Using HashiCorp Vault for key management
* `vault-transit-signer`: Using Vault Transit for secure signing
* `stellar-vault-transit-signer`: Using Vault Transit for Stellar secure signing
* `evm-gcp-kms-signer`: Using Google Cloud KMS for EVM secure signing
* `evm-turnkey-signer`: Using Turnkey for EVM secure signing
* `solana-turnkey-signer`: Using Turnkey for Solana secure signing
Expand Down
4 changes: 4 additions & 0 deletions docs/stellar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,16 @@ Soroban operations support different authorization modes:
Stellar networks support the following signer types:

* ***Local Signer***: Uses encrypted keystore files (suitable for development)
* ***Vault Transit***: Uses HashiCorp Vault Transit with an Ed25519 key for hosted signing
* ***AWS KMS***: Uses AWS Key Management Service with Ed25519 keys (recommended for production)
* ***Google Cloud KMS***: Uses Google Cloud Key Management Service with ED25519 keys (recommended for production)
* ***Turnkey***: Uses Turnkey’s secure key management infrastructure with ED25519 keys (recommended for production)

For detailed signer configuration, see the [Signers Configuration](/relayer/configuration/signers) guide.

For complete examples:
- Vault Transit: [vault-transit-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/vault-transit-signer)
- AWS KMS: [aws-kms-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/aws-kms-signer)
Comment on lines 536 to +538

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix Vault Transit example link target.

The listed Vault Transit example path does not match the Stellar example directory added in this change set, so readers will be sent to the wrong location.

Suggested patch
-- Vault Transit: [vault-transit-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/vault-transit-signer)
+- Vault Transit: [stellar-vault-transit-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/stellar-vault-transit-signer)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
For complete examples:
- Vault Transit: [vault-transit-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/vault-transit-signer)
- AWS KMS: [aws-kms-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/aws-kms-signer)
For complete examples:
- Vault Transit: [stellar-vault-transit-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/stellar-vault-transit-signer)
- AWS KMS: [aws-kms-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/aws-kms-signer)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/stellar.mdx` around lines 536 - 538, The Vault Transit example link in
the documentation points to an incorrect path that does not match the Stellar
example directory structure added in this changeset. Update the
vault-transit-signer example link to reference the correct location of the
Stellar Vault Transit example directory so that readers are directed to the
correct example code.

- Google Cloud KMS: [stellar-gcp-kms-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/stellar-gcp-kms-signer)
- Turnkey: [stellar-turnkey-signer example](https://github.com/OpenZeppelin/openzeppelin-relayer/tree/main/examples/stellar-turnkey-signer)

Expand Down
10 changes: 10 additions & 0 deletions examples/stellar-vault-transit-signer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Redis Configuration
REDIS_URL=redis://redis:6379

# API Configuration
API_KEY=
WEBHOOK_SIGNING_KEY=

# Vault Transit AppRole Configuration
VAULT_ROLE_ID=
VAULT_SECRET_ID=
213 changes: 213 additions & 0 deletions examples/stellar-vault-transit-signer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# Using HashiCorp Vault Transit for Secure Stellar Transaction Signing in OpenZeppelin Relayer

This example demonstrates how to use HashiCorp Vault's Transit engine to securely sign Stellar transactions in OpenZeppelin Relayer. It uses a Stellar testnet relayer with a Vault Transit Ed25519 key, and includes a Docker Compose setup with Vault running in development mode.

> **Note:** This example uses Vault in development mode, which is not suitable for production. For production deployments, use a properly configured and sealed Vault instance with appropriate security controls.

## Prerequisites

1. [Docker](https://docs.docker.com/get-docker/)
2. [Docker Compose](https://docs.docker.com/compose/install/)
3. [HashiCorp Vault CLI](https://developer.hashicorp.com/vault/tutorials/get-started/install-binary?productSlug=vault&tutorialSlug=getting-started&tutorialSlug=getting-started-install) (optional but recommended)
4. Rust and Cargo installed
5. Git

## Getting Started

### Step 1: Clone the Repository

```bash
git clone https://github.com/OpenZeppelin/openzeppelin-relayer
cd openzeppelin-relayer
```

### Step 2: Start Vault

Start the Vault service:

```bash
docker compose -f examples/stellar-vault-transit-signer/docker-compose.yaml up vault
```

Vault will run in dev mode and be available at [http://localhost:8200](http://localhost:8200).

### Step 3: Configure the Vault CLI

If you have the Vault CLI installed, point it at the dev server:

```bash
export VAULT_ADDR='http://0.0.0.0:8200'
export VAULT_TOKEN='dev-only-token'
Comment on lines +38 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use localhost for VAULT_ADDR in CLI examples.

0.0.0.0 is a listen/bind address, not the recommended client destination. This can fail on some setups; use 127.0.0.1 (or localhost) in the command example.

Suggested patch
-export VAULT_ADDR='http://0.0.0.0:8200'
+export VAULT_ADDR='http://127.0.0.1:8200'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
export VAULT_ADDR='http://0.0.0.0:8200'
export VAULT_TOKEN='dev-only-token'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/stellar-vault-transit-signer/README.md` around lines 38 - 40, The
VAULT_ADDR environment variable example in the README uses 0.0.0.0 as the host
address, which is a listen/bind address and not appropriate for client
connections. Replace 0.0.0.0 with 127.0.0.1 or localhost in the VAULT_ADDR
export statement to provide a correct and reliable example that works across
different system configurations.

```

### Step 4: Enable Transit and Create a Stellar Signing Key

Enable the Transit engine:

```bash
vault secrets enable transit
```

Create an exportable Ed25519 signing key:

```bash
vault write -f transit/keys/my_signing_key type=ed25519 exportable=true
```

### Step 5: Create the Vault Policy

Create a policy that allows signing and verification with the Transit key:

```bash
vault policy write transit-sign-policy -<<EOF
path "transit/sign/my_signing_key" {
capabilities = ["update"]
}

path "transit/verify/my_signing_key" {
capabilities = ["update"]
}
EOF
```

### Step 6: Enable AppRole Authentication

```bash
vault auth enable approle
```

Create an AppRole for the relayer:

```bash
vault write auth/approle/role/my-role \
policies="transit-sign-policy" \
token_ttl=1h \
token_max_ttl=4h
```

### Step 7: Retrieve the Role ID, Secret ID, and Base64 Public Key

Retrieve the AppRole `role_id`:

```bash
vault read auth/approle/role/my-role/role-id
```

Generate a `secret_id`:

```bash
vault write -f auth/approle/role/my-role/secret-id
```

Retrieve the Transit public key from Vault. In the Vault UI, open `transit/my_signing_key`, choose the key version, and copy the public key value.

For this Stellar signer, the `pubkey` field in the relayer config must contain the raw Ed25519 public key encoded as standard base64.

### Step 8: Configure the Relayer Files

Copy the environment example:

```bash
cp examples/stellar-vault-transit-signer/.env.example examples/stellar-vault-transit-signer/.env
```

Update `examples/stellar-vault-transit-signer/.env`:

```env
VAULT_ROLE_ID=your_role_id
VAULT_SECRET_ID=your_secret_id
```

Update `examples/stellar-vault-transit-signer/config/config.json` and set the signer `pubkey` to the base64 public key from Vault.

### Step 9: Generate API and Webhook Keys

Generate an API key:

```bash
cargo run --example generate_uuid
```

Generate a webhook signing key:

```bash
cargo run --example generate_uuid
```

Add both values to `examples/stellar-vault-transit-signer/.env`:

```env
API_KEY=generated_api_key
WEBHOOK_SIGNING_KEY=generated_webhook_key
```

### Step 10: Configure the Webhook URL

Update `examples/stellar-vault-transit-signer/config/config.json` and set `notifications[0].url`.

For testing, you can use [Webhook.site](https://webhook.site).

### Step 11: Start the Relayer and Redis

```bash
docker compose -f examples/stellar-vault-transit-signer/docker-compose.yaml up -d
```

### Step 12: Test the Relayer

Check that the relayer is running:

```bash
curl -X GET http://localhost:8080/api/v1/relayers \
-H "Content-Type: application/json" \
-H "AUTHORIZATION: Bearer YOUR_API_KEY"
```

This should return the Stellar relayer and its address derived from the Vault Transit public key.

### Step 13: Test a Stellar Payment Transaction

Submit a Stellar testnet payment transaction:

```bash
curl -X POST http://localhost:8080/api/v1/relayers/stellar-example/transactions \
-H "Content-Type: application/json" \
-H "AUTHORIZATION: Bearer YOUR_API_KEY" \
-d '{
"network": "testnet",
"operations": [
{
"type": "payment",
"destination": "GDESTINATION_ADDRESS_HERE",
"asset": { "type": "native" },
"amount": 1000000
}
],
"memo": { "type": "text", "value": "Vault Transit test payment" }
}'
```

This creates a payment of `0.1 XLM` (`1,000,000` stroops) on Stellar testnet, signs it through Vault Transit, and submits it through the relayer.

## Troubleshooting

1. **Vault connection issues**
- Verify `VAULT_ROLE_ID` and `VAULT_SECRET_ID`
- Confirm Vault is reachable at `http://localhost:8200`
- Ensure the Transit engine is mounted at `transit`

2. **Signing failures**
- Confirm the Transit key is Ed25519
- Verify the policy grants `update` access to `transit/sign/my_signing_key`
- Check that the configured `pubkey` is the raw Ed25519 public key in standard base64

3. **Stellar transaction issues**
- Make sure the destination account is a valid Stellar address
- Ensure the relayer account has testnet funds before submitting transactions

## Additional Resources

- [HashiCorp Vault Documentation](https://www.vaultproject.io/docs/)
- [AppRole Authentication](https://developer.hashicorp.com/vault/docs/auth/approle)
- [Stellar Documentation](https://developers.stellar.org/)
- [OpenZeppelin Relayer Documentation](https://docs.openzeppelin.com/relayer)
49 changes: 49 additions & 0 deletions examples/stellar-vault-transit-signer/config/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"relayers": [
{
"id": "stellar-example",
"name": "Stellar Testnet Example",
"network": "testnet",
"paused": false,
"notification_id": "notification-example",
"signer_id": "stellar-vault-transit-signer",
"network_type": "stellar",
"policies": {
"min_balance": 0,
"fee_payment_strategy": "relayer"
}
}
],
"notifications": [
{
"id": "notification-example",
"type": "webhook",
"url": "",
"signing_key": {
"type": "env",
"value": "WEBHOOK_SIGNING_KEY"
}
}
],
"signers": [
{
"id": "stellar-vault-transit-signer",
"type": "vault_transit",
"config": {
"address": "http://vault:8200",
"role_id": {
"type": "env",
"value": "VAULT_ROLE_ID"
},
"secret_id": {
"type": "env",
"value": "VAULT_SECRET_ID"
},
"key_name": "my_signing_key",
"pubkey": ""
}
Comment on lines +32 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

vault_transit example config is invalid with empty pubkey.

Line 43 sets "pubkey": "", but VaultTransitSignerConfig.pubkey is validated as non-empty and signer derivation also expects a valid base64 Ed25519 public key. This will fail config validation/startup for the example.

Suggested fix
-        "pubkey": ""
+        "pubkey": "REPLACE_WITH_BASE64_ED25519_PUBLIC_KEY"

Based on the provided config contract, pubkey must be present/non-empty in src/models/signer/mod.rs (VaultTransitSignerConfig validation).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"config": {
"address": "http://vault:8200",
"role_id": {
"type": "env",
"value": "VAULT_ROLE_ID"
},
"secret_id": {
"type": "env",
"value": "VAULT_SECRET_ID"
},
"key_name": "my_signing_key",
"pubkey": ""
}
"config": {
"address": "http://vault:8200",
"role_id": {
"type": "env",
"value": "VAULT_ROLE_ID"
},
"secret_id": {
"type": "env",
"value": "VAULT_SECRET_ID"
},
"key_name": "my_signing_key",
"pubkey": "REPLACE_WITH_BASE64_ED25519_PUBLIC_KEY"
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/stellar-vault-transit-signer/config/config.json` around lines 32 -
44, The `pubkey` field in the vault_transit configuration is set to an empty
string, but the `VaultTransitSignerConfig` validation in
src/models/signer/mod.rs requires it to be a non-empty, valid base64-encoded
Ed25519 public key. Replace the empty string value with a valid base64-encoded
Ed25519 public key that corresponds to the signing key specified in the
`key_name` field to satisfy the validation requirements and allow the example to
start successfully.

}
],
"networks": "./config/networks",
"plugins": []
}
Loading
Loading