Skip to the content.

OpenBao

Information

OpenBao is an open-source, community-governed secrets and encryption management platform. It is designed to centralize sensitive data handling such as application secrets, encryption keys, certificates, and machine identities while enforcing policy-based access and auditability.

At a practical level, OpenBao gives teams one place to:

OpenBao Overview

OpenBao is commonly used as a control plane for secret lifecycle and cryptographic operations rather than as a place where applications directly embed sensitive material.

What it is used for

Core platform characteristics

Compatibility notes in OpenBao context

OpenBao is frequently used through APIs, workflows, and client libraries that were originally popular in the broader Vault-compatible ecosystem. In practice, that means developers will often encounter familiar endpoint structures, policy concepts, HCL configuration style, and integration libraries.

For this page, the important point is that OpenBao can usually fit into those operational patterns while still being documented and operated as its own platform with its own binary (bao), environment variables (BAO_*), release lifecycle, and community roadmap.

Ecosystem support

OpenBao can be integrated with:

Main Functionalities and Features

What OpenBao Commonly Supports in Practice

Depending on enabled auth methods and secrets engines, OpenBao is commonly used for:

Supported Cryptographic Algorithms

OpenBao supports a wide range of algorithms, primarily through its Transit engine:

Post-Quantum Cryptography (PQC) Notes

OpenBao is primarily used today with classical cryptographic primitives such as AES, RSA, ECDSA, Ed25519, SHA-2, and ChaCha20-Poly1305. In practice, you should treat PQC support as architecture and integration guidance, not as a built-in guarantee that all OpenBao cryptographic operations are already quantum-resistant.

What to keep in mind:

Practical recommendation:

  1. Use OpenBao normally for secrets, Transit, PKI, and access control.
  2. Terminate TLS with a component that can adopt modern hybrid PQC ciphersuites or key exchange earlier than your application stack.
  3. Keep cryptographic agility in application design so that key types, certificates, and transport security can be replaced as standards and product support mature.
  4. Track OpenBao release notes and the surrounding crypto library ecosystem for native PQC-related enhancements.

Making OpenBao Deployment PQC-Ready

If your goal is to make OpenBao data handling more future-ready against quantum-era risks, the practical focus should be on crypto agility, transport protection, and key-lifecycle planning, not on assuming current stored Raft data is magically converted into a PQC format.

Recommended approach:

Short version: make the surrounding architecture PQC-ready now, and be ready to adopt native PQC features in OpenBao and its ecosystem later.

Installation

CentOS, Rocky Linux

OpenBao can be installed by downloading the binary from the official releases.

  1. Download and Install:
    BAO_VER="2.0.0"
    wget https://github.com/openbao/openbao/releases/download/v${BAO_VER}/openbao_${BAO_VER}_linux_amd64.zip
    unzip openbao_${BAO_VER}_linux_amd64.zip
    sudo mv bao /usr/local/bin/
    

macOS

Install via Homebrew (check for official tap or community formulas):

brew install openbao

FreeBSD

pkg install openbao

Fedora

OpenBao is often installed the same way as on Rocky Linux: download the release archive and place the bao binary into a directory on PATH.

BAO_VER="2.0.0"
wget https://github.com/openbao/openbao/releases/download/v${BAO_VER}/openbao_${BAO_VER}_linux_amd64.zip
unzip openbao_${BAO_VER}_linux_amd64.zip
sudo mv bao /usr/local/bin/

OpenIndiana

If no native package is available in your repository set, install from the upstream release archive and place the binary in a system path similarly to Linux or use a containerized deployment.

Setup with Docker for Developer

For local development, you can start OpenBao in “Dev Mode”. This mode is unsealed and stores data in-memory.

docker-compose.yaml:

version: '3.8'
services:
    openbao:
        image: quay.io/openbao/openbao:2.0.0
        container_name: openbao-dev
        environment:
            - BAO_DEV_ROOT_TOKEN_ID=main-secret
            - BAO_ADDR=http://0.0.0.0:8200
        ports:
            - "8200:8200"
        cap_add:
            - IPC_LOCK
        command: server -dev

Start with:

docker-compose up -d

Useful developer checks:

docker-compose logs -f openbao
docker exec -it openbao-dev bao status
docker exec -it openbao-dev bao secrets list

Developer notes:

Learning Examples (Step-by-Step)

Follow these steps to explore core functionalities using curl.

0. Environment Setup

export BAO_ADDR='http://127.0.0.1:8200'
export BAO_TOKEN='main-secret'

Quick health check:

curl $BAO_ADDR/v1/sys/health
curl --header "X-Bao-Token: $BAO_TOKEN" $BAO_ADDR/v1/sys/seal-status

Optional CLI login:

bao login $BAO_TOKEN
bao status

0.1 Enable KV v2 for Simple Secret Storage

Before using advanced engines, it is helpful to verify the basic read/write flow.

  1. Enable KV v2:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type":"kv-v2"}' \
         $BAO_ADDR/v1/sys/mounts/secret
    
  2. Write a secret:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"data":{"username":"demo","password":"s3cr3t"}}' \
         $BAO_ADDR/v1/secret/data/my-app
    
  3. Read the secret:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/secret/data/my-app
    

1. Data Encryption and Decryption

Use the Transit engine to encrypt data.

  1. Enable Transit engine:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type":"transit"}' \
         $BAO_ADDR/v1/sys/mounts/transit
    
  2. Create an encryption key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         $BAO_ADDR/v1/transit/keys/my-key
    
  3. Encrypt data: (Data must be base64 encoded)
    # Plaintext: "Hello OpenBao" -> Base64: "SGVsbG8gT3BlbkJhbw=="
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"plaintext": "SGVsbG8gT3BlbkJhbw=="}' \
         $BAO_ADDR/v1/transit/encrypt/my-key
    
  4. Decrypt data:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"ciphertext": "bao:v1:..."}' \
         $BAO_ADDR/v1/transit/decrypt/my-key
    
  5. Generate a data key: This is useful when your application wants to encrypt locally but still have key generation controlled by OpenBao.
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"bits":256}' \
         $BAO_ADDR/v1/transit/datakey/plaintext/my-key
    

2. Digital Signing and Verification

  1. Create a signing key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type": "ecdsa-p256"}' \
         $BAO_ADDR/v1/transit/keys/signing-key
    
  2. Sign a message:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"input": "SGVsbG8gT3BlbkJhbw=="}' \
         $BAO_ADDR/v1/transit/sign/signing-key
    
  3. Verify signature:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"input": "SGVsbG8gT3BlbkJhbw==", "signature": "bao:v1:..."}' \
         $BAO_ADDR/v1/transit/verify/signing-key
    

3. Key Pair Generation (Asymmetric)

  1. Create an asymmetric key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type": "rsa-4096", "exportable": true}' \
         $BAO_ADDR/v1/transit/keys/asymmetric-key
    
  2. Read Public Key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/transit/keys/asymmetric-key
    
  3. Export key material if the key was marked exportable:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/transit/export/encryption-key/asymmetric-key
    

4. Certificate Generation (PKI)

  1. Enable PKI engine:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type":"pki"}' \
         $BAO_ADDR/v1/sys/mounts/pki
    
  2. Generate Root CA:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"common_name": "example.com", "ttl": "87600h"}' \
         $BAO_ADDR/v1/pki/root/generate/internal
    
  3. Create a Role:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"allowed_domains": "example.com", "allow_subdomains": true, "max_ttl": "72h"}' \
         $BAO_ADDR/v1/pki/roles/web-certs
    
  4. Issue Certificate:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"common_name": "test.example.com"}' \
         $BAO_ADDR/v1/pki/issue/web-certs
    

5. AppRole for Machine-to-Machine Access

AppRole is one of the most common ways to let applications authenticate without interactive login.

  1. Enable AppRole auth:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type":"approle"}' \
         $BAO_ADDR/v1/sys/auth/approle
    
  2. Create a role:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"token_ttl":"1h","token_max_ttl":"4h"}' \
         $BAO_ADDR/v1/auth/approle/role/my-service
    
  3. Read the Role ID:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/auth/approle/role/my-service/role-id
    
  4. Generate a Secret ID:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --request POST \
         $BAO_ADDR/v1/auth/approle/role/my-service/secret-id
    
  5. Login using Role ID and Secret ID:
    curl --header "Content-Type: application/json" \
         --request POST \
         --data '{"role_id":"ROLE_ID","secret_id":"SECRET_ID"}' \
         $BAO_ADDR/v1/auth/approle/login
    

Live Environment Setup

Storage Requirements (Integrated Storage)

