OpenBao is the open-source alternative to Hashicrop Vault which itself a secrets manager. Similar to a password manager, a secrets manager allows you to centrally store sensitive values such as API keys or application passwords. You can also query OpenBao via plugins such as the vals command from Helm or using something like the External Secrets Operator (ESO) in a Kubernetes cluster.
I primarily run my OpenBao instance as a Docker container separate from my Kubernetes cluster. This allows me to make changes to the cluster without affecting OpenBao.
There are a few steps you need to go through to setup OpenBao.
The Docker Compose setup I use has two primary files: the docker-compose.yaml itself along with a config file openbao.hcl that is mounted into the container. These two directory structure looks like so:
openbao/
├── docker-compose.yaml
├── config/
│ └── openbao.hcl
└── data/
└── ...
Make sure both the
dataandconfigfolders as well as their contents are owner by the1000:1000user. This can be accomplish by using the following command:sudo chown -R 1000:1000 data configfrom inside theopenbaofolder.
A sample docker-compose.yaml and the openbao.hcl are provided for reference. Idealy you'd want to have OpenBao behind a reverse proxy such as Traefik for TLS.
# docker-compose.yaml
services:
openbao:
image: openbao/openbao
container_name: openbao
restart: unless-stopped
user: "1000:1000"
environment:
- BAO_ADDR=http://0.0.0.0:8200
command:
- server
- -config=/openbao/config/openbao.hcl
cap_add:
- IPC_LOCK
volumes:
- ./data:/openbao/data
- ./config/openbao.hcl:/openbao/config/openbao.hcl:ro
# openbao.hcl
ui = true
api_addr = "http://openbao.example.com"
cluster_addr = "http://127.0.0.1:8201"
cluster_name = "openbao-prod"
storage "raft" {
path = "/openbao/data"
node_id = "node1"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = true
}
log_level = "info"
These snippets are taking from my actively working instance. Running an instance solely from these configs is not advised. Consult the OpenBao documentation for more information.
With OpenBao running you may notice that the web interface isn't reachable or loading. That's because you need to initialize the vault. Since this is a Docker container you can enter the container with the following command docker exec -it openbao sh
Once inside the container you can initialize the vault with the following command: bao operator init -key-shares=1 -key-threshold=1 It will print out a few keys and a root token. You will use this root token to login to the web interface. Store everything someplace safe.
Open your web browser and type in the IP of your OpenBao install plus the port. You should have something like this: http://192.168.0.15:8200
Enter the root token you got earlier and you should be in.
The
-key-sharesoption defines how many keys you want to generate. Likewise-key-thresholdis how many keys are needed to unseal the vault. These keys should be stored somewhere safe as they will be needed to unseal the vault should the container ever be restarted. If you do not specify the-key-sharesand-key-thresholdoptions then fice keys will be generated with three needed to unseal the vault.
You should not use the provide values in a production environment. The defaults of five keys with three needed to unseal the vault are considered standard with any increase in those numbers being more secure.
OpenBao uses an Access Control List (ACL) like policies to control what a user has access to. In these policies you should define at least two; one for an admin user that isn't the root user, and one for an account that will be able to read secrets.
The admin user basically needs full rights to OpenBao to manage it effectively. As such the policy should allow for all permissions.
This is a sample of the policy I am currently using for my admin user.
path "sys/mounts" {
capabilities = ["read", "list"]
}
path "sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "sys/mounts/*/tune" {
capabilities = ["read", "update"]
}
path "sys/internal/ui/mounts" {
capabilities = ["read", "list"]
}
path "sys/internal/ui/mounts/*" {
capabilities = ["read", "list"]
}
path "+/data/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "+/metadata/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "sys/*" {
capabilities = ["read", "list"]
}
This is a sample policy and while it may work for you without any tweaks you should still look over it just to be sure there are no issues.
This policy does not work currently work and is subject to change. Use at your own risk!
This policy is for a user to be able to read any secrets in the KV secrets engine which is primarily what I use. This policy is used both to query secrets via the curl command or via the External Secrets Operator (ESO) in a Kubernetes cluster.
This is a sample from the policy I am currently using:
path "kv/data/*" {
capabilities = ["read", "list"]
}
path "kv/metadata/*" {
capabilities = ["read", "list"]
}
path "sys/internal/ui/mounts/kv" {
capabilities = ["read"]
}
path "sys/internal/ui/mounts/kv/*" {
capabilities = ["read"]
}
This is a sample policy and while it may work for you without any tweaks you should still look over it just to be sure there are no issues.
There are several ways to handle authentication with OpenBao. The default method is token auth which you use when logging in with the root token. If you have an existing authentication server such as Active Directory (AD), Light Weight Directory Protocol (LDAP), or OpenID you would integrat OpenBao with any of those solutions. But to keep things simple I elected to use username and password authentication.
Click on the Access tab on the left pane. From there you should be dropped into the Authentication Methods page where you will see an option Enable new method in the top right. Click that and then select the Username & Password option under the Generic section then click the Next button to continue. You will have the option to change the name of the method under the Path box. If you don't have any custom configurations then click the Enable Method button at the bottom of the page and you should have just enabled username and password based authentication.
Now if you go back to the Authentication Methods screen you should now see the newly create method. Click on the new method and then in the top right click the Create user button. From here we will create the Read-Only user. Enter the username and the password for the user and then expand the Token section. In here go to the Generated Token's Policy and enter the name of the Read-Only policy created earlier and the click the Save button at the bottom.
Repeat the same steps to add the admin user and enter the admin policy in the Generated Token's Policy when creating the user.
The current admin policy does not work so this new admin user will not have admin rights on the server!
On the left side of the page, click on the Secrets Engines and select the KV engine under the Generic section then click the Next button. From here you shouldn't need to change anything so just click the Enable Engine button at the bottom.
From here you should be able to click on the newly created engine and you should see a Create secret option in the top right. From here you can specify the path your secret will be stored at along with the data. You can have multipls keys with different values along with editing the metadat of the secret.
Now lets create test secret. In the KV secrets engine, click the Create secrets option and fill out the secret with the following values:
Path: /secret/foo
Key: my-value
Value: example-value
You can then test if you can reach the token then you can use the root token to test. Or you can login as the Read-Only user created early and click the user icon in the top left corner and select the Copy token option.
You can then use the following commands to test if you can reach the key:
# Store the token in the environment variable
export BAO_TOKEN=<Read-Only-Token>
# Use that token to check if you can access the secret
curl -H "X-Vault-Token: ${BAO_TOKEN}" http://192.168.0.15:8200/v1/kv/data/secret/foo
When querying a secret via
curlyou will need to putdataafter thekvportion but before thesecretsoption. You may try without thedataoption but it has failed to properly query the secret when left out in my experience.