This commit is contained in:
Shelvacu
2024-10-23 19:12:43 -07:00
parent 79c4c5ada6
commit aee5440fde
15 changed files with 303 additions and 217 deletions

View File

@@ -1,4 +1,5 @@
{ lib, config, ... }:{ { lib, config, ... }:
{
imports = [ imports = [
./makeWrapper.nix ./makeWrapper.nix
]; ];

View File

@@ -4,55 +4,90 @@
... ...
}: }:
let let
inherit (lib) optionals optional mapAttrsFlatten concatMap escapeShellArg escapeShellArgs; inherit (lib)
optionals
optional
mapAttrsFlatten
concatMap
escapeShellArg
escapeShellArgs
;
in in
{ {
config.vacu.vaculib.makeWrapper = { config.vacu.vaculib.makeWrapper =
original, {
new, original,
argv0 ? null, new,
inherit_argv0 ? false, argv0 ? null,
resolve_argv0 ? false, inherit_argv0 ? false,
set ? {}, resolve_argv0 ? false,
set_default ? {}, set ? { },
unset ? [], set_default ? { },
chdir ? null, unset ? [ ],
run ? [], chdir ? null,
prepend_flags ? [], run ? [ ],
add_flags ? [], prepend_flags ? [ ],
append_flags ? [], add_flags ? [ ],
}@args: let append_flags ? [ ],
prependFlags = prepend_flags ++ add_flags; }@args:
escapeFlags = flags: builtins.concatStringsSep " " (map escapeShellArg flags); let
originalBin = if lib.isDerivation original then lib.getExe original else original; prependFlags = prepend_flags ++ add_flags;
makeWrapperFlags = escapeFlags = flags: builtins.concatStringsSep " " (map escapeShellArg flags);
(optionals (argv0 != null) [ "--argv0" argv0]) ++ originalBin = if lib.isDerivation original then lib.getExe original else original;
(optional inherit_argv0 "--inherit-argv0") ++ makeWrapperFlags =
(optional resolve_argv0 "--resolve-argv0") ++ (optionals (argv0 != null) [
(mapAttrsFlatten (k: v: [ "--set" k v ] ) set) ++ "--argv0"
(mapAttrsFlatten (k: v: [ "--set-default" k v ] ) set_default) ++ argv0
(concatMap (k: [ "--unset" k ]) unset) ++ ])
(optionals (chdir != null) [ "--chdir" chdir ]) ++ ++ (optional inherit_argv0 "--inherit-argv0")
(concatMap (k: [ "--run" k ]) run) ++ ++ (optional resolve_argv0 "--resolve-argv0")
(optionals (prependFlags != []) [ "--add-flags" (escapeFlags prependFlags) ]) ++ ++ (mapAttrsFlatten (k: v: [
(optionals (append_flags != []) [ "--append-flags" (escapeFlags append_flags) ]) "--set"
; k
in pkgs.stdenvNoCC.mkDerivation { v
name = new; ]) set)
++ (mapAttrsFlatten (k: v: [
"--set-default"
k
v
]) set_default)
++ (concatMap (k: [
"--unset"
k
]) unset)
++ (optionals (chdir != null) [
"--chdir"
chdir
])
++ (concatMap (k: [
"--run"
k
]) run)
++ (optionals (prependFlags != [ ]) [
"--add-flags"
(escapeFlags prependFlags)
])
++ (optionals (append_flags != [ ]) [
"--append-flags"
(escapeFlags append_flags)
]);
in
pkgs.stdenvNoCC.mkDerivation {
name = new;
nativeBuildInputs = [ pkgs.makeWrapper ]; nativeBuildInputs = [ pkgs.makeWrapper ];
phases = [ "installPhase" ]; phases = [ "installPhase" ];
installPhase = '' installPhase = ''
runHook preInstall runHook preInstall
mkdir -p $out/bin mkdir -p $out/bin
makeWrapper ${escapeShellArg originalBin} $out/bin/${escapeShellArg new} ${escapeShellArgs makeWrapperFlags} makeWrapper ${escapeShellArg originalBin} $out/bin/${escapeShellArg new} ${escapeShellArgs makeWrapperFlags}
runHook postInstall runHook postInstall
''; '';
meta.mainProgram = new; meta.mainProgram = new;
}; };
} }

View File

@@ -26,7 +26,10 @@ let
wrappedBashPkg = vaculib.makeWrapper { wrappedBashPkg = vaculib.makeWrapper {
original = pkgs.bash; original = pkgs.bash;
new = "vacuinit-bash"; new = "vacuinit-bash";
prepend_flags = [ "--init-file" vacuInitFile ]; prepend_flags = [
"--init-file"
vacuInitFile
];
}; };
wrappedBash = lib.getExe wrappedBashPkg; wrappedBash = lib.getExe wrappedBashPkg;
in in

View File

@@ -9,36 +9,38 @@ let
userKeys = lib.attrValues config.vacu.ssh.authorizedKeys; userKeys = lib.attrValues config.vacu.ssh.authorizedKeys;
liamKey = config.vacu.ssh.knownHosts.liam.publicKey; liamKey = config.vacu.ssh.knownHosts.liam.publicKey;
ssh-to-age = lib.getExe pkgs.ssh-to-age; ssh-to-age = lib.getExe pkgs.ssh-to-age;
sopsConfig = pkgs.runCommand "sops.yaml" { env.sshUserKeys = lib.concatStringsSep "\n" userKeys; } '' sopsConfig =
set -xe pkgs.runCommand "sops.yaml" { env.sshUserKeys = lib.concatStringsSep "\n" userKeys; }
liamKey="$(echo "${liamKey}" | ${ssh-to-age})" ''
declare -a userKeys set -xe
mapfile -t userKeys < <(echo "$sshUserKeys" | ${ssh-to-age}) liamKey="$(echo "${liamKey}" | ${ssh-to-age})"
declare -p userKeys declare -a userKeys
cat <<END >> $out mapfile -t userKeys < <(echo "$sshUserKeys" | ${ssh-to-age})
creation_rules: declare -p userKeys
- path_regex: ^secrets/misc/ cat <<END >> $out
key_groups: creation_rules:
- age: - path_regex: ^secrets/misc/
END key_groups:
for k in "''${userKeys[@]}"; do - age:
echo " - $k" >> $out END
done for k in "''${userKeys[@]}"; do
cat <<END >> $out echo " - $k" >> $out
- path_regex: ^secrets/liam/ done
key_groups: cat <<END >> $out
- age: - path_regex: ^secrets/liam/
- $liamKey key_groups:
END - age:
for k in "''${userKeys[@]}"; do - $liamKey
echo " - $k" >> $out END
done for k in "''${userKeys[@]}"; do
cat <<END >> $out echo " - $k" >> $out
- path_regex: ^tests/test_secrets done
key_groups: cat <<END >> $out
- age: age1eqv5759uknu7d46rqyyzsmgt43qumsge33yp2xygapprnt8zu3sqx6kt8w - path_regex: ^tests/test_secrets
END key_groups:
''; - age: age1eqv5759uknu7d46rqyyzsmgt43qumsge33yp2xygapprnt8zu3sqx6kt8w
END
'';
in in
{ {
options.vacu.sopsConfig = mkOption { options.vacu.sopsConfig = mkOption {

View File

@@ -38,7 +38,7 @@ in
#vacu.ssh.authorizedKeys = mkOption { type = types.listOf types.str; }; #vacu.ssh.authorizedKeys = mkOption { type = types.listOf types.str; };
vacu.ssh.authorizedKeys = mkOption { vacu.ssh.authorizedKeys = mkOption {
type = types.attrsOf types.str; type = types.attrsOf types.str;
default = {}; default = { };
}; };
vacu.ssh.config = mkOption { type = types.lines; }; vacu.ssh.config = mkOption { type = types.lines; };
# Straight copied from nixpkgs # Straight copied from nixpkgs

View File

@@ -99,11 +99,15 @@
x86 = "x86_64-linux"; x86 = "x86_64-linux";
arm = "aarch64-linux"; arm = "aarch64-linux";
lib = import "${nixpkgs}/lib"; lib = import "${nixpkgs}/lib";
mkPkgs = arg: mkPkgs =
arg:
let let
argAttr = if builtins.isString arg then { system = arg; } else arg; argAttr = if builtins.isString arg then { system = arg; } else arg;
config = { allowUnfree = true; } // (argAttr.config or {}); config = {
in import nixpkgs (argAttr // { inherit config; }); allowUnfree = true;
} // (argAttr.config or { });
in
import nixpkgs (argAttr // { inherit config; });
pkgs = mkPkgs x86; pkgs = mkPkgs x86;
mkNixosConfig = mkNixosConfig =
{ {
@@ -349,7 +353,9 @@
# snmpb = pkgs.libsForQt5.callPackage ./packages/snmpb/package.nix { }; # snmpb = pkgs.libsForQt5.callPackage ./packages/snmpb/package.nix { };
# snmp-mibs-downloader = pkgs.callPackage ./packages/snmp-mibs-downloader.nix { }; # snmp-mibs-downloader = pkgs.callPackage ./packages/snmp-mibs-downloader.nix { };
authorizedKeys = pkgs.writeText "authorizedKeys" ( authorizedKeys = pkgs.writeText "authorizedKeys" (
lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${v} ${k}") plain.config.vacu.ssh.authorizedKeys) lib.concatStringsSep "\n" (
lib.mapAttrsToList (k: v: "${v} ${k}") plain.config.vacu.ssh.authorizedKeys
)
); );
sopsConfig = plain.config.vacu.sopsConfig; sopsConfig = plain.config.vacu.sopsConfig;
nixvim = inputs.nixvim.legacyPackages.${system}.makeNixvimWithModule { nixvim = inputs.nixvim.legacyPackages.${system}.makeNixvimWithModule {

View File

@@ -4,7 +4,13 @@
... ...
}: }:
let let
inherit (lib.strings) concatStringsSep splitString match replaceStrings concatStrings; inherit (lib.strings)
concatStringsSep
splitString
match
replaceStrings
concatStrings
;
inherit (lib.lists) reverseList length elemAt; inherit (lib.lists) reverseList length elemAt;
email_folders = [ email_folders = [
"24nm-domain@shelvacu.com" "24nm-domain@shelvacu.com"

View File

@@ -3,7 +3,7 @@
writers, writers,
curl, curl,
sops, sops,
lib lib,
}: }:
let let
sopsCommand = [ sopsCommand = [
@@ -21,7 +21,7 @@ let
]; ];
in in
writers.writeScriptBin "update-gitea-keys" '' writers.writeScriptBin "update-gitea-keys" ''
age_key=$(ssh-to-age -private-key -i $HOME/.ssh/id_ed25519) age_key=$(ssh-to-age -private-key -i $HOME/.ssh/id_ed25519)
gitea_api_key="$(SOPS_AGE_KEY="$age_key" sops --config ${../.sops.yaml} --extract '["git.uninsane.org"]' -d ${../secrets/misc/git-keys.json})" gitea_api_key="$(SOPS_AGE_KEY="$age_key" sops --config ${../.sops.yaml} --extract '["git.uninsane.org"]' -d ${../secrets/misc/git-keys.json})"
curl curl
'' ''

View File

@@ -22,17 +22,17 @@ let
(lib.filter (c: c.enable)) (lib.filter (c: c.enable))
]; ];
serviceValidDomainAssertions = map (proxiedConfig: { serviceValidDomainAssertions = map (proxiedConfig: {
assertion = lib.any (availableDomain: assertion = lib.any (
(lib.hasSuffix ("." + availableDomain) proxiedConfig.domain) || availableDomain:
(proxiedConfig.domain == availableDomain) (lib.hasSuffix ("." + availableDomain) proxiedConfig.domain)
|| (proxiedConfig.domain == availableDomain)
) domains; ) domains;
message = "proxiedService ${proxiedConfig.name}'s `domain` does not match any of the known domains"; message = "proxiedService ${proxiedConfig.name}'s `domain` does not match any of the known domains";
}) proxied; }) proxied;
mapListToAttrs = f: list: lib.listToAttrs (map f list); mapListToAttrs = f: list: lib.listToAttrs (map f list);
in in
{ {
assertions = [ ] assertions = [ ] ++ serviceValidDomainAssertions;
++ serviceValidDomainAssertions;
security.acme.acceptTerms = true; security.acme.acceptTerms = true;
security.acme.defaults = { security.acme.defaults = {
email = "nix-acme@shelvacu.com"; email = "nix-acme@shelvacu.com";
@@ -44,8 +44,8 @@ in
postRun = "${pkgs.nixos-container}/bin/nixos-container run frontproxy -- systemctl reload haproxy"; postRun = "${pkgs.nixos-container}/bin/nixos-container run frontproxy -- systemctl reload haproxy";
}; };
security.acme.certs = mapListToAttrs (domain: security.acme.certs = mapListToAttrs (
lib.nameValuePair domain { extraDomainNames = [ "*.${domain}" ]; } domain: lib.nameValuePair domain { extraDomainNames = [ "*.${domain}" ]; }
) domains; ) domains;
users.groups.acme.gid = 993; users.groups.acme.gid = 993;
@@ -69,10 +69,13 @@ in
autoStart = true; autoStart = true;
restartIfChanged = true; restartIfChanged = true;
ephemeral = true; ephemeral = true;
bindMounts = mapListToAttrs (d: lib.nameValuePair "/certs/${d}" { bindMounts = mapListToAttrs (
hostPath = outer_config.security.acme.certs.${d}.directory; d:
isReadOnly = true; lib.nameValuePair "/certs/${d}" {
}) domains; hostPath = outer_config.security.acme.certs.${d}.directory;
isReadOnly = true;
}
) domains;
config = config =
{ config, ... }: { config, ... }:
{ {

View File

@@ -6,93 +6,103 @@
}: }:
let let
enableKeylog = false; enableKeylog = false;
cleanName = name: lib.replaceStrings ["-" " "] [ "_" "_" ] name; cleanName =
name:
lib.replaceStrings
[
"-"
" "
]
[
"_"
"_"
]
name;
aclName = config: "host_" + (cleanName config.name); aclName = config: "host_" + (cleanName config.name);
backendName = config: "backend_" + (cleanName config.name); backendName = config: "backend_" + (cleanName config.name);
concatMap = sep: f: list: lib.concatStringsSep sep (map f list); concatMap =
sep: f: list:
lib.concatStringsSep sep (map f list);
mapLines = f: list: concatMap "\n" f list; mapLines = f: list: concatMap "\n" f list;
certs = concatMap " " (d: "crt /certs/${d}/full.pem") domains; certs = concatMap " " (d: "crt /certs/${d}/full.pem") domains;
in in
'' ''
${lib.optionalString enableKeylog '' ${lib.optionalString enableKeylog ''
# ssl keylogging # ssl keylogging
global
tune.ssl.keylog on
lua-load ${./sslkeylog.lua}
''}
global global
tune.ssl.keylog on close-spread-time 1s
lua-load ${./sslkeylog.lua} hard-stop-after 3s
''} description "triple-dezert frontproxy"
no insecure-fork-wanted
global log stdout format short daemon
close-spread-time 1s numa-cpu-mapping
hard-stop-after 3s tune.listener.default-shards by-thread
description "triple-dezert frontproxy" tune.ssl.lifetime 24h
no insecure-fork-wanted zero-warning
log stdout format short daemon log 127.0.0.1 syslog debug
numa-cpu-mapping
tune.listener.default-shards by-thread
tune.ssl.lifetime 24h
zero-warning
log 127.0.0.1 syslog debug
defaults defaults
# https://world.hey.com/goekesmi/haproxy-chrome-tcp-preconnect-and-error-408-a-post-preserved-from-the-past-2497d1f7 # https://world.hey.com/goekesmi/haproxy-chrome-tcp-preconnect-and-error-408-a-post-preserved-from-the-past-2497d1f7
timeout server 30s timeout server 30s
timeout client 10s timeout client 10s
timeout connect 10s timeout connect 10s
option http-ignore-probes option http-ignore-probes
timeout tunnel 1h timeout tunnel 1h
log global log global
mode http
option httplog
frontend main
bind :80
bind :443 ssl ${certs}
mode http
acl has_sni ssl_fc_sni -m found
acl has_host_hdr req.fhdr(host) -m found
http-request set-var(req.host) req.fhdr(host),host_only
# Check whether the client is attempting domain fronting.
acl ssl_sni_http_host_match ssl_fc_sni,strcmp(req.host) eq 0
${mapLines (c:
'' acl ${aclName c} var(req.host) -m str "${c.domain}"''
) proxied}
http-after-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" if { ssl_fc }
http-request deny status 400 if !{ req.fhdr_cnt(host) eq 1 }
http-request deny status 421 if has_sni has_host_hdr !ssl_sni_http_host_match
http-request return lf-string "%ci\n" content-type text/plain if { var(req.host) -m str "shelvacu.com" } { path /ip }
http-request redirect scheme https code 301 if !{ ssl_fc }
# garunteed ssl-only from here on
${mapLines (d:
'' http-request redirect location "https://${d}%[capture.req.uri]" code 301 if { var(req.host) -m str "www.${d}" }''
) domains}
http-request return string "Shelvacu is awesome" content-type text/plain if { path / } { var(req.host) -m str "shelvacu.com" }
http-request return string "Jean-luc is awesome" content-type text/plain if { path / } { var(req.host) -m str "jean-luc.org" }
${mapLines (c:
'' http-request allow if ${aclName c}''
) proxied}
http-request return status 404 string "not found" content-type text/plain
${mapLines (c:
'' use_backend ${backendName c} if ${aclName c}''
) proxied}
${concatMap "\n\n" (c:
''
backend ${backendName c}
mode http mode http
${lib.optionalString c.forwardFor "option forwardfor"} option httplog
server main ${c.name}:${builtins.toString c.port} check maxconn ${builtins.toString c.maxConnections} ${if c.useSSL then "ssl verify none ssl-reuse" else "proto h1"}
'' frontend main
) proxied} bind :80
bind :443 ssl ${certs}
mode http
acl has_sni ssl_fc_sni -m found
acl has_host_hdr req.fhdr(host) -m found
http-request set-var(req.host) req.fhdr(host),host_only
# Check whether the client is attempting domain fronting.
acl ssl_sni_http_host_match ssl_fc_sni,strcmp(req.host) eq 0
${mapLines (c: ''acl ${aclName c} var(req.host) -m str "${c.domain}"'') proxied}
http-after-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" if { ssl_fc }
http-request deny status 400 if !{ req.fhdr_cnt(host) eq 1 }
http-request deny status 421 if has_sni has_host_hdr !ssl_sni_http_host_match
http-request return lf-string "%ci\n" content-type text/plain if { var(req.host) -m str "shelvacu.com" } { path /ip }
http-request redirect scheme https code 301 if !{ ssl_fc }
# garunteed ssl-only from here on
${
mapLines (
d:
''http-request redirect location "https://${d}%[capture.req.uri]" code 301 if { var(req.host) -m str "www.${d}" }''
) domains
}
http-request return string "Shelvacu is awesome" content-type text/plain if { path / } { var(req.host) -m str "shelvacu.com" }
http-request return string "Jean-luc is awesome" content-type text/plain if { path / } { var(req.host) -m str "jean-luc.org" }
${mapLines (c: ''http-request allow if ${aclName c}'') proxied}
http-request return status 404 string "not found" content-type text/plain
${mapLines (c: ''use_backend ${backendName c} if ${aclName c}'') proxied}
${concatMap "\n\n" (c: ''
backend ${backendName c}
mode http
${lib.optionalString c.forwardFor "option forwardfor"}
server main ${c.name}:${builtins.toString c.port} check maxconn ${builtins.toString c.maxConnections} ${
if c.useSSL then "ssl verify none ssl-reuse" else "proto h1"
}
'') proxied}
'' ''

View File

@@ -3,12 +3,14 @@ let
inherit (lib) mkOption types; inherit (lib) mkOption types;
outerConfig = config; outerConfig = config;
ip4Segment = ''[0-9]{1,3}''; ip4Segment = ''[0-9]{1,3}'';
ip4Address = types.addCheck ip4Address = types.addCheck (types.strMatching (
(types.strMatching (lib.concatStringsSep ''\.'' [ip4Segment ip4Segment ip4Segment ip4Segment])) lib.concatStringsSep ''\.'' [
(s: ip4Segment
lib.all (p: (lib.toInt p) < 255) (lib.splitString "." s) ip4Segment
) ip4Segment
; ip4Segment
]
)) (s: lib.all (p: (lib.toInt p) < 255) (lib.splitString "." s));
# Note: This accepts plenty of strings that aren't valid ipv6 addresses, this is just to catch when you accidentally put an ipv4 or something else in # Note: This accepts plenty of strings that aren't valid ipv6 addresses, this is just to catch when you accidentally put an ipv4 or something else in
ip6Address = types.strMatching ''([a-fA-F0-9]{4}::?){1,7}[a-fA-F0-9]{4}''; ip6Address = types.strMatching ''([a-fA-F0-9]{4}::?){1,7}[a-fA-F0-9]{4}'';
ipAddress = types.either ip4Address ip6Address; ipAddress = types.either ip4Address ip6Address;
@@ -16,41 +18,58 @@ in
{ {
# vacu.proxiedServices.habitat # vacu.proxiedServices.habitat
options.vacu.proxiedServices = mkOption { options.vacu.proxiedServices = mkOption {
default = {}; default = { };
type = types.attrsOf (types.submodule ({name, config, ...}: { type = types.attrsOf (
options = { types.submodule (
enable = mkOption { type = types.bool; default = false; }; { name, config, ... }:
{
options = {
enable = mkOption {
type = types.bool;
default = false;
};
name = mkOption { name = mkOption {
default = name; default = name;
type = types.str; type = types.str;
}; };
fromContainer = mkOption { fromContainer = mkOption {
default = null; default = null;
type = types.nullOr types.str; type = types.nullOr types.str;
}; };
port = mkOption { type = types.port; }; port = mkOption { type = types.port; };
ipAddress = mkOption { ipAddress = mkOption {
type = ipAddress; type = ipAddress;
}; };
domain = mkOption { type = types.str; }; domain = mkOption { type = types.str; };
forwardFor = mkOption { type = types.bool; default = false; }; forwardFor = mkOption {
type = types.bool;
default = false;
};
maxConnections = mkOption { type = types.int; default = 500; }; maxConnections = mkOption {
type = types.int;
default = 500;
};
useSSL = mkOption { type = types.bool; default = false; }; useSSL = mkOption {
}; type = types.bool;
default = false;
};
};
config = lib.mkMerge [ config = lib.mkMerge [
(lib.mkIf (config.fromContainer != null) { (lib.mkIf (config.fromContainer != null) {
ipAddress = outerConfig.containers.${config.fromContainer}.localAddress; ipAddress = outerConfig.containers.${config.fromContainer}.localAddress;
}) })
]; ];
})); }
)
);
}; };
} }

View File

@@ -1,4 +1,5 @@
{ ... }: { { ... }:
{
vacu.proxiedServices.habitat = { vacu.proxiedServices.habitat = {
domain = "habitat.pwrhs.win"; domain = "habitat.pwrhs.win";
ipAddress = "10.78.79.114"; ipAddress = "10.78.79.114";

View File

@@ -1,5 +1,6 @@
{ {
config, ... config,
...
}: }:
let let
contain = config.containers.llm; contain = config.containers.llm;

View File

@@ -25,13 +25,12 @@
isReadOnly = true; isReadOnly = true;
}; };
config = config = {
{ system.stateVersion = "23.11";
system.stateVersion = "23.11"; networking.firewall.enable = false;
networking.firewall.enable = false;
services.nginx.enable = true; services.nginx.enable = true;
services.nginx.virtualHosts."tulpaudcast.jean-luc.org".root = "/static-stuff/tulpaudcast.jean-luc.org"; services.nginx.virtualHosts."tulpaudcast.jean-luc.org".root = "/static-stuff/tulpaudcast.jean-luc.org";
}; };
}; };
} }