OpenBao supports Integrated Storage (Raft), which is recommended for high availability without external dependencies.

Before going live, plan for:

Configuration (bao.hcl):

storage "raft" {
  path    = "./bao/data"
  node_id = "node1"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 0
  tls_cert_file = "/etc/bao/tls/bao.crt"
  tls_key_file  = "/etc/bao/tls/bao.key"
}

api_addr = "https://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201"
ui = true

Recommended directory ownership example:

sudo mkdir -p /etc/bao /etc/bao/tls /var/lib/bao
sudo chown -R openbao:openbao /etc/bao /var/lib/bao
sudo chmod 750 /etc/bao /var/lib/bao

Rocky Linux (systemd service)

  1. Create a dedicated service account and directories:
    sudo useradd --system --home /etc/bao --shell /sbin/nologin openbao
    sudo mkdir -p /etc/bao /etc/bao/tls /var/lib/bao
    sudo chown -R openbao:openbao /etc/bao /var/lib/bao
    
  2. Create a service file: /etc/systemd/system/openbao.service
    [Unit]
    Description=OpenBao Server
    Requires=network-online.target
    After=network-online.target
    
    [Service]
    User=openbao
    Group=openbao
    ExecStart=/usr/local/bin/bao server -config=/etc/bao/bao.hcl
    ExecReload=/bin/kill --signal HUP $MAINPID
    KillMode=process
    Restart=on-failure
    LimitNOFILE=65536
    
    [Install]
    WantedBy=multi-user.target
    
  3. Enable and Start:
    sudo systemctl daemon-reload
    sudo systemctl enable --now openbao
    

Production Docker Setup

For a small self-managed environment, you can also run OpenBao in a persistent containerized setup.

docker-compose.prod.yaml:

version: '3.8'
services:
    openbao:
        image: quay.io/openbao/openbao:2.0.0
        container_name: openbao-prod
        restart: always
        ports:
            - "8200:8200"
            - "8201:8201"
        volumes:
            - ./config:/etc/bao
            - ./data:/var/lib/bao
            - ./tls:/etc/bao/tls:ro
        cap_add:
            - IPC_LOCK
        command: server -config=/etc/bao/bao.hcl

Start with:

docker-compose -f docker-compose.prod.yaml up -d

Post-Startup: Initialization and Unsealing

After starting a new non-dev instance, initialize it once and securely store the generated keys.

  1. Initialize:
    export BAO_ADDR='https://127.0.0.1:8200'
    bao operator init
    

    Save the unseal keys and root token in a secure offline location or a dedicated secure bootstrap process.

  2. Unseal:
    bao operator unseal
    

    Repeat until the configured threshold is reached.

  3. Login:
    bao login
    
  4. Create an initial admin policy rather than using root everywhere:
    cat > admin-policy.hcl <<'EOF'
    path "*" {
      capabilities = ["create", "read", "update", "delete", "list", "sudo"]
    }
    EOF
    bao policy write admin admin-policy.hcl
    

Backup and Restore Notes

OpenBao backup planning should cover more than just the Raft data directory. A restorable deployment typically requires data snapshots, configuration, TLS material references, audit configuration, and secure custody of bootstrap / recovery material.

Developer / Local Machine Backups

For developers, the first question is whether the local setup is ephemeral or worth preserving:

Practical developer backup scope:

Example developer snapshot command:

export BAO_ADDR='https://127.0.0.1:8200'
bao operator raft snapshot save ./backup/openbao-dev-$(date +%F).snap

Developer tips:

Live / Production Backups

For live environments, define a repeatable backup set:

  1. Raft snapshot on a schedule.
  2. Configuration backup for bao.hcl, systemd unit overrides, container manifests, and auth/audit-related environment configuration.
  3. TLS asset backup or reproducible certificate issuance process.
  4. Recovery key custody records and bootstrap documentation stored separately and securely.
  5. Policy / automation / infrastructure-as-code backup so the control plane can be rebuilt consistently.

Typical Raft snapshot command:

export BAO_ADDR='https://bao.example.internal:8200'
bao operator raft snapshot save /secure-backup/openbao-$(date +%F-%H%M).snap

Important live backup notes:

What to Test During Restore

At minimum, verify that you can:

Backup and PQC Readiness Together

If you are preparing for long-term PQC migration, backup design should also support future cryptographic transitions:

AWS KMS Auto-Unseal

