mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +03:00
nixos/openbao: init
- Added a NixOS module using RFC42 and plenty of systemd hardening - Added a NixOS VM Test which checks the basic functionality - Refactored the package to support HSM and UI
This commit is contained in:
parent
9d47e86d18
commit
7da9ff9fab
6 changed files with 326 additions and 24 deletions
|
@ -1426,6 +1426,7 @@
|
|||
./services/security/nginx-sso.nix
|
||||
./services/security/oauth2-proxy.nix
|
||||
./services/security/oauth2-proxy-nginx.nix
|
||||
./services/security/openbao.nix
|
||||
./services/security/opensnitch.nix
|
||||
./services/security/paretosecurity.nix
|
||||
./services/security/pass-secret-service.nix
|
||||
|
|
160
nixos/modules/services/security/openbao.nix
Normal file
160
nixos/modules/services/security/openbao.nix
Normal file
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.openbao;
|
||||
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.openbao = {
|
||||
enable = lib.mkEnableOption "OpenBao daemon";
|
||||
|
||||
package = lib.mkPackageOption pkgs "openbao" {
|
||||
example = "pkgs.openbao.override { withHsm = false; withUi = false; }";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = ''
|
||||
Settings of OpenBao.
|
||||
|
||||
See [documentation](https://openbao.org/docs/configuration) for more details.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
ui = true;
|
||||
|
||||
listener.default = {
|
||||
type = "tcp";
|
||||
tls_acme_email = config.security.acme.defaults.email;
|
||||
tls_acme_domains = [ "example.com" ];
|
||||
tls_acme_disable_http_challenge = true;
|
||||
};
|
||||
|
||||
cluster_addr = "http://127.0.0.1:8201";
|
||||
api_addr = "https://example.com";
|
||||
|
||||
storage.raft.path = "/var/lib/openbao";
|
||||
}
|
||||
'';
|
||||
|
||||
type = lib.types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
ui = lib.mkEnableOption "the OpenBao web UI";
|
||||
|
||||
listener = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ config, ... }:
|
||||
{
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"tcp"
|
||||
"unix"
|
||||
];
|
||||
description = ''
|
||||
The listener type to enable.
|
||||
'';
|
||||
};
|
||||
address = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = if config.type == "unix" then "/run/openbao/openbao.sock" else "127.0.0.1:8200";
|
||||
defaultText = lib.literalExpression ''if config.services.openbao.settings.listener.<name>.type == "unix" then "/run/openbao/openbao.sock" else "127.0.0.1:8200"'';
|
||||
description = ''
|
||||
The TCP address or UNIX socket path to listen on.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
description = ''
|
||||
Configure a listener for responding to requests.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Additional arguments given to OpenBao.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.services.openbao = {
|
||||
description = "OpenBao - A tool for managing secrets";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients.
|
||||
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
|
||||
ExecStart = lib.escapeShellArgs (
|
||||
[
|
||||
(lib.getExe cfg.package)
|
||||
"server"
|
||||
"-config"
|
||||
(settingsFormat.generate "openbao.hcl.json" cfg.settings)
|
||||
]
|
||||
++ cfg.extraArgs
|
||||
);
|
||||
ExecReload = "${lib.getExe' pkgs.coreutils "kill"} -SIGHUP $MAINPID";
|
||||
|
||||
StateDirectory = "openbao";
|
||||
StateDirectoryMode = "0700";
|
||||
RuntimeDirectory = "openbao";
|
||||
RuntimeDirectoryMode = "0700";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
DynamicUser = true;
|
||||
LimitCORE = 0;
|
||||
LockPersonality = true;
|
||||
MemorySwapMax = 0;
|
||||
MemoryZSwapMax = 0;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
Restart = "on-failure";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"@resources"
|
||||
"~@privileged"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -972,6 +972,7 @@ in
|
|||
ollama-rocm = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./ollama-rocm.nix;
|
||||
ombi = handleTest ./ombi.nix { };
|
||||
openarena = handleTest ./openarena.nix { };
|
||||
openbao = runTest ./openbao.nix;
|
||||
openldap = handleTest ./openldap.nix { };
|
||||
opensearch = discoverTests (import ./opensearch.nix);
|
||||
openresty-lua = handleTest ./openresty-lua.nix { };
|
||||
|
|
105
nixos/tests/openbao.nix
Normal file
105
nixos/tests/openbao.nix
Normal file
|
@ -0,0 +1,105 @@
|
|||
{ lib, ... }:
|
||||
let
|
||||
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||||
domain = certs.domain;
|
||||
in
|
||||
{
|
||||
name = "openbao";
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ kranzes ];
|
||||
|
||||
nodes.machine =
|
||||
{ config, ... }:
|
||||
{
|
||||
security.pki.certificateFiles = [ certs.ca.cert ];
|
||||
|
||||
networking.extraHosts = ''
|
||||
127.0.0.1 ${domain}
|
||||
'';
|
||||
|
||||
services.openbao = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
ui = true;
|
||||
|
||||
listener = {
|
||||
default = {
|
||||
type = "tcp";
|
||||
tls_cert_file = certs.${domain}.cert;
|
||||
tls_key_file = certs.${domain}.key;
|
||||
};
|
||||
|
||||
unix = {
|
||||
type = "unix";
|
||||
};
|
||||
};
|
||||
|
||||
cluster_addr = "https://127.0.0.1:8201";
|
||||
api_addr = "https://${domain}:8200";
|
||||
|
||||
storage.raft.path = "/var/lib/openbao";
|
||||
};
|
||||
};
|
||||
|
||||
environment.variables = {
|
||||
BAO_ADDR = config.services.openbao.settings.api_addr;
|
||||
BAO_FORMAT = "json";
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
import json
|
||||
|
||||
start_all()
|
||||
|
||||
with subtest("Wait for OpenBao to start up"):
|
||||
machine.wait_for_unit("openbao.service")
|
||||
machine.wait_for_open_port(8200)
|
||||
machine.wait_for_open_unix_socket("${nodes.machine.services.openbao.settings.listener.unix.address}")
|
||||
|
||||
with subtest("Check that the web UI is being served"):
|
||||
machine.succeed("curl -L --fail --show-error --silent $BAO_ADDR | grep '<title>OpenBao</title>'")
|
||||
|
||||
with subtest("Check that OpenBao is not initialized"):
|
||||
status_output = json.loads(machine.fail("bao status"))
|
||||
assert not status_output["initialized"]
|
||||
|
||||
with subtest("Initialize OpenBao"):
|
||||
init_output = json.loads(machine.succeed("bao operator init"))
|
||||
|
||||
with subtest("Check that OpenBao is initialized and sealed"):
|
||||
status_output = json.loads(machine.fail("bao status"))
|
||||
assert status_output["initialized"]
|
||||
assert status_output["sealed"]
|
||||
|
||||
with subtest("Unseal OpenBao"):
|
||||
for key in init_output["unseal_keys_b64"][:init_output["unseal_threshold"]]:
|
||||
machine.succeed(f"bao operator unseal {key}")
|
||||
|
||||
with subtest("Check that OpenBao is not sealed"):
|
||||
status_output = json.loads(machine.succeed("bao status"))
|
||||
assert not status_output["sealed"]
|
||||
|
||||
with subtest("Login with root token"):
|
||||
machine.succeed(f"bao login {init_output["root_token"]}")
|
||||
|
||||
with subtest("Enable userpass auth method"):
|
||||
machine.succeed("bao auth enable userpass")
|
||||
|
||||
with subtest("Create a user in userpass"):
|
||||
machine.succeed("bao write auth/userpass/users/testuser password=testpassword")
|
||||
|
||||
with subtest("Login to a user from userpass"):
|
||||
machine.succeed("bao login -method userpass username=testuser password=testpassword")
|
||||
|
||||
with subtest("Write a secret to cubbyhole"):
|
||||
machine.succeed("bao write cubbyhole/my-secret my-value=s3cr3t")
|
||||
|
||||
with subtest("Read a secret from cubbyhole"):
|
||||
read_output = json.loads(machine.succeed("bao read cubbyhole/my-secret"))
|
||||
assert read_output["data"]["my-value"] == "s3cr3t"
|
||||
'';
|
||||
}
|
|
@ -3,20 +3,23 @@
|
|||
fetchFromGitHub,
|
||||
buildGoModule,
|
||||
go_1_24,
|
||||
testers,
|
||||
openbao,
|
||||
versionCheckHook,
|
||||
nix-update-script,
|
||||
nixosTests,
|
||||
callPackage,
|
||||
stdenvNoCC,
|
||||
withUi ? true,
|
||||
withHsm ? stdenvNoCC.hostPlatform.isLinux,
|
||||
}:
|
||||
|
||||
buildGoModule.override { go = go_1_24; } rec {
|
||||
buildGoModule.override { go = go_1_24; } (finalAttrs: {
|
||||
pname = "openbao";
|
||||
version = "2.2.0";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "openbao";
|
||||
repo = "openbao";
|
||||
tag = "v${version}";
|
||||
tag = "v${finalAttrs.version}";
|
||||
hash = "sha256-dDMOeAceMaSrF7P4JZ2MKy6zDa10LxCQKkKwu/Q3kOU=";
|
||||
};
|
||||
|
||||
|
@ -26,33 +29,24 @@ buildGoModule.override { go = go_1_24; } rec {
|
|||
|
||||
subPackages = [ "." ];
|
||||
|
||||
tags = [
|
||||
"openbao"
|
||||
"bao"
|
||||
];
|
||||
tags = lib.optional withHsm "hsm" ++ lib.optional withUi "ui";
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X github.com/openbao/openbao/version.GitCommit=${src.rev}"
|
||||
"-X github.com/openbao/openbao/version.fullVersion=${version}"
|
||||
"-X github.com/openbao/openbao/version.GitCommit=${finalAttrs.src.rev}"
|
||||
"-X github.com/openbao/openbao/version.fullVersion=${finalAttrs.version}"
|
||||
"-X github.com/openbao/openbao/version.buildDate=1970-01-01T00:00:00Z"
|
||||
];
|
||||
|
||||
postConfigure = lib.optionalString withUi ''
|
||||
cp -r --no-preserve=mode ${finalAttrs.passthru.ui} http/web_ui
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
mv $out/bin/openbao $out/bin/bao
|
||||
'';
|
||||
|
||||
# TODO: Enable the NixOS tests after adding OpenBao as a NixOS service in an upcoming PR and
|
||||
# adding NixOS tests
|
||||
#
|
||||
# passthru.tests = { inherit (nixosTests) vault vault-postgresql vault-dev vault-agent; };
|
||||
|
||||
passthru.tests.version = testers.testVersion {
|
||||
package = openbao;
|
||||
command = "HOME=$(mktemp -d) bao --version";
|
||||
version = "v${version}";
|
||||
};
|
||||
|
||||
nativeInstallCheckInputs = [
|
||||
versionCheckHook
|
||||
];
|
||||
|
@ -61,15 +55,22 @@ buildGoModule.override { go = go_1_24; } rec {
|
|||
doInstallCheck = true;
|
||||
|
||||
passthru = {
|
||||
updateScript = nix-update-script { };
|
||||
ui = callPackage ./ui.nix { };
|
||||
tests = { inherit (nixosTests) openbao; };
|
||||
updateScript = nix-update-script {
|
||||
extraArgs = [
|
||||
"--subpackage"
|
||||
"ui"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
homepage = "https://www.openbao.org/";
|
||||
description = "Open source, community-driven fork of Vault managed by the Linux Foundation";
|
||||
changelog = "https://github.com/openbao/openbao/blob/v${version}/CHANGELOG.md";
|
||||
changelog = "https://github.com/openbao/openbao/blob/v${finalAttrs.version}/CHANGELOG.md";
|
||||
license = lib.licenses.mpl20;
|
||||
mainProgram = "bao";
|
||||
maintainers = with lib.maintainers; [ brianmay ];
|
||||
};
|
||||
}
|
||||
})
|
||||
|
|
34
pkgs/by-name/op/openbao/ui.nix
Normal file
34
pkgs/by-name/op/openbao/ui.nix
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
stdenvNoCC,
|
||||
openbao,
|
||||
yarn-berry_3,
|
||||
nodejs,
|
||||
}:
|
||||
|
||||
stdenvNoCC.mkDerivation (finalAttrs: {
|
||||
pname = openbao.pname + "-ui";
|
||||
inherit (openbao) version src;
|
||||
sourceRoot = "${finalAttrs.src.name}/ui";
|
||||
|
||||
offlineCache = yarn-berry_3.fetchYarnBerryDeps {
|
||||
inherit (finalAttrs) src sourceRoot;
|
||||
hash = "sha256-bQ+ph7CvPtygvCoCMjTMadYLn/ds2ZOGQL29x3hFuLg=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
yarn-berry_3.yarnBerryConfigHook
|
||||
nodejs
|
||||
yarn-berry_3
|
||||
];
|
||||
|
||||
env.YARN_ENABLE_SCRIPTS = 0;
|
||||
|
||||
postConfigure = ''
|
||||
substituteInPlace .ember-cli \
|
||||
--replace-fail "../http/web_ui" "$out"
|
||||
'';
|
||||
|
||||
buildPhase = "yarn run ember build --environment=production";
|
||||
|
||||
dontInstall = true;
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue