Merge pull request 'feat/tests' (#224) from feat/tests into main

Reviewed-on: #224
Reviewed-by: teutat3s <teutat3s@noreply.git.pub.solar>
This commit is contained in:
teutat3s 2024-08-27 10:45:56 +00:00
commit fb8ee1278a
Signed by: pub.solar gitea
GPG key ID: F0332B04B7054873
20 changed files with 701 additions and 35 deletions

View file

@ -18,14 +18,20 @@ jobs:
# Prevent cache garbage collection by creating GC roots # Prevent cache garbage collection by creating GC roots
mkdir -p /var/lib/gitea-runner/tankstelle/.local/state/nix/results mkdir -p /var/lib/gitea-runner/tankstelle/.local/state/nix/results
for target in $(nix flake show --json --all-systems | jq ' for target in $(nix flake show --json --all-systems | jq --raw-output '
.["nixosConfigurations"] | .["nixosConfigurations"] |
to_entries[] | to_entries[] |
.key .key'
' | tr -d '"'
); do ); do
nix --print-build-logs --verbose --accept-flake-config --access-tokens '' \ nix --print-build-logs --verbose --accept-flake-config --access-tokens '' \
build --out-link /var/lib/gitea-runner/tankstelle/.local/state/nix/results/"$target" ".#nixosConfigurations.${target}.config.system.build.toplevel" build --out-link /var/lib/gitea-runner/tankstelle/.local/state/nix/results/"$target" ".#nixosConfigurations.${target}.config.system.build.toplevel"
done done
nix --print-build-logs --verbose --accept-flake-config --access-tokens '' flake check for check in $(nix flake show --json --all-systems | jq --raw-output '
.checks."x86_64-linux" |
to_entries[] |
.key'
); do
nix --print-build-logs --verbose --accept-flake-config --access-tokens '' \
build --out-link /var/lib/gitea-runner/tankstelle/.local/state/nix/results/"$check" ".#checks.x86_64-linux.${check}"
done

View file

@ -65,6 +65,7 @@
system, system,
pkgs, pkgs,
config, config,
lib,
... ...
}: }:
{ {
@ -77,6 +78,27 @@
unstable = import inputs.unstable { inherit system; }; unstable = import inputs.unstable { inherit system; };
master = import inputs.master { inherit system; }; master = import inputs.master { inherit system; };
}; };
checks =
let
nixos-lib = import (inputs.nixpkgs + "/nixos/lib") { };
testDir = builtins.attrNames (builtins.readDir ./tests);
testFiles = builtins.filter (n: builtins.match "^.*.nix$" n != null) testDir;
in
builtins.listToAttrs (
map (x: {
name = "test-${lib.strings.removeSuffix ".nix" x}";
value = nixos-lib.runTest (
import (./tests + "/${x}") {
inherit self;
inherit pkgs;
inherit lib;
inherit config;
}
);
}) testFiles
);
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ buildInputs = with pkgs; [
deploy-rs deploy-rs
@ -95,6 +117,7 @@
jq jq
]; ];
}; };
devShells.ci = pkgs.mkShell { buildInputs = with pkgs; [ nodejs ]; }; devShells.ci = pkgs.mkShell { buildInputs = with pkgs; [ nodejs ]; };
}; };

View file

@ -11,6 +11,7 @@
self.nixosModules.unlock-zfs-on-boot self.nixosModules.unlock-zfs-on-boot
self.nixosModules.core self.nixosModules.core
self.nixosModules.docker self.nixosModules.docker
self.nixosModules.backups
self.nixosModules.nginx self.nixosModules.nginx
self.nixosModules.collabora self.nixosModules.collabora
@ -49,6 +50,7 @@
./flora-6 ./flora-6
self.nixosModules.overlays self.nixosModules.overlays
self.nixosModules.core self.nixosModules.core
self.nixosModules.backups
self.nixosModules.keycloak self.nixosModules.keycloak
self.nixosModules.caddy self.nixosModules.caddy
@ -68,6 +70,7 @@
self.nixosModules.overlays self.nixosModules.overlays
self.nixosModules.unlock-zfs-on-boot self.nixosModules.unlock-zfs-on-boot
self.nixosModules.core self.nixosModules.core
self.nixosModules.backups
self.nixosModules.mail self.nixosModules.mail
self.nixosModules.prometheus-exporters self.nixosModules.prometheus-exporters
self.nixosModules.promtail self.nixosModules.promtail
@ -83,6 +86,7 @@
./tankstelle ./tankstelle
self.nixosModules.overlays self.nixosModules.overlays
self.nixosModules.core self.nixosModules.core
self.nixosModules.backups
self.nixosModules.prometheus-exporters self.nixosModules.prometheus-exporters
self.nixosModules.promtail self.nixosModules.promtail
]; ];

