Set up firezone

This commit is contained in:
Natsu Kagami 2023-04-27 02:32:10 +02:00
parent 8d8052c5cc
commit 09b62faa4a
Signed by: nki
GPG key ID: 7306B3D3C3AD6E51
6 changed files with 157 additions and 10 deletions

View file

@ -0,0 +1,97 @@
{ pkgs, config, lib, ... }:
with lib;
let
cfg = config.cloud.firezone;
mkImage =
{ imageName, imageDigest, ... }: "${imageName}@${imageDigest}";
# If we can pullImage we can just do
# mkImage = pkgs.dockerTools.pullImage;
images = {
postgresql = mkImage {
imageName = "postgres";
finalImageTag = "15-alpine";
imageDigest = "sha256:07ec36ad2d5ab9250f38c8ef749239b662cf15d03c9ddb7167422edbbdf71156";
};
firezone = mkImage {
imageName = "firezone/firezone";
finalImageTag = "latest";
imageDigest = "sha256:76d869f322998432a09e3f3366f9f5908fe8b2f2968c80b4a60a1a78f879482f";
};
};
in
{
options.cloud.firezone = {
enable = mkEnableOption "Enable authentik OAuth server";
envFile = mkOption {
type = types.path;
description = "Path to an environment file that is generated by bin/gen_env";
};
httpPort = mkOption {
type = types.int;
description = "Exposed HTTP port";
default = 51880;
};
wireguardPort = mkOption {
type = types.int;
description = "Exposed Wireguard port";
default = 51821;
};
};
config = mkIf cfg.enable {
systemd.services.arion-firezone.serviceConfig.EnvironmentFile = cfg.envFile;
virtualisation.arion.projects.firezone.settings = {
services.postgres.service = {
image = images.postgresql;
restart = "unless-stopped";
healthcheck = {
test = [ "CMD-SHELL" "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}" ];
start_period = "20s";
interval = "30s";
retries = 5;
timeout = "5s";
};
volumes = [ "/var/lib/firezone/database:/var/lib/postgresql/data" ];
environment = {
POSTGRES_USER = "postgres";
POSTGRES_DB = "firezone";
POSTGRES_PASSWORD = "\${DATABASE_PASSWORD}";
};
networks = [ "firezone-network" ];
};
services.firezone.out.service.networks.firezone-network = {
ipv4_address = "172.25.0.100";
ipv6_address = "2001:3990:3990::99";
};
services.firezone.service = {
image = images.firezone;
restart = "unless-stopped";
volumes = [ "/var/lib/firezone/data:/var/firezone" ];
env_file = [ cfg.envFile ];
ports = [
"${toString cfg.httpPort}:13000"
"${toString cfg.wireguardPort}:51820/udp"
];
capabilities.NET_ADMIN = true;
capabilities.SYS_MODULE = true;
sysctls = {
"net.ipv6.conf.all.disable_ipv6" = 0;
"net.ipv4.ip_forward" = 1;
"net.ipv6.conf.all.forwarding" = 1;
};
depends_on = [ "postgres" ];
};
networks.firezone-network = {
enable_ipv6 = true;
driver = "bridge";
ipam.config = [
{ subnet = "172.25.0.0/16"; }
{ subnet = "2001:3990:3990::/64"; gateway = "2001:3990:3990::1"; }
];
};
};
};
}

26
modules/cloud/firezone/gen_env Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env sh
cat <<-EOF
VERSION=latest
EXTERNAL_URL=_CHANGE_ME_
DEFAULT_ADMIN_EMAIL=_CHANGE_ME_
DEFAULT_ADMIN_PASSWORD=$(openssl rand -base64 12)
GUARDIAN_SECRET_KEY=$(openssl rand -base64 48)
SECRET_KEY_BASE=$(openssl rand -base64 48)
LIVE_VIEW_SIGNING_SALT=$(openssl rand -base64 24)
COOKIE_SIGNING_SALT=$(openssl rand -base64 6)
COOKIE_ENCRYPTION_SALT=$(openssl rand -base64 6)
DATABASE_ENCRYPTION_KEY=$(openssl rand -base64 32)
DATABASE_PASSWORD=$(openssl rand -base64 12)
# The ability to change the IPv4 and IPv6 address pool will be removed
# in a future Firezone release in order to reduce the possible combinations
# of network configurations we need to handle.
#
# Due to the above, we recommend not changing these unless absolutely
# necessary.
WIREGUARD_IPV4_NETWORK=100.64.0.0/10
WIREGUARD_IPV4_ADDRESS=100.64.0.1
WIREGUARD_IPV6_NETWORK=fd00::/106
WIREGUARD_IPV6_ADDRESS=fd00::1
EOF

View file