AWS KMS auto-unseal lets OpenBao automatically decrypt the internal seal material during startup. In practical terms, OpenBao still protects all data with its internal barrier and master key hierarchy, but it no longer requires operators to manually enter unseal key shards after every restart.

How it works at a high level:

  1. During initialization, OpenBao generates the internal root/master material used to protect the barrier.
  2. Instead of relying only on manual Shamir unseal operations, OpenBao encrypts the seal-wrapping material with the AWS KMS key you configure.
  3. On restart, OpenBao calls AWS KMS to decrypt that seal-wrapping material and automatically becomes unsealed if it can access KMS successfully.
  4. Recovery keys are still important in auto-unseal deployments because they replace the old manual unseal workflow for disaster recovery and certain privileged operations.

Important clarifications:

When AWS KMS Auto-Unseal Fits Well

Typical good-fit scenarios:

Typical non-goals:

Production / Live Prerequisites

Before enabling AWS KMS auto-unseal, prepare:

Example bao.hcl for AWS KMS Auto-Unseal

This example keeps Raft as the storage backend and uses AWS KMS only for auto-unseal:

storage "raft" {
  path    = "/var/lib/bao"
  node_id = "node1"
}

listener "tcp" {
  address         = "0.0.0.0:8200"
  cluster_address = "0.0.0.0:8201"
  tls_disable     = 0
  tls_cert_file   = "/etc/bao/tls/bao.crt"
  tls_key_file    = "/etc/bao/tls/bao.key"
}

seal "awskms" {
  region     = "eu-central-1"
  kms_key_id = "arn:aws:kms:eu-central-1:123456789012:key/11111111-2222-3333-4444-555555555555"
  endpoint   = "https://kms.eu-central-1.amazonaws.com"
}

api_addr     = "https://bao.example.internal:8200"
cluster_addr = "https://bao.example.internal:8201"
ui           = true

Notes:

Example IAM Policy for OpenBao Runtime

Attach a least-privilege IAM policy to the role used by the OpenBao process:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "OpenBaoKmsAutoUnseal",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:DescribeKey",
                "kms:GenerateDataKey",
                "kms:GenerateDataKeyWithoutPlaintext"
            ],
            "Resource": "arn:aws:kms:eu-central-1:123456789012:key/11111111-2222-3333-4444-555555555555"
        }
    ]
}

If you also restrict usage in the KMS key policy, ensure the runtime role is explicitly allowed there too.

Rocky Linux / systemd Example with IAM-Friendly Configuration

If the server runs on EC2, the cleanest pattern is usually:

  1. Attach an instance profile / IAM role to the VM.
  2. Keep AWS credentials out of bao.hcl and out of the systemd unit.
  3. Let OpenBao use the instance metadata credentials automatically.

The service file can remain simple:

[Unit]
Description=OpenBao Server
Requires=network-online.target
After=network-online.target

[Service]
User=openbao
Group=openbao
ExecStart=/usr/local/bin/bao server -config=/etc/bao/bao.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

If you are not on EC2 and must pass AWS settings through environment variables, prefer an environment file with restricted permissions, for example /etc/openbao/openbao.env:

AWS_REGION=eu-central-1
AWS_ROLE_ARN=arn:aws:iam::123456789012:role/openbao-prod-role
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

Then reference it in systemd:

EnvironmentFile=/etc/openbao/openbao.env

Ensure only the service user and administrators can read that file.

Production Docker Example with AWS KMS Auto-Unseal

For containers, the preferred production pattern is again to avoid static access keys and rely on the platform’s IAM integration.

docker-compose.prod.yaml:

version: '3.8'
services:
    openbao:
        image: quay.io/openbao/openbao:2.0.0
        container_name: openbao-prod
        restart: always
        ports:
            - "8200:8200"
            - "8201:8201"
        environment:
            - AWS_REGION=eu-central-1
        volumes:
            - ./config:/etc/bao:ro
            - ./data:/var/lib/bao
            - ./tls:/etc/bao/tls:ro
        cap_add:
            - IPC_LOCK
        command: server -config=/etc/bao/bao.hcl

In real orchestrated environments, map that idea to:

