Tailscale Integration for OpenBao
Plugin repository: https://github.com/SamPlaysKeys/openbao-plugin-secrets-tailscale
This guide details how to set up an on-demand, dynamic Tailscale integration in OpenBao. When a client (such as a Docker container) requests a secret from docker/tailscale/auth-token/<name> (for example, docker/tailscale/auth-token/nginx), OpenBao will automatically call the Tailscale API to generate a short-lived, preauthorized, and ephemeral authentication key labeled for that specific container, returning it to the client immediately.
Architectural Choices & Routing
Can we support other paths later (e.g., docker/tailscale/idp)?
Yes, absolutely. You have two clean options to achieve this:
Option A: Extend the Plugin (Recommended) Our plugin is modular. If you need a new path later, such as
docker/tailscale/idpthat interfaces with another service or maps configuration, you can simply add a new path handler inside the plugin code (e.g., creatingpath_idp.goand adding it toPathsinbackend.go). This keeps all Tailscale-related integrations housed within a single secrets engine binary.Option B: OpenBao Nested Mount Routing OpenBao (and HashiCorp Vault) routes API requests based on the most specific matching path prefix.
- If you mount our plugin at
docker/tailscale, it owns everything underdocker/tailscale/*. - However, you can mount a completely separate secrets engine (like a standard Key-Value store or a database engine) at a nested subpath, such as
docker/tailscale/idp:
In this scenario, a request to
docker/tailscale/idp/my-secretis routed to the KV engine, while a request todocker/tailscale/auth-token/nginxis routed to our Tailscale plugin.- If you mount our plugin at
Prerequisites
- OpenBao running in dev mode on the host (
127.0.0.1:8200with root tokendev-only-token). - Docker installed on the host (used to compile the plugin without requiring a Go installation on your machine).
- A Tailscale API Key (e.g.,
example-api-key-here) and your Tailnet name.
Step-by-Step Configuration
Step 1: Compile the Plugin using Docker
Since Go is not required on your host, you can compile the plugin binaries for macOS and Linux using a containerized Go environment.
Navigate to the plugin source folder:
Build the Docker builder image:
Run the builder to extract the binaries into a
bin/directory on your host:
This creates four binaries in your wip/openbao-tailscale-integration/bin/ folder:
openbao-plugin-secrets-tailscale-darwin-arm64(Apple Silicon Mac)openbao-plugin-secrets-tailscale-darwin-amd64(Intel Mac)openbao-plugin-secrets-tailscale-linux-arm64(Linux ARM64/Raspberry Pi)openbao-plugin-secrets-tailscale-linux-amd64(Linux AMD64)
Step 2: Configure OpenBao for Plugins
To load external plugins, OpenBao must be configured with a plugin directory.
If running OpenBao in Dev Mode on your macOS host, start the server using the -dev-plugin-dir flag and point it to the absolute path of your built binaries:
Step 3: Register the Plugin in the Catalog
Before enabling the secrets engine, OpenBao requires you to register the binary in its internal catalog with a SHA256 signature to guarantee code integrity.
Set your environment variables:
Calculate the SHA256 checksum of your plugin binary:
Register the plugin into the OpenBao Catalog:
Step 4: Enable the Secrets Engine at docker/tailscale
Mount the newly registered secrets engine plugin:
Step 5: Configure the Tailscale Secrets Engine
Write your Tailscale credentials to the plugin’s configuration endpoint:
Verification
To verify that the integration is working and generating dynamic tokens, request a read operation for a specific app name (e.g. nginx):
Expected Output:
Passing Custom Key Parameters
You can customize the characteristics of the generated Tailscale key at request time:
Requesting Secrets inside Docker Containers
When requesting secrets from within a Docker container, the container needs to resolve the host address 127.0.0.1:8200 to contact OpenBao.
Common Pitfall: Localhost Resolution
Inside a Docker container, 127.0.0.1 refers to the container itself, not the host machine.
- On macOS, Docker provides the host alias
host.docker.internal. - On Linux, you should use the default bridge gateway IP (typically
172.17.0.1) or run Docker Compose withextra_hoststo inject the host IP.
Example: Container Bootstrap Script (entrypoint.sh)
This script can run as the entrypoint inside your docker container (in this case, for an nginx service) to automatically register itself on Tailscale using the token fetched from OpenBao:
Example: Docker Compose configuration
Troubleshooting & Common Pitfalls
- Permission Denied (Execution): If OpenBao logs
fork/exec /Users/sam/Workspace/openbao-plugins/openbao-plugin-secrets-tailscale: permission denied, verify that the plugin file is executable by runningchmod +xon it. - Architecture Mismatch: Ensure you copied the correct architecture binary. If OpenBao runs on Apple Silicon macOS, you must use the
darwin-arm64binary. If it runs inside a Linux Docker container, you must use thelinux-amd64orlinux-arm64binary depending on your host. - Invalid Tag Prefix: When requesting a token with tags, Tailscale API strictly requires tags to begin with
tag:(e.g.tag:docker, notdocker).