View file

@ -48,9 +48,26 @@
owner = "root"; owner = "root";
}; };
pub-solar-os.auth.enable = true; age.secrets.keycloak-database-password = {
file = "${flake.self}/secrets/keycloak-database-password.age";
mode = "600";
#owner = "keycloak";
};
nixpkgs.config.permittedInsecurePackages = [ "keycloak-23.0.6" ]; pub-solar-os.auth = {
enable = true;
database-password-file = config.age.secrets.keycloak-database-password.path;
};
pub-solar-os.backups.repos.storagebox = {
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
};
systemd.services.postgresql = {
after = [ "var-lib-postgresql.mount" ];
requisite = [ "var-lib-postgresql.mount" ];
};
# This value determines the NixOS release with which your system is to be # This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database # compatible, in order to avoid breaking some software such as database

274
modules/backups/default.nix Normal file
View file

@ -0,0 +1,274 @@
{
flake,
config,
lib,
pkgs,
...
}:
let
utils = import "${flake.inputs.nixpkgs}/nixos/lib/utils.nix" {
inherit lib;
inherit config;
inherit pkgs;
};
# Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
inherit (utils.systemdUtils.unitOptions) unitOption;
inherit (lib)
literalExpression
mkOption
mkPackageOption
types
;
in
{
options.pub-solar-os.backups = {
repos = mkOption {
description = ''
Configuration of Restic repositories.
'';
type = types.attrsOf (
types.submodule (
{ name, ... }:
{
options = {
passwordFile = mkOption {
type = types.str;
description = ''
Read the repository password from a file.
'';
example = "/etc/nixos/restic-password";
};
repository = mkOption {
type = with types; nullOr str;
default = null;
description = ''
repository to backup to.
'';
example = "sftp:backup@192.168.1.100:/backups/${name}";
};
};
}
)
);
default = { };
example = {
remotebackup = {
repository = "sftp:backup@host:/backups/home";
passwordFile = "/etc/nixos/secrets/restic-password";
};
};
};
backups = mkOption {
description = ''
Periodic backups to create with Restic.
'';
type = types.attrsOf (
types.submodule (
{ name, ... }:
{
options = {
paths = mkOption {
# This is nullable for legacy reasons only. We should consider making it a pure listOf
# after some time has passed since this comment was added.
type = types.nullOr (types.listOf types.str);
default = [ ];
description = ''
Which paths to backup, in addition to ones specified via
`dynamicFilesFrom`. If null or an empty array and
`dynamicFilesFrom` is also null, no backup command will be run.
This can be used to create a prune-only job.
'';
example = [
"/var/lib/postgresql"
"/home/user/backup"
];
};
exclude = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Patterns to exclude when backing up. See
https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files for
details on syntax.
'';
example = [
"/var/cache"
"/home/*/.cache"
".git"
];
};
timerConfig = mkOption {
type = types.nullOr (types.attrsOf unitOption);
default = {
OnCalendar = "daily";
Persistent = true;
};
description = ''
When to run the backup. See {manpage}`systemd.timer(5)` for
details. If null no timer is created and the backup will only
run when explicitly started.
'';
example = {
OnCalendar = "00:05";
RandomizedDelaySec = "5h";
Persistent = true;
};
};
user = mkOption {
type = types.str;
default = "root";
description = ''
As which user the backup should run.
'';
example = "postgresql";
};
extraBackupArgs = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Extra arguments passed to restic backup.
'';
example = [ "--exclude-file=/etc/nixos/restic-ignore" ];
};
extraOptions = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Extra extended options to be passed to the restic --option flag.
'';
example = [ "sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'" ];
};
initialize = mkOption {
type = types.bool;
default = false;
description = ''
Create the repository if it doesn't exist.
'';
};
pruneOpts = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
A list of options (--keep-\* et al.) for 'restic forget
--prune', to automatically prune old snapshots. The
'forget' command is run *after* the 'backup' command, so
keep that in mind when constructing the --keep-\* options.
'';
example = [
"--keep-daily 7"
"--keep-weekly 5"
"--keep-monthly 12"
"--keep-yearly 75"
];
};
runCheck = mkOption {
type = types.bool;
default = (builtins.length config.pub-solar-os.backups.backups.${name}.checkOpts > 0);
defaultText = literalExpression ''builtins.length config.services.backups.${name}.checkOpts > 0'';
description = "Whether to run the `check` command with the provided `checkOpts` options.";
example = true;
};
checkOpts = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
A list of options for 'restic check'.
'';
example = [ "--with-cache" ];
};
dynamicFilesFrom = mkOption {
type = with types; nullOr str;
default = null;
description = ''
A script that produces a list of files to back up. The
results of this command are given to the '--files-from'
option. The result is merged with paths specified via `paths`.
'';
example = "find /home/matt/git -type d -name .git";
};
backupPrepareCommand = mkOption {
type = with types; nullOr str;
default = null;
description = ''
A script that must run before starting the backup process.
'';
};
backupCleanupCommand = mkOption {
type = with types; nullOr str;
default = null;
description = ''
A script that must run after finishing the backup process.
'';
};
package = mkPackageOption pkgs "restic" { };
createWrapper = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to generate and add a script to the system path, that has the same environment variables set
as the systemd service. This can be used to e.g. mount snapshots or perform other opterations, without
having to manually specify most options.
'';
};
};
}
)
);
default = { };
example = {
localbackup = {
paths = [ "/home" ];
exclude = [ "/home/*/.cache" ];
initialize = true;
};
remotebackup = {
paths = [ "/home" ];
extraOptions = [
"sftp.command='ssh backup@host -i /etc/nixos/secrets/backup-private-key -s sftp'"
];
timerConfig = {
OnCalendar = "00:05";
RandomizedDelaySec = "5h";
};
};
};
};
};
config = {
services.restic.backups =
let
repos = config.pub-solar-os.backups.repos;
backups = config.pub-solar-os.backups.backups;
storeNames = builtins.attrNames repos;
backupNames = builtins.attrNames backups;
createBackups =
backupName:
map (storeName: {
name = "${backupName}-${storeName}";
value = repos."${storeName}" // backups."${backupName}";
}) storeNames;
in
builtins.listToAttrs (lib.lists.flatten (map createBackups backupNames));
};
}

