machines/nix/modules/nixos/infrastructure/hetzner-instance/default.nix
Kaare Hoff Skovgaard cd8a0db1b6
Some checks failed
/ dev-shell (push) Successful in 1m8s
/ check (push) Failing after 1m29s
/ systems (push) Failing after 33s
/ rust-packages (push) Successful in 3m40s
/ terraform-providers (push) Successful in 5m13s
Begin reverting back to simple-nixos-mailserver
It appears I can get app passwords with kanidm and ldap
so just going to a more stable, probably supported setup,
should be good.
2025-07-28 12:02:24 +02:00

276 lines
7.1 KiB
Nix

{
config,
lib,
inputs,
...
}:
let
cfg = config.khscodes.infrastructure.hetzner-instance;
fqdn = config.khscodes.networking.fqdn;
provisioningUserData = config.khscodes.infrastructure.provisioning.instanceUserData;
firewallTcpRules = lib.lists.map (p: {
direction = "in";
protocol = "tcp";
port = p;
source_ips = [
"0.0.0.0/0"
"::/0"
];
}) config.networking.firewall.allowedTCPPorts;
firewallUdpRules = lib.lists.map (p: {
direction = "in";
protocol = "udp";
port = p;
source_ips = [
"0.0.0.0/0"
"::/0"
];
}) config.networking.firewall.allowedUDPPorts;
firewallIcmpRules = lib.lists.optional config.networking.firewall.allowPing {
direction = "in";
protocol = "icmp";
source_ips = [
"0.0.0.0/0"
"::/0"
];
description = "ping";
};
firewallRules =
firewallTcpRules
++ firewallUdpRules
++ firewallIcmpRules
++ cfg.extraFirewallRules
++ [
{
direction = "out";
protocol = "tcp";
port = 80;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "http";
}
{
direction = "out";
protocol = "tcp";
port = 443;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "http";
}
{
direction = "out";
protocol = "udp";
port = 443;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "quic";
}
{
direction = "out";
protocol = "udp";
port = 53;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "dns";
}
{
direction = "out";
protocol = "tcp";
port = 53;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "dns";
}
];
firewallEnable = config.networking.firewall.enable;
in
{
options.khscodes.infrastructure.hetzner-instance = {
enable = lib.mkEnableOption "enables generating a opentofu config";
dnsName = lib.mkOption {
type = lib.types.str;
default = fqdn;
};
dnsAliases = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = lib.lists.unique (
lib.lists.filter (alias: alias != cfg.dnsName) config.khscodes.networking.aliases
);
};
bucket = {
key = lib.mkOption {
type = lib.types.str;
description = "Key for use in the bucket";
default = "${fqdn}.tfstate";
};
};
datacenter = lib.mkOption {
type = lib.types.str;
description = "The Hetzner datacenter to create a server in";
default = "hel1-dc2";
};
mapRdns = lib.mkOption {
type = lib.types.bool;
description = "Sets up RDNS for the server";
default = false;
};
server_type = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "The server type to create";
default = null;
};
extraFirewallRules = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
description = "Extra firewall rules added to the instance";
default = [
{
direction = "out";
protocol = "tcp";
port = 80;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "http";
}
{
direction = "out";
protocol = "tcp";
port = 443;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "https";
}
{
direction = "out";
protocol = "udp";
port = 443;
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "quic";
}
{
direction = "out";
protocol = "icmp";
destination_ips = [
"0.0.0.0/0"
"::/0"
];
description = "Ping";
}
];
};
};
config = lib.mkIf cfg.enable (
let
labels = {
app = fqdn;
};
modules = [
(
{ config, ... }:
{
imports = [
inputs.self.terranixModules.cloudflare
inputs.self.terranixModules.hcloud
inputs.self.terranixModules.s3
];
config = {
khscodes.s3 = {
enable = true;
bucket.key = cfg.bucket.key;
};
khscodes.hcloud.data.ssh_key.khs = {
name = "ca.kaareskovgaard.net";
};
khscodes.hcloud.enable = true;
khscodes.hcloud.server.compute = {
inherit (cfg) server_type datacenter;
inherit labels;
name = fqdn;
initial_image = "debian-12";
rdns = lib.mkIf cfg.mapRdns fqdn;
ssh_keys = [ config.khscodes.hcloud.output.data.ssh_key.khs.id ];
user_data = builtins.toJSON provisioningUserData;
};
khscodes.cloudflare = {
enable = true;
dns = {
enable = true;
aRecords = [
{
fqdn = cfg.dnsName;
content = config.khscodes.hcloud.output.server.compute.ipv4_address;
}
];
aaaaRecords = [
{
fqdn = cfg.dnsName;
content = config.khscodes.hcloud.output.server.compute.ipv6_address;
}
];
cnameRecords = lib.lists.map (domain: {
fqdn = domain;
content = cfg.dnsName;
}) cfg.dnsAliases;
};
};
resource.hcloud_firewall.fw = lib.mkIf firewallEnable {
inherit labels;
name = fqdn;
apply_to = {
server = config.khscodes.hcloud.output.server.compute.id;
};
rule = firewallRules;
};
output.ipv4_address = {
value = config.khscodes.hcloud.output.server.compute.ipv4_address;
sensitive = false;
};
output.ipv6_address = {
value = config.khscodes.hcloud.output.server.compute.ipv6_address;
sensitive = false;
};
};
}
)
];
in
{
assertions = [
{
assertion = config.khscodes.networking.fqdn != null;
message = "Must set config.khscodes.networking.fqdn when using opentofu";
}
];
khscodes.services.openssh = {
enable = true;
hostCertificate = {
enable = true;
};
};
khscodes.services.read-vault-auth-from-userdata = {
url = "http://169.254.169.254/latest/user-data";
doubleDecodeJsonData = true;
};
khscodes.infrastructure.provisioning.pre = {
modules = modules;
};
}
);
}