From 88a0b09706cdbda653455ce88afb6758f1b2f5a4 Mon Sep 17 00:00:00 2001 From: Adam Overa Date: Thu, 8 May 2025 08:58:15 -0400 Subject: [PATCH 1/2] [NEW] Deploying OpenBao on Kubernetes with Linode LKE (#7251) * Deploying OpenBao on Kubernetes with Linode LKE * Tech Edit 1 * Tech Edit 2 * Tech Edit 3 * Title Change 1 * copy edits --------- Co-authored-by: jddocs --- .../index.md | 622 ++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 docs/guides/security/secrets-management/deploy-openbao-on-linode-kubernetes-engine/index.md diff --git a/docs/guides/security/secrets-management/deploy-openbao-on-linode-kubernetes-engine/index.md b/docs/guides/security/secrets-management/deploy-openbao-on-linode-kubernetes-engine/index.md new file mode 100644 index 00000000000..dc45b841f44 --- /dev/null +++ b/docs/guides/security/secrets-management/deploy-openbao-on-linode-kubernetes-engine/index.md @@ -0,0 +1,622 @@ +--- +slug: deploy-openbao-on-linode-kubernetes-engine +title: "Deploy OpenBao on Linode Kubernetes Engine" +description: "Learn to deploy and manage OpenBao on Linode Kubernetes Engine (LKE) using Helm. This guide covers setup, unsealing, testing, and production best practices." +authors: ["Akamai"] +contributors: ["Akamai"] +published: 2025-05-07 +keywords: ['openbao','openbao kubernetes deployment','install openbao on linode','openbao lke','linode kubernetes engine openbao','helm openbao chart','initialize openbao','unseal openbao kubernetes','openbao on akamai cloud','openbao cluster setup','openbao helm install guide','deploy openbao on kubernetes'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +external_resources: +- '[OpenBao](https://openbao.org/)' +- '[Helm](https://helm.sh/)' +--- + +[OpenBao](https://openbao.org/) is an open source secrets management solution and fork of HashiCorp Vault. This guide walks through how to deploy [OpenBao on Kubernetes](https://openbao.org/docs/platform/k8s/) with Linode Kubernetes Engine (LKE) on Akamai Cloud using the [OpenBao Helm chart](https://github.com/openbao/openbao-helm). + +If you prefer a one-click, single-instance deployment, see our [OpenBao Marketplace app](/docs/marketplace-docs/guides/openbao/). + +## Before You Begin + +1. Follow our [Get Started](https://techdocs.akamai.com/cloud-computing/docs/getting-started) guide, and create an Akamai Cloud account if you do not already have one. + +1. Create an API token with proper permissions using the instructions in our [Manage personal access tokens](https://techdocs.akamai.com/cloud-computing/docs/manage-personal-access-tokens) guide. + +1. Install the Linode CLI using the instructions in our [Install and configure the CLI](https://techdocs.akamai.com/cloud-computing/docs/install-and-configure-the-cli) guide. + +1. Follow the steps in the *Install `kubectl`* section of the [Getting started with LKE](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-lke-linode-kubernetes-engine#install-kubectl) guide to install and configure kubectl. + +1. Install the [Helm CLI](https://helm.sh/docs/intro/install/) on your workstation. Helm is a package manager for Kubernetes that simplifies the deployment of applications. + +1. Install the [OpenBao CLI](https://openbao.org/docs/install/) on your workstation. + +{{< note >}} +This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you’re not familiar with the `sudo` command, see the [Users and Groups](/docs/guides/linux-users-and-groups/) guide. +{{< /note >}} + +## Provision an LKE Cluster + +While there are several ways to create a Kubernetes cluster on Akamai Cloud, this tutorial uses the [Linode CLI](https://github.com/linode/linode-cli) to provision resources. + +See our [Create a cluster](https://techdocs.akamai.com/cloud-computing/docs/create-a-cluster) guide for instructions on provisioning an LKE cluster using Cloud Manager. + +1. Using the Linode CLI (`linode-cli`), list available Kubernetes versions: + + ```command + linode-cli lke versions-list + ``` + + ```output + ┌───────┐ + │ id │ + ├───────┤ + │ 1.32 │ + ├───────┤ + │ 1.31 │ + └───────┘ + ``` + + It’s generally recommended to provision the latest version of Kubernetes unless specific requirements dictate otherwise. + +1. Use the following command to list available Akamai Cloud plans, including plan ID, pricing, and performance details. For more detailed plan and pricing information, see [Akamai Cloud: Pricing](https://www.linode.com/pricing/): + + ```command + linode-cli linodes types + ``` + +1. The examples in this guide use the **g6-standard-2** Linode, which features 2 CPU cores and 4 GB of memory. Run the following command to display detailed information in JSON for this Akamai Cloud plan: + + ```command + linode-cli linodes types --label "Linode 4GB" --json --pretty + ``` + + ```output + [ + { + "addons": {...} + "class": "standard", + "disk": 81920, + "gpus": 0, + "id": "g6-standard-2", + "label": "Linode 4GB", + "memory": 4096, + "network_out": 4000, + "price": {...}, + "region_prices": [...], + "successor": null, + "transfer": 4000, + "vcpus": 2 + } + ] + ``` + +1. View available regions with the `regions list` command. See our [Region Availability](https://www.linode.com/global-infrastructure/availability/) page for a complete list of compute regions and region IDs: + + ```command + linode-cli regions list + ``` + +1. After selecting a Kubernetes version and Linode instance type, use the following command to create a cluster named `openbao-cluster` in the `us-mia` (Miami, FL) region with three nodes and auto-scaling. Replace `{{< placeholder "openbao-cluster" >}}` and `{{< placeholder "us-mia" >}}` with a cluster label and region of your choosing, respectively: + + ```command + linode lke cluster-create \ + --label {{< placeholder "openbao-cluster" >}} \ + --k8s_version 1.32 \ + --region {{< placeholder "us-mia" >}} \ + --node_pools '[{ + "type": "g6-standard-2", + "count": 3, + "autoscaler": { + "enabled": true, + "min": 3, + "max": 8 + } + }]' + ``` + + Once your cluster is successfully created, you should see output similar to the following: + + ```output + Using default values: {}; use the --no-defaults flag to disable defaults + ┌────────┬─────────────────┬────────┬─────────────┬─────────────────────────────────┬──────┐ + │ id │ label │ region │ k8s_version │ control_plane.high_availability │ tier │ + ├────────┼─────────────────┼────────┼─────────────┼─────────────────────────────────┼──────┤ + │ 415365 │ openbao-cluster │ us-mia │ 1.32 │ False │ │ + └────────┴─────────────────┴────────┴─────────────┴─────────────────────────────────┴──────┘ + ``` + +## Access the LKE Cluster + +To access your cluster, fetch the cluster credentials in the form of a `kubeconfig` file. Your cluster’s `kubeconfig` can also be [downloaded via the Cloud Manager](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-lke-linode-kubernetes-engine#access-and-download-your-kubeconfig). + +1. Use the following command to retrieve the cluster’s ID: + + ```command + CLUSTER_ID=$(linode lke clusters-list --json | jq -r \ + '.[] | select(.label == "openbao-cluster") | .id') + ``` + +1. On your workstation, create a hidden `.kube` folder in your user’s home directory: + + ```command + mkdir ~/.kube + ``` + +1. Retrieve the `kubeconfig` file and save it to `~/.kube/lke-config`: + + ```command + linode-cli lke kubeconfig-view --json "$CLUSTER_ID" | \ + jq -r '.[0].kubeconfig' | \ + base64 --decode > ~/.kube/lke-config + ``` + +1. After saving the `kubeconfig` file, confirm access to your cluster by checking the status of your cluster nodes with `kubectl` and specifying the file name: + + ```command + kubectl get no --kubeconfig ~/.kube/lke-config + ``` + + ```output + NAME STATUS ROLES AGE VERSION + lke415365-625696-3fe27ca40000 Ready 115s v1.32.1 + lke415365-625696-4f320a5f0000 Ready 117s v1.32.1 + lke415365-625696-5a43a1510000 Ready 119s v1.32.1 + ``` + + {{< note >}} + Alternatively, to avoid specifying `--kubeconfig ~/.kube/lke-config` with every `kubectl` command, you can set an environment variable for your current terminal window session: + + ```command + export KUBECONFIG=~/.kube/lke-config + ``` + + Then run: + + ```command + kubectl get no + ``` + {{< /note >}} + +## Set Up OpenBao on LKE + +[Helm](https://helm.sh/) is a package manager for Kubernetes that simplifies application deployment via [*charts*](https://helm.sh/docs/topics/charts/). The OpenBao development team maintains an official [Helm chart](https://github.com/openbao/openbao-helm) and is the recommended method for deploying OpenBao on Kubernetes. + +By default, this Helm chart installs OpenBao in *standalone mode*, which sets up a single server with a file storage backend. This profile is useful for testing, but other profiles are available in this chart (e.g. development server, high-availability cluster). See the [OpenBao Helm README](https://github.com/openbao/openbao-helm/blob/main/charts/openbao/README.md) for more information. + +1. Add the OpenBao chart repository to your local Helm installation: + + ```command + helm repo add openbao https://openbao.github.io/openbao-helm + ``` + + ```output + "openbao" has been added to your repositories + ``` + +1. Use Helm to deploy the OpenBao chart: + + ```command + helm install openbao openbao/openbao + ``` + + ```output + NAME: openbao + LAST DEPLOYED: Wed Apr 30 16:14:55 2025 + NAMESPACE: default + STATUS: deployed + REVISION: 1 + NOTES: + Thank you for installing OpenBao! + + Now that you have deployed OpenBao, you should look over the docs on using + OpenBao with Kubernetes available here: + + https://openbao.org/docs/ + + + Your release is named openbao. To learn more about the release, try: + + $ helm status openbao + $ helm get manifest openbao + ``` + +1. Run the following command to view the complete YAML manifests generated during installation: + + ```command + helm get manifest openbao + ``` + + This returns all the YAML configuration files for the newly deployed OpenBao system, which can be useful for inspecting the system’s initial configuration data. + + {{< note title="Customize the Installation" >}} + To override any of these configuration options at installation time, use the `--set` command line argument when installing the Helm chart, for example: + + ```command + helm install openbao openbao/openbao --set server.dev.enabled=true + ``` + + You can also override the entire configuration in a file and run it with the following command, for example: + + ```command + helm install openbao openbao/openbao --values override-values.yml + ``` + {{< /note >}} + +## Initialize and Unseal the OpenBao Development Server + +Once the OpenBao server is installed on the Kubernetes cluster, it must be initialized. The initialization generates the credentials needed to [unseal](https://openbao.org/docs/concepts/seal/#why) the server for use. + +1. To view all the currently configured OpenBao servers in your cluster, run the following: + + ```command + kubectl get pods -l app.kubernetes.io/name=openbao + ``` + + There should only be one pod for the `standalone` profile. Notice that the `READY` count is `0`, indicating the server has not been initialized yet: + + ```output + NAME READY STATUS RESTARTS AGE + openbao-0 0/1 Running 0 4m20s + ``` + +1. To initialize the server, run the following: + + ```command + kubectl exec -ti openbao-0 -- bao operator init + ``` + + The output displays the `Unseal Key` shares and the `Initial Root Token` for the server: + + ```output + Unseal Key 1: amIfRt7lBrC0/x5mOtkyk9WvOF5IH6ycPEl8Gy4FnqTh + Unseal Key 2: mjUsz45ghgsExRS7l6m11u11CBhe6djQAJHcZ/uZkvOw + Unseal Key 3: CCl0vH8Ajw5Rrue6DIbI7nYNUCPQFoCva4Fn0GK7nu0K + Unseal Key 4: oqjxlFVel57HqcdqWGX1M7y9BndZ8c/Q0URw6r3cjABG + Unseal Key 5: WTEAz+IinG/H+kJ364ALIx2ubhyMh6TJqyDT2LCleyXI + + Initial Root Token: s.aLWUBcxF6f1e2RVZ5pEsXwMe + + Vault initialized with 5 key shares and a key threshold of 3. Please securely + distribute the key shares printed above. When the Vault is re-sealed, + restarted, or stopped, you must supply at least 3 of these keys to unseal it + before it can start servicing requests. + + Vault does not store the generated root key. Without at least 3 keys to + reconstruct the root key, Vault will remain permanently sealed! + + It is possible to generate new unseal keys, provided you have a quorum of + existing unseal keys shares. See "bao operator rekey" for more information. + ``` + + You must unseal the OpenBao server with the unseal keys provided until the key threshold is met. Unsealing must be done a **total of three times**, as this is the default quorum for the OpenBao unsealing process. + + Take note of the `Initial Root Token` as it is needed in subsequent steps. + +1. Use the following command to begin unsealing the vault using one of the unseal keys: + + ```command + kubectl exec -ti openbao-0 -- \ + bao operator unseal amIfRt7lBrC0/x5mOtkyk9WvOF5IH6ycPEl8Gy4FnqTh + ``` + + ```output + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed true + Total Shares 5 + Threshold 3 + Unseal Progress 1/3 + Unseal Nonce 3521df43-fe19-7fa7-9a7c-9442dbe8de68 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + HA Enabled false + ``` + +1. Unseal the vault again, but enter a different unseal key when prompted: + + ```command + kubectl exec -ti openbao-0 -- \ + bao operator unseal mjUsz45ghgsExRS7l6m11u11CBhe6djQAJHcZ/uZkvOw + ``` + + ```output + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed true + Total Shares 5 + Threshold 3 + Unseal Progress 2/3 + Unseal Nonce 3521df43-fe19-7fa7-9a7c-9442dbe8de68 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + HA Enabled false + ``` + +1. Unseal the vault for the third and final time, using yet another unseal key: + + ```command + kubectl exec -ti openbao-0 -- \ + bao operator unseal CCl0vH8Ajw5Rrue6DIbI7nYNUCPQFoCva4Fn0GK7nu0K + ``` + + After unsealing the vault with three different unseal keys, OpenBao should report the following status: + + ```output + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed false + Total Shares 5 + Threshold 3 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + Cluster Name vault-cluster-7d68e84b + Cluster ID 07352961-8d7e-edeb-7757-74d04b221500 + HA Enabled false + ``` + + The vault has now been initialized and unsealed. + +1. After unsealing, verify that the pod is now ready: + + ```command + kubectl get pods -l app.kubernetes.io/name=openbao + ``` + + After the OpenBao server is unsealed, the pod should also report as `READY`: + + ```output + NAME READY STATUS RESTARTS AGE + openbao-0 1/1 Running 0 11m + ``` + + The OpenBao server is now ready for testing. + +## Test the OpenBao Development Server + +1. To test the connection directly through the Kubernetes cluster, forward port `8200` from the cluster to your `localhost` with the following command: + + ```command + kubectl port-forward openbao-0 8200:8200 + ``` + + ```output + Forwarding from 127.0.0.1:8200 -> 8200 + Forwarding from [::1]:8200 -> 8200 + ``` + +1. With port forwarding enabled and active, open a separate terminal window. Set the following environment variable so that the OpenBao CLI looks to the forwarded port on `localhost`. + + ```command + export BAO_ADDR=http://127.0.0.1:8200 + ``` + +1. While in the new terminal session, use the `bao login` command with the `Initial Root Token` provided upon vault initialization to log in to the OpenBao server on the LKE cluster: + + ```command + bao login -method=token {{< placeholder "INITIAL_ROOT_TOKEN" >}} + ``` + + ```output + Success! You are now authenticated. The token information displayed below is + already stored in the token helper. You do NOT need to run "bao login" again. + Future OpenBao requests will automatically use this token. + + Key Value + --- ----- + token s.aLWUBcxF6f1e2RVZ5pEsXwMe + token_accessor zOoW9kLqFjYtZuEZM2UOfn1d + token_duration ∞ + token_renewable false + token_policies ["root"] + identity_policies [] + policies ["root"] + ``` + +1. Enable the key/value store in the server: + + ```command + bao secrets enable kv + ``` + + ```output + Success! Enabled the kv secrets engine at: kv/ + ``` + +1. Use cURL to test storing and retrieving secrets from the OpenBao server. Store a secret with the following command, replacing {{< placeholder "INITIAL_ROOT_TOKEN" >}} with your `Initial Root Token` value. + + In the example below, the secret stored is represented under the `--data` field as `"hello"` and `"world"`: + + ```command + curl -X POST \ + --header "X-Vault-Token: {{< placeholder "INITIAL_ROOT_TOKEN" >}}" \ + --header "Content-Type: application/json" \ + --data '{"data": {"hello": "world"}}' \ + http://127.0.0.1:8200/v1/kv/test-secret + ``` + +1. Run the following cURL command to retrieve the secret, once again using your `Initial Root Token` as verification: + + ```command + curl -X GET \ + --header "X-Vault-Token: {{< placeholder "INITIAL_ROOT_TOKEN" >}}" \ + http://127.0.0.1:8200/v1/kv/test-secret | json_pp + ``` + + ```output + { + "auth" : null, + "data" : { + "data" : { + "hello" : "world" + } + }, + "lease_duration" : 2764800, + "lease_id" : "", + "renewable" : false, + "request_id" : "2bfd095a-924f-4d2e-abcc-99ebbca045b5", + "warnings" : null, + "wrap_info" : null + } + ``` + + If successful, you should see the secret data `"hello"` and `"world"` as displayed above. + +1. When done, you can close the second terminal session. + +1. In the original terminal session, press Ctrl+C to stop port forwarding. + +## Configure OpenBao for External Access + +To access the OpenBao server externally rather than through Kubernetes port-forwarding, use a [LoadBalancer](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/) service. + +1. Open the pod configuration for OpenBao: + + ```command + kubectl edit service openbao + ``` + + By default, the OpenBao service is created as a `ClusterIP`. To expose it externally, change the service type to `LoadBalancer`. Press the I key to edit the file, and make the following change (see Line 44), leaving the rest of the file unchanged: + + ```file {hl_lines="44"} + # Please edit the object below. Lines beginning with a '#' will be ignored, + # and an empty file will abort the edit. If an error occurs while saving this file will be + # reopened with the relevant failures. + # + apiVersion: v1 + kind: Service + metadata: + annotations: + meta.helm.sh/release-name: openbao + meta.helm.sh/release-namespace: default + creationTimestamp: "2025-04-28T18:12:12Z" + labels: + app.kubernetes.io/instance: openbao + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: openbao + helm.sh/chart: openbao-0.12.0 + name: openbao + namespace: default + resourceVersion: "7082" + uid: 6e1cb14b-a108-466f-ac77-ddc9c63519ff + spec: + clusterIP: 10.128.82.244 + clusterIPs: + - 10.128.82.244 + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: http + port: 8200 + protocol: TCP + targetPort: 8200 + - name: https-internal + port: 8201 + protocol: TCP + targetPort: 8201 + publishNotReadyAddresses: true + selector: + app.kubernetes.io/instance: openbao + app.kubernetes.io/name: openbao + component: server + sessionAffinity: None + type: LoadBalancer + status: + loadBalancer: {} + ``` + + When done, press the ESC to exit edit mode, followed by `:wq` to save the changes and exit. + + ```output + service/openbao edited + ``` + +1. Wait for a public IP address to be supplied to the pod, then query for the IP address with the following command: + + ```command + kubectl get service openbao + ``` + + ```output + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + openbao LoadBalancer 10.128.154.209 172.233.167.79 8200:31550/TCP,8201:32438/TCP 47m + ``` + +1. To test this connection, issue the `curl` command again to retrieve the previously stored secret, changing the {{< placeholder "EXTERNAL_IP_ADDRESS" >}} field to the external one shown above (under `EXTERNAL-IP`), at port `8200`. For example: + + ```command + curl -X GET \ + --header "X-Vault-Token: {{< placeholder "INITIAL_ROOT_TOKEN" >}}" \ + http://{{< placeholder "EXTERNAL_IP_ADDRESS" >}}:8200/v1/kv/test-secret | json_pp + ``` + + ```output + { + "auth" : null, + "data" : { + "data" : { + "hello" : "world" + } + }, + "lease_duration" : 2764800, + "lease_id" : "", + "renewable" : false, + "request_id" : "8603ab17-1810-f63d-13c5-fc044cb4c101", + "warnings" : null, + "wrap_info" : null + } + ``` + +## Additional Considerations for Production Deployments + +When deploying OpenBao to a Kubernetes cluster for production-grade workloads, consider the following additional points. + +### Auto-Unseal in a Clustered Environment + +Kubernetes facilitates auto-unseal mechanisms by integrating cloud-based key management systems (such as AWS KMS, GCP KMS, or Azure Key Vault). Store the unseal keys securely in a Kubernetes Secret object encrypted by a separate key management system or similar mechanism. This ensures the OpenBao vault remains sealed until securely auto-unsealed by Kubernetes on pod startup. + +With auto-unseal enabled, Kubernetes can automatically unseal OpenBao when pods start, removing the need for manual unseal operations (as demonstrated above). + +### High-Availability Mode + +To achieve high availability, [enable the high availability control plane for LKE](https://techdocs.akamai.com/cloud-computing/docs/high-availability-ha-control-plane-on-lke) then deploy OpenBao in a stateful set with multiple replicas. To do this, you need: + +- A distributed, highly available storage backend (such as HashiCorp Consul or PostgreSQL) that supports concurrent access across replicas. +- A Kubernetes StatefulSet for stable network identities and persistent storage. + +The [OpenBao Helm chart](https://github.com/openbao/openbao-helm/blob/main/charts/openbao/README.md) has options for configuring a high-availability profile. To use upon installation, run the following: + +```command +helm install openbao openbao/openbao --set "server.ha.enabled=true" +``` + +This automatically sets up multiple OpenBao servers in your LKE cluster, all configured to share a common, replicated storage backend. See the official documentation for [an example](https://openbao.org/docs/platform/k8s/helm/run/#config-example) usage of this Helm configuration. + +### Separate Configurations from Secrets + +Store the non-sensitive information for an OpenBao configuration in a Kubernetes [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/). Separately store sensitive information (e.g. root tokens and unseal keys) as Kubernetes [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/). Encrypt all Kubernetes Secrets at rest, and avoid exposing them in logs or environment variables. + +### Secure the LKE Cluster Network + +Harden the network for your LKE cluster by taking the following measures: + +- Encrypt all traffic to and from OpenBao using TLS. +- Use Kubernetes Secrets to store TLS certificates and private keys securely. +- Validate certificates to prevent man-in-the-middle attacks. +- Enforce secure communication between OpenBao and its clients. + +### Restrict Access to OpenBao + +Use Kubernetes [NetworkPolicies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) to restrict access to the OpenBao service. Reduce the attack surface by denying all incoming traffic by default. Explicitly allow only required communication paths. Policies should limit the source of ingress traffic to trusted pods, namespaces, or IP ranges. + +Deploy the OpenBao management UI only when necessary. If using the UI, secure access to it by integrating it with Kubernetes [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/), [OpenID Connect (OIDC)](https://kubernetes.io/docs/concepts/security/hardening-guide/authentication-mechanisms/#openid-connect-token-authentication), or an external authentication gateway. Limit access to specific IP ranges or authenticated users to prevent unauthorized access. \ No newline at end of file From 105f7a321891a92681585adbd1663394d789fa5b Mon Sep 17 00:00:00 2001 From: Adam Overa Date: Thu, 8 May 2025 08:58:25 -0400 Subject: [PATCH 2/2] [NEW] Deploying OpenBao on a Linode Compute Instance (#7247) * Deploying OpenBao on a Linode Compute Instance * Edit 1 * Edit 2 * Edit 3 * update title and slug, copy edit --------- Co-authored-by: jddocs --- .../index.md | 613 ++++++++++++++++++ 1 file changed, 613 insertions(+) create mode 100644 docs/guides/security/secrets-management/deploying-openbao-on-a-linode-instance/index.md diff --git a/docs/guides/security/secrets-management/deploying-openbao-on-a-linode-instance/index.md b/docs/guides/security/secrets-management/deploying-openbao-on-a-linode-instance/index.md new file mode 100644 index 00000000000..266f2ae3bb5 --- /dev/null +++ b/docs/guides/security/secrets-management/deploying-openbao-on-a-linode-instance/index.md @@ -0,0 +1,613 @@ +--- +slug: deploying-openbao-on-a-linode-instance +title: "Deploying OpenBao on a Linode Instance" +description: "Deploy OpenBao on a Linode instance using Ubuntu 24.04 LTS and the Linode CLI. Learn how to install, configure, unseal, and securely manage secrets." +authors: ["Akamai"] +contributors: ["Akamai"] +published: 2025-05-06 +keywords: ['openbao','openbao linode','openbao ubuntu install','secrets management linode','how to install openbao','secure secrets storage linux','openbao ubuntu 24.04','deploy openbao cli','install vault alternative','hashicorp vault fork','openbao setup tutorial','linux secrets manager','initialize openbao server','openbao unseal process','openbao vs vault','openbao config hcl','how to deploy openbao on a linode instance','secure secrets management with openbao','install and configure openbao on ubuntu','openbao systemd service setup','openbao cli secret storage example','openbao firewall and api access configuration','openbao key value store example','setting up openbao secrets engine'] +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' +--- + +[OpenBao](https://openbao.org/) is an open source secrets management solution and fork of HashiCorp Vault. This guide walks through a manual installation of OpenBao on a Linode instance with an Ubuntu 24.04 distribution. + +If you prefer an automated one-click deployment, see our [OpenBao Marketplace app](/docs/marketplace-docs/guides/openbao/). + +## Before You Begin + +1. If you do not already have an account or virtual machine to use, see our [Get Started](https://techdocs.akamai.com/cloud-computing/docs/getting-started) and [Create a Compute Instance](https://techdocs.akamai.com/cloud-computing/docs/create-a-compute-instance) guides to create an Akamai Cloud account, familiarize yourself with Cloud Manager, and provision a new Compute Instance. + + While OpenBao does not provide explicit hardware recommendations, its architecture closely mirrors that of HashiCorp Vault. Based on [Vault’s recommended specifications](https://developer.hashicorp.com/vault/tutorials/day-one-raft/raft-reference-architecture#hardware-sizing-for-vault-servers), this guide uses a Shared CPU **Linode 8 GB** plan (`g6-standard-4`) with 4 vCPUs and 160 GB of storage. Deployment time may vary. + + {{< note title="Provisioning Compute Instances with the Linode CLI" type="secondary" isCollapsible="yes" >}} + Use these steps if you prefer to use the [Linode CLI](https://techdocs.akamai.com/cloud-computing/docs/install-and-configure-the-cli) to provision resources. + + The following command creates a Linode 8 GB Compute Instance (`g6-standard-4`) running Ubuntu 24.04 LTS (`linode/ubuntu24.04`) in the Miami datacenter (`us-mia`): + + ```command + linode-cli linodes create \ + --image linode/ubuntu24.04 \ + --region us-mia \ + --type g6-standard-4 \ + --root_pass {{< placeholder "ROOT_PASSWORD" >}} \ + --authorized_keys "$(cat ~/.ssh/id_ed25519.pub)" \ + --label openbao-linode + ``` + + Note the following key points: + + - Replace `us-mia` with your preferred data center region. Run `linode-cli regions list` to view options. + - Replace {{< placeholder "ROOT_PASSWORD" >}} with a secure alternative for your root password. + - This command assumes that an SSH public/private key pair exists, with the public key stored as `id_ed25519.pub` in the user’s `$HOME/.ssh/` folder. + - The `--label` argument specifies the name of the new server (e.g. `openbao-linode`). + {{< /note >}} + +1. Follow our [Set Up and Secure a Compute Instance](https://techdocs.akamai.com/cloud-computing/docs/set-up-and-secure-a-compute-instance) guide to update your system and create a limited user account. You may also wish to set the timezone, configure your hostname, and harden SSH access. + + {{< note >}} + This guide is written for a non-root user. Commands that require elevated privileges are prefixed with `sudo`. If you’re not familiar with the `sudo` command, see the [Users and Groups](/docs/guides/linux-users-and-groups/) guide. + {{< /note >}} + +## Install OpenBao + +Log into your Linode instance, and install the OpenBao package. + +1. SSH into the newly provisioned Linode as a user with `sudo` privileges, replacing {{< placeholder "USERNAME" >}} with your username and {{< placeholder "IP_ADDRESS" >}} with the IP address of your Linode: + + ```command + ssh {{< placeholder "USERNAME" >}}@{{< placeholder "IP_ADDRESS" >}} + ``` + +1. Download the latest appropriate version of OpenBao from the [downloads page](https://openbao.org/downloads/). This tutorial uses `v2.2.0` of the AMD 64-bit Debian package: + + ```command + wget https://github.com/openbao/openbao/releases/download/v2.2.0/bao_2.2.0_linux_amd64.deb + ``` + +1. Install the package: + + ```command + sudo dpkg -i bao_2.2.0_linux_amd64.deb + ``` + + ```output + Selecting previously unselected package bao. + (Reading database ... 124865 files and directories currently installed.) + Preparing to unpack bao_2.2.0_linux_amd64.deb ... + Unpacking bao (2.2.0) ... + Setting up bao (2.2.0) ... + Generating OpenBao TLS key and self-signed certificate... + ... + OpenBao TLS key and self-signed certificate have been generated in '/opt/openbao/tls'. + ``` + +1. Verify successful installation by checking the OpenBao version: + + ```command + bao -v + ``` + + ```output + OpenBao v2.2.0 (a2bf51c891680240888f7363322ac5b2d080bb23), built 2025-03-05T13:07:08Z + ``` +### Verify Swap Memory Limits + +For Linux distributions, ensure that the OpenBao service settings do not impose a soft limit on Swap memory. To check this with a systemd-based Linux distro, use the following command: + +```command +systemctl cat openbao +``` + +```output +# /usr/lib/systemd/system/openbao.service +[Unit] +Description="OpenBao - A tool for managing secrets" +... + +[Service] +... +TimeoutStopSec=30 +LimitNOFILE=65536 +MemorySwapMax=0 + +[Install] +WantedBy=multi-user.target +``` + +Verify that `MemorySwapMax=0` appears in the results under the `Service` heading. + +## Test the OpenBao Development Server + +OpenBao provides a development server that you can use to verify settings and explore OpenBao features. + +{{< note type="warning" >}} +The development server runs entirely in memory and is not suitable for production use. Data is not persisted between restarts, and TLS is disabled. +{{< /note >}} + +1. Run this command to start the server in development mode and set a primary key. Replace {{< placeholder "MY_DEV_TOKEN" >}} with a secure key that you have created: + + ```command + bao server -dev \ + -dev-root-token-id="{{< placeholder "MY_DEV_TOKEN" >}}" + ``` + + The OpenBao server configuration should print to the screen along with a tail of the logs: + + ```output + ==> OpenBao server configuration: + + Administrative Namespace: + Api Address: http://127.0.0.1:8200 + Cgo: disabled + Cluster Address: https://127.0.0.1:8201 + Environment Variables: HOME, LANG, LESSCLOSE, LESSOPEN, LOGNAME, LS_COLORS, MAIL, PATH, PWD, SHELL, SHLVL, SUDO_COMMAND, SUDO_GID, SUDO_UID, SUDO_USER, TERM, USER, _ + Go Version: go1.22.9 + Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled") + Log Level: + Recovery Mode: false + Storage: inmem + Version: OpenBao v2.0.3, built 2024-11-15T16:54:47Z + Version Sha: a2522eb71d1854f83c7e2e02fdbfc01ae74c3a78 + + ==> OpenBao server started! Log data will stream in below: + + ... + 2024-11-25T10:07:57.493-0700 [INFO] core: vault is unsealed + 2024-11-25T10:07:57.495-0700 [INFO] expiration: revoked lease: lease_id=auth/token/root/hf0285ed983c6c93bd02f9422f179d20f12508b046d39228a7b2e13c245293de6 + 2024-11-25T10:07:57.498-0700 [INFO] core: successful mount: namespace="" path=secret/ type=kv version="" + 2024-11-25T10:07:57.499-0700 [INFO] secrets.kv.kv_cd63d9f9: collecting keys to upgrade + 2024-11-25T10:07:57.499-0700 [INFO] secrets.kv.kv_cd63d9f9: done collecting keys: num_keys=1 + 2024-11-25T10:07:57.499-0700 [INFO] secrets.kv.kv_cd63d9f9: upgrading keys finished + ... + ``` + + Leave this server process running in the background. + +1. Open a separate terminal window and connect to the Linode instance using another shell session: + + ```command + ssh {{< placeholder "USERNAME" >}}@{{< placeholder "IP_ADDRESS" >}} + ``` + +1. OpenBao expects certain variables to be set for every request. Rather than setting these variables repeatedly with each command, set the following environment variables in the shell: + + ```command + export VAULT_TOKEN="{{< placeholder "MY_DEV_TOKEN" >}}" + export OPENBAO_IP="127.0.0.1" + export OPENBAO_PORT="8200" + ``` + +1. Send a request with `curl` to store a secret as a key-value pair. Replace {{< placeholder "VAULT_PASSWORD" >}} with a secure password. + + ```command + curl -X POST \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --header "Content-Type: application/json" \ + --data '{"data": {"password": "{{< placeholder "VAULT_PASSWORD" >}}"}}' \ + http://$OPENBAO_IP:$OPENBAO_PORT/v1/secret/data/test-password-1 \ + | json_pp + ``` + + ```output + { + "auth" : null, + "data" : { + "created_time" : "2025-04-17T16:53:43.538885271Z", + "custom_metadata" : null, + "deletion_time" : "", + "destroyed" : false, + "version" : 1 + }, + "lease_duration" : 0, + "lease_id" : "", + "renewable" : false, + "request_id" : "8b6538d0-e52c-7a7a-27a4-6d4c58d9fc02", + "warnings" : null, + "wrap_info" : null + } + ``` + + The development server is only exposed on `localhost`. Therefore, this command must be run on the server itself. Authentication is handled by supplying the `X-Vault-Token` header. The structure of the URI follows the pattern `/v1/secret/data/{{< placeholder "SECRET_NAME" >}}`. This `POST` request stores the key-value pair at location `/data/{{< placeholder "SECRET_NAME" >}}`. + + The response provides metadata regarding the secret stored in the `data` object, including versioning when the secret gets updated. + +1. To retrieve the secret, send the following request: + + ```command + curl \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + http://$OPENBAO_IP:$OPENBAO_PORT/v1/secret/data/test-password-1 \ + | json_pp + ``` + + The original secret is found within the data object as a key-value pair. + + ```output + { + "auth" : null, + "data" : { + "data" : { + "password" : "OpenBao123" + }, + "metadata" : { + "created_time" : "2025-04-17T16:53:43.538885271Z", + "custom_metadata" : null, + "deletion_time" : "", + "destroyed" : false, + "version" : 1 + } + }, + "lease_duration" : 0, + "lease_id" : "", + "renewable" : false, + "request_id" : "7ec0baa1-126d-1bd8-56a3-4ea4555821ff", + "warnings" : null, + "wrap_info" : null + } + ``` + +1. When done, you can close the second terminal session. + +1. Return to the original terminal session with OpenBao running, and press Ctrl+C to stop OpenBao. + +## Run OpenBao as a Service + +In a real-world use case, OpenBao is ideally run as a service managed by a tool like `systemd`. + +1. Run the following `systemctl` command to check the status of the OpenBao service: + + ```command + systemctl status openbao + ``` + + This shows that `systemd` is aware of the OpenBao service, but it has not been started: + + ```output + ○ openbao.service - "OpenBao - A tool for managing secrets" + Loaded: loaded (/usr/lib/systemd/system/openbao.service; disabled; preset: enabled) + Active: inactive (dead) + Docs: https://github.com/openbao/openbao/tree/main/website/content/docs + ``` + +1. Edit the OpenBao configuration file located at `/etc/openbao/openbao.hcl` in a command line text editor such as `nano`: + + ```command + sudo nano /etc/openbao/openbao.hcl + ``` + + Replace the contents of the file with the following minimal configuration to run OpenBao as a publicly available service without TLS: + + ```file {title="/etc/openbao/openbao.hcl" lang="hcl"} + ui = false + + storage "file" { + path = "/opt/openbao/data" + } + api_addr = "http://0.0.0.0:8200" + + listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 + } + ``` + + {{< note type="warning">}} + The configuration above is insecure and not suitable for production use. It is only for demonstration purposes of this tutorial. For a production-grade deployment, reference the [**Configuration**](#configuration) section at the end of this guide. + {{< /note >}} + + When done, press CTRL+X, followed by Y then Enter to save the file and exit `nano`. + +1. Start the OpenBao service: + + ```command + systemctl start openbao + ``` + +1. Recheck its status: + + ```command + systemctl status openbao + ``` + + The output should now show `active (running)`: + + ```output + ● openbao.service - "OpenBao - A tool for managing secrets" + Loaded: loaded (/usr/lib/systemd/system/openbao.service; disabled; preset: enabled) + Active: active (running) since Mon 2024-11-25 10:38:04 MST; 7s ago + Docs: https://github.com/openbao/openbao/tree/main/website/content/docs + Main PID: 642487 (bao) + Tasks: 6 (limit: 1124) + Memory: 12.2M (swap max: 0B peak: 12.5M) + CPU: 66ms + CGroup: /system.slice/openbao.service + └─642487 /usr/bin/bao server -config=/etc/openbao/openbao.hcl + ``` + + Press the Q key to exit the status output and return to the terminal prompt. + +1. Run the following command to enable the service to start automatically on boot: + + ```command + systemctl enable openbao + ``` + +## Configure OpenBao for External Access + +Although OpenBao is now running as a service on the Linode instance, additional configuration is required before it can be used. Use the [OpenBao CLI](https://openbao.org/docs/commands/) (`bao`) to interact with the running server, retrieving its current status: + +```command +bao status --address=http://0.0.0.0:8200 +``` + +```output +Key Value +--- ----- +Seal Type shamir +Initialized false +Sealed true +Total Shares 0 +Threshold 0 +Unseal Progress 0/0 +Unseal Nonce n/a +Version 2.2.0 +Build Date 2025-03-05T13:07:08Z +Storage Type file +HA Enabled false +``` + +This shows that the server has not been initialized and is sealed. Both of these issues must be resolved before you can interact with the server. + +### Initialize the Server + +1. Set the `BAO_ADDR` environment variable, which is used in several subsequent commands: + + ```command + export BAO_ADDR=http://0.0.0.0:8200 + ``` + + {{< note type="warning">}} + This tutorial sets `BAO_ADDR` to `http://0.0.0.0:8200` for demonstration purposes. In production deployments, it should match the public IP address or domain name used to connect to the server. + {{< /note >}} + +1. Initialize the server: + + ```command + bao operator init + ``` + + ```output + Unseal Key 1: SNP+diKq1L2MYYre8pn+PIqSEn/nK76n7C6coUoVby4g + Unseal Key 2: 9Bm3d5ZHsWBT/LghfVYbGrVn0Lcmr5CvNu6H8UYVx+R/ + Unseal Key 3: IrPLoIFrl2ol7dF4mA9C+kTaE44qogwT/pZ+kTrS7M4j + Unseal Key 4: O7fs+9492lVGdI5295n4AKis5c3cFZ8VEtkBmLg3lYAJ + Unseal Key 5: 0gnwUnHfkeFTaE6xIkVWy/5s4Hfwh5WxVWOrCrApGHig + + Initial Root Token: s.V82B9tynwZkQtDyOne7PJ1IS + + Vault initialized with 5 key shares and a key threshold of 3. Please securely + distribute the key shares printed above. When the Vault is re-sealed, + restarted, or stopped, you must supply at least 3 of these keys to unseal it + before it can start servicing requests. + + Vault does not store the generated root key. Without at least 3 keys to + reconstruct the root key, Vault will remain permanently sealed! + + It is possible to generate new unseal keys, provided you have a quorum of + existing unseal keys shares. See "bao operator rekey" for more information. + ``` + + Store the values for each `Unseal Key` and `Initial Root Token` in a secure location. + +### Unseal the Vault (Three Times for Quorum) + +When unsealing a vault, the `bao operator unseal` command must be performed a total of three times using different `Unseal Key` values each time. This is the default quorum for OpenBao's unsealing process. + +1. Use the following command to begin unsealing the vault: + + ```command + bao operator unseal + ``` + + When prompted, enter one of the unseal keys provided in the previous section: + + ```output + Unseal Key (will be hidden): SNP+diKq1L2MYYre8pn+PIqSEn/nK76n7C6coUoVby4g + ``` + + After this first execution, the `Unseal Progress` output value shows `1/3`: + + ```output + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed true + Total Shares 5 + Threshold 3 + Unseal Progress 1/3 + Unseal Nonce e88d59f4-db7f-a074-c9e5-6476e55d77c4 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + HA Enabled false + ``` + +1. Unseal the vault again, but enter a different unseal key when prompted: + + ```command + bao operator unseal + ``` + + ```output + Unseal Key (will be hidden): 9Bm3d5ZHsWBT/LghfVYbGrVn0Lcmr5CvNu6H8UYVx+R/ + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed true + Total Shares 5 + Threshold 3 + Unseal Progress 2/3 + Unseal Nonce e88d59f4-db7f-a074-c9e5-6476e55d77c4 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + HA Enabled false + ``` + +1. Unseal the vault for the third and final time, using yet another unsealing key when prompted: + + ```command + bao operator unseal + ``` + + After unsealing the vault with three different unseal keys, OpenBao should report the following status: + + ```output + Unseal Key (will be hidden): IrPLoIFrl2ol7dF4mA9C+kTaE44qogwT/pZ+kTrS7M4j + Key Value + --- ----- + Seal Type shamir + Initialized true + Sealed false + Total Shares 5 + Threshold 3 + Version 2.2.0 + Build Date 2025-03-05T13:07:08Z + Storage Type file + Cluster Name vault-cluster-bf06dcdc + Cluster ID e241640b-4e62-5063-04fb-e71562706b8c + HA Enabled false + ``` + + The vault has now been initialized and unsealed. + +### Authenticate the CLI + +To authenticate the CLI with the server, use the `bao login` command with the `Initial Root Token` output value provided upon vault initialization. + +```command +bao login -method=token {{< placeholder "INITIAL_ROOT_TOKEN" >}} +``` + +```output +Success! You are now authenticated. The token information displayed below is +already stored in the token helper. You do NOT need to run "bao login" again. +Future OpenBao requests will automatically use this token. + +Key Value +--- ----- +token s.V82B9tynwZkQtDyOne7PJ1IS +token_accessor 4IjIYjvf9TLIPPXgMVFFJYzG +token_duration ∞ +token_renewable false +token_policies ["root"] +identity_policies [] +policies ["root"] +``` + +### Enable Key-Value Storage + +Lastly, run the following command to enable a key-value store in OpenBao for storing and retrieving secrets via the API: + +```command +bao secrets enable kv +``` + +```output +Success! Enabled the kv secrets engine at: kv/ +``` + +### Storing and Retrieving a Secret Remotely Over HTTP + +OpenBao can now be accessed externally via the API. Ensure that any firewall on the Linode instance allows traffic on port `8200`. + +1. From a remote machine, store a new secret, providing the `Initial Root Token` for authentication. + + ```command + curl -X POST \ + --header "X-Vault-Token: {{< placeholder "INITIAL_ROOT_TOKEN" >}}" \ + --header "Content-Type: application/json" \ + --data '{"data": {"hello": "world"}}' \ + http://{{< placeholder "OPENBAO_LINODE_IP" >}}:8200/v1/kv/test-secret + ``` + +1. Get the newly created secret to verify it was stored properly. + + ```command + curl -X GET \ + --header "X-Vault-Token: {{< placeholder "INITIAL_ROOT_TOKEN" >}}" \ + http://{{< placeholder "OPENBAO_LINODE_IP" >}}:8200/v1/kv/test-secret \ + | json_pp + ``` + + ```output + { + "auth" : null, + "data" : { + "hello" : "world" + }, + "lease_duration" : 2764800, + "lease_id" : "", + "renewable" : false, + "request_id" : "3bbd69a5-b77a-62b0-686d-a8a3103d6d6b", + "warnings" : null, + "wrap_info" : null + } + ``` + +## Considerations for Production Deployments + +Several additional steps are recommended to harden an OpenBao server for production use. + +### Auto Unseal + +OpenBao starts with its vault in a sealed state, meaning all data is encrypted. For more information on the seal and unseal concepts, see the [OpenBao documentation](https://openbao.org/docs/concepts/seal/). + +In production, [auto-unseal](https://openbao.org/docs/concepts/seal/#auto-unseal) is recommended to minimize manual operations that could lead to mistakes or exposure. Auto-unseal is configured using cloud-based key management systems to ensure the unsealing key is never exposed directly. + +### Authentication + +Enable and configure secure authentication methods such as: + +- AppRole +- JSON Web Tokens (JWT) +- TLS certificates +- Lightweight directory access protocol (LDAP) +- OpenID Connect (OIDC) + +TLS certificate authentication provides secure, mutual TLS verification for sensitive environments. Meanwhile, AppRole allows service accounts and applications to securely authenticate without human interaction. For LDAP or OIDC deployments, enforce multi-factor authentication (MFA) for human operators to enhance security, if supported. + +### Configuration + +OpenBao supports two configuration formats: [HashiCorp Configuration Language](https://developer.hashicorp.com/terraform/language/syntax/configuration) (HCL) and JSON. + +Properly configuring your OpenBao server is essential to ensuring a secure production environment. The main configuration aspects include the UI, TLS certificate, and address/port settings. A default production configuration HCL file may look like this: + +```file {title="/etc/openbao/openbao.hcl" lang="hcl"} +ui = false + +storage "file" { + path = "/opt/openbao/data" +} +api_addr = "https://0.0.0.0:8200" + +listener "tcp" { + address = "0.0.0.0:8200" + tls_cert_file = "/opt/openbao/tls/tls.crt" + tls_key_file = "/opt/openbao/tls/tls.key" +} +``` + +In production, disabling or securing the UI is crucial, as it exposes OpenBao's management interface, which could be exploited if left unprotected. If the UI is required, limit its exposure by restricting access to trusted IP ranges or VPN users only. Implement strong authentication methods like OIDC for access control. + +If the UI is not required, set `ui = false`. + +TLS or SSL certificates encrypt traffic to and from the OpenBao server, ensuring data confidentiality and integrity. Using a valid, trusted TLS certificate prevents man-in-the-middle attacks and validates the server's identity to clients. Obtain a certificate from a trusted Certificate Authority (CA) and configure OpenBao to use it as shown in the example configuration above. + +For environments using an internal CA, ensure that all clients trust it, and renew the certificates periodically to avoid downtime. + +Controlling the address and ports on which OpenBao listens reduces exposure and minimizes the risk of unauthorized access. Limit OpenBao's exposure by binding it to an internal IP address such as `127.0.0.1` or a specific internal network IP. Ensure that OpenBao only listens on the necessary port, where the default port is `8200`. Use firewall rules to restrict access to this port to authorized networks or users only. + +These hardening measures can reduce the attack surface of the OpenBao server, enhance security controls, and ensure that only authorized entities have access. \ No newline at end of file