apply treefmt

main
Jörg Thalheim 2 years ago
parent cc78160e6e
commit 16ab6ae069

@ -1,6 +1,7 @@
# systemd-vaultd - load vault credentials with systemd units
> Mostly written in a train
- Jörg Thalheim
systemd-vaultd is a proxy between systemd and [vault agent](https://vaultproject.io).

@ -1,4 +1,4 @@
{pkgs ? import <nixpkgs> {}}:
{ pkgs ? import <nixpkgs> { } }:
pkgs.buildGoModule {
name = "systemd-vaultd";
src = ./.;
@ -7,7 +7,7 @@ pkgs.buildGoModule {
description = "A proxy for secrets between systemd services and vault";
homepage = "https://github.com/numtide/systemd-vaultd";
license = licenses.mit;
maintainers = with maintainers; [mic92];
maintainers = with maintainers; [ mic92 ];
platforms = platforms.unix;
};
}

@ -9,21 +9,18 @@
treefmt-nix.url = "github:numtide/treefmt-nix";
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
systems = ["x86_64-linux" "aarch64-linux"];
outputs = inputs @ { flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" "aarch64-linux" ];
imports = [
./nix/checks/flake-module.nix
];
perSystem = {
config,
self',
inputs',
pkgs,
system,
...
perSystem =
{ config
, pkgs
, ...
}: {
packages.default = pkgs.callPackage ./default.nix {};
packages.default = pkgs.callPackage ./default.nix { };
devShells.default = pkgs.mkShellNoCC {
buildInputs = with pkgs; [
python3.pkgs.pytest

@ -1,10 +1,8 @@
{
config,
lib,
pkgs,
...
{ config
, pkgs
, ...
}: {
environment.systemPackages = [pkgs.vault];
environment.systemPackages = [ pkgs.vault ];
services.vault = {
enable = true;
dev = true;
@ -14,8 +12,8 @@
environment.variables.VAULT_TOKEN = config.services.vault.devRootTokenID;
systemd.services.setup-vault-agent-approle = {
path = [pkgs.jq pkgs.vault pkgs.systemd];
wantedBy = ["multi-user.target"];
path = [ pkgs.jq pkgs.vault pkgs.systemd ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
@ -51,7 +49,7 @@
# Make sure our setup service is started before our vault-agent
systemd.services.vault-agent-test = {
wants = ["setup-vault-agent-approle.service"];
after = ["setup-vault-agent-approle.service"];
wants = [ "setup-vault-agent-approle.service" ];
after = [ "setup-vault-agent-approle.service" ];
};
}

@ -1,13 +1,10 @@
{inputs, ...}: {
{ inputs, ... }: {
imports = [
inputs.treefmt-nix.flakeModule
];
perSystem = {
self',
inputs',
pkgs,
system,
...
perSystem =
{ pkgs
, ...
}: {
treefmt = {
# Used to find the project root
@ -29,7 +26,7 @@
''
"--"
];
includes = ["*.nix"];
includes = [ "*.nix" ];
};
python = {
@ -42,7 +39,8 @@
''
"--" # this argument is ignored by bash
];
includes = ["*.py"];
includes = [ "*.py" ];
};
};
};
@ -56,13 +54,4 @@
inherit (nixosTests) unittests vault-agent systemd-vaultd;
};
};
checks = let
nixosTests = pkgs.callPackages ./nix/checks/nixos-test.nix {
makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix");
};
in {
inherit (nixosTests) unittests vault-agent systemd-vaultd;
};
};
}

@ -1,13 +1,15 @@
{
makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>,
pkgs ? (import <nixpkgs> {}),
}: let
{ makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>
, pkgs ? (import <nixpkgs> { })
,
}:
let
makeTest' = args:
makeTest args {
inherit pkgs;
inherit (pkgs) system;
};
in {
in
{
vault-agent = makeTest' (import ./vault-agent-test.nix);
systemd-vaultd = makeTest' (import ./systemd-vaultd-test.nix);
unittests = makeTest' {

@ -1,9 +1,9 @@
{
name = "systemd-vaultd";
nodes.server = {
config,
pkgs,
...
nodes.server =
{ config
, pkgs
, ...
}: {
imports = [
../modules/vault-agent.nix
@ -12,7 +12,7 @@
];
systemd.services.service1 = {
wantedBy = ["multi-user.target"];
wantedBy = [ "multi-user.target" ];
script = ''
cat $CREDENTIALS_DIRECTORY/foo > /tmp/service1
echo -n "$SECRET_ENV" > /tmp/service1-env
@ -24,7 +24,7 @@
template = ''
{{ with secret "secret/my-secret" }}{{ .Data.data | toJSON }}{{ end }}
'';
secrets.foo = {};
secrets.foo = { };
environmentTemplate = ''
{{ with secret "secret/my-secret" }}
SECRET_ENV={{ .Data.data.foo }}
@ -34,7 +34,7 @@
};
systemd.services.service2 = {
wantedBy = ["multi-user.target"];
wantedBy = [ "multi-user.target" ];
script = ''
set -x
while true; do
@ -43,13 +43,13 @@
done
'';
serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
serviceConfig.LoadCredential = ["secret:/run/systemd-vaultd/sock"];
serviceConfig.LoadCredential = [ "secret:/run/systemd-vaultd/sock" ];
vault = {
template = ''
{{ with secret "secret/blocking-secret" }}{{ scratch.MapSet "secrets" "secret" .Data.data.foo }}{{ end }}
{{ scratch.Get "secrets" | explodeMap | toJSON }}
'';
secrets.secret = {};
secrets.secret = { };
};
};

@ -1,14 +1,15 @@
{
writeShellScript,
python3,
pkgs,
lib,
coreutils,
}: let
systemd-vaultd = pkgs.callPackage ../../default.nix {};
systemd = pkgs.callPackage ../pkgs/systemd.nix {};
{ writeShellScript
, python3
, pkgs
, lib
, coreutils
,
}:
let
systemd-vaultd = pkgs.callPackage ../../default.nix { };
systemd = pkgs.callPackage ../pkgs/systemd.nix { };
in
writeShellScript "unittests" ''
writeShellScript "unittests" ''
set -eu -o pipefail
export PATH=${lib.makeBinPath [python3.pkgs.pytest coreutils systemd]}
export SYSTEMD_VAULTD_BIN=${systemd-vaultd}/bin/systemd-vaultd
@ -19,4 +20,4 @@ in
pytest -s ./tests
# we need this in our nixos tests
touch /tmp/success
''
''

@ -1,9 +1,8 @@
{
name = "vault-agent";
nodes.server = {
config,
pkgs,
...
nodes.server =
{ config
, ...
}: {
imports = [
./dev-vault-server.nix

@ -1,20 +1,19 @@
{ pkgs
, ...
}:
let
systemd-vaultd = pkgs.callPackage ../../default.nix { };
in
{
config,
lib,
pkgs,
...
}: let
systemd-vaultd = pkgs.callPackage ../../default.nix {};
in {
imports = [
./vault-secrets.nix
];
systemd.package = pkgs.callPackage ../pkgs/systemd.nix {};
systemd.package = pkgs.callPackage ../pkgs/systemd.nix { };
systemd.sockets.systemd-vaultd = {
description = "systemd-vaultd socket";
wantedBy = ["sockets.target"];
wantedBy = [ "sockets.target" ];
socketConfig = {
ListenStream = "/run/systemd-vaultd/sock";
@ -24,8 +23,8 @@ in {
};
systemd.services.systemd-vaultd = {
description = "systemd-vaultd daemon";
requires = ["systemd-vaultd.socket"];
after = ["systemd-vaultd.socket"];
requires = [ "systemd-vaultd.socket" ];
after = [ "systemd-vaultd.socket" ];
# Restarting can break services waiting for secrets
stopIfChanged = false;
serviceConfig = {

@ -1,11 +1,11 @@
{
config,
lib,
pkgs,
...
}: let
{ config
, lib
, pkgs
, ...
}:
let
cfg = config.services.vault;
settingsFormat = pkgs.formats.json {};
settingsFormat = pkgs.formats.json { };
autoAuthMethodModule = lib.types.submodule {
freeformType = lib.types.attrsOf lib.types.unspecified;
@ -27,7 +27,7 @@
options = {
method = lib.mkOption {
type = lib.types.listOf autoAuthMethodModule;
default = [];
default = [ ];
};
};
};
@ -49,18 +49,19 @@
options = {
auto_auth = lib.mkOption {
type = autoAuthModule;
default = {};
default = { };
};
template_config = lib.mkOption {
type = templateConfigModule;
default = {};
default = { };
};
};
};
in {
in
{
options.services.vault.agents = lib.mkOption {
default = {};
default = { };
description = "Instances of vault agent";
type = lib.types.attrsOf (lib.types.submodule {
options = {
@ -72,17 +73,18 @@ in {
});
};
config = {
systemd.services = lib.mapAttrs' (name: instanceCfg:
systemd.services = lib.mapAttrs'
(name: instanceCfg:
lib.nameValuePair "vault-agent-${name}" {
after = ["network.target"];
wantedBy = ["multi-user.target"];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
# Services that also have `stopIfChanged = false` might wait for secrets
# while `vault-agent` is still stopped. This for example happens with nginx.service.
stopIfChanged = false;
# Needs getent in PATH
path = [pkgs.glibc];
path = [ pkgs.glibc ];
serviceConfig = {
Restart = "on-failure";
ExecStart = "${pkgs.vault}/bin/vault agent -config=${settingsFormat.generate "agent.json" instanceCfg.settings}";

@ -1,11 +1,11 @@
{
lib,
config,
pkgs,
...
}: let
{ lib
, config
, pkgs
, ...
}:
let
secretType = serviceName:
lib.types.submodule ({config, ...}: {
lib.types.submodule ({ config, ... }: {
options = {
name = lib.mkOption {
type = lib.types.str;
@ -59,19 +59,22 @@
vaultTemplates = config:
(lib.mapAttrsToList
(serviceName: service:
(serviceName: _service:
getSecretTemplate serviceName services.${serviceName}.vault)
(lib.filterAttrs (n: v: v.vault.secrets != {} && v.vault.agent == config._module.args.name) services))
(lib.filterAttrs (_n: v: v.vault.secrets != { } && v.vault.agent == config._module.args.name) services))
++ (lib.mapAttrsToList
(serviceName: service:
(serviceName: _service:
getEnvironmentTemplate serviceName services.${serviceName}.vault)
(lib.filterAttrs (n: v: v.vault.environmentTemplate != null && v.vault.agent == config._module.args.name) services));
in {
(lib.filterAttrs (_n: v: v.vault.environmentTemplate != null && v.vault.agent == config._module.args.name) services));
in
{
options = {
systemd.services = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: let
type = lib.types.attrsOf (lib.types.submodule ({ config, ... }:
let
serviceName = config._module.args.name;
in {
in
{
options.vault = {
changeAction = lib.mkOption {
description = ''
@ -110,29 +113,31 @@ in {
secrets = lib.mkOption {
type = lib.types.attrsOf (secretType serviceName);
default = {};
default = { };
description = "List of secrets to load from vault agent template";
example = {
some-secret.template = ''{{ with secret "secret/some-secret" }}{{ .Data.data.some-key }}{{ end }}'';
};
};
};
config = let
config =
let
mkIfHasEnv = lib.mkIf (config.vault.environmentTemplate != null);
in {
after = mkIfHasEnv ["${serviceName}-envfile.service"];
bindsTo = mkIfHasEnv ["${serviceName}-envfile.service"];
in
{
after = mkIfHasEnv [ "${serviceName}-envfile.service" ];
bindsTo = mkIfHasEnv [ "${serviceName}-envfile.service" ];
serviceConfig = {
LoadCredential = lib.mapAttrsToList (_: config: "${config.name}:/run/systemd-vaultd/sock") config.vault.secrets;
EnvironmentFile = mkIfHasEnv ["/run/systemd-vaultd/secrets/${serviceName}.service.EnvironmentFile"];
EnvironmentFile = mkIfHasEnv [ "/run/systemd-vaultd/secrets/${serviceName}.service.EnvironmentFile" ];
};
};
}));
};
services.vault.agents = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: {
config.settings.template = vaultTemplates config;
}));
};
@ -140,14 +145,17 @@ in {
config = {
# we cannot use `systemd.services` here since this would create infinite recursion
systemd.packages = let
servicesWithEnv = builtins.attrNames (lib.filterAttrs (n: v: v.vault.environmentTemplate != null) services);
in [
(pkgs.runCommand "env-services" {}
systemd.packages =
let
servicesWithEnv = builtins.attrNames (lib.filterAttrs (_n: v: v.vault.environmentTemplate != null) services);
in
[
(pkgs.runCommand "env-services" { }
(''
mkdir -p $out/lib/systemd/system
''
+ (lib.concatMapStringsSep "\n" (service: ''
+ (lib.concatMapStringsSep "\n"
(service: ''
cat > $out/lib/systemd/system/${service}-envfile.service <<EOF
[Unit]
Before=${service}.service

@ -1,6 +1,6 @@
{
systemd,
fetchpatch,
{ systemd
, fetchpatch
,
}:
systemd.overrideAttrs (old: {
patches =

@ -0,0 +1,20 @@
[tool.ruff]
line-length = 88
select = ["E", "F", "I"]
ignore = [ "E501" ]
[tool.mypy]
python_version = "3.10"
warn_redundant_casts = true
disallow_untyped_calls = true
disallow_untyped_defs = true
no_implicit_optional = true
[[tool.mypy.overrides]]
module = "setuptools.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "pytest.*"
ignore_missing_imports = true

@ -1,6 +1,6 @@
{pkgs ? import <nixpkgs> {}}:
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
mkShellNoCC {
mkShellNoCC {
buildInputs = [
python3.pkgs.pytest
python3.pkgs.mypy
@ -12,4 +12,4 @@ with pkgs;
go
just
];
}
}

@ -3,8 +3,8 @@
import os
import signal
import subprocess
from typing import IO, Any, Dict, Iterator, List, Union
from pathlib import Path
from typing import IO, Any, Dict, Iterator, List, Union
import pytest

@ -1,8 +1,8 @@
#!/usr/bin/env python3
import json
import random
import string
import json
from dataclasses import dataclass
from pathlib import Path

@ -1,9 +1,10 @@
#!/usr/bin/env python3
import os
import pytest
from pathlib import Path
from typing import Optional
import pytest
from command import run
BIN: Optional[Path] = None

@ -1,10 +1,11 @@
#!/usr/bin/env python3
import pytest
from tempfile import TemporaryDirectory
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Iterator
import pytest
@pytest.fixture
def tempdir() -> Iterator[Path]:

@ -1,6 +1,6 @@
import subprocess
from pathlib import Path
import time
from pathlib import Path
from command import Command
from random_service import random_service

@ -1,7 +1,7 @@
#!/usr/bin/env python3
import time
import subprocess
import time
from pathlib import Path
from command import Command, run

Loading…
Cancel
Save