@ -48,7 +48,7 @@ let
description = "The port that the service is listening on"; description = "The port that the service is listening on";
}; };
entrypoints = mkOption { entrypoints = mkOption {
type = listOf (enum [ "http" "https" "smtp-submission" "smtp-submission-ssl" "imap" ]); type = listOf (enum [ "http" "https" "smtp-submission" "smtp-submission-ssl" "imap" "wireguard" ]);
default = [ "https" ]; default = [ "https" ];
description = "The entrypoints that will serve the host"; description = "The entrypoints that will serve the host";
}; };
@ -58,7 +58,7 @@ let
description = "The middlewares to be used with the host."; description = "The middlewares to be used with the host.";
}; };
protocol = mkOption { protocol = mkOption {
type = enum [ "http" "tcp" ]; type = enum [ "http" "tcp" "udp" ];
default = "http"; default = "http";
description = "The protocol of the router and service"; description = "The protocol of the router and service";
}; };
@ -82,18 +82,18 @@ let
# Turns a host configuration into dynamic traefik configuration # Turns a host configuration into dynamic traefik configuration
hostToConfig = name: host: { hostToConfig = name: host: {
"${host.protocol}" = { "${host.protocol}" = {
routers."${name}-router" = { routers."${name}-router" = (if (host.protocol != "udp") then {
rule = filterOfHost host; rule = filterOfHost host;
entryPoints = host.entrypoints;
tls = { certResolver = "le"; } // (if host.protocol == "tcp" then { passthrough = if (host ? tlsPassthrough) then host.tlsPassthrough else true; } else { }); tls = { certResolver = "le"; } // (if host.protocol == "tcp" then { passthrough = if (host ? tlsPassthrough) then host.tlsPassthrough else true; } else { });
} else { }) // {
entryPoints = host.entrypoints;
service = "${name}-service"; service = "${name}-service";
} // ( } // (
if host.protocol == "http" then if host.protocol == "http" then
{ middlewares = lists.imap0 (id: m: "${name}-middleware-${toString id}") host.middlewares; } { middlewares = lists.imap0 (id: m: "${name}-middleware-${toString id}") host.middlewares; }
else if host.middlewares == [ ] then else if host.middlewares == [ ] then
{ } { }
else abort "Cannot have middlewares on tcp routers" else abort "Cannot have middlewares on non-http routers"
); );
services."${name}-service".loadBalancer.servers = [ services."${name}-service".loadBalancer.servers = [
( (

View file

@ -61,6 +61,8 @@ in
entrypoints.imap.address = ":993"; entrypoints.imap.address = ":993";
entrypoints.smtp-submission.address = ":587"; entrypoints.smtp-submission.address = ":587";
entrypoints.smtp-submission-ssl.address = ":465"; entrypoints.smtp-submission-ssl.address = ":465";
## Wireguard
entrypoints.wireguard.address = ":51820/udp";
# Logging # Logging
# ------- # -------
@ -84,5 +86,8 @@ in
# Set up firewall to allow traefik traffic. # Set up firewall to allow traefik traffic.
config.networking.firewall.allowedTCPPorts = [ 80 443 993 587 465 ]; config.networking.firewall.allowedTCPPorts = [ 80 443 993 587 465 ];
config.networking.firewall.allowedUDPPorts = [ 443 ]; # QUIC config.networking.firewall.allowedUDPPorts = [
443 # QUIC
51820 # Wireguard
];
} }

View file

@ -4,6 +4,7 @@
# Set up cloud # Set up cloud
../modules/cloud/authentik ../modules/cloud/authentik
../modules/cloud/firezone
../modules/cloud/postgresql ../modules/cloud/postgresql
../modules/cloud/traefik ../modules/cloud/traefik
../modules/cloud/bitwarden ../modules/cloud/bitwarden
@ -151,12 +152,29 @@
# Writefreely # Writefreely
cloud.writefreely.enable = true; cloud.writefreely.enable = true;
# Authentik (running under docker-compose T_T) # Authentik
sops.secrets.authentik-env = { }; sops.secrets.authentik-env = { };
cloud.authentik.enable = true; cloud.authentik.enable = true;
cloud.authentik.envFile = config.sops.secrets.authentik-env.path; cloud.authentik.envFile = config.sops.secrets.authentik-env.path;
cloud.traefik.hosts.authentik = { host = "auth.dtth.ch"; port = config.cloud.authentik.port; }; cloud.traefik.hosts.authentik = { host = "auth.dtth.ch"; port = config.cloud.authentik.port; };
# Firezone
sops.secrets.firezone-env = { };
cloud.firezone.enable = true;
cloud.firezone.envFile = config.sops.secrets.firezone-env.path;
cloud.traefik.hosts.firezone = {
host = "vpn.dtth.ch";
port = config.cloud.firezone.httpPort;
localHost = "127.0.0.1";
};
cloud.traefik.hosts.firezone-vpn = {
host = "vpn.dtth.ch";
port = config.cloud.firezone.wireguardPort;
entrypoints = [ "wireguard" ];
protocol = "udp";
};
# Outline # Outline
sops.secrets.minio-secret-key = { }; sops.secrets.minio-secret-key = { };
sops.secrets.authentik-oidc-client-secret = { owner = "outline"; }; sops.secrets.authentik-oidc-client-secret = { owner = "outline"; };

View file

@ -14,6 +14,7 @@ outline:
heisenbridge: ENC[AES256_GCM,data:rJY7gpcOY8nODR3KlYW1rEs54mKxr+AjNBeg1/2vTG0Gzpuvjgbnn5UVJS+P8uej/P4HfeFtlQSFZCEy8cXcwvwq97ppVliCGL4GMLRWaFmop35feC8t2ovh79cy/vKC7drASeGvWYNUmGRjboPuKA8W5LARa0HVDPGDLIEMVgJfYry/YKR3gsGmLzU7Mx1yLO6M/EFOJQJc84bSuu+CPSZcyUVF4SSNBiaDU5/NazlqaA9KWL6Xzu1MD2LEYdEFkRfitNgYj2m2gLd9voyGV4cfaCqJvYjJPwuZeZUoqCpDnom2JoV29q/Yq/gmyumPgOvriGxLsYBqV14MaCcE6KXE2uLicD+I/5or1AxepVDVjG9NoSgho1HpLvpRhMSCeXLk9+U+ykH3QA+0M+VVu9pswMMVQifnTtXZRM6pWxOnRVAzGf2tGDo4jy36S7pHaRn7SJcrljjWLfwHuNiu7E2uZhMrkcCjnjcBA9Xrb3drDQYVHya7XcoD4wOBHBDvVZwhYkNdkS3oYkom8A==,iv:fO1onfon3EdSNC/LjN1aWxpHBYq5aa0F/h0V6gl88ac=,tag:NL9p2nhIlEqgOdvUDM19Dg==,type:str] heisenbridge: ENC[AES256_GCM,data:rJY7gpcOY8nODR3KlYW1rEs54mKxr+AjNBeg1/2vTG0Gzpuvjgbnn5UVJS+P8uej/P4HfeFtlQSFZCEy8cXcwvwq97ppVliCGL4GMLRWaFmop35feC8t2ovh79cy/vKC7drASeGvWYNUmGRjboPuKA8W5LARa0HVDPGDLIEMVgJfYry/YKR3gsGmLzU7Mx1yLO6M/EFOJQJc84bSuu+CPSZcyUVF4SSNBiaDU5/NazlqaA9KWL6Xzu1MD2LEYdEFkRfitNgYj2m2gLd9voyGV4cfaCqJvYjJPwuZeZUoqCpDnom2JoV29q/Yq/gmyumPgOvriGxLsYBqV14MaCcE6KXE2uLicD+I/5or1AxepVDVjG9NoSgho1HpLvpRhMSCeXLk9+U+ykH3QA+0M+VVu9pswMMVQifnTtXZRM6pWxOnRVAzGf2tGDo4jy36S7pHaRn7SJcrljjWLfwHuNiu7E2uZhMrkcCjnjcBA9Xrb3drDQYVHya7XcoD4wOBHBDvVZwhYkNdkS3oYkom8A==,iv:fO1onfon3EdSNC/LjN1aWxpHBYq5aa0F/h0V6gl88ac=,tag:NL9p2nhIlEqgOdvUDM19Dg==,type:str]
matrix-discord-bridge: ENC[AES256_GCM,data:/rlSjD6inKfak7HKKghH5ays5RjKmb9czGsoIOYHyTZC4A5EMucCbfn8DL1gkYXgvRHJ+QglGX/BGo5ebaxSj6nF60+aW87UG31KggOt5kkMuWsPsjvrufoc5IlNfWnXIWmqf8cdC01hmHEp7biUpI8CcfEZiD9OkOxbZcRfYqW+ttnzplFniRBjGPVZfL5g4DBbuJen5MuOrrMDo5CT+78n,iv:r9VBbDCAAElisCaDehrB6PhJHsaaHjdrk3103lmBT7o=,tag:WoNMMfyMifsL56yWq3MUOg==,type:str] matrix-discord-bridge: ENC[AES256_GCM,data:/rlSjD6inKfak7HKKghH5ays5RjKmb9czGsoIOYHyTZC4A5EMucCbfn8DL1gkYXgvRHJ+QglGX/BGo5ebaxSj6nF60+aW87UG31KggOt5kkMuWsPsjvrufoc5IlNfWnXIWmqf8cdC01hmHEp7biUpI8CcfEZiD9OkOxbZcRfYqW+ttnzplFniRBjGPVZfL5g4DBbuJen5MuOrrMDo5CT+78n,iv:r9VBbDCAAElisCaDehrB6PhJHsaaHjdrk3103lmBT7o=,tag:WoNMMfyMifsL56yWq3MUOg==,type:str]
authentik-env: ENC[AES256_GCM,data:CjxTaqIcpBX7ea9L3tgJDELr8HBPJdxXsrOfhsiH4cXwCEzktsNKHjF7l95ZFgI5O08q4Vlbln5Dg4xPEx33nwUesEbQrT5d+n+2YaAxmm/WInrYzF+jB7HYTXASb3rY9PWgd2C3v+YPBkJetHlTUc/k19Q7lOQRNw==,iv:cG8Bi2eCsS+v94tSJBsqp+bjVLzXZvvwX1QVVSYExL8=,tag:VmbfcxCcfi3IpKjg3f8QPw==,type:str] authentik-env: ENC[AES256_GCM,data:CjxTaqIcpBX7ea9L3tgJDELr8HBPJdxXsrOfhsiH4cXwCEzktsNKHjF7l95ZFgI5O08q4Vlbln5Dg4xPEx33nwUesEbQrT5d+n+2YaAxmm/WInrYzF+jB7HYTXASb3rY9PWgd2C3v+YPBkJetHlTUc/k19Q7lOQRNw==,iv:cG8Bi2eCsS+v94tSJBsqp+bjVLzXZvvwX1QVVSYExL8=,tag:VmbfcxCcfi3IpKjg3f8QPw==,type:str]
firezone-env: ENC[AES256_GCM,data:D83cSNjwtoZ8wVXTHoqclHGFfydhwKyna7q1LMhHGS2nieF2Yg9vWDSDqrlKy7NklKNqgQ9rzZwdAmnSrFDiO7y4Le1N5vsLcPrL7JmIjS6yyh5tpMw4jjZkwEvwtSx+9hI6ec5beE9vOGceO0hCmN8zr0Tt6Wr8gUGrvMACF8mkFSatbowZi4RGvCEOjnPue66LQXGbVcAZX8jP7/UuIiqujiVsOI0xa1VwbpeAtQ9Pu+9JuMycpR7OcnXv2ImRZYGYYL1Fd/peXYIrwZiASYb4Yx3TsC88I4br+dVATicsP/k0O8FZCRL53CIogt44thAy8a/Gba1k9By92agLUlnJ0EUBB17JoQ/Ad8MQuR/F4s39ANAqztMig9oRfQBuNXb0HrBHBAGfgXLCzTw3wK/jiGwpQF5EMapT7jsZJFEFRIQLgI/uXaiuDtqd1evUljmtRwF35+8iqx1Jid+fM/kJ+aqx2B244L/8kEeRxqewY2eL0K7Tr+2LP0YQVsNFmvN6eY7DiA4m4jYBDlzUsBSRBIfj8oEvQML/STmmf4YqB8bPVQEEtKFwdRooDPqdozTGpaZlkEjAemUvI+xxe/8ZDq44uPswN154389gDRWO3fGPKmeRHx9HkMH8/6kMHiUnYnooqGnQ3SQdp+4v,iv:N0XBePOw2DYzN/GSBlza+sa3KwAZOrjavB++zrmqMAg=,tag:z0BA512TIgIxtQ4z40Zatg==,type:str]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
@ -47,8 +48,8 @@ sops:
by9kZFlTRVdCZFkxYTVVb0RIRk8zUlkKCqMw9oL9RaYBV5Hhy3o8Nm5xmGrPH8Sd by9kZFlTRVdCZFkxYTVVb0RIRk8zUlkKCqMw9oL9RaYBV5Hhy3o8Nm5xmGrPH8Sd
hv36sxRFFNZT/DCKaHaSRbT3mfpBZSTXJt1dgl4nZe6whH54t/1KmA== hv36sxRFFNZT/DCKaHaSRbT3mfpBZSTXJt1dgl4nZe6whH54t/1KmA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2023-04-26T19:50:09Z" lastmodified: "2023-04-26T22:43:56Z"
mac: ENC[AES256_GCM,data:QSS+gJoTtSwaB/seeo4QHEjdmzQ+qdYwmDtKWKV44KZnudHQuNYTlklKBC7gzLncOIaoPgQ04ZSlL/J4RSI4gLLrNuf+DkxX8OSIOv44U8ynBP/yWObgCPz8XjS38Jl9ovhLAPXYb6GK3DGl4q01ghXSpvfVsjCpz8W7SAVkVSA=,iv:Po0fPtu+gznmPalCm77RG3WloTKtRIEHLAec5lTYvaE=,tag:ulfUHDy1UAmj6d/R4kO42A==,type:str] mac: ENC[AES256_GCM,data:dWWck84crzDOwD8SlMjWarWn1ObcV4m7HJiS3+rpKdvjl4jYS5Nq5CXHwIY3YCsq63nelqLEjo8koas1wlEq4JsSYNpM1jVX5tjQia8wPjue6F5RNJdamfuQcctNEfqS4Wxo9HaxgpWrdRzpvTHzWfUjVn1UGGTnGArx8YeMQQ8=,iv:7CVQ01GQOPoqSkTi/o8XksOctGMpUJN06SxJy/nk88U=,tag:xDQoA8gQVt1mUFIj0k1aig==,type:str]
pgp: [] pgp: []
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.7.3 version: 3.7.3