A fork of https://github.com/numtide/systemd-vaultd modified to support OpenBao rather than HashiCorp Vault.
Find a file
cinereal 93fa80b068
fix(tests): fix the tests in ./nix/checks/
Signed-off-by: cinereal <cinereal@riseup.net>
2025-11-13 12:39:41 +01:00
.github drop github update-flake-lock in favour of renovate bot 2023-05-11 16:19:26 +02:00
cmd/systemd-vaultd-update-secrets feat(go): further adapt to the new socket location 2024-10-22 18:11:01 +02:00
etc fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
nix fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
npins feat: we don't need flakes where we are going 2024-10-20 21:30:38 +02:00
tests fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
.envrc feat: we don't need flakes where we are going 2024-10-20 21:30:38 +02:00
.gitignore fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
.mergify.yml fix mergify (#60) 2024-06-17 08:50:23 +02:00
bors.toml update bors configuration 2023-01-17 10:34:07 +01:00
default.nix feat(secrets): further adapt to openbao 2024-10-22 18:02:26 +02:00
epoll.go epoll: don't log errors if fd already has been removed 2022-07-03 13:33:51 +02:00
go.mod fix: move to Go 1.22 2024-10-22 14:53:14 +02:00
justfile fix defaults for systemd runtime directory 2022-06-11 12:39:47 +02:00
LICENSE feat(branding): rebrand the README for accurate documentation 2025-01-01 02:15:58 +01:00
main.go feat(go): further adapt to the new socket location 2024-10-22 18:11:01 +02:00
Makefile fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
Procfile fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
pyproject.toml apply treefmt 2023-01-17 10:34:07 +01:00
README.md fix(tests): fix the tests in ./nix/checks/ 2025-11-13 12:39:41 +01:00
renovate.json renovate: enable lockfile maintainance 2023-05-11 16:26:17 +02:00
secrets.go add support for environment variables 2022-10-28 16:50:19 +02:00
setup.cfg mvp + tests 2022-06-11 09:45:43 +02:00
shell.nix feat: we don't need flakes where we are going 2024-10-20 21:30:38 +02:00
systemd_sockets.go implement systemd socket activation 2022-06-11 10:35:01 +02:00
watcher.go add support for environment variables 2022-10-28 16:50:19 +02:00

systemd-openbaod - load openbao credentials with systemd units

This is a fork of the original project made in https://github.com/numtide/systemd-vaultd for OpenBao, which is, itself a fork of HashiCorp Vault.

Mostly written in a train

  • Jörg Thalheim

systemd-openbaod is a proxy between systemd and vault agent. It provides a unix socket that can be used in systemd services in the LoadCredential option and then waits for vault agent to write these secrets in json format at /run/systemd-openbaod/<service_name>.service.json.

This project's goal is to simplify the loading of OpenBao secrets from systemd units.

Problem statement

Systemd has an option called LoadCredentials that allows to provide credentials to a service:

# myservice.service
[Service]
ExecStart=/usr/bin/myservice.sh
LoadCredential=foobar:/etc/myfoobarcredential.txt

In this case systemd will load credential the file /etc/myfoobarcredential.txt and provide it to the service at $CREDENTIAL_PATH/foobar.

It's handy because it bypasses file permission issues. /etc/myfoobarcredential.txt can be owned by root, and the unit run as a different or dynamic user.

While vault agent also supports writing these secrets, a major issue is that the consumer service may be started before vault agent was able to retrieve secrets from vault. In that case, systemd would fail to start the service.

The solution

In order to do so, I wrote a systemd-openbaod service which acts as a proxy between systemd and vault agent that is running on the machine. It provides a unix socket that can be used in systemd services in the LoadCredential option and then waits for vault agent to write these secrets at /run/systemd-openbaod/<service_name>.json.

We take advantage that in addition to normal paths, systemd also supports loading credentials from unix sockets.

With systemd-openbaod the service myservice.service would look like this:

[Service]
ExecStart=/usr/bin/myservice.sh
LoadCredential=foobar:/run/systemd-openbaod/sock

vault agent is then expected to write secrets to /run/systemd-openbaod/ in json format.

template {
  # this exposes all secrets in `secret/my-secret` to the service
  contents = "#{{ with secret \"secret/my-secret\" }}{{ .Data.data | toJSON }}{{ end }}"

  # an alternative is to expose only selected secrets like this:
  #  contents = <<EOF
  #  {{ with secret "secret/my-secret" }}{{ scratch.MapSet "secrets" "foobar" .Data.data.foo }}{{ end }}
  #  {{ scratch.Get "foobar" | explodeMap | toJSON }}
  #  EOF

  destination  = "/run/systemd-openbaod/secrets/myservice.service.json"
}

When myservice is started, systemd will open a connection to systemd-openbaod's socket. systemd-openbaod then either serve the secrets from /run/systemd-openbaod/secrets/myservice.service.json or it waits with inotify on secret directory for vault agent to write the secret.

Once the file /run/systemd-openbaod/secrets/myservice.service.json is present, systemd-openbaod will parse it into a json map and lookup the keys specified in LoadCredential.

Installation

The installation requires a go compiler and make to be installed.

This command will install the systemd-openbaod binary to /usr/bin/systemd-openbaod as well as installing a following systemd unit files: systemd-vaultd.service, systemd-openbaod.socket:

make install

Known limitations

systemd's LoadCredential option will not update credentials if a service is reloaded. However systemd-openbaod called systemd-vaultd-update-secrets comes with a helper program that can write secrets from the json file generated by systemd-openbaod to a directory readable by the service. Checkout systemd-openbaod/nix/checks/systemd-vaultd-test.nix for more details.

License

Copyright (c) 2024 Ryan Lahfa and contributors. Copyright (c) 2022 Jörg Thalheim and contributors.

This project is free software, and may be redistributed under the terms specified in the LICENSE file.