OpenBAO (Open Build, Authenticate, and Operate) is an open-source fork of HashiCorp Vault that remains fully open-source under the MPL 2.0 license. This setup is designed for managing secrets across multiple namespaces, ideal for multi-tenant applications and integrations with various systems like n8n.
- What is OpenBAO?
- Why OpenBAO for Secrets Management?
- Installation and Setup
- Getting Started
- Docker Setup
- User Management
- Managing Organizations and Services
- Security Features
- Application Integration
- Available Scripts Reference
- Frequently Asked Questions
OpenBAO is an open-source fork of HashiCorp Vault that emerged after HashiCorp decided to change the license of their products from the open-source MPL 2.0 to the more restrictive Business Source License (BSL) in 2023.
OpenBAO offers the same core features as HashiCorp Vault:
- Secure storage of secrets (API keys, passwords, etc.)
- Encryption of sensitive data
- Access management with policies
- Various authentication methods
When working with sensitive data like API keys, secure storage is essential. By using OpenBAO:
- Centralized secrets: All sensitive data in one secure place
- Multi-tenant isolation: Each namespace/client has its own isolated environment
- Dynamic access: Applications can dynamically retrieve secrets based on namespace/client ID
- Enhanced security: Central management of access rights and audit logs
- Flexible authentication: Different authentication methods for different use cases
This repository contains a Docker-based setup for both development and production.
- Docker and Docker Compose
- Basic command line knowledge
- jq (for processing JSON in scripts)
openbao-vault/
βββ docs/ # Documentation
β βββ API_INTEGRATION.md # Guide for API integration with AppRole
β βββ ROTATING_TOKENS.md # Guide for token rotation best practices
βββ scripts/
β βββ add_service.sh # Script for adding services
β βββ create_namespace.sh # Script for namespace preparation
β βββ create_global_admin.sh # Script for creating global admin users
β βββ create_operator.sh # Script for creating service operators
β βββ enable_mfa.sh # Script for enabling multi-factor authentication
β βββ init_openbao.sh # Script for initial setup
β βββ revoke_root_token.sh # Script for securely revoking root token
β βββ rotate_tokens.sh # Script for token lifecycle management
βββ vault/ # Data and configuration directories
βββ data/ # Persistent storage (automatically created)
βββ config/ # Configuration files
βββ tls/ # TLS certificates (for production)
βββ docker-compose.dev.yml # Docker Compose for development
βββ docker-compose.prod.yml # Docker Compose for production
βββ .env.vault.dev # Environment variables for development
βββ .env.vault.prod # Environment variables for production- Storage type: In-memory (temporary)
- Security: Minimal (for ease of development)
- Startup: Automatic, no manual steps required
- Data persistence: None, everything disappears on restart
- Root Token: Automatically generated on startup (shown in container logs)
- Storage type: Persistent on disk
- Security: Maximum (sealed/unsealed concept)
- Startup: Manual steps required
- Data persistence: Full, everything is preserved
- Root Token: Generated during initialization, must be stored securely
-
Start OpenBAO in development mode
# Build the custom Docker image with jq and start the container docker-compose -f docker-compose.dev.yml up -d --buildThe first time, you need to use the
--buildflag to build the custom Docker image that includesjqfor JSON processing in the scripts. -
Get the root token
# Get the root token from the container logs docker logs openbao-dev | grep "Root Token" # Then export it export VAULT_TOKEN=<token-from-logs>
Note: In development mode, OpenBAO is automatically initialized and unsealed. The
init_openbao.shscript is primarily used in production to check if OpenBAO is accessible. -
Running scripts
The OpenBAO scripts need to run inside the Docker container. You can use the provided wrapper script to execute them:
# The wrapper script automatically finds the root token if VAULT_TOKEN is not set ./run_in_container.sh create_namespace.sh --namespace exampleOr run them directly in the container:
# Manual execution in the container docker exec -e VAULT_TOKEN=$VAULT_TOKEN openbao-dev /opt/bin/create_namespace.sh --namespace example
-
Prepare a namespace
./run_in_container.sh create_namespace.sh --namespace example
This script sets up the basic configuration for a namespace and displays the credentials you'll need for application integration.
-
Add a service
./run_in_container.sh add_service.sh -o acme-corp -s payment -k stripe=sk_test_12345 -k paypal=client_id_abcdef
-
Create a global admin user (optional but recommended)
./run_in_container.sh create_global_admin.sh --username admin
-
Create a service operator (optional)
./run_in_container.sh create_operator.sh --organization acme-corp --service payment --username payment-operator
-
Start OpenBAO in development mode
docker-compose -f docker-compose.dev.yml up -d --build
-
Create a namespace for your organization
./run_in_container.sh create_namespace.sh --organization acme-corp
-
Add a service with secrets
./run_in_container.sh add_service.sh -o acme-corp -s payment -k stripe=sk_test_12345
-
Create a global admin user (optional but recommended)
./run_in_container.sh create_global_admin.sh --username admin
-
Create service operators (optional)
./run_in_container.sh create_operator.sh --organization acme-corp --service payment --username payment-operator
-
Revoke the root token (optional but recommended for security)
./run_in_container.sh revoke_root_token.sh
-
Start OpenBAO in production mode
docker-compose -f docker-compose.prod.yml up -d --build
-
Initialize OpenBAO (first time only)
docker exec openbao-prod openbao operator init -key-shares=3 -key-threshold=2 > init.txt
This generates:
- 3 unseal keys (you need 2 to unseal)
- 1 root token
Store these securely and distribute the unseal keys to different trusted individuals.
-
Unseal OpenBAO (required after each restart)
# Run this command 2 times with different unseal keys docker exec -it openbao-prod openbao operator unseal
-
Export the root token
export VAULT_TOKEN=<root-token-from-init.txt>
-
Follow the development steps 2-6 above
When you restart the production container, OpenBAO will be sealed and you need to unseal it:
-
Start the container if it's not running
docker-compose -f docker-compose.prod.yml up -d
-
Unseal OpenBAO
# Run this command 2 times with different unseal keys docker exec -it openbao-prod openbao operator unseal
-
Log in with your admin user
docker exec -it openbao-prod openbao login -method=userpass username=admin
This OpenBAO implementation uses a custom Docker setup with the following features:
- Custom Docker image: Based on the official OpenBAO image with added
jqfor JSON processing in scripts - Volume mounts: Scripts are mounted as volumes instead of being copied into the image
- This allows removing scripts in production after initial setup
- Script changes are immediately available without rebuilding the image
- Development vs Production:
- Development: Runs in
-devmode with automatic unseal and in-memory storage - Production: Uses configuration files and persistent storage
- Development: Runs in
The run_in_container.sh wrapper script makes it easy to run scripts inside the container:
./run_in_container.sh <script_name> [arguments]This script:
- Checks if the OpenBAO container is running
- Automatically retrieves the root token from container logs if
VAULT_TOKENis not set - Makes the script executable in the container
- Executes the script in the appropriate directory within the container
This repository includes several utility scripts to help you manage your OpenBAO instance:
This script checks if OpenBAO is accessible and displays its status. It's primarily used in production environments, as in development mode OpenBAO is automatically initialized and unsealed.
This script prepares an organization namespace by:
- Creating an organization namespace
- Enabling the KV secrets engine at the services path
- Configuring AppRole authentication
- Creating policies
- Generating Role ID and Secret ID for the organization
Usage:
./scripts/create_namespace.sh --organization [name] --path [path] --role [role] --ttl [time]This script adds a new service to an organization in OpenBAO with the appropriate secrets.
Usage with command-line parameters:
./scripts/add_service.sh -o acme-corp -s payment -k stripe=sk_test_12345 -k paypal=client_id_abcdefUsage with JSON file:
./scripts/add_service.sh -o acme-corp -s notification -f keys.jsonExample of a keys.json file:
{
"slack": "xoxb-67890",
"twitter": "ghijkl",
"api_key": "your-api-key"
}This script creates a global admin user who can manage all namespaces. This admin replaces the root token for daily use.
Usage:
./run_in_container.sh create_global_admin.sh --username adminPermissions:
- Full system access (can manage all namespaces, policies, auth methods, etc.)
- Can create and manage all secrets engines
- Can create and manage all policies
- Can create and manage all namespaces
This script revokes the current root token after creating a global admin, improving security by removing the root token from circulation.
Usage:
./run_in_container.sh revoke_root_token.sh
# Or to skip confirmation prompt
./run_in_container.sh revoke_root_token.sh --forceFeatures:
- Verifies that the current token is a root token
- Provides warnings and confirmation prompts
- Ensures you don't accidentally revoke access to your OpenBAO system
This script creates an operator for a specific service who can only manage that service's secrets within an organization namespace.
Usage:
./run_in_container.sh create_operator.sh --organization acme-corp --service payment --username payment-operatorPermissions:
- Limited to a single service's secrets within the specified organization
- Can read/write only that service's secrets
- Cannot access other services' secrets or system configuration
This script enables Multi-Factor Authentication (MFA) for a user, adding an extra layer of security especially for administrative accounts.
Usage:
# For TOTP (Time-based One-Time Password)
./run_in_container.sh enable_mfa.sh -u admin.user -t totp
# For Duo Security
./run_in_container.sh enable_mfa.sh -u admin.user -t duo -d DUO_INTEGRATION_KEY -s DUO_SECRET_KEY -h DUO_API_HOSTFeatures:
- Supports TOTP (compatible with Google Authenticator, Authy, etc.)
- Supports Duo Security integration
- Enforces MFA for sensitive operations
- Generates QR codes for easy setup
This script implements token lifecycle management, allowing you to create short-lived tokens with automatic expiration.
Usage:
# Create a token for a user
./run_in_container.sh rotate_tokens.sh -u admin.user -t 1h -m 24h -p admin
# Create a token for an AppRole
./run_in_container.sh rotate_tokens.sh -r payment-service -t 1h -p payment-service-policyFeatures:
- Creates tokens with limited TTL (Time-To-Live)
- Supports both userpass and AppRole authentication
- Implements token lifecycle management for enhanced security
For detailed information about token rotation best practices and implementation, see ROTATING_TOKENS.md.
The system implements a hierarchical access model:
- Root Token: Full system access, should only be used for initial setup and emergencies
- Admin Users: Global administrators who can manage the entire system
- Operator Users: Service-specific operators who can only manage their assigned service's secrets
This follows the principle of least privilege - users only get access to what they need to perform their specific tasks.
OpenBAO uses a hierarchy of user roles for secure management:
-
Root Token
- Highest level of access
- Only use for initial setup and emergencies
- Should be revoked after use
- Has access to all functions and data
-
Admin
- Global administrator who can manage all organization namespaces
- Can create organizations, auth methods, and policies
- Replaces the root token for daily management
- Created via
create_global_admin.sh
-
Operators
- One operator per service within an organization
- Can only manage the secrets of that specific service
- No access to system settings or other services
- Created via
create_operator.sh
-
AppRole
- For applications like n8n
- Read-only access to specific secrets
- Short-lived tokens
- Created via
create_namespace.sh
Use the create_global_admin.sh script to create a global admin:
./run_in_container.sh create_global_admin.sh --username adminThe admin gets full rights to:
- Manage organization namespaces
- Configure auth methods
- Manage secrets engines
- Create policies
- Access all secrets
After creating an admin, you can choose to revoke the root token for better security:
./run_in_container.sh revoke_root_token.shUse the create_operator.sh script to create an operator for each service:
./run_in_container.sh create_operator.sh --organization acme-corp --service payment --username payment-operatorThe operator gets limited rights:
- Full access to the secrets of only that specific service
- Read-only access to the services list
- No access to other services or system settings
Operators can log in with:
export VAULT_NAMESPACE=acme-corp
vault login -method=userpass username=payment-operatorOpenBAO provides several advanced security features to enhance your secrets management:
For sensitive operations and administrative accounts, you can enable Multi-Factor Authentication (MFA) using the enable_mfa.sh script:
# Enable TOTP (Time-based One-Time Password) for an admin user
./run_in_container.sh enable_mfa.sh -u admin.user -t totpThis supports:
- TOTP (compatible with Google Authenticator, Authy, etc.)
- Duo Security integration
MFA adds an extra layer of security by requiring something you know (password) and something you have (authenticator app).
Proper token management is crucial for security. The rotate_tokens.sh script helps implement token lifecycle best practices:
# Create a short-lived token for a user
./run_in_container.sh rotate_tokens.sh -u admin.user -t 1h -m 24h -p adminThis creates tokens with:
- Limited TTL (Time-To-Live)
- Maximum lifetime constraints
- Proper policy attachments
For detailed information about token rotation best practices and implementation, see ROTATING_TOKENS.md.
After initial setup, it's recommended to revoke the root token using the revoke_root_token.sh script:
./run_in_container.sh revoke_root_token.shThis improves security by:
- Removing the most powerful token from circulation
- Enforcing the use of properly scoped admin accounts
- Preventing accidental exposure of root-level access
In emergency situations, a new root token can be generated using the unseal keys.
Use the create_namespace.sh script:
./scripts/create_namespace.sh --organization marketing --path secrets --role api-accessUse the add_service.sh script as described above.
# Set the organization namespace
export VAULT_NAMESPACE=acme-corp
# View a service's secrets
vault kv get services/payment/api-keys# Update a service's secrets
vault kv put services/payment/api-keys stripe=new-token paypal=new-tokenTo integrate applications with OpenBAO, you'll need:
-
AppRole credentials:
- Role ID and Secret ID for the organization
- Obtained during namespace creation
-
Service path:
- The path to the service secrets
- Format:
services/<service-name>
-
Organization namespace:
- The namespace for the organization
- Format:
<organization-name>/
For detailed instructions on integrating applications with OpenBAO, including authentication, token renewal, error handling, and complete workflow examples, see API_INTEGRATION.md.
# Start the container
docker-compose -f docker-compose.dev.yml up -d
# Get the root token from logs
docker logs openbao-dev | grep "Root Token"
# Set the root token
export VAULT_TOKEN=<token-from-logs>
# Optional: Check if OpenBAO is accessible
# ./scripts/init_openbao.sh
# Prepare a namespace
./scripts/create_namespace.sh --namespace example-
Start OpenBAO in production mode:
docker-compose -f docker-compose.prod.yml up -d --build
The first time, you need to use the
--buildflag to build the custom Docker image that includesjqfor JSON processing in the scripts. -
Initialize OpenBAO (you only do this once):
docker exec -it vault-prod sh vault operator init -
Save the output securely! You'll get:
- 5 unseal keys (by default)
- 1 root token
For example:
Unseal Key 1: a3EfGhIjK4lMnOpQrStUvWxYz0123456789ABCDEFG Unseal Key 2: bCdEfGhIjK4lMnOpQrStUvWxYz0123456789ABCDEF Unseal Key 3: cDeFgHiJkL4mNoPqRsTuVwXyZ0123456789ABCDE Unseal Key 4: dEfGhIjKlM4nOpQrStUvWxYz0123456789ABCDE Unseal Key 5: eFgHiJkLmN4oPqRsTuVwXyZ0123456789ABCD Root Token: hvs.UvWxYz0123456789ABCDEFGhIjKlMnOpQrSt -
Unseal OpenBAO (use 3 of the 5 keys):
vault operator unseal [Unseal Key 1] vault operator unseal [Unseal Key 2] vault operator unseal [Unseal Key 3]
-
Log in with the root token:
vault login [Root Token]
-
Exit the container:
exit -
Set up your environment:
export VAULT_ADDR=http://127.0.0.1:8200 export VAULT_TOKEN=[Root Token]
-
Create a global admin user (optional but recommended):
# For production, run scripts directly in the container docker exec -e VAULT_TOKEN=$VAULT_TOKEN openbao-prod /opt/bin/create_global_admin.sh --username admin
-
Prepare organizations and add services:
docker exec -e VAULT_TOKEN=$VAULT_TOKEN openbao-prod /opt/bin/create_namespace.sh --organization acme-corp docker exec -e VAULT_TOKEN=$VAULT_TOKEN openbao-prod /opt/bin/add_service.sh -o acme-corp -s payment -k api_key=12345
When you restart the OpenBAO container in production, it will be sealed. Follow these steps to unseal it:
-
Check the status:
export VAULT_ADDR=http://127.0.0.1:8200 vault statusYou should see
Sealed: true. -
Unseal OpenBAO (use 3 of the 5 keys):
vault operator unseal [Unseal Key 1] vault operator unseal [Unseal Key 2] vault operator unseal [Unseal Key 3]
-
Log in: Use the same root token as during initialization or use your admin user
vault login [Root Token] # OR vault login -method=userpass username=admin
A root token has unlimited access to all functions and data in OpenBAO. A regular token only has access to specific paths and functions, based on the assigned policies.
In the development environment: until the container is restarted. In production: until the token is revoked or expires (if a TTL is set).
In development: restart the container and use the new token from the logs.
In production: use the unseal keys to generate a new root token with vault operator generate-root.
Yes, in the production environment, you must unseal OpenBAO after each restart with at least 3 of the 5 unseal keys.
Technically yes, but this is discouraged from a security perspective. The purpose of sealing is precisely to require manual intervention during a restart.
An admin has global rights to manage the entire system, including all namespaces. An operator only has rights to manage the secrets of one specific client within a namespace.
It's good security practice to revoke the root token after creating an admin user, but it's not mandatory. Keep in mind that:
- If you revoke the root token, you can no longer log in as root
- You can always generate a new root token with
vault operator generate-rootand your unseal keys - The admin can perform all daily management tasks without the security risk of an active root token
A client operator must first set the namespace and can then log in with the userpass method:
export VAULT_NAMESPACE=example
vault login -method=userpass username=client1-operator- Sealed: OpenBAO is locked, the encryption key is not in memory, data is inaccessible
- Unsealed: OpenBAO is unlocked, the encryption key is loaded in memory, data is accessible
By default, OpenBAO generates 5 keys, of which you need 3 to unseal (this is called "Shamir's Secret Sharing"). You can adjust this during initialization.
The production setup is secured with the following measures:
- OpenBAO is only locally accessible (127.0.0.1:8200)
- TLS termination is handled by a reverse proxy like LiteSpeed
- Scripts are removed from the production container
- Swapping is disabled (mem_swappiness: 0)
For additional security, we recommend:
- Setting up firewall rules for the reverse proxy
- Making regular backups of the data directory
- Enabling audit logging