View file

@ -6,7 +6,7 @@
... ...
}: }:
{ {
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ ]; nixpkgs.config = lib.mkDefault { allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ ]; };
nix = { nix = {
# Use default version alias for nix package # Use default version alias for nix package

View file

@ -6,23 +6,22 @@
... ...
}: }:
{ {
options.pub-solar-os.auth = { options.pub-solar-os.auth = with lib; {
enable = lib.mkEnableOption "Enable keycloak to run on the node"; enable = mkEnableOption "Enable keycloak to run on the node";
realm = lib.mkOption { realm = mkOption {
description = "Name of the realm"; description = "Name of the realm";
type = lib.types.str; type = types.str;
default = config.pub-solar-os.networking.domain; default = config.pub-solar-os.networking.domain;
}; };
database-password-file = mkOption {
description = "Database password file path";
type = types.str;
};
}; };
config = lib.mkIf config.pub-solar-os.auth.enable { config = lib.mkIf config.pub-solar-os.auth.enable {
age.secrets.keycloak-database-password = {
file = "${flake.self}/secrets/keycloak-database-password.age";
mode = "600";
#owner = "keycloak";
};
services.nginx.virtualHosts."auth.${config.pub-solar-os.networking.domain}" = { services.nginx.virtualHosts."auth.${config.pub-solar-os.networking.domain}" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
@ -46,7 +45,7 @@
# keycloak # keycloak
services.keycloak = { services.keycloak = {
enable = true; enable = true;
database.passwordFile = config.age.secrets.keycloak-database-password.path; database.passwordFile = config.pub-solar-os.auth.database-password-file;
settings = { settings = {
hostname = "auth.${config.pub-solar-os.networking.domain}"; hostname = "auth.${config.pub-solar-os.networking.domain}";
http-host = "127.0.0.1"; http-host = "127.0.0.1";
@ -59,14 +58,12 @@
}; };
}; };
services.restic.backups.keycloak-storagebox = { pub-solar-os.backups.backups.keycloak = {
paths = [ "/tmp/keycloak-backup.sql" ]; paths = [ "/tmp/keycloak-backup.sql" ];
timerConfig = { timerConfig = {
OnCalendar = "*-*-* 03:00:00 Etc/UTC"; OnCalendar = "*-*-* 03:00:00 Etc/UTC";
}; };
initialize = true; initialize = true;
passwordFile = config.age.secrets."restic-repo-storagebox".path;
repository = "sftp:u377325@u377325.your-storagebox.de:/backups";
backupPrepareCommand = '' backupPrepareCommand = ''
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d keycloak > /tmp/keycloak-backup.sql ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump -d keycloak > /tmp/keycloak-backup.sql
''; '';

View file

@ -7,7 +7,7 @@
services.nginx.virtualHosts = { services.nginx.virtualHosts = {
"www.${config.pub-solar-os.networking.domain}" = { "www.${config.pub-solar-os.networking.domain}" = {
enableACME = true; enableACME = true;
addSSL = true; forceSSL = true;
extraConfig = '' extraConfig = ''
error_log /dev/null; error_log /dev/null;

View file

@ -25,9 +25,4 @@
full_page_writes = false; full_page_writes = false;
}; };
}; };
systemd.services.postgresql = {
after = [ "var-lib-postgresql.mount" ];
requisite = [ "var-lib-postgresql.mount" ];
};
} }

92
tests/keycloak.nix Normal file
View file

@ -0,0 +1,92 @@
{
self,
pkgs,
lib,
config,
...
}:
let
in
{
name = "keycloak";
hostPkgs = pkgs;
node.pkgs = pkgs;
node.specialArgs = self.outputs.nixosConfigurations.nachtigall._module.specialArgs;
nodes = {
acme-server = {
imports = [
self.nixosModules.home-manager
self.nixosModules.core
./support/ca.nix
];
};
client = {
imports = [
self.nixosModules.home-manager
self.nixosModules.core
./support/client.nix
];
};
nachtigall = {
imports = [
self.inputs.agenix.nixosModules.default
self.nixosModules.home-manager
self.nixosModules.core
self.nixosModules.backups
self.nixosModules.nginx
self.nixosModules.keycloak
self.nixosModules.postgresql
./support/global.nix
];
systemd.tmpfiles.rules = [ "f /tmp/dbf 1777 root root 10d password" ];
virtualisation.memorySize = 4096;
pub-solar-os.auth = {
enable = true;
database-password-file = "/tmp/dbf";
};
services.keycloak.database.createLocally = true;
networking.interfaces.eth0.ipv4.addresses = [
{
address = "192.168.1.3";
prefixLength = 32;
}
];
};
};
testScript =
{ nodes, ... }:
let
user = nodes.client.users.users.${nodes.client.pub-solar-os.authentication.username};
#uid = toString user.uid;
bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u ${user.name})/bus";
gdbus = "${bus} gdbus";
su = command: "su - ${user.name} -c '${command}'";
gseval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval";
wmClass = su "${gdbus} ${gseval} global.display.focus_window.wm_class";
in
''
start_all()
nachtigall.wait_for_unit("system.slice")
nachtigall.succeed("ping 127.0.0.1 -c 2")
nachtigall.wait_for_unit("nginx.service")
nachtigall.wait_for_unit("keycloak.service")
nachtigall.wait_until_succeeds("curl http://127.0.0.1:8080/")
nachtigall.wait_until_succeeds("curl https://auth.test.pub.solar/")
client.wait_for_unit("system.slice")
client.sleep(30)
# client.wait_until_succeeds("${wmClass} | grep -q 'firefox'")
client.screenshot("screen")
'';
}

47
tests/support/ca.nix Normal file
View file

@ -0,0 +1,47 @@
{
pkgs,
lib,
config,
...
}:
{
imports = [ ./global.nix ];
systemd.tmpfiles.rules = [ "f /tmp/step-ca-intermediate-pw 1777 root root 10d password" ];
networking.interfaces.eth0.ipv4.addresses = [
{
address = "192.168.1.1";
prefixLength = 32;
}
];
services.step-ca =
let
certificates = pkgs.stdenv.mkDerivation {
name = "certificates";
src = ./step;
installPhase = ''
mkdir -p $out;
cp -r certs $out/
cp -r secrets $out/
'';
};
in
{
enable = true;
openFirewall = true;
intermediatePasswordFile = "/tmp/step-ca-intermediate-pw";
port = 443;
address = "0.0.0.0";
settings = (builtins.fromJSON (builtins.readFile ./step/config/ca.json)) // {
root = "${certificates}/certs/root_ca.crt";
crt = "${certificates}/certs/intermediate_ca.crt";
key = "${certificates}/secrets/intermediate_ca_key";
db = {
type = "badgerv2";
dataSource = "/var/lib/step-ca/db";
};
};
};
}

35
tests/support/client.nix Normal file
View file

@ -0,0 +1,35 @@
{
pkgs,
lib,
config,
...
}:
{
imports = [ ./global.nix ];
services.xserver.enable = true;
services.xserver.displayManager.gdm.enable = true;
services.xserver.desktopManager.gnome.enable = true;
services.xserver.displayManager.autoLogin.enable = true;
services.xserver.displayManager.autoLogin.user = config.pub-solar-os.authentication.username;
systemd.user.services = {
"org.gnome.Shell@wayland" = {
serviceConfig = {
ExecStart = [
# Clear the list before overriding it.
""
# Eval API is now internal so Shell needs to run in unsafe mode.
"${pkgs.gnome.gnome-shell}/bin/gnome-shell --unsafe-mode"
];
};
};
};
networking.interfaces.eth0.ipv4.addresses = [
{
address = "192.168.1.2";
prefixLength = 32;
}
];
}

50
tests/support/global.nix Normal file
View file

@ -0,0 +1,50 @@
{
pkgs,
lib,
config,
...
}:
{
pub-solar-os.networking.domain = "test.pub.solar";
security.acme.defaults.server = "https://ca.${config.pub-solar-os.networking.domain}/acme/acme/directory";
security.pki.certificates = [ (builtins.readFile ./step/certs/root_ca.crt) ];
services.openssh = {
enable = true;
openFirewall = true;
settings = {
PermitRootLogin = lib.mkForce "yes";
PermitEmptyPasswords = lib.mkForce "yes";
PasswordAuthentication = lib.mkForce true;
};
};
security.pam.services.sshd.allowNullPassword = true;
virtualisation.forwardPorts =
let
address = (builtins.elemAt config.networking.interfaces.eth0.ipv4.addresses 0).address;
lastAddressPart = builtins.elemAt (lib.strings.splitString "." address) 3;
in
[
{
from = "host";
host.port = 2000 + (lib.strings.toInt lastAddressPart);
guest.port = 22;
}
];
networking.interfaces.eth0.useDHCP = false;
networking.hosts = {
"192.168.1.1" = [ "ca.${config.pub-solar-os.networking.domain}" ];
"192.168.1.2" = [ "client.${config.pub-solar-os.networking.domain}" ];
"192.168.1.3" = [
"${config.pub-solar-os.networking.domain}"
"www.${config.pub-solar-os.networking.domain}"
"auth.${config.pub-solar-os.networking.domain}"
];
};
}

View file

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB4DCCAYagAwIBAgIQVR/3c0swvc/ifeYqLQn3HTAKBggqhkjOPQQDAjA6MRcw
FQYDVQQKEw5wdWIuc29sYXItdGVzdDEfMB0GA1UEAxMWcHViLnNvbGFyLXRlc3Qg
Um9vdCBDQTAeFw0yNDA4MjQwMTI3MTBaFw0zNDA4MjIwMTI3MTBaMEIxFzAVBgNV
BAoTDnB1Yi5zb2xhci10ZXN0MScwJQYDVQQDEx5wdWIuc29sYXItdGVzdCBJbnRl
cm1lZGlhdGUgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATpCjy3PAiawAeb
47ZZ9kPXuuV0EavOfFlgnlZBkOc2AXY0R6P1jK06US0SiPo17rqyNgUWH0oV4v8i
/HbZYNXYo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAd
BgNVHQ4EFgQU1hueYsLAH6+wxjArqCM3IHFqnIEwHwYDVR0jBBgwFoAUxg/BmKK7
9Zs+b1bvlpYwggy5lnswCgYIKoZIzj0EAwIDSAAwRQIgfxkjyC4HHADRmNDLqZ5L
0po+JD5/9b1L//JoXG+vgXECIQDgkRe8r8/0Ep/NWgBtbkA3oTYq8vCwo1FewBZZ
43fo5w==
-----END CERTIFICATE-----

View file

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBuDCCAV2gAwIBAgIQMXg7xoEIrVjgvKcrRaxo0DAKBggqhkjOPQQDAjA6MRcw
FQYDVQQKEw5wdWIuc29sYXItdGVzdDEfMB0GA1UEAxMWcHViLnNvbGFyLXRlc3Qg
Um9vdCBDQTAeFw0yNDA4MjQwMTI3MDlaFw0zNDA4MjIwMTI3MDlaMDoxFzAVBgNV
BAoTDnB1Yi5zb2xhci10ZXN0MR8wHQYDVQQDExZwdWIuc29sYXItdGVzdCBSb290
IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYNxMcHclQP/zv2y6LJIGx9pg
Q2337Zb8TuPY+DnL1MjuCMoeTaMwngzjU/DSbKL0Vx/y+I+PBjhHmPrYcGDcSKNF
MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
FMYPwZiiu/WbPm9W75aWMIIMuZZ7MAoGCCqGSM49BAMCA0kAMEYCIQDcgr9WyR1C
806aEQ38alYgGg3PhQdT14q47tWIUOnpygIhAM0x/QK/mm7VvQxBLAA4DT6X730m
k/tBvh9SHNbwPxCt
-----END CERTIFICATE-----

View file

@ -0,0 +1,44 @@
{
"federatedRoots": null,
"address": ":443",
"insecureAddress": "",
"dnsNames": ["ca.test.pub.solar"],
"logger": {
"format": "text"
},
"db": {
"type": "badgerv2",
"badgerFileLoadingMode": ""
},
"authority": {
"provisioners": [
{
"name": "acme",
"type": "ACME"
},
{
"type": "JWK",
"name": "test.pub.solar",
"key": {
"use": "sig",
"kty": "EC",
"kid": "lM-BJXRwwQcdgxLqAS4Za23A2YatZpwXx-PP5NIt8JM",
"crv": "P-256",
"alg": "ES256",
"x": "ouB2mP04Kt8rDa10C8ZzYyzA36rrz-k0c4_ud1hVjyg",
"y": "RbXKcudQRPEFqjG_5AxuqCQXn7pyRToQCwC4MrwLVUQ"
},
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjYwMDAwMCwicDJzIjoiNWR5T2puR2Y5aFFNRlc1U25fRWhzUSJ9.a3xtSBuMmzZCMsdfHAXMgFpe9bq8A6bGGOoW9F2Gw7AhxL4bG-AlgA.IA68rSJSGTAKnaVS.XDQc4da-8D9Ykfw-8S4uphsauq5gsEm4qp7zKQUIvcjUlnPAtiHP3xiiBie29ncdg8rKmyzprEEOpTNvXtQl7LsPsHXyKV3SqsTnJecvim9YXGDneAHyWe-XF6hyCZAfSoFbFMgLDKR6d44hMht3ueazL_TPlkFUBLrJbsW782MfdfF3nzcaDf_JDuhKsKHDmKqZyNXDzwf6rINe8adrf5gqaLM2_sGhk7i3XyXygn8HHVw1Dj_w2gPOVm4MS7CO_NgikPqAtGuXDhpWZfXte-FlnMO6d9xQF67b0cwB8kmColPSp1zRiCKPAk9vof8Nn-gGE_aw8zxPi0CJkoY.xbuqSSspgLc_Uw17uiRF7Q"
}
]
},
"tls": {
"cipherSuites": [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
],
"minVersion": 1.2,
"maxVersion": 1.3,
"renegotiation": false
}
}

View file

@ -0,0 +1,6 @@
{
"ca-url": "https://ca.test.pub.solar",
"ca-config": "/home/b12f/.step/config/ca.json",
"fingerprint": "4d6a1a918355380acbd0256a2203d0a0da8436bb788e8f19326589045c3cd842",
"root": "/home/b12f/.step/certs/root_ca.crt"
}

View file

@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,0b34c00cb76ffc16441f5fe762d8d915
xJQ5r5kGiaG6rCsmVnONxm99sqceb62dO8/YvgdZ/ouHAxz1OlXYpTJNd2GvezAc
XA6Zx6eGzNCOyhgMNJTXEn8QmcJcMd6OjVLxQ9Tr2Mi3LShcBzMPs30/X2XYsM22
5G4fRhQD0L4nQ08B3GG6FjPe/HYmkRNZmAeDc2wE5Fg=
-----END EC PRIVATE KEY-----

View file

@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,48f59a57e5a2b81359e0a3668161b61e
jMZbpiHSFa74ns30QrAnIlcguqWp+FE20cXbiIVPpLAJpzGskc3k5vRFTpPM8geg
sZ6bVvq3APbKmkopxZHWpd4ly6uHkolbtR1NFxTNKymaJZuSuKspUmDohkIyZN6c
KG0upERMZIOg6Ky1JiM5pLJMHBTsCmzJBmdFCW7GSww=
-----END EC PRIVATE KEY-----

View file

@ -8,17 +8,52 @@
{ {
name = "website"; name = "website";
nodes.nachtigall-test = self.nixosConfigurations.nachtigall-test;
node.specialArgs = self.outputs.nixosConfigurations.nachtigall._module.specialArgs;
hostPkgs = pkgs; hostPkgs = pkgs;
enableOCR = true; node.pkgs = pkgs;
node.specialArgs = self.outputs.nixosConfigurations.nachtigall._module.specialArgs;
nodes = {
acme-server = {
imports = [
self.nixosModules.home-manager
self.nixosModules.core
./support/ca.nix
];
};
nachtigall = {
imports = [
self.nixosModules.home-manager
self.nixosModules.core
self.nixosModules.nginx
self.nixosModules.nginx-website
./support/global.nix
];
virtualisation.memorySize = 4096;
networking.interfaces.eth0.ipv4.addresses = [
{
address = "192.168.1.3";
prefixLength = 32;
}
];
};
};
testScript = '' testScript = ''
machine.wait_for_unit("system.slice") start_all()
machine.succeed("ping 127.0.0.1 -c 2")
machine.wait_for_unit("nginx.service") acme_server.wait_for_unit("system.slice")
machine.succeed("curl -H 'Host:pub.solar' http://127.0.0.1/") acme_server.wait_for_unit("step-ca.service")
acme_server.succeed("ping ca.test.pub.solar -c 2")
acme_server.wait_until_succeeds("curl 127.0.0.1:443")
nachtigall.wait_for_unit("system.slice")
nachtigall.succeed("ping test.pub.solar -c 2")
nachtigall.succeed("ping ca.test.pub.solar -c 2")
nachtigall.wait_for_unit("nginx.service")
nachtigall.wait_until_succeeds("curl https://test.pub.solar/")
''; '';
} }