change secrets management to its own module and update hetzner-vm with it
This commit is contained in:
parent
c81a933217
commit
0a2aae3a43
|
@ -1,68 +0,0 @@
|
||||||
{ }: {
|
|
||||||
mpd_control_password = {
|
|
||||||
user = "mpd";
|
|
||||||
group = "mpd";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/mpd_control_password";
|
|
||||||
};
|
|
||||||
music_stream_passwd = {
|
|
||||||
user = "nginx";
|
|
||||||
group = "nginx";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/music_stream_passwd";
|
|
||||||
};
|
|
||||||
chaos_mail_passwd = {
|
|
||||||
user = "dovecot2";
|
|
||||||
group = "dovecot2";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/chaos_mail_passwd";
|
|
||||||
};
|
|
||||||
gitlab_env = {
|
|
||||||
user = "gitlab_artifacts_sync";
|
|
||||||
group = "gitlab_artifacts_sync";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/gitlab_env";
|
|
||||||
};
|
|
||||||
restic_password = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/restic_password";
|
|
||||||
};
|
|
||||||
restic_env = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/restic_env";
|
|
||||||
};
|
|
||||||
wg_privkey = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/wg_privkey";
|
|
||||||
};
|
|
||||||
wg_preshared_tablet = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/wg_preshared_tablet";
|
|
||||||
};
|
|
||||||
wg_preshared_vault = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/wg_preshared_vault";
|
|
||||||
};
|
|
||||||
wg_preshared_storage = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/wg_preshared_storage";
|
|
||||||
};
|
|
||||||
wg_preshared_iphone8 = {
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
permissions = "660";
|
|
||||||
path = "/secrets/wg_preshared_iphone8";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,97 +1,87 @@
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }: {
|
||||||
let secrets-db = (import ./secrets-db.nix { });
|
services.secrets = {
|
||||||
in {
|
enable = true;
|
||||||
systemd.tmpfiles.rules = [ "d /secrets - root root" ];
|
|
||||||
environment.systemPackages = [
|
|
||||||
(pkgs.writeShellScriptBin "init-secrets" ''
|
|
||||||
set -e -o pipefail
|
|
||||||
|
|
||||||
VAULT_ADDR_DEFAULT="https://vault.owo.monster"
|
extraPackages = with pkgs;
|
||||||
[ -n "$VAULT_ADDR" ] && export VAULT_ADDR="$VAULT_ADDR_DEFAULT"
|
[
|
||||||
|
# for music & mail passwd files
|
||||||
|
apacheHttpd
|
||||||
|
];
|
||||||
|
|
||||||
export PATH=$PATH:${pkgs.vault}/bin
|
secrets = {
|
||||||
export PATH=$PATH:${pkgs.jq}/bin
|
mpd_control_password = {
|
||||||
export PATH=$PATH:${pkgs.apacheHttpd}/bin
|
user = "mpd";
|
||||||
|
group = "mpd";
|
||||||
kv_get() {
|
fetchScript = ''
|
||||||
vault kv get -format json $1
|
simple_get "/api-keys/mpd" .password > $secretFile
|
||||||
}
|
'';
|
||||||
|
};
|
||||||
simple_get() {
|
music_stream_passwd = {
|
||||||
kv_get $1 | jq .data.data$2 -r
|
user = "nginx";
|
||||||
}
|
group = "nginx";
|
||||||
|
fetchScript = ''
|
||||||
file=${secrets-db.mpd_control_password.path}
|
username=$(simple_get "/api-keys/music-stream" .username)
|
||||||
echo $file
|
password=$(simple_get "/api-keys/music-stream" .password)
|
||||||
simple_get "/api-keys/mpd" .password > $file
|
htpasswd -bc $secretFile "$username" "$password" 2>/dev/null
|
||||||
chown ${secrets-db.mpd_control_password.user}:${secrets-db.mpd_control_password.group} $file
|
'';
|
||||||
chmod ${secrets-db.mpd_control_password.permissions} $file
|
};
|
||||||
|
chaos_mail_passwd = {
|
||||||
file=${secrets-db.music_stream_passwd.path}
|
user = "dovecot2";
|
||||||
echo $file
|
group = "dovecot2";
|
||||||
username=$(simple_get "/api-keys/music-stream" .username)
|
fetchScript = ''
|
||||||
password=$(simple_get "/api-keys/music-stream" .password)
|
password=$(simple_get "/passwords/mail" .password)
|
||||||
htpasswd -bc $file "$username" "$password"
|
htpasswd -nbB "" "$password" 2>/dev/null | cut -d: -f2 > $secretFile
|
||||||
chown ${secrets-db.music_stream_passwd.user}:${secrets-db.music_stream_passwd.group} $file
|
'';
|
||||||
chmod ${secrets-db.music_stream_passwd.permissions} $file
|
};
|
||||||
|
gitlab_env = {
|
||||||
file=${secrets-db.chaos_mail_passwd.path}
|
user = "gitlab_artifacts_sync";
|
||||||
echo $file
|
group = "gitlab_artifacts_sync";
|
||||||
password=$(simple_get "/passwords/mail" .password)
|
fetchScript = ''
|
||||||
htpasswd -nbB "" "$password" | cut -d: -f2 > $file
|
token=$(simple_get "/api-keys/gitlab/gitlab_pages_serve" .token)
|
||||||
chown ${secrets-db.chaos_mail_passwd.user}:${secrets-db.chaos_mail_passwd.group} $file
|
echo "GITLAB_TOKEN=$token" > $secretFile
|
||||||
chmod ${secrets-db.chaos_mail_passwd.permissions} $file
|
'';
|
||||||
|
};
|
||||||
file=${secrets-db.gitlab_env.path}
|
restic_password = {
|
||||||
echo $file
|
fetchScript = ''
|
||||||
token=$(simple_get "/api-keys/gitlab/gitlab_pages_serve" .token)
|
simple_get "/private-public-keys/restic/HetznerVM" .password > $secretFile
|
||||||
echo "GITLAB_TOKEN=$token" > $file
|
'';
|
||||||
chown ${secrets-db.gitlab_env.user}:${secrets-db.gitlab_env.group} $file
|
};
|
||||||
chmod ${secrets-db.gitlab_env.permissions} $file
|
restic_env = {
|
||||||
|
fetchScript = ''
|
||||||
file=${secrets-db.restic_password.path}
|
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/HetznerVM" .username)
|
||||||
echo $file
|
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/HetznerVM" .password)
|
||||||
simple_get "/private-public-keys/restic/HetznerVM" .password > $file
|
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/HetznerVM" > $secretFile
|
||||||
chown ${secrets-db.restic_password.user}:${secrets-db.restic_password.group} $file
|
'';
|
||||||
chmod ${secrets-db.restic_password.permissions} $file
|
};
|
||||||
|
wg_privkey = {
|
||||||
file=${secrets-db.restic_env.path}
|
fetchScript = ''
|
||||||
echo $file
|
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .private > $secretFile
|
||||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/HetznerVM" .username)
|
'';
|
||||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/HetznerVM" .password)
|
};
|
||||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/HetznerVM" > $file
|
wg_preshared_tablet = {
|
||||||
chown ${secrets-db.restic_env.user}:${secrets-db.restic_env.group} $file
|
path = "/secrets/wg_preshared_tablet";
|
||||||
chmod ${secrets-db.restic_env.permissions} $file
|
fetchScript = ''
|
||||||
|
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.tablet > $secretFile
|
||||||
file=${secrets-db.wg_privkey.path}
|
'';
|
||||||
echo $file
|
};
|
||||||
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .private > $file
|
wg_preshared_vault = {
|
||||||
chown ${secrets-db.wg_privkey.user}:${secrets-db.wg_privkey.group} $file
|
path = "/secrets/wg_preshared_vault";
|
||||||
chmod ${secrets-db.wg_privkey.permissions} $file
|
fetchScript = ''
|
||||||
|
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.vault > $secretFile
|
||||||
file=${secrets-db.wg_preshared_tablet.path}
|
'';
|
||||||
echo $file
|
};
|
||||||
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.tablet > $file
|
wg_preshared_storage = {
|
||||||
chown ${secrets-db.wg_preshared_tablet.user}:${secrets-db.wg_preshared_tablet.group} $file
|
path = "/secrets/wg_preshared_storage";
|
||||||
chmod ${secrets-db.wg_preshared_tablet.permissions} $file
|
fetchScript = ''
|
||||||
|
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.storage > $secretFile
|
||||||
file=${secrets-db.wg_preshared_vault.path}
|
'';
|
||||||
echo $file
|
};
|
||||||
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.vault > $file
|
wg_preshared_iphone8 = {
|
||||||
chown ${secrets-db.wg_preshared_vault.user}:${secrets-db.wg_preshared_vault.group} $file
|
path = "/secrets/wg_preshared_iphone8";
|
||||||
chmod ${secrets-db.wg_preshared_vault.permissions} $file
|
fetchScript = ''
|
||||||
|
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.iphone8 > $secretFile
|
||||||
file=${secrets-db.wg_preshared_storage.path}
|
'';
|
||||||
echo $file
|
};
|
||||||
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.storage > $file
|
};
|
||||||
chown ${secrets-db.wg_preshared_storage.user}:${secrets-db.wg_preshared_storage.group} $file
|
};
|
||||||
chmod ${secrets-db.wg_preshared_storage.permissions} $file
|
|
||||||
|
|
||||||
file=${secrets-db.wg_preshared_iphone8.path}
|
|
||||||
echo $file
|
|
||||||
simple_get "/private-public-keys/wireguard/chaos-internal/hetzner-vm" .preshared_keys.iphone8 > $file
|
|
||||||
chown ${secrets-db.wg_preshared_iphone8.user}:${secrets-db.wg_preshared_iphone8.group} $file
|
|
||||||
chmod ${secrets-db.wg_preshared_iphone8.permissions} $file
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{ ... }:
|
{ config, ... }:
|
||||||
let secrets-db = (import ../secrets-db.nix { });
|
let secrets = config.services.secrets.secrets;
|
||||||
in {
|
in {
|
||||||
services.gitlab_artifacts_sync = {
|
services.gitlab_artifacts_sync = {
|
||||||
enable = true;
|
enable = true;
|
||||||
credentialsEnvironmentFile = "${secrets-db.gitlab_env.path}";
|
credentialsEnvironmentFile = "${secrets.gitlab_env.path}";
|
||||||
repos = [
|
repos = [
|
||||||
{
|
{
|
||||||
repoName = "ChaotiCryptidz/VaultUI";
|
repoName = "ChaotiCryptidz/VaultUI";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{ }:
|
{ config }:
|
||||||
let secrets-db = (import ../../secrets-db.nix { });
|
let secrets = config.services.secrets.secrets;
|
||||||
in rec {
|
in rec {
|
||||||
fqdn = "mail.owo.monster";
|
fqdn = "mail.owo.monster";
|
||||||
domains = [
|
domains = [
|
||||||
|
@ -21,7 +21,7 @@ in rec {
|
||||||
accounts = {
|
accounts = {
|
||||||
"chaoticryptidz@owo.monster" = {
|
"chaoticryptidz@owo.monster" = {
|
||||||
name = "chaoticryptidz@owo.monster";
|
name = "chaoticryptidz@owo.monster";
|
||||||
passwordFile = "${secrets-db.chaos_mail_passwd.path}";
|
passwordFile = "${secrets.chaos_mail_passwd.path}";
|
||||||
aliases = [
|
aliases = [
|
||||||
"all@owo.monster"
|
"all@owo.monster"
|
||||||
# for sending from
|
# for sending from
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
|
|
||||||
passwdDir = "/run/dovecot2";
|
passwdDir = "/run/dovecot2";
|
||||||
passwdFile = "${passwdDir}/passwd";
|
passwdFile = "${passwdDir}/passwd";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
|
|
||||||
dkimUser = config.services.opendkim.user;
|
dkimUser = config.services.opendkim.user;
|
||||||
dkimGroup = config.services.opendkim.group;
|
dkimGroup = config.services.opendkim.group;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
submissionHeaderCleanupRules =
|
submissionHeaderCleanupRules =
|
||||||
pkgs.writeText "submission_header_cleanup_rules" (''
|
pkgs.writeText "submission_header_cleanup_rules" (''
|
||||||
/^Received:/ IGNORE
|
/^Received:/ IGNORE
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
|
|
||||||
ports = (import ../../ports.nix { });
|
ports = (import ../../ports.nix { });
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{ pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
acmeRoot = "/var/lib/acme/acme-challenge";
|
acmeRoot = "/var/lib/acme/acme-challenge";
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
mail_config = (import ./config.nix { });
|
mail_config = (import ./config.nix { config = config; });
|
||||||
|
|
||||||
v = mail_config.vmail_config;
|
v = mail_config.vmail_config;
|
||||||
sieve_directory = mail_config.sieve_directory;
|
sieve_directory = mail_config.sieve_directory;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{ ... }:
|
{ config, ... }:
|
||||||
let mail_config = (import ./config.nix { });
|
let mail_config = (import ./config.nix { config = config; });
|
||||||
in {
|
in {
|
||||||
services.roundcube = {
|
services.roundcube = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ pkgs, lib, tree, ... }:
|
{ config, pkgs, lib, tree, ... }:
|
||||||
let
|
let
|
||||||
ports = (import ../ports.nix { });
|
ports = (import ../ports.nix { });
|
||||||
secrets-db = (import ../secrets-db.nix { });
|
secrets = config.services.secrets.secrets;
|
||||||
in {
|
in {
|
||||||
environment.systemPackages = with pkgs; [ mpc_cli ];
|
environment.systemPackages = with pkgs; [ mpc_cli ];
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ in {
|
||||||
network.listenAddress = "0.0.0.0";
|
network.listenAddress = "0.0.0.0";
|
||||||
musicDirectory = "https://storage-webdav.owo.monster/music_ro/";
|
musicDirectory = "https://storage-webdav.owo.monster/music_ro/";
|
||||||
credentials = [{
|
credentials = [{
|
||||||
passwordFile = "${secrets-db.mpd_control_password.path}";
|
passwordFile = "${secrets.mpd_control_password.path}";
|
||||||
permissions = [ "read" "add" "control" "admin" ];
|
permissions = [ "read" "add" "control" "admin" ];
|
||||||
}];
|
}];
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
@ -53,14 +53,14 @@ in {
|
||||||
proxyPass = "http://127.0.0.1:${toString ports.mpd-opus}";
|
proxyPass = "http://127.0.0.1:${toString ports.mpd-opus}";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
auth_basic "Music Password";
|
auth_basic "Music Password";
|
||||||
auth_basic_user_file ${secrets-db.music_stream_passwd.path};
|
auth_basic_user_file ${secrets.music_stream_passwd.path};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
"/flac" = {
|
"/flac" = {
|
||||||
proxyPass = "http://127.0.0.1:${toString ports.mpd-flac}";
|
proxyPass = "http://127.0.0.1:${toString ports.mpd-flac}";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
auth_basic "Music Password";
|
auth_basic "Music Password";
|
||||||
auth_basic_user_file ${secrets-db.music_stream_passwd.path};
|
auth_basic_user_file ${secrets.music_stream_passwd.path};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ lib, config, pkgs, ... }:
|
{ lib, config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
secrets-db = (import ../secrets-db.nix { });
|
secrets = config.services.secrets.secrets;
|
||||||
mail_config = (import ./mailserver/config.nix { });
|
mail_config = (import ./mailserver/config.nix { config = config; });
|
||||||
|
|
||||||
backupPrepareCommand = "${
|
backupPrepareCommand = "${
|
||||||
(pkgs.writeShellScriptBin "backupPrepareCommand" ''
|
(pkgs.writeShellScriptBin "backupPrepareCommand" ''
|
||||||
|
@ -12,8 +12,8 @@ in {
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
(pkgs.writeShellScriptBin "restic-hetzner-vm" ''
|
(pkgs.writeShellScriptBin "restic-hetzner-vm" ''
|
||||||
env \
|
env \
|
||||||
RESTIC_PASSWORD_FILE=${secrets-db.restic_password.path} \
|
RESTIC_PASSWORD_FILE=${secrets.restic_password.path} \
|
||||||
$(cat ${secrets-db.restic_env.path}) \
|
$(cat ${secrets.restic_env.path}) \
|
||||||
${pkgs.restic}/bin/restic $@
|
${pkgs.restic}/bin/restic $@
|
||||||
'')
|
'')
|
||||||
];
|
];
|
||||||
|
@ -40,8 +40,8 @@ in {
|
||||||
# repository is overrided in environmentFile to contain auth
|
# repository is overrided in environmentFile to contain auth
|
||||||
# make sure to keep up to date when changing repository
|
# make sure to keep up to date when changing repository
|
||||||
repository = "rest:https://storage-restic.owo.monster/HetznerVM";
|
repository = "rest:https://storage-restic.owo.monster/HetznerVM";
|
||||||
passwordFile = "${secrets-db.restic_password.path}";
|
passwordFile = "${secrets.restic_password.path}";
|
||||||
environmentFile = "${secrets-db.restic_env.path}";
|
environmentFile = "${secrets.restic_env.path}";
|
||||||
|
|
||||||
timerConfig = {
|
timerConfig = {
|
||||||
OnBootSec = "1m";
|
OnBootSec = "1m";
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
{ ... }:
|
{ config, ... }:
|
||||||
let secrets-db = (import ../secrets-db.nix { });
|
let secrets = config.services.secrets.secrets;
|
||||||
in {
|
in {
|
||||||
networking.wg-quick.interfaces = {
|
networking.wg-quick.interfaces = {
|
||||||
wg0 = {
|
wg0 = {
|
||||||
address = [ "10.69.42.1/32" ];
|
address = [ "10.69.42.1/32" ];
|
||||||
listenPort = 51820;
|
listenPort = 51820;
|
||||||
privateKeyFile = "${secrets-db.wg_privkey.path}";
|
privateKeyFile = "${secrets.wg_privkey.path}";
|
||||||
peers = [
|
peers = [
|
||||||
# tablet
|
# tablet
|
||||||
{
|
{
|
||||||
publicKey = "jXA0DeprEaL/ARQ3K81l8xWuUI5C/90DcY3bIfcIjz8=";
|
publicKey = "jXA0DeprEaL/ARQ3K81l8xWuUI5C/90DcY3bIfcIjz8=";
|
||||||
presharedKeyFile = "${secrets-db.wg_preshared_tablet.path}";
|
presharedKeyFile = "${secrets.wg_preshared_tablet.path}";
|
||||||
allowedIPs = [ "10.69.42.2/32" ];
|
allowedIPs = [ "10.69.42.2/32" ];
|
||||||
}
|
}
|
||||||
# vault
|
# vault
|
||||||
{
|
{
|
||||||
publicKey = "IGq+WanFM/bKNUkwjO/0AAtDhJLvtvU+mVxH27QyHTc=";
|
publicKey = "IGq+WanFM/bKNUkwjO/0AAtDhJLvtvU+mVxH27QyHTc=";
|
||||||
presharedKeyFile = "${secrets-db.wg_preshared_vault.path}";
|
presharedKeyFile = "${secrets.wg_preshared_vault.path}";
|
||||||
endpoint = "vault.servers.genderfucked.monster:51820";
|
endpoint = "vault.servers.genderfucked.monster:51820";
|
||||||
allowedIPs = [ "10.69.42.3/32" ];
|
allowedIPs = [ "10.69.42.3/32" ];
|
||||||
}
|
}
|
||||||
# storage
|
# storage
|
||||||
{
|
{
|
||||||
publicKey = "biNNeCkjAWi2jUVoL5+1pBtXGa3OFZi4DltB2dqGjGg=";
|
publicKey = "biNNeCkjAWi2jUVoL5+1pBtXGa3OFZi4DltB2dqGjGg=";
|
||||||
presharedKeyFile = "${secrets-db.wg_preshared_storage.path}";
|
presharedKeyFile = "${secrets.wg_preshared_storage.path}";
|
||||||
allowedIPs = [ "10.69.42.4/32" ];
|
allowedIPs = [ "10.69.42.4/32" ];
|
||||||
}
|
}
|
||||||
# iphone8
|
# iphone8
|
||||||
{
|
{
|
||||||
publicKey = "2BgT08bDKh8WlFFSeRArI9a1GpFgUyqEApvJy4KgAmw=";
|
publicKey = "2BgT08bDKh8WlFFSeRArI9a1GpFgUyqEApvJy4KgAmw=";
|
||||||
presharedKeyFile = "${secrets-db.wg_preshared_iphone8.path}";
|
presharedKeyFile = "${secrets.wg_preshared_iphone8.path}";
|
||||||
allowedIPs = [ "10.69.42.5/32" ];
|
allowedIPs = [ "10.69.42.5/32" ];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -21,6 +21,7 @@ let
|
||||||
|
|
||||||
tree.impure.modules.nixos.rclone-serve
|
tree.impure.modules.nixos.rclone-serve
|
||||||
tree.impure.modules.nixos.rclone-sync
|
tree.impure.modules.nixos.rclone-sync
|
||||||
|
tree.impure.modules.nixos.secrets
|
||||||
];
|
];
|
||||||
|
|
||||||
nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem;
|
nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem;
|
||||||
|
|
251
modules/nixos/secrets.nix
Normal file
251
modules/nixos/secrets.nix
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.secrets;
|
||||||
|
defaultPackages = with pkgs; [ pkgs.vault pkgs.jq ];
|
||||||
|
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
services.secrets = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
debug = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
createSecretsDir = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
secretsDirUser = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
secretsDirGroup = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
secretsDir = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/secrets";
|
||||||
|
};
|
||||||
|
|
||||||
|
vaultURL = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "https://vault.owo.monster";
|
||||||
|
description = "default Vault URL, can be overrided with env variables";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraFunctions = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
description = "extra bash functions to add to top of script";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPackages = mkOption {
|
||||||
|
type = types.listOf types.package;
|
||||||
|
default = [ ];
|
||||||
|
description = "extra packages for script";
|
||||||
|
};
|
||||||
|
|
||||||
|
secrets = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule ({ config, name, ... }: {
|
||||||
|
options = {
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
permissions = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "660";
|
||||||
|
};
|
||||||
|
path = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${cfg.secretsDir}/${name}";
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchScript = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
description = ''
|
||||||
|
script used to fetch secrets, $file is secret.path
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
checkScript = mkOption {
|
||||||
|
type = types.nullOr types.lines;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
script used to check contents of secret file, set LOCAL_FAIL to true on failure
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
manual = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "should the secret be manually deployed";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf (cfg.enable) (let
|
||||||
|
scriptBase = ''
|
||||||
|
set -e -o pipefail
|
||||||
|
${if cfg.debug then "set -x" else ""}
|
||||||
|
'';
|
||||||
|
|
||||||
|
manualSecrets = filterAttrs (name: secret: secret.manual) cfg.secrets;
|
||||||
|
nonManualSecrets = filterAttrs (name: secret: !secret.manual) cfg.secrets;
|
||||||
|
|
||||||
|
initScript = ''
|
||||||
|
${scriptBase}
|
||||||
|
|
||||||
|
VAULT_ADDR_DEFAULT="${cfg.vaultURL}"
|
||||||
|
[ -n "$VAULT_ADDR" ] && export VAULT_ADDR="$VAULT_ADDR_DEFAULT"
|
||||||
|
|
||||||
|
kv_get() {
|
||||||
|
vault kv get -format json "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_get() {
|
||||||
|
kv_get "$1" | jq ".data.data$2" -r
|
||||||
|
}
|
||||||
|
|
||||||
|
${cfg.extraFunctions}
|
||||||
|
'' + (lib.concatStringsSep "\n" (lib.mapAttrsToList (name: secret: ''
|
||||||
|
if [[ ! -f "${secret.path}" ]]; then
|
||||||
|
echo "Initializing Secret ${secret.path}"
|
||||||
|
else
|
||||||
|
echo "Updating Secret ${secret.path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
secretFile="${secret.path}"
|
||||||
|
${secret.fetchScript}
|
||||||
|
|
||||||
|
chown ${secret.user}:${secret.group} "${secret.path}"
|
||||||
|
chmod ${secret.permissions} "${secret.path}"
|
||||||
|
'') nonManualSecrets)) + (lib.concatStringsSep "\n" (lib.mapAttrsToList
|
||||||
|
(name: secret: ''
|
||||||
|
if [[ ! -f "${secret.path}" ]]; then
|
||||||
|
echo "Manual Secret ${secret.path} Doesn't Exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updating Permissions on Manual Secret ${secret.path}"
|
||||||
|
|
||||||
|
chown ${secret.user}:${secret.group} "${secret.path}"
|
||||||
|
chmod ${secret.permissions} "${secret.path}"
|
||||||
|
'') manualSecrets)) + ''
|
||||||
|
echo "Secrets Deployed"
|
||||||
|
'';
|
||||||
|
|
||||||
|
checkScript = ''
|
||||||
|
${scriptBase}
|
||||||
|
|
||||||
|
getUser() {
|
||||||
|
stat --format "%U" "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroup() {
|
||||||
|
stat --format "%U" "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermissions() {
|
||||||
|
stat --format "%a" "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
GLOBAL_FAIL=false
|
||||||
|
'' + (lib.concatStringsSep "\n" (lib.mapAttrsToList (name: secret: ''
|
||||||
|
LOCAL_FAIL=false
|
||||||
|
|
||||||
|
echo "Secret: ${name}"
|
||||||
|
echo "Checking ${secret.path}"
|
||||||
|
|
||||||
|
# some variables which can be used by checkScript
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
secretFile="${secret.path}"
|
||||||
|
|
||||||
|
if [[ -f "${secret.path}" ]]; then
|
||||||
|
echo "✅ File Exists"
|
||||||
|
else
|
||||||
|
echo "❌ File Does Not Exist"
|
||||||
|
LOCAL_FAIL=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if getUser "${secret.path}" >/dev/null && [[ "$(getUser "${secret.path}")" == "${secret.user}" ]]; then
|
||||||
|
echo "✅ File Is Owned By Correct User"
|
||||||
|
else
|
||||||
|
echo "❌ File Is Not Owned By Correct User (${secret.user})"
|
||||||
|
LOCAL_FAIL=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if getGroup "${secret.path}" >/dev/null && [[ "$(getGroup "${secret.path}")" == "${secret.group}" ]]; then
|
||||||
|
echo "✅ File Is Owned By Correct Group"
|
||||||
|
else
|
||||||
|
echo "❌ File Is Not Owned By Correct Group (${secret.user})"
|
||||||
|
LOCAL_FAIL=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if getPermissions "${secret.path}" >/dev/null && [[ "$(getPermissions "${secret.path}")" -eq "${secret.permissions}" ]]; then
|
||||||
|
echo "✅ File Has Correct Permissions"
|
||||||
|
else
|
||||||
|
echo "❌ File Does Not Have Correct Permissions (${secret.permissions})"
|
||||||
|
LOCAL_FAIL=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
${if secret.checkScript != null then secret.checkScript else ""}
|
||||||
|
|
||||||
|
if [[ "$LOCAL_FAIL" == "true" ]]; then
|
||||||
|
echo "❌ File Did Not Pass The Vibe Check"
|
||||||
|
GLOBAL_FAIL=true
|
||||||
|
else
|
||||||
|
echo "✅ File Passed The Vibe Check"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
'') cfg.secrets)) + ''
|
||||||
|
if [[ "$GLOBAL_FAIL" == "true" ]]; then
|
||||||
|
echo "❌ One Or More Secrets Did Not Pass The Vibe Check"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "✅ All Secrets Passed The Vibe Check"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
environment.systemPackages = [
|
||||||
|
(pkgs.writeShellApplication {
|
||||||
|
name = "secrets-check";
|
||||||
|
runtimeInputs = defaultPackages ++ cfg.extraPackages;
|
||||||
|
text = checkScript;
|
||||||
|
})
|
||||||
|
(pkgs.writeShellApplication {
|
||||||
|
name = "secrets-init";
|
||||||
|
runtimeInputs = defaultPackages ++ cfg.extraPackages;
|
||||||
|
text = initScript;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
}))
|
||||||
|
|
||||||
|
(mkIf (cfg.enable && cfg.createSecretsDir) {
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${cfg.secretsDir} - ${cfg.secretsDirUser} ${cfg.secretsDirGroup}"
|
||||||
|
];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
|
@ -35,7 +35,8 @@ in {
|
||||||
initrd.luks.devices = {
|
initrd.luks.devices = {
|
||||||
"${drive_data.root_mapper_name}" = {
|
"${drive_data.root_mapper_name}" = {
|
||||||
device = "${drive_data.encrypted_root_path}";
|
device = "${drive_data.encrypted_root_path}";
|
||||||
keyFile = "${usb_data.encryption_keys_path}/${config.networking.hostName}.key";
|
keyFile =
|
||||||
|
"${usb_data.encryption_keys_path}/${config.networking.hostName}.key";
|
||||||
preLVM = false;
|
preLVM = false;
|
||||||
allowDiscards = true;
|
allowDiscards = true;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue