Merge pull request #108411 from hercules-ci/vault-multiple-config-files

vault: Support multiple config files (no secrets in store)
This commit is contained in:
Robert Hensing 2021-01-24 13:49:06 +01:00 committed by GitHub
commit 530df49d7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 2 deletions

View File

@ -27,6 +27,11 @@ let
''} ''}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
allConfigPaths = [configFile] ++ cfg.extraSettingsPaths;
configOptions = escapeShellArgs (concatMap (p: ["-config" p]) allConfigPaths);
in in
{ {
@ -84,7 +89,14 @@ in
storageConfig = mkOption { storageConfig = mkOption {
type = types.nullOr types.lines; type = types.nullOr types.lines;
default = null; default = null;
description = "Storage configuration"; description = ''
HCL configuration to insert in the storageBackend section.
Confidential values should not be specified here because this option's
value is written to the Nix store, which is publicly readable.
Provide credentials and such in a separate file using
<xref linkend="opt-services.vault.extraSettingsPaths"/>.
'';
}; };
telemetryConfig = mkOption { telemetryConfig = mkOption {
@ -98,6 +110,36 @@ in
default = ""; default = "";
description = "Extra text appended to <filename>vault.hcl</filename>."; description = "Extra text appended to <filename>vault.hcl</filename>.";
}; };
extraSettingsPaths = mkOption {
type = types.listOf types.path;
default = [];
description = ''
Configuration files to load besides the immutable one defined by the NixOS module.
This can be used to avoid putting credentials in the Nix store, which can be read by any user.
Each path can point to a JSON- or HCL-formatted file, or a directory
to be scanned for files with <literal>.hcl</literal> or
<literal>.json</literal> extensions.
To upload the confidential file with NixOps, use for example:
<programlisting><![CDATA[
# https://releases.nixos.org/nixops/latest/manual/manual.html#opt-deployment.keys
deployment.keys."vault.hcl" = let db = import ./db-credentials.nix; in {
text = ${"''"}
storage "postgresql" {
connection_url = "postgres://''${db.username}:''${db.password}@host.example.com/exampledb?sslmode=verify-ca"
}
${"''"};
user = "vault";
};
services.vault.extraSettingsPaths = ["/run/keys/vault.hcl"];
services.vault.storageBackend = "postgresql";
users.users.vault.extraGroups = ["keys"];
]]></programlisting>
'';
};
}; };
}; };
@ -136,7 +178,7 @@ in
serviceConfig = { serviceConfig = {
User = "vault"; User = "vault";
Group = "vault"; Group = "vault";
ExecStart = "${cfg.package}/bin/vault server -config ${configFile}"; ExecStart = "${cfg.package}/bin/vault server ${configOptions}";
ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
PrivateDevices = true; PrivateDevices = true;
PrivateTmp = true; PrivateTmp = true;

View File

@ -407,6 +407,7 @@ in
uwsgi = handleTest ./uwsgi.nix {}; uwsgi = handleTest ./uwsgi.nix {};
v2ray = handleTest ./v2ray.nix {}; v2ray = handleTest ./v2ray.nix {};
vault = handleTest ./vault.nix {}; vault = handleTest ./vault.nix {};
vault-postgresql = handleTest ./vault-postgresql.nix {};
vector = handleTest ./vector.nix {}; vector = handleTest ./vector.nix {};
victoriametrics = handleTest ./victoriametrics.nix {}; victoriametrics = handleTest ./victoriametrics.nix {};
virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {}; virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};

View File

@ -0,0 +1,70 @@
/* This test checks that
- multiple config files can be loaded
- the storage backend can be in a file outside the nix store
as is required for security (required because while confidentiality is
always covered, availability isn't)
- the postgres integration works
*/
import ./make-test-python.nix ({ pkgs, ... }:
{
name = "vault-postgresql";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ lnl7 roberth ];
};
machine = { lib, pkgs, ... }: {
virtualisation.memorySize = 512;
environment.systemPackages = [ pkgs.vault ];
environment.variables.VAULT_ADDR = "http://127.0.0.1:8200";
services.vault.enable = true;
services.vault.extraSettingsPaths = [ "/run/vault.hcl" ];
systemd.services.vault = {
after = [
"postgresql.service"
];
# Try for about 10 minutes rather than the default of 5 attempts.
serviceConfig.RestartSec = 1;
serviceConfig.StartLimitBurst = 600;
};
# systemd.services.vault.unitConfig.RequiresMountsFor = "/run/keys/";
services.postgresql.enable = true;
services.postgresql.initialScript = pkgs.writeText "init.psql" ''
CREATE USER vaultuser WITH ENCRYPTED PASSWORD 'thisisthepass';
GRANT CONNECT ON DATABASE postgres TO vaultuser;
-- https://www.vaultproject.io/docs/configuration/storage/postgresql
CREATE TABLE vault_kv_store (
parent_path TEXT COLLATE "C" NOT NULL,
path TEXT COLLATE "C",
key TEXT COLLATE "C",
value BYTEA,
CONSTRAINT pkey PRIMARY KEY (path, key)
);
CREATE INDEX parent_path_idx ON vault_kv_store (parent_path);
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO vaultuser;
'';
};
testScript =
''
secretConfig = """
storage "postgresql" {
connection_url = "postgres://vaultuser:thisisthepass@localhost/postgres?sslmode=disable"
}
"""
start_all()
machine.wait_for_unit("multi-user.target")
machine.succeed("cat >/root/vault.hcl <<EOF\n%s\nEOF\n" % secretConfig)
machine.succeed(
"install --owner vault --mode 0400 /root/vault.hcl /run/vault.hcl; rm /root/vault.hcl"
)
machine.wait_for_unit("vault.service")
machine.wait_for_open_port(8200)
machine.succeed("vault operator init")
machine.succeed("vault status | grep Sealed | grep true")
'';
})

View File

@ -8,6 +8,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
environment.systemPackages = [ pkgs.vault ]; environment.systemPackages = [ pkgs.vault ];
environment.variables.VAULT_ADDR = "http://127.0.0.1:8200"; environment.variables.VAULT_ADDR = "http://127.0.0.1:8200";
services.vault.enable = true; services.vault.enable = true;
virtualisation.memorySize = 512;
}; };
testScript = testScript =