-
Notifications
You must be signed in to change notification settings - Fork 65
feat: Vault Transit secrets engine signer support for Stellar #801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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= |
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use localhost for
Suggested patch-export VAULT_ADDR='http://0.0.0.0:8200'
+export VAULT_ADDR='http://127.0.0.1:8200'📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| ``` | ||||||||
|
|
||||||||
| ### 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) | ||||||||
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 43 sets Suggested fix- "pubkey": ""
+ "pubkey": "REPLACE_WITH_BASE64_ED25519_PUBLIC_KEY"Based on the provided config contract, 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "networks": "./config/networks", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "plugins": [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
📝 Committable suggestion
🤖 Prompt for AI Agents