This example demonstrates how to use HashiCorp Vault for securely storing private keys for OpenZeppelin Relayer. It includes a Docker Compose setup with Vault in development mode and instructions for configuring the KV-v2 secrets engine with AppRole authentication.
Note: This example uses Vault in development mode which is not suitable for production environments. For production deployments, use a properly configured and sealed Vault instance with appropriate security measures.
- Docker
- Docker Compose
- HashiCorp Vault CLI (Optional, for advanced operations)
Clone this repository to your local machine:
git clone https://github.com/OpenZeppelin/openzeppelin-relayer
cd openzeppelin-relayerStart the Vault service with the following command:
docker compose -f examples/vault-secret-signer/docker-compose.yaml up vault
Vault will run in dev mode and bind to 0.0.0.0:8200. You can access its UI by navigating to http://localhost:8200 in your browser.
If you haven't already, install the Vault CLI by following the instructions in the Vault installation guide.
Set the necessary environment variables so that your CLI can communicate with Vault:
export VAULT_ADDR='http://0.0.0.0:8200'
export VAULT_TOKEN='dev-only-token' # This is the default token for dev mode defined in docker-compose fi;eEnable the KV-v2 secrets engine at the secret path:
vault secrets enable -path=secret kv-v2Create secret with private key value:
vault kv put secret/my-app value=REPLACE_WITH_PRIVATE_KEYNote: For Solana, we can use this tool for development purposes to generate a key.
Create a policy that grants your service permissions to manage secrets. Save the following policy as secret-policy in Vault:
vault policy write secret-policy - <<EOF
path "secret/data/*" {
capabilities = ["create", "read", "update", "delete"]
}
path "secret/metadata/*" {
capabilities = ["list"]
}
EOFThis policy allows:
- Data operations (create, read, update, delete) on
secret/data/* - Listing of secrets via the metadata endpoint
secret/metadata/*
Enable the AppRole authentication method in Vault, which allows your service to authenticate using a RoleID and SecretID:
vault auth enable approleCreate an AppRole and attach the secret-policy to it:
vault write auth/approle/role/my-role \
policies="secret-policy" \
token_ttl=1h \
token_max_ttl=4hRetrieve the RoleID for your AppRole(store these values as they are needed for next step):
vault read auth/approle/role/my-role/role-idUpdate
Then, generate a SecretID for your AppRole:
vault write -f auth/approle/role/my-role/secret-idUse these credentials within your application to authenticate with Vault and access secrets securely.
Now that you have set up Vault with the appropriate permissions, configure your OpenZeppelin Relayer service to use the Vault credentials for authentication.
Create an environment file by copying the example:
cp examples/vault-secret-signer/.env.example examples/vault-secret-signer/.envThen edit this file and update the following variables with the values obtained in the previous step:
VAULT_ROLE_ID: The Role ID retrieved from Vault
VAULT_SECRET_ID: The Secret ID generated from Vault
Generate random keys for API authentication and webhook signing by running the UUID generation script twice:
cargo run --example generate_uuidThen update the following fields in your .env file:
WEBHOOK_SIGNING_KEY: The key used for signing webhook notifications
API_KEY: They api key used to authorize requests
examples/vault-secret-signer/config/config.json file is partially pre-configured. You need to specify the webhook URL that will receive updates from the relayer service.
For simplicity, visit Webhook.site, copy your unique URL, and then update the notifications[0].url field in examples/vault-secret-signer/config/config.json with this value.
To sign webhook notification payloads, populate the WEBHOOK_SIGNING_KEY entry in the examples/vault-secret-signer/.env file.
For development purposes, you can generate the signing key using:
cargo run --example generate_uuidNote: Alternatively, you can use any online UUID generator.
Copy the generated UUID and update the WEBHOOK_SIGNING_KEY entry in the examples/vault-secret-signer/.env file.
Generate an API key signing key for development purposes using:
cargo run --example generate_uuidNote: Alternatively, you can use any online UUID generator.
Copy the generated UUID and update the API_KEY entry in the examples/vault-secret-signer/.env file.
Start remaining docker-compose service with command:
docker compose -f examples/vault-secret-signer/docker-compose.yaml up -d
The service is available at http://localhost:8080/api/v1
curl -X GET http://localhost:8080/api/v1/relayers \
-H "Content-Type: application/json" \
-H "AUTHORIZATION: Bearer YOUR_API_KEY"-
Vault UI Not Accessible: Ensure that the Vault container is running and that the command includes
-dev-listen-address=0.0.0.0:8200so Vault binds to all network interfaces. -
Permission Denied Errors: Verify that the policy includes both
secret/data/*andsecret/metadata/*paths. Also, ensure that the policy name provided during AppRole creation matches exactly with the policy you created. -
Connectivity Issues: Confirm that environment variables such as
VAULT_ADDRandVAULT_TOKENare correctly set.