claude'd better security things
This commit is contained in:
parent
9e35448f04
commit
f9515dd160
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1 +1,3 @@
|
|||||||
secrets/** filter=git-crypt diff=git-crypt
|
secrets/** filter=git-crypt diff=git-crypt
|
||||||
|
usb-secrets/usb-secrets/usb-secrets-key filter=git-crypt diff=git-crypt
|
||||||
|
|
||||||
|
|||||||
64
age-secrets.nix
Normal file
64
age-secrets.nix
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Configure all agenix secrets
|
||||||
|
age.secrets = {
|
||||||
|
# ZFS encryption key
|
||||||
|
zfs-key = {
|
||||||
|
file = ./secrets/zfs-key.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Secureboot keys archive
|
||||||
|
secureboot-tar = {
|
||||||
|
file = ./secrets/secureboot.tar.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
# System passwords
|
||||||
|
hashedPass = {
|
||||||
|
file = ./secrets/hashedPass.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Service authentication
|
||||||
|
caddy_auth = {
|
||||||
|
file = ./secrets/caddy_auth.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
jellyfin-api-key = {
|
||||||
|
file = ./secrets/jellyfin-api-key.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
slskd_env = {
|
||||||
|
file = ./secrets/slskd_env.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
wg0-conf = {
|
||||||
|
file = ./secrets/wg0.conf.age;
|
||||||
|
mode = "0400";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -14,6 +14,8 @@
|
|||||||
./hardware.nix
|
./hardware.nix
|
||||||
./zfs.nix
|
./zfs.nix
|
||||||
./impermanence.nix
|
./impermanence.nix
|
||||||
|
./usb-secrets.nix
|
||||||
|
./age-secrets.nix
|
||||||
|
|
||||||
./services/postgresql.nix
|
./services/postgresql.nix
|
||||||
./services/jellyfin.nix
|
./services/jellyfin.nix
|
||||||
@ -26,8 +28,6 @@
|
|||||||
./services/qbittorrent.nix
|
./services/qbittorrent.nix
|
||||||
./services/bitmagnet.nix
|
./services/bitmagnet.nix
|
||||||
|
|
||||||
# ./services/matrix.nix
|
|
||||||
# ./services/owntracks.nix
|
|
||||||
./services/soulseek.nix
|
./services/soulseek.nix
|
||||||
|
|
||||||
./services/llama-cpp.nix
|
./services/llama-cpp.nix
|
||||||
@ -111,17 +111,19 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
system.activationScripts = {
|
system.activationScripts = {
|
||||||
# extract all my secureboot keys
|
# extract secureboot keys from agenix-decrypted tar
|
||||||
# TODO! awful secrets management, it's globally readable in /nix/store
|
"secureboot-keys" = {
|
||||||
"secureboot-keys".text = ''
|
deps = [ "agenix" ];
|
||||||
|
text = ''
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -fr ${config.boot.lanzaboote.pkiBundle} || true
|
rm -fr ${config.boot.lanzaboote.pkiBundle} || true
|
||||||
mkdir -p ${config.boot.lanzaboote.pkiBundle}
|
mkdir -p ${config.boot.lanzaboote.pkiBundle}
|
||||||
${pkgs.gnutar}/bin/tar xf ${./secrets/secureboot.tar} -C ${config.boot.lanzaboote.pkiBundle}
|
${pkgs.gnutar}/bin/tar xf ${config.age.secrets.secureboot-tar.path} -C ${config.boot.lanzaboote.pkiBundle}
|
||||||
chown -R root:wheel ${config.boot.lanzaboote.pkiBundle}
|
chown -R root:wheel ${config.boot.lanzaboote.pkiBundle}
|
||||||
chmod -R 500 ${config.boot.lanzaboote.pkiBundle}
|
chmod -R 500 ${config.boot.lanzaboote.pkiBundle}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
environment.etc = {
|
environment.etc = {
|
||||||
"issue".text = "";
|
"issue".text = "";
|
||||||
@ -286,7 +288,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# TODO! use proper secrets management
|
# TODO! use proper secrets management
|
||||||
hashedPassword = lib.strings.trim (builtins.readFile ./secrets/hashedPass);
|
hashedPasswordFile = config.age.secrets.hashedPass.path;
|
||||||
|
|
||||||
openssh.authorizedKeys.keys = [
|
openssh.authorizedKeys.keys = [
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO4jL6gYOunUlUtPvGdML0cpbKSsPNqQ1jit4E7U1RyH" # laptop
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO4jL6gYOunUlUtPvGdML0cpbKSsPNqQ1jit4E7U1RyH" # laptop
|
||||||
|
|||||||
88
flake.lock
generated
88
flake.lock
generated
@ -1,5 +1,28 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"agenix": {
|
||||||
|
"inputs": {
|
||||||
|
"darwin": "darwin",
|
||||||
|
"home-manager": "home-manager",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754433428,
|
||||||
|
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"crane": {
|
"crane": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754269165,
|
"lastModified": 1754269165,
|
||||||
@ -15,6 +38,28 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"darwin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744478979,
|
||||||
|
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
|
||||||
|
"owner": "lnl7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lnl7",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"deploy-rs": {
|
"deploy-rs": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
@ -146,7 +191,7 @@
|
|||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_2"
|
"systems": "systems_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
@ -185,6 +230,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1745494811,
|
||||||
|
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home-manager_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
@ -360,9 +426,10 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"agenix": "agenix",
|
||||||
"deploy-rs": "deploy-rs",
|
"deploy-rs": "deploy-rs",
|
||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager_2",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
"lanzaboote": "lanzaboote",
|
"lanzaboote": "lanzaboote",
|
||||||
"llamacpp": "llamacpp",
|
"llamacpp": "llamacpp",
|
||||||
@ -463,6 +530,21 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"trackerlist": {
|
"trackerlist": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -481,7 +563,7 @@
|
|||||||
},
|
},
|
||||||
"utils": {
|
"utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
|
|||||||
14
flake.nix
14
flake.nix
@ -47,6 +47,11 @@
|
|||||||
url = "github:nix-community/impermanence";
|
url = "github:nix-community/impermanence";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
agenix = {
|
||||||
|
url = "github:ryantm/agenix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
senior_project-website = {
|
senior_project-website = {
|
||||||
url = "github:Titaniumtown/senior-project-website";
|
url = "github:Titaniumtown/senior-project-website";
|
||||||
flake = false;
|
flake = false;
|
||||||
@ -76,6 +81,7 @@
|
|||||||
srvos,
|
srvos,
|
||||||
deploy-rs,
|
deploy-rs,
|
||||||
impermanence,
|
impermanence,
|
||||||
|
agenix,
|
||||||
...
|
...
|
||||||
}@inputs:
|
}@inputs:
|
||||||
let
|
let
|
||||||
@ -97,7 +103,6 @@
|
|||||||
jellyfin = 8096; # no services.jellyfin option for this
|
jellyfin = 8096; # no services.jellyfin option for this
|
||||||
torrent = 6011;
|
torrent = 6011;
|
||||||
bitmagnet = 3333;
|
bitmagnet = 3333;
|
||||||
owntracks = 3825;
|
|
||||||
gitea = 2283;
|
gitea = 2283;
|
||||||
immich = 2284;
|
immich = 2284;
|
||||||
soulseek_web = 5030;
|
soulseek_web = 5030;
|
||||||
@ -110,7 +115,6 @@
|
|||||||
certs = services_dir + "/http_certs";
|
certs = services_dir + "/http_certs";
|
||||||
domain = "gardling.com";
|
domain = "gardling.com";
|
||||||
wg_ip = "192.168.15.1";
|
wg_ip = "192.168.15.1";
|
||||||
matrix_hostname = "matrix.${service_configs.https.domain}";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
gitea = {
|
gitea = {
|
||||||
@ -142,10 +146,6 @@
|
|||||||
cacheDir = services_dir + "/jellyfin_cache";
|
cacheDir = services_dir + "/jellyfin_cache";
|
||||||
};
|
};
|
||||||
|
|
||||||
owntracks = {
|
|
||||||
data_dir = services_dir + "/owntracks";
|
|
||||||
};
|
|
||||||
|
|
||||||
slskd = rec {
|
slskd = rec {
|
||||||
base = "/var/lib/slskd";
|
base = "/var/lib/slskd";
|
||||||
downloads = base + "/downloads";
|
downloads = base + "/downloads";
|
||||||
@ -221,6 +221,8 @@
|
|||||||
|
|
||||||
lanzaboote.nixosModules.lanzaboote
|
lanzaboote.nixosModules.lanzaboote
|
||||||
|
|
||||||
|
agenix.nixosModules.default
|
||||||
|
|
||||||
home-manager.nixosModules.home-manager
|
home-manager.nixosModules.home-manager
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
|
|||||||
22
secrets.nix
Normal file
22
secrets.nix
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
let
|
||||||
|
# USB secrets key - for encrypting/decrypting all secrets
|
||||||
|
usbSecretsKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN8+eSX2LH5wEHVG9sSv97ceD5zdTarV0lRvoUso4A7p USB secrets decryption key";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# ZFS encryption key
|
||||||
|
"zfs-key.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
|
||||||
|
# Secureboot keys archive
|
||||||
|
"secureboot.tar.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
|
||||||
|
# System passwords and auth
|
||||||
|
"hashedPass.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
|
||||||
|
# Service authentication
|
||||||
|
"caddy_auth.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
"jellyfin-api-key.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
"slskd_env.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
"wg0.conf.age".publicKeys = [ usbSecretsKey ];
|
||||||
|
}
|
||||||
Binary file not shown.
BIN
secrets/caddy_auth.age
Normal file
BIN
secrets/caddy_auth.age
Normal file
Binary file not shown.
Binary file not shown.
BIN
secrets/hashedPass.age
Normal file
BIN
secrets/hashedPass.age
Normal file
Binary file not shown.
Binary file not shown.
BIN
secrets/jellyfin-api-key.age
Normal file
BIN
secrets/jellyfin-api-key.age
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
secrets/secureboot.tar.age
Normal file
BIN
secrets/secureboot.tar.age
Normal file
Binary file not shown.
BIN
secrets/slskd_env.age
Normal file
BIN
secrets/slskd_env.age
Normal file
Binary file not shown.
BIN
secrets/wg0.conf
BIN
secrets/wg0.conf
Binary file not shown.
BIN
secrets/wg0.conf.age
Normal file
BIN
secrets/wg0.conf.age
Normal file
Binary file not shown.
BIN
secrets/zfs-key
BIN
secrets/zfs-key
Binary file not shown.
BIN
secrets/zfs-key.age
Normal file
BIN
secrets/zfs-key.age
Normal file
Binary file not shown.
@ -25,7 +25,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts."bitmagnet.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."bitmagnet.${service_configs.https.domain}".extraConfig = ''
|
||||||
${builtins.readFile ../secrets/caddy_auth}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy ${service_configs.https.wg_ip}:${builtins.toString service_configs.ports.bitmagnet}
|
reverse_proxy ${service_configs.https.wg_ip}:${builtins.toString service_configs.ports.bitmagnet}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,6 +66,12 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Add agenix dependency for caddy service
|
||||||
|
systemd.services.caddy = {
|
||||||
|
after = [ "agenix.service" ];
|
||||||
|
requires = [ "agenix.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d ${config.services.caddy.dataDir} 700 ${config.services.caddy.user} ${config.services.caddy.group}"
|
"d ${config.services.caddy.dataDir} 700 ${config.services.caddy.user} ${config.services.caddy.group}"
|
||||||
];
|
];
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
systemd.services.llama-cpp.serviceConfig.DynamicUser = lib.mkForce false;
|
systemd.services.llama-cpp.serviceConfig.DynamicUser = lib.mkForce false;
|
||||||
|
|
||||||
services.caddy.virtualHosts."llm.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."llm.${service_configs.https.domain}".extraConfig = ''
|
||||||
${builtins.readFile ../secrets/caddy_auth}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy :${builtins.toString config.services.llama-cpp.port}
|
reverse_proxy :${builtins.toString config.services.llama-cpp.port}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
service_configs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
services.matrix-conduit.settings.global.registration_token =
|
|
||||||
builtins.readFile ../secrets/matrix_reg_token;
|
|
||||||
|
|
||||||
services.caddy.virtualHosts.${service_configs.https.domain}.extraConfig = lib.mkBefore ''
|
|
||||||
header /.well-known/matrix/* Content-Type application/json
|
|
||||||
header /.well-known/matrix/* Access-Control-Allow-Origin *
|
|
||||||
respond /.well-known/matrix/server `{"m.server": "${service_configs.https.matrix_hostname}:${service_configs.ports.https}"}`
|
|
||||||
respond /.well-known/matrix/client `{"m.server":{"base_url":"https://${service_configs.https.matrix_hostname}"},"m.homeserver":{"base_url":"https://${service_configs.https.matrix_hostname}"},"org.matrix.msc3575.proxy":{"base_url":"https://${config.services.matrix-conduit.settings.global.server_name}"}}`
|
|
||||||
'';
|
|
||||||
|
|
||||||
services.caddy.virtualHosts."${service_configs.https.matrix_hostname}".extraConfig = ''
|
|
||||||
reverse_proxy :${builtins.toString config.services.matrix-conduit.settings.global.port}
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Exact duplicate
|
|
||||||
services.caddy.virtualHosts."${service_configs.https.matrix_hostname}:8448".extraConfig =
|
|
||||||
config.services.caddy.virtualHosts."${config.services.matrix-conduit.settings.global.server_name
|
|
||||||
}".extraConfig;
|
|
||||||
|
|
||||||
services.matrix-conduit = {
|
|
||||||
enable = true;
|
|
||||||
package = pkgs.conduwuit;
|
|
||||||
|
|
||||||
settings.global = {
|
|
||||||
port = 6167;
|
|
||||||
server_name = service_configs.https.domain;
|
|
||||||
database_backend = "rocksdb";
|
|
||||||
allow_registration = true;
|
|
||||||
|
|
||||||
new_user_displayname_suffix = "";
|
|
||||||
|
|
||||||
trusted_servers = [
|
|
||||||
"matrix.org"
|
|
||||||
"constellatory.net"
|
|
||||||
"tchncs.de"
|
|
||||||
"envs.net"
|
|
||||||
];
|
|
||||||
|
|
||||||
# without this, conduit fails to start
|
|
||||||
address = "0.0.0.0";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"Z /var/lib/private/matrix-conduit 0770 conduit conduit"
|
|
||||||
];
|
|
||||||
|
|
||||||
# for federation
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
8448
|
|
||||||
];
|
|
||||||
|
|
||||||
# for federation
|
|
||||||
networking.firewall.allowedUDPPorts = [
|
|
||||||
8448
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
service_configs,
|
|
||||||
username,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
owntracks_pkg = pkgs.owntracks-recorder.overrideAttrs (old: {
|
|
||||||
installPhase = old.installPhase + ''
|
|
||||||
mkdir -p $out/usr/share/ot-recorder
|
|
||||||
cp -R docroot/* $out/usr/share/ot-recorder'';
|
|
||||||
});
|
|
||||||
in
|
|
||||||
{
|
|
||||||
users.groups.owntracks = { };
|
|
||||||
users.users.owntracks = {
|
|
||||||
isNormalUser = true;
|
|
||||||
group = "owntracks";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.owntracks = {
|
|
||||||
enable = true;
|
|
||||||
description = "Store and access data published by OwnTracks apps";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
User = "owntracks";
|
|
||||||
Group = "owntracks";
|
|
||||||
WorkingDirectory = "${owntracks_pkg}";
|
|
||||||
ExecStart = "${owntracks_pkg}/bin/ot-recorder -S ${service_configs.owntracks.data_dir} --doc-root usr/share/ot-recorder --http-port ${builtins.toString service_configs.ports.owntracks} --port 0";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"Z ${service_configs.owntracks.data_dir} 0770 owntracks owntracks"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.caddy.virtualHosts."owntracks.${service_configs.https.domain}".extraConfig = ''
|
|
||||||
${builtins.readFile ../secrets/owntracks_caddy_auth}
|
|
||||||
reverse_proxy :${builtins.toString service_configs.ports.owntracks}
|
|
||||||
'';
|
|
||||||
|
|
||||||
users.users.${username}.extraGroups = [
|
|
||||||
"owntracks"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@ -102,7 +102,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
services.caddy.virtualHosts."torrent.${service_configs.https.domain}".extraConfig = ''
|
services.caddy.virtualHosts."torrent.${service_configs.https.domain}".extraConfig = ''
|
||||||
${builtins.readFile ../secrets/caddy_auth}
|
import ${config.age.secrets.caddy_auth.path}
|
||||||
reverse_proxy ${service_configs.https.wg_ip}:${builtins.toString config.services.qbittorrent.webuiPort}
|
reverse_proxy ${service_configs.https.wg_ip}:${builtins.toString config.services.qbittorrent.webuiPort}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ in
|
|||||||
"skskd_env".text = ''
|
"skskd_env".text = ''
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -fr ${slskd_env} || true
|
rm -fr ${slskd_env} || true
|
||||||
cp ${../secrets/slskd_env} ${slskd_env}
|
cp ${config.age.secrets.slskd_env.path} ${slskd_env}
|
||||||
chmod 0500 ${slskd_env}
|
chmod 0500 ${slskd_env}
|
||||||
chown ${config.services.slskd.user}:${config.services.slskd.group} ${slskd_env}
|
chown ${config.services.slskd.user}:${config.services.slskd.group} ${slskd_env}
|
||||||
'';
|
'';
|
||||||
@ -67,6 +67,12 @@ in
|
|||||||
users.users.${config.services.jellyfin.user}.extraGroups = [ "music" ];
|
users.users.${config.services.jellyfin.user}.extraGroups = [ "music" ];
|
||||||
users.users.${username}.extraGroups = [ "music" ];
|
users.users.${username}.extraGroups = [ "music" ];
|
||||||
|
|
||||||
|
# Add agenix dependencies for slskd service
|
||||||
|
systemd.services.slskd = {
|
||||||
|
after = [ "agenix.service" ];
|
||||||
|
requires = [ "agenix.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"Z ${service_configs.music_dir} 0750 ${username} music"
|
"Z ${service_configs.music_dir} 0750 ${username} music"
|
||||||
"Z ${service_configs.slskd.base} 0750 ${config.services.slskd.user} ${config.services.slskd.group}"
|
"Z ${service_configs.slskd.base} 0750 ${config.services.slskd.user} ${config.services.slskd.group}"
|
||||||
|
|||||||
@ -2,13 +2,14 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
service_configs,
|
service_configs,
|
||||||
eth_interface,
|
eth_interface,
|
||||||
|
config,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
# network namespace that is proxied through mullvad
|
# network namespace that is proxied through mullvad
|
||||||
vpnNamespaces.wg = {
|
vpnNamespaces.wg = {
|
||||||
enable = true;
|
enable = true;
|
||||||
wireguardConfigFile = ../secrets/wg0.conf;
|
wireguardConfigFile = config.age.secrets.wg0-conf.path;
|
||||||
accessibleFrom = [
|
accessibleFrom = [
|
||||||
# "192.168.0.0/24"
|
# "192.168.0.0/24"
|
||||||
];
|
];
|
||||||
@ -20,13 +21,15 @@
|
|||||||
"network.target"
|
"network.target"
|
||||||
"jellyfin.service"
|
"jellyfin.service"
|
||||||
"qbittorrent.service"
|
"qbittorrent.service"
|
||||||
|
"agenix.service"
|
||||||
];
|
];
|
||||||
|
requires = [ "agenix.service" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
ExecStart = pkgs.writeShellScript "jellyfin-monitor-start" ''
|
ExecStart = pkgs.writeShellScript "jellyfin-monitor-start" ''
|
||||||
export JELLYFIN_API_KEY=$(cat ${../secrets/jellyfin-api-key})
|
export JELLYFIN_API_KEY=$(cat ${config.age.secrets.jellyfin-api-key.path})
|
||||||
exec ${
|
exec ${
|
||||||
pkgs.python3.withPackages (ps: with ps; [ requests ])
|
pkgs.python3.withPackages (ps: with ps; [ requests ])
|
||||||
}/bin/python ${./jellyfin-qbittorrent-monitor.py}
|
}/bin/python ${./jellyfin-qbittorrent-monitor.py}
|
||||||
|
|||||||
58
usb-secrets.nix
Normal file
58
usb-secrets.nix
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Extract USB secrets key in main system before agenix
|
||||||
|
systemd.services.usb-secrets = {
|
||||||
|
description = "Extract USB secrets key";
|
||||||
|
wantedBy = [ "sysinit.target" ];
|
||||||
|
before = [ "agenix.service" ];
|
||||||
|
wants = [ "local-fs.target" ];
|
||||||
|
after = [ "local-fs.target" ];
|
||||||
|
unitConfig.DefaultDependencies = false;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
mkdir -p /run/secrets /mnt/usb
|
||||||
|
|
||||||
|
# Check if key already exists
|
||||||
|
if [ -f /run/secrets/usb-secrets-key ]; then
|
||||||
|
echo "USB secrets key already loaded"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait for USB devices
|
||||||
|
for i in {1..30}; do
|
||||||
|
[ -e /dev/disk/by-label/SECRETS ] && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Mount USB and copy key
|
||||||
|
if mount /dev/disk/by-label/SECRETS /mnt/usb 2>/dev/null; then
|
||||||
|
if [ -f /mnt/usb/usb-secrets-key ]; then
|
||||||
|
install -m 600 /mnt/usb/usb-secrets-key /run/secrets/usb-secrets-key
|
||||||
|
umount /mnt/usb
|
||||||
|
echo "USB secrets key loaded"
|
||||||
|
else
|
||||||
|
umount /mnt/usb
|
||||||
|
echo "Key file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "USB not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
age.identityPaths = [ "/run/secrets/usb-secrets-key" ];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /run/secrets 0700 root root -"
|
||||||
|
];
|
||||||
|
}
|
||||||
44
usb-secrets/setup-usb.sh
Executable file
44
usb-secrets/setup-usb.sh
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#! nix-shell -i bash -p parted dosfstools
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||||
|
USB_DEVICE="$1"
|
||||||
|
if [[ -z "${USB_DEVICE:-}" ]]; then
|
||||||
|
echo "Usage: $0 <usb_device>"
|
||||||
|
echo "Example: $0 /dev/sdb"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -b "$USB_DEVICE" ]]; then
|
||||||
|
echo "Error: $USB_DEVICE is not a block device"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$SCRIPT_DIR/usb-secrets/usb-secrets-key" ]]; then
|
||||||
|
echo "Error: usb-secrets-key not found at $SCRIPT_DIR/usb-secrets/usb-secrets-key"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "WARNING: This will completely wipe $USB_DEVICE"
|
||||||
|
echo "Press Ctrl+C to abort, or Enter to continue..."
|
||||||
|
read
|
||||||
|
|
||||||
|
echo "Creating partition and formatting as FAT32..."
|
||||||
|
parted -s "$USB_DEVICE" mklabel msdos
|
||||||
|
parted -s "$USB_DEVICE" mkpart primary fat32 0% 100%
|
||||||
|
parted -s "$USB_DEVICE" set 1 boot on
|
||||||
|
|
||||||
|
USB_PARTITION="${USB_DEVICE}1"
|
||||||
|
mkfs.fat -F 32 -n "SECRETS" "$USB_PARTITION"
|
||||||
|
|
||||||
|
echo "Copying key to USB..."
|
||||||
|
MOUNT_POINT=$(mktemp -d)
|
||||||
|
trap "umount $MOUNT_POINT 2>/dev/null || true; rmdir $MOUNT_POINT" EXIT
|
||||||
|
|
||||||
|
mount "$USB_PARTITION" "$MOUNT_POINT"
|
||||||
|
cp "$SCRIPT_DIR/usb-secrets/usb-secrets-key" "$MOUNT_POINT/"
|
||||||
|
umount "$MOUNT_POINT"
|
||||||
|
|
||||||
|
echo "USB setup complete! Label: SECRETS"
|
||||||
|
echo "Create multiple backup USB keys for redundancy."
|
||||||
BIN
usb-secrets/usb-secrets/usb-secrets-key
Normal file
BIN
usb-secrets/usb-secrets/usb-secrets-key
Normal file
Binary file not shown.
1
usb-secrets/usb-secrets/usb-secrets-key.pub
Normal file
1
usb-secrets/usb-secrets/usb-secrets-key.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN8+eSX2LH5wEHVG9sSv97ceD5zdTarV0lRvoUso4A7p USB secrets decryption key
|
||||||
12
zfs.nix
12
zfs.nix
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
config,
|
||||||
service_configs,
|
service_configs,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
@ -10,13 +11,14 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
system.activationScripts = {
|
system.activationScripts = {
|
||||||
# TODO! replace with proper secrets management
|
# Copy decrypted ZFS key from agenix to expected location
|
||||||
|
# /etc is on tmpfs due to impermanence, so no persistent storage risk
|
||||||
"zfs-key".text = ''
|
"zfs-key".text = ''
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rm -fr ${zfs-key} || true
|
rm -f ${zfs-key} || true
|
||||||
cp ${./secrets/zfs-key} ${zfs-key}
|
cp ${config.age.secrets.zfs-key.path} ${zfs-key}
|
||||||
chmod 0500 ${zfs-key}
|
chmod 0400 ${zfs-key}
|
||||||
chown root:wheel ${zfs-key}
|
chown root:root ${zfs-key}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user