Skip to content

Providers

A Provider is a connection to an external secret store. You configure it once with credentials; Bella proxies all secret reads and writes through it.

Supported Provider Types

TypeDescription
Vault / OpenBaoHashiCorp Vault or OpenBao (KV secrets engine)
VaultDatabaseOpenBao / Vault Database secrets engine — ephemeral DB credentials
AwsSecretsManagerAWS Secrets Manager
AwsParameterStoreAWS Systems Manager Parameter Store
AzureKeyVaultAzure Key Vault
GoogleSecretManagerGCP Secret Manager
HttpRestCustom HTTP endpoint — bring your own secret backend

System Provider

Every tenant automatically gets a System Provider — a Bella-managed OpenBao instance. It requires no configuration. Use it immediately after signing up.

The system provider's ID is well-known (00000000-0000-0000-0000-000000000001) and is pre-assigned to every new project.

Create a Provider

sh
bella providers create \
  --name "AWS Production" \
  --type AwsSecretsManager \
  --region us-east-1 \
  --access-key-id AKIAXXXXXXXX \
  --secret-access-key secret
http
POST /api/v1/providers
Content-Type: application/json

{
  "name": "AWS Production",
  "type": "AwsSecretsManager",
  "configuration": {
    "region": "us-east-1",
    "accessKeyId": "AKIAXXXXXXXX",
    "secretAccessKey": "***"
  }
}

Sensitive configuration values (access keys, tokens, client secrets) are encrypted at rest using ASP.NET Data Protection before storing. They are masked in all API responses as ***ENCRYPTED***.

Provider Scoping

Providers are tenant-scoped — they can be assigned to multiple projects:

Tenant
 └── "AWS Production" provider
       ├── assigned to "Project Alpha"
       └── assigned to "Project Beta"

Assign a Provider to a Project

sh
bella providers assign --project my-project --provider "AWS Production"

Or from the WebApp: Project → Providers → Assign Provider

Assign a Provider to an Environment

Each environment within a project can use a specific provider:

sh
bella environments assign-provider \
  --project my-project \
  --environment production \
  --provider "AWS Production"

Multiple providers can be assigned to one environment — Bella reads from the primary provider and optionally syncs to others.

Test a Provider Connection

sh
bella providers test my-provider-id

Verifies that credentials are valid and the API is reachable.

Vault / OpenBao Configuration

json
{
  "type": "Vault",
  "configuration": {
    "url": "https://vault.example.com",
    "mountPath": "secret",
    "authMethod": "AppRole",
    "roleId": "...",
    "secretId": "..."
  }
}

Supported Vault auth methods: AppRole, Token, Kubernetes, GitHub.

AWS Secrets Manager Configuration

json
{
  "type": "AwsSecretsManager",
  "configuration": {
    "region": "us-east-1",
    "accessKeyId": "AKIAXXXXXXXX",
    "secretAccessKey": "***"
  }
}

IAM role-based auth is also supported — omit accessKeyId/secretAccessKey when running on EC2 or ECS with an instance role.

Azure Key Vault Configuration

json
{
  "type": "AzureKeyVault",
  "configuration": {
    "vaultUrl": "https://my-vault.vault.azure.net",
    "tenantId": "...",
    "clientId": "...",
    "clientSecret": "***"
  }
}

Managed Identity is supported — omit credentials when running on Azure resources with a system-assigned identity.

VaultDatabase (Dynamic Credentials) Configuration

The VaultDatabase provider type connects to OpenBao's Database secrets engine to generate short-lived database credentials on demand. Unlike other provider types, it does not store static secrets — it issues ephemeral credentials with an automatic TTL.

json
{
  "type": "VaultDatabase",
  "configuration": {
    "server_url": "https://vault.example.com",
    "auth_method": "approle",
    "role_id": "...",
    "mount_path": "database",
    "default_role": "app-readwrite",
    "connection_url_template": "postgres://{username}:{password}@db.example.com:5432/myapp"
  }
}
FieldRequiredDefaultDescription
server_urlVault / OpenBao base URL
auth_methodapproleapprole or token
role_idAppRoleAppRole role ID
secret_idAppRoleAppRole secret ID (stored encrypted)
root_tokenTokenRoot / service token (stored encrypted)
mount_pathdatabaseMount path of the Database secrets engine
default_roleDefault OpenBao role when none is specified
connection_url_templateTemplate with {username} / {password} placeholders

When connection_url_template is set, the generate endpoint returns a ready-to-use connectionUrl with credentials already substituted.

Setting up OpenBao for dynamic credentials

Before configuring the Bella provider, enable and configure the Database secrets engine in OpenBao:

sh
# Enable the database engine
vault secrets enable database

# Configure a Postgres connection
vault write database/config/my-postgres \
  plugin_name=postgresql-database-plugin \
  allowed_roles="app-readwrite" \
  connection_url="postgresql://{{username}}:{{password}}@postgres:5432/myapp" \
  username="vault-admin" \
  password="admin-password"

# Create a role (TTL 1 hour)
vault write database/roles/app-readwrite \
  db_name=my-postgres \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

The Bella provider's AppRole policy must allow read on database/creds/*:

hcl
path "database/creds/*" {
  capabilities = ["read"]
}

path "database/roles/*" {
  capabilities = ["list", "read"]
}

See Dynamic Database Credentials for usage.

HttpRest — Custom HTTP Provider

The HttpRest provider type lets you connect any secret backend that you control. Bella sends a single signed POST request to your endpoint for every secret operation. Use it to:

  • Keep secrets in your own database or internal API without granting Bella cloud credentials
  • Proxy to a legacy secret store that doesn't have a native Bella adapter
  • Self-host on-premises with a fully custom secret backend

How It Works

Bella API
  └─ POST {your-endpoint}
       X-Bella-Signature: t={unix},v1={hmac-sha256-hex}
       {ApiKeyHeader}: {ApiKey}   // optional

       { "action": "list"|"get"|"set"|"delete", "path": "...", "key": "...", "value": "..." }

Request / Response Contract

ActionRequest bodyResponse body
list{ action, path, requestId }{ "secrets": { "KEY": "value" } }
get{ action, path, key, requestId }{ "value": "..." }
set{ action, path, key, value, requestId }{ "success": true }
delete{ action, path, key, requestId }{ "success": true }
errornon-2xx + { "error": "message" }

The path is composed as {namespace_prefix}/{environment_slug} (e.g. myapp/production).

Signature Verification

Every request carries an X-Bella-Signature header using HMAC-SHA256 — the same format used by Bella webhooks and rotation functions:

X-Bella-Signature: t={unix-epoch-seconds},v1={hmac-sha256-hex}

Verify it in your function using @bella-baxter/sdk:

typescript
import { verifyWebhookSignature } from '@bella-baxter/sdk';

const valid = await verifyWebhookSignature(
  process.env.BELLA_SIGNING_SECRET!,
  req.headers.get('x-bella-signature') ?? '',
  rawBody,
);
if (!valid) return { status: 401 };

Configuration

json
{
  "type": "HttpRest",
  "configuration": {
    "endpoint": "https://your-function.example.com/bella-secrets",
    "signing_secret": "openssl-rand-hex-32-output",
    "api_key_header": "X-Api-Key",
    "api_key": "your-api-key-or-ref:SECRET_NAME",
    "namespace_prefix": "myapp/production"
  }
}
FieldRequiredDescription
endpointHTTPS URL Bella will POST all operations to
signing_secretRecommendedHMAC-SHA256 signing secret. Generate with openssl rand -hex 32
api_key_headerHTTP header name to send the API key in (e.g. X-Api-Key, Authorization)
api_keyAPI key value, or ref:SECRET_NAME to read from the system OpenBao provider
namespace_prefixPrepended to all paths (e.g. myapp/production)

The api_key field supports a secret reference. Use ref:MY_API_KEY to read the value from the system provider at secret/data/_bella-baxter/provider-api-keys/{providerId} — write it there via Vault CLI or Terraform to enable automatic rotation.

Function Templates

Ready-to-use templates are available in the repository:

PlatformLanguageTemplate
AWS LambdaNode.js/TypeScriptaws-lambda/nodejs
AWS LambdaC#aws-lambda/csharp
GCP Cloud RunNode.js/TypeScriptgcp-cloud-run/nodejs
GCP Cloud RunC#gcp-cloud-run/csharp
Azure FunctionsNode.js/TypeScriptazure-functions/nodejs
Azure FunctionsC#azure-functions/csharp
DockerNode.js/TypeScriptdocker/nodejs
DockerC#docker/csharp

The WebApp shows a template snippet preview directly in the provider form — pick a runtime, copy the snippet, download the full template, and implement listSecrets(), getSecret(), setSecret(), and deleteSecret().

Released under the ELv2 License.