Step-by-Step Live Setup Flow

  1. Create or select the KMS key in AWS KMS.
  2. Create an IAM role for the OpenBao nodes/containers with the minimum KMS permissions.
  3. Enable CloudTrail and, if applicable, KMS key rotation according to your policy.
  4. Update bao.hcl to include the seal "awskms" block.
  5. Deploy the configuration and start OpenBao.
  6. Initialize once:
    export BAO_ADDR='https://bao.example.internal:8200'
    bao operator init
    
  7. Securely store the recovery keys and initial root token in an offline or separately controlled bootstrap process.
  8. Restart OpenBao and verify that it comes back unsealed automatically.

How to Verify Auto-Unseal Is Working

After initialization, test a controlled restart.

Useful checks:

bao status
curl --silent $BAO_ADDR/v1/sys/seal-status

For systemd:

sudo systemctl restart openbao
sudo journalctl -u openbao -n 50 --no-pager
bao status

For Docker:

docker restart openbao-prod
docker logs --tail 50 openbao-prod
docker exec -it openbao-prod bao status

What you want to see:

Developer Workstation Best Practices

For developer laptops and local machines, the best practice is usually not to use AWS KMS auto-unseal by default.

Recommended approach for most developers:

If a developer truly needs to test AWS KMS auto-unseal locally:

Practical developer pattern:

  1. Learn OpenBao features in -dev mode first.
  2. Learn production concepts such as init/recovery/TLS with a local non-prod config next.
  3. Test AWS KMS auto-unseal only in a dedicated sandbox when you specifically need to validate IAM, KMS, or restart automation.

Security and Operational Best Practices

Common Pitfalls

Payment / PIN System Notes

Payment Systems, PIN Protection, and Chip & PIN Considerations

For payment environments, especially where PIN data, PIN blocks, cardholder data, or EMV / Chip & PIN related keys are involved, the answer is nuanced:

In practical terms:

Is OpenBao Supported for PIN Encryption?

OpenBao is technically capable of cryptographic operations and key management, but whether it is “supported” depends on the type of support you mean:

If your requirement is specifically “store or process PIN-related keys and PIN blocks in a way acceptable for production card-payment operations,” the safer guidance is:

  1. Use OpenBao for orchestration, secret distribution, application auth, certificates, and possibly non-PIN encryption.
  2. Use a certified HSM or payment HSM for actual PIN generation, PIN translation, PIN verification, Zone PIN Key handling, and other card-scheme-sensitive cryptographic operations.
  3. Document the boundary very clearly so developers and auditors can distinguish general secret management from * *payment cryptographic processing**.

PCI-DSS is broader than just encryption. Using OpenBao does not itself make an environment PCI-compliant. You still need architecture, process, and operational controls.

Typical expectations include:

If PIN data is involved, you may also need to consider requirements beyond general PCI-DSS, such as PCI PIN Security expectations and the payment-network rules applicable to your role.

What Should Be Done in Practice

If you want to use OpenBao in a payment environment, a practical approach is:

  1. Classify the data and operations:
    • Are you protecting ordinary application secrets?
    • Are you handling PAN data?
    • Are you handling actual PIN blocks or issuer/acquirer PIN keys?
  2. Keep payment-HSM responsibilities separate when PIN processing is in scope.
  3. Use Transit carefully for application encryption use cases, but do not assume it replaces a certified payment cryptographic module.
  4. Enable audit devices early and ship logs to a protected central system.
  5. Use auto-unseal carefully:
    • Good for operational startup automation.
    • Not a replacement for HSM-backed payment cryptography.
  6. Apply strict policy design:
    • Separate admin, operator, application, and auditor roles.
    • Avoid the use of root tokens outside the bootstrap.
    • Prefer short-lived auth methods such as AppRole, Kubernetes auth, or cloud IAM.
  7. Document compensating controls for auditors:
    • Where keys live.
    • Which component performs encryption.
    • Which component is certified or not certified.
    • How key rotation, revocation, and incident response are handled.
  8. Validate with your QSA / compliance team before go-live if the system will touch cardholder data or payment cryptography.

Short Recommendation

Usage, tips and tricks

Importing Key or Key Pairs via REST/curl

OpenBao Transit can import externally generated keys, but the imported material must first be wrapped with the Transit wrapping key.

  1. Fetch the Wrapping Key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/transit/wrapping_key
    
  2. Create an import-capable target key:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"type":"rsa-4096","imported_key":true}' \
         $BAO_ADDR/v1/transit/keys/imported-rsa
    
  3. Wrap the external key material: The private key or symmetric key must be wrapped outside OpenBao using the previously fetched wrapping key. The exact wrapping procedure depends on the key type and the helper tooling you use.

  4. Import wrapped key: Submit the wrapped key blob to the import endpoint.
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         --header "Content-Type: application/json" \
         --request POST \
         --data '{"ciphertext":"BASE64_WRAPPED_KEY","hash_function":"sha256"}' \
         $BAO_ADDR/v1/transit/keys/imported-rsa/import
    
  5. Verify imported key metadata:
    curl --header "X-Bao-Token: $BAO_TOKEN" \
         $BAO_ADDR/v1/transit/keys/imported-rsa
    

Typical use cases for import:

Policy Example for an Application

Example policy that allows an application to read one KV path and use one Transit key:

path "secret/data/my-app" {
  capabilities = ["read"]
}

path "transit/encrypt/my-key" {
  capabilities = ["update"]
}

path "transit/decrypt/my-key" {
  capabilities = ["update"]
}

Load it with:

bao policy write my-app-policy my-app-policy.hcl

Libraries for Application Integration

If you want to integrate OpenBao into application code instead of using only curl, the most practical approach is to use Vault-compatible clients because OpenBao keeps strong API compatibility with Vault 1.14-style APIs.

Java

Common library choices for Java applications:

Typical Java use cases:

Python

Common library choices for Python applications:

Typical Python use cases:

Library Selection Tips

Java Example (Using Spring Vault/OpenBao compatible client)

While curl is preferred for demonstration, Java applications can use standard libraries and Vault-compatible clients.

Java Example: Read KV Secret with Spring Vault

This example reads a KV v2 secret from secret/data/my-app.

import java.util.Map;

import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.client.VaultEndpoint;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponseSupport;

public class OpenBaoSpringVaultKvExample {

    public static void main(String[] args) {
        VaultEndpoint endpoint = VaultEndpoint.create("127.0.0.1", 8200);
        endpoint.setScheme("http");

        VaultTemplate vaultTemplate = new VaultTemplate(
            endpoint,
            new TokenAuthentication("main-secret")
        );

        VaultResponseSupport<Map> response = vaultTemplate.read("secret/data/my-app", Map.class);
        System.out.println(response);
    }
}

Typical Maven dependency:


<dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
</dependency>

Java Example: Transit Encrypt via REST API

This example calls the Transit engine directly and keeps the request format very close to the earlier curl examples.

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class OpenBaoTransitEncryptExample {

    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();

        String plaintext = Base64.getEncoder()
            .encodeToString("Hello OpenBao".getBytes(StandardCharsets.UTF_8));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("X-Bao-Token", "main-secret");

        HttpEntity<Map<String, String>> request = new HttpEntity<>(
            Map.of("plaintext", plaintext),
            headers
        );

        ResponseEntity<Map> response = restTemplate.postForEntity(
            "http://127.0.0.1:8200/v1/transit/encrypt/my-key",
            request,
            Map.class
        );

        System.out.println(response.getBody());
    }
}

Python Example: Read KV Secret with HVAC

This example uses the common hvac client.

import hvac

client = hvac.Client(url="http://127.0.0.1:8200", token="main-secret")

secret = client.secrets.kv.v2.read_secret_version(path="my-app", mount_point="secret")
print(secret["data"]["data"])

Install dependency:

pip install hvac

Python Example: Transit Encrypt via REST API

This example uses requests and mirrors the earlier REST flow.

import base64
import requests

bao_addr = "http://127.0.0.1:8200"
bao_token = "main-secret"

plaintext = base64.b64encode(b"Hello OpenBao").decode("utf-8")

response = requests.post(
    f"{bao_addr}/v1/transit/encrypt/my-key",
    headers={
        "X-Bao-Token": bao_token,
        "Content-Type": "application/json",
    },
    json={"plaintext": plaintext},
    timeout=30,
)

response.raise_for_status()
print(response.json())

Python Example: AppRole Login

This is a common machine-to-machine bootstrap flow for Python services.

import requests

bao_addr = "http://127.0.0.1:8200"

response = requests.post(
    f"{bao_addr}/v1/auth/approle/login",
    headers={"Content-Type": "application/json"},
    json={
        "role_id": "ROLE_ID",
        "secret_id": "SECRET_ID",
    },
    timeout=30,
)

response.raise_for_status()
client_token = response.json()["auth"]["client_token"]
print(client_token)

Tips

See also