new proxies config logic

This commit is contained in:
catvayor 2024-10-20 18:52:05 +02:00
parent f5115525c2
commit 063d092de9
Signed by: lbailly
GPG key ID: CE3E645251AC63F3
15 changed files with 290 additions and 335 deletions

View file

@ -1,234 +0,0 @@
{ lib, config, ... }:
with lib;
let
vm-module = {
options = {
ip = mkOption { type = types.str; };
ssh = mkOption {
type = types.nullOr types.ints.unsigned;
default = null;
};
aliases = mkOption {
type = types.listOf types.str;
default = [ ];
};
port-forward = mkOption {
type = types.listOf types.ints.unsigned;
default = [ ];
};
};
};
hypervisor-module =
{ config, name, ... }:
{
options = {
ip = mkOption { type = types.str; };
host = mkOption { type = types.str; };
vms = mkOption { type = types.attrsOf (types.submodule vm-module); };
port-forward = mkOption {
type = types.listOf types.ints.unsigned;
default = [ ];
};
domain-list = mkOption {
type = types.listOf types.str;
internal = true;
readOnly = true;
};
ports = mkOption {
type = types.listOf types.ints.unsigned;
internal = true;
readOnly = true;
};
redirects = mkOption {
type = types.unspecified;
internal = true;
readOnly = true;
};
};
config = rec {
domain-list = flatten (
mapAttrsToList (main: vm: [
main
vm.aliases
]) config.vms
);
ports =
config.port-forward
++ flatten (mapAttrsToList (_: vm: vm.port-forward ++ optional (!isNull vm.ssh) vm.ssh) config.vms);
redirects = {
stream = flatten (
mapAttrsToList (
_: vm:
optional (!isNull vm.ssh) {
input = vm.ssh;
out = 22;
ip = vm.ip;
}
++ map (port: {
input = port;
out = port;
ip = vm.ip;
}) vm.port-forward
) config.vms
);
http = mapAttrs (_: vm: { inherit (vm) ip aliases; }) config.vms;
domain-list = domain-list;
};
};
};
entry-module =
{ config, name, ... }:
{
options = {
host = mkOption { type = types.str; };
hypervisors = mkOption { type = types.attrsOf (types.submodule hypervisor-module); };
redirects = mkOption {
type = types.unspecified;
internal = true;
readOnly = true;
};
hosts-redirects = mkOption {
type = types.unspecified;
internal = true;
readOnly = true;
};
};
config = rec {
redirects = {
stream = flatten (
mapAttrsToList (
_: hyp:
map (port: {
input = port;
out = port;
ip = hyp.ip;
}) hyp.ports
) config.hypervisors
);
http = mapAttrs (_: hyp: {
ip = hyp.ip;
aliases = hyp.domain-list;
}) config.hypervisors;
domain-list = flatten (
mapAttrsToList (fqdn: hyp: [ fqdn ] ++ hyp.redirects.domain-list) config.hypervisors
);
};
hosts-redirects =
mergeAttrs
(listToAttrs (
mapAttrsToList (main: hyp: {
name = hyp.host;
value = {
fqdn = main;
inherit (hyp.redirects) stream http domain-list;
};
}) config.hypervisors
))
{
${config.host} = {
fqdn = name;
inherit (redirects) stream http domain-list;
};
};
};
};
cfg = config.kat-proxies;
hosts-redirects = zipAttrsWith (_: vals: mergeAttrsList vals) (
mapAttrsToList (_: entry: entry.hosts-redirects) cfg.entries
);
hostname = config.networking.hostName;
redirects = hosts-redirects.${hostname};
in
{
options.kat-proxies = {
enable = mkEnableOption "nginx configuration of proxies";
entries = mkOption { type = types.attrsOf (types.submodule entry-module); };
internal-webroot = mkOption { type = types.package; };
};
config = mkIf cfg.enable {
security.acme.certs.${redirects.fqdn}.extraDomainNames = redirects.domain-list;
networking.firewall.allowedTCPPorts = [
80
443
] ++ map ({ input, ... }: input) redirects.stream;
services.nginx = {
enable = true;
virtualHosts =
mapAttrs (
_:
{ aliases, ip }:
{
useACMEHost = redirects.fqdn;
forceSSL = true;
acmeFallbackHost = ip;
acmeFallbackRecommendedProxySettings = true;
serverAliases = aliases;
locations = {
"/.${hostname}" = {
extraConfig = ''
internal;
error_page 404 =418 /.${hostname}/error/418.html;
'';
root = cfg.internal-webroot;
};
"/" = {
recommendedProxySettings = true;
proxyPass = "https://${ip}/";
extraConfig = ''
proxy_set_header Connection ''';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
error_page 502 =599 "/.${hostname}/error/599.html";
'';
};
};
}
) redirects.http
// {
${redirects.fqdn} = {
default = true;
enableACME = true;
addSSL = true;
locations = {
"/.${hostname}" = {
extraConfig = ''
internal;
error_page 404 =418 /.${hostname}/error/418.html;
'';
root = cfg.internal-webroot;
};
"/" = {
extraConfig = ''
return 418;
error_page 418 =418 /.${hostname}/error/418.html;
'';
};
};
};
};
streamConfig = concatStringsSep "\n" (
map (
{
input,
ip,
out,
}:
''
server {
listen ${toString input};
listen [::]:${toString input};
proxy_pass ${ip}:${toString out};
}
''
) redirects.stream
);
};
};
}

View file

@ -1,42 +0,0 @@
{
kat-proxies.entries = {
"watcher.katvayor.net" = {
host = "kat-watcher";
hypervisors."manah.katvayor.net" = {
host = "kat-manah";
ip = "10.42.0.1";
port-forward = [ 9000 9500 ];
vms = {
"degette.katvayor.net" = {
ssh = 22000;
ip = "192.168.122.2";
aliases = [ ];
};
"betamail.katvayor.net" = {
ssh = 22002;
ip = "192.168.122.3";
aliases = [ "catvayor.sh" ];
port-forward = [
25
465
993
];
};
"son.katvayor.net" = {
ssh = null;
ip = "192.168.122.5";
aliases = [ ];
};
"orchid.katvayor.net" = {
ssh = 22042;
ip = "192.168.122.6";
aliases = [
"simply-wise.fr"
"www.simply-wise.fr"
];
};
};
};
};
};
}

View file

@ -33,8 +33,6 @@ in
./kat
"${sources.home-manager}/nixos"
"${sources.disko}/module.nix"
./domain-proxies-module.nix
./domain-proxies.nix
];
networking.hostName = name;
};
@ -59,6 +57,7 @@ in
{
deployment.targetHost = "manah.kat";
services.openssh.enable = true;
kat.fqdn = "manah.katvayor.net";
imports = [
./machines/kat-manah
];
@ -69,6 +68,7 @@ in
{
deployment.targetHost = "watcher.kat";
services.openssh.enable = true;
kat.fqdn = "watcher.katvayor.net";
imports = [
./machines/kat-watcher
];
@ -84,6 +84,7 @@ in
services.openssh.enable = true;
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0" ];
kat.fqdn = "degette.katvayor.net";
imports = [
./machines/kat-virt
@ -104,6 +105,7 @@ in
services.openssh.enable = true;
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0" ];
kat.fqdn = "betamail.katvayor.net";
imports = [
./machines/kat-mail-test
@ -121,6 +123,7 @@ in
services.openssh.enable = true;
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0" ];
kat.fqdn = "son.katvayor.net";
imports = [
./machines/kat-son
];
@ -136,6 +139,7 @@ in
services.openssh.enable = true;
services.qemuGuest.enable = true;
boot.kernelParams = [ "console=ttyS0" ];
kat.fqdn = "orchid.katvayor.net";
imports = [
./machines/kat-orchid
];

View file

@ -8,12 +8,16 @@ with lib;
{
imports = [
./users
./proxies
./root.nix
];
options.kat = {
wireguardPubKey = mkOption {
type = types.str;
};
fqdn = mkOption {
type = types.str;
};
path = mkOption {
readOnly = true;
type = types.path;

View file

@ -14,7 +14,7 @@
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
<br/>
<small>Error in watcher.</small>
<small>Error in config.hostname.</small>
</div>
</body>
</html>

View file

@ -9,13 +9,13 @@
<div role="main" align="center">
<h1>599 Network Connect Timeout Error</h1>
<img src="https://http.cat/599.jpg"/>
<p>Le contact avec l'hyperviseur n'a pas pu se faire.</p>
<p>Il y a eu un problème de connection dans une redirection.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
<br/>
<small>Error in watcher.</small>
<small>Error in config.hostname.</small>
</div>
</body>
</html>

224
kat/proxies/default.nix Normal file
View file

@ -0,0 +1,224 @@
{
pkgs,
lib,
config,
nodes ? { },
...
}:
with lib;
let
redirected-ports-mod.options = {
external = mkOption {
type = types.port;
};
internal = mkOption {
type = types.port;
};
};
redirection-port-type = types.coercedTo types.port (port: {
external = port;
internal = port;
}) (types.submodule redirected-ports-mod);
fqdn = config.kat.fqdn;
hostname = config.networking.hostName;
cfg = config.kat.proxies;
error-webroot = pkgs.runCommand "${hostname}-error-webroot" { } ''
mkdir $out
cp ${./418.html} $out/418.html
cp ${./599.html} $out/599.html
substituteInPlace $out/* \
--replace-fail 'config.hostname' "${hostname}"
'';
redirections =
lib.fold
(a: b: {
domains = a.domains ++ b.domains;
tcp = a.tcp ++ b.tcp;
udp = a.udp ++ b.udp;
vhosts = a.vhosts // b.vhosts;
})
{
domains = [ ];
tcp = [ ];
udp = [ ];
vhosts = { };
}
(
map (
host:
let
fqdn = nodes.${host}.config.kat.fqdn;
host-cfg = nodes.${host}.config.kat.proxies;
in
{
domains = [ fqdn ] ++ host-cfg.aliases;
tcp = map (
{ external, internal }:
{
input = external;
ip = host-cfg.ip;
out = internal;
}
) host-cfg.open-tcp;
udp = map (
{ external, internal }:
{
input = external;
ip = host-cfg.ip;
out = internal;
}
) host-cfg.open-udp;
vhosts.${fqdn} = {
ip = host-cfg.ip;
aliases = host-cfg.aliases;
};
}
) cfg.redirects
);
in
{
options.kat.proxies = {
enable = mkEnableOption "kat-proxies autoconfiguration" // {
default = cfg.redirects != [ ];
defaultText = ''config.kat.proxies.redirects != [ ]'';
};
ip = mkOption {
type = types.str;
};
aliases = mkOption {
type = types.listOf types.str;
default = [ ];
};
open-tcp = mkOption {
type = types.listOf redirection-port-type;
default = [ ];
};
open-udp = mkOption {
type = types.listOf redirection-port-type;
default = [ ];
};
redirects = mkOption {
type = types.listOf types.str;
default = [ ];
};
test = mkOption {
type = types.raw;
};
};
config = mkIf cfg.enable {
kat.proxies = {
test = redirections;
aliases = redirections.domains;
open-tcp = map ({ input, ... }: input) redirections.tcp;
open-udp = map ({ input, ... }: input) redirections.udp;
};
networking.firewall = {
allowedTCPPorts = [
80
443
] ++ map ({ internal, ... }: internal) cfg.open-tcp;
allowedUDPPorts = map ({ internal, ... }: internal) cfg.open-udp;
};
security.acme.certs.${fqdn}.extraDomainNames = cfg.aliases;
services.nginx = {
enable = true;
virtualHosts =
mapAttrs (
_:
{ aliases, ip }:
{
useACMEHost = fqdn;
forceSSL = true;
acmeFallbackHost = ip;
acmeFallbackRecommendedProxySettings = true;
serverAliases = aliases;
locations = {
"/.${hostname}/" = {
extraConfig = ''
internal;
error_page 404 =418 /.${hostname}/418.html;
'';
alias = "${error-webroot}/";
};
"/" = {
recommendedProxySettings = true;
proxyPass = "https://${ip}/";
extraConfig = ''
proxy_set_header Connection ''';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
error_page 502 =599 "/.${hostname}/599.html";
'';
};
};
}
) redirections.vhosts
// {
${fqdn} = {
default = true;
enableACME = true;
addSSL = true;
locations = {
"/.${hostname}/" = {
extraConfig = ''
internal;
error_page 404 =418 /.${hostname}/418.html;
'';
alias = "${error-webroot}/";
};
"/" = {
extraConfig = ''
return 418;
error_page 418 =418 /.${hostname}/418.html;
'';
};
};
};
};
streamConfig = concatStringsSep "\n" (
map (
{
input,
ip,
out,
}:
''
server {
listen ${toString input};
listen [::]:${toString input};
proxy_pass ${ip}:${toString out};
}
''
) redirections.tcp
++ map (
{
input,
ip,
out,
}:
''
server {
listen ${toString input} udp;
listen [::]:${toString input} udp;
proxy_pass ${ip}:${toString out};
}
''
) redirections.udp
);
};
};
}

View file

@ -17,6 +17,20 @@ in
./modo.nix
];
kat.proxies = {
ip = "192.168.122.3";
aliases = [ "catvayor.sh" ];
open-tcp = [
{
internal = 22;
external = 22002;
}
25
465
993
];
};
boot.loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;

View file

@ -69,12 +69,18 @@
acceptTerms = true;
defaults.email = "root@katvayor.net";
};
kat-proxies = {
enable = true;
internal-webroot = pkgs.runCommand "manah" { } ''
mkdir -p $out/.kat-manah/
ln -nsf ${./error} $out/.kat-manah/error
'';
kat.proxies = {
ip = "10.42.0.1";
open-tcp = [
9000
9500
];
redirects = [
"kat-orchid"
"kat-son"
"kat-virt"
"kat-mail-test"
];
};
services.weechat = {

View file

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>418 Im a teapot</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>418 Im a teapot</h1>
<img src="https://http.cat/418.jpg"/>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
<br/>
<small>Error in manah.</small>
</div>
</body>
</html>

View file

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>599 Network Connect Timeout Error</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>599 Network Connect Timeout Error</h1>
<img src="https://http.cat/599.jpg"/>
<p>Le contact avec la vm n'a pas pu se faire.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
<br/>
<small>Error in manah.</small>
</div>
</body>
</html>

View file

@ -16,6 +16,20 @@
efi.canTouchEfiVariables = true;
};
kat.proxies = {
ip = "192.168.122.6";
aliases = [
"simply-wise.fr"
"www.simply-wise.fr"
];
open-tcp = [
{
internal = 22;
external = 22042;
}
];
};
systemd.network.enable = lib.mkForce false;
networking = {
useNetworkd = lib.mkForce false;

View file

@ -15,6 +15,8 @@
efi.canTouchEfiVariables = true;
};
kat.proxies.ip = "192.168.122.5";
systemd.network.enable = lib.mkForce false;
networking = {
useNetworkd = lib.mkForce false;

View file

@ -12,6 +12,16 @@
efi.canTouchEfiVariables = true;
};
kat.proxies = {
ip = "192.168.122.2";
open-tcp = [
{
internal = 22;
external = 22000;
}
];
};
systemd.network.enable = lib.mkForce false;
networking = {
useNetworkd = lib.mkForce false;

View file

@ -100,13 +100,7 @@
acceptTerms = true;
defaults.email = "root@katvayor.net";
};
kat-proxies = {
enable = true;
internal-webroot = pkgs.runCommand "watcher" { } ''
mkdir -p $out/.kat-watcher/
ln -nsf ${./error} $out/.kat-watcher/error
'';
};
kat.proxies.redirects = [ "kat-manah" ];
environment.systemPackages = with pkgs; [ tcpdump ];