summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/default.nix6
-rw-r--r--ext/openwrt/default.nix13
-rw-r--r--ext/openwrt/turret/default.nix32
-rw-r--r--ext/openwrt/turret/files/etc/config/dhcp50
-rw-r--r--ext/openwrt/turret/files/etc/config/dropbear7
-rw-r--r--ext/openwrt/turret/files/etc/config/firewall131
-rw-r--r--ext/openwrt/turret/files/etc/config/https-dns-proxy16
-rw-r--r--ext/openwrt/turret/files/etc/config/luci41
-rw-r--r--ext/openwrt/turret/files/etc/config/network30
-rw-r--r--ext/openwrt/turret/files/etc/config/rpcd10
-rw-r--r--ext/openwrt/turret/files/etc/config/system16
-rw-r--r--ext/openwrt/turret/files/etc/config/ucitrack56
-rw-r--r--ext/openwrt/turret/files/etc/config/uhttpd31
-rw-r--r--ext/openwrt/turret/files/etc/config/wireless34
-rw-r--r--ext/openwrt/turret/files/etc/dropbear/authorized_keys1
-rw-r--r--ext/terranix/cloud.nix7
-rw-r--r--ext/terranix/cloudflare/default.nix21
-rw-r--r--ext/terranix/cloudflare/dns.nix64
-rw-r--r--ext/terranix/cloudflare/ruleset.nix64
-rw-r--r--ext/terranix/cloudflare/tunnels.nix11
-rw-r--r--ext/terranix/default.nix20
-rw-r--r--ext/terranix/tailscale/acl.nix25
-rw-r--r--ext/terranix/tailscale/default.nix12
-rw-r--r--ext/terranix/tailscale/devices.nix17
-rw-r--r--ext/terranix/tailscale/dns.nix5
-rw-r--r--ext/terranix/tailscale/tags.nix16
-rw-r--r--ext/terranix/vars.nix11
-rw-r--r--ext/terranix/versions.nix15
28 files changed, 762 insertions, 0 deletions
diff --git a/ext/default.nix b/ext/default.nix
new file mode 100644
index 0000000..1001f94
--- /dev/null
+++ b/ext/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./openwrt
+ ./terranix
+ ];
+}
diff --git a/ext/openwrt/default.nix b/ext/openwrt/default.nix
new file mode 100644
index 0000000..16f0fb9
--- /dev/null
+++ b/ext/openwrt/default.nix
@@ -0,0 +1,13 @@
+{
+ withSystem,
+ inputs,
+ ...
+}: {
+ flake.legacyPackages.x86_64-linux = withSystem "x86_64-linux" ({pkgs, ...}: {
+ openWrtImages = {
+ turret = pkgs.callPackage ./systems/turret {
+ inherit (inputs) openwrt-imagebuilder;
+ };
+ };
+ });
+}
diff --git a/ext/openwrt/turret/default.nix b/ext/openwrt/turret/default.nix
new file mode 100644
index 0000000..90ec750
--- /dev/null
+++ b/ext/openwrt/turret/default.nix
@@ -0,0 +1,32 @@
+{
+ pkgs,
+ openwrt-imagebuilder,
+ ...
+}: let
+ wrtProfiles = openwrt-imagebuilder.lib.profiles {
+ inherit pkgs;
+ release = "22.03.3";
+ };
+
+ image =
+ wrtProfiles.identifyProfile "netgear_wac104"
+ // {
+ packages = ["https-dns-proxy"];
+
+ files = pkgs.runCommand "image-files" {} ''
+ mkdir -p $out/etc/uci-defaults
+
+ cat > $out/etc/uci-defaults/99-custom <<EOF
+ uci -q batch << EOI
+ set system.@system[0].hostname='turret'
+ commit
+ EOI
+ EOF
+
+ # copy custom files
+ cp -fr ${./files}/* $out/
+ chmod 0644 $out/etc/{config,dropbear}/*
+ '';
+ };
+in
+ openwrt-imagebuilder.lib.build image
diff --git a/ext/openwrt/turret/files/etc/config/dhcp b/ext/openwrt/turret/files/etc/config/dhcp
new file mode 100644
index 0000000..f1ffd42
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/dhcp
@@ -0,0 +1,50 @@
+
+config dnsmasq
+ option domainneeded '1'
+ option localise_queries '1'
+ option rebind_protection '1'
+ option rebind_localhost '1'
+ option local '/lan/'
+ option domain 'lan'
+ option expandhosts '1'
+ option authoritative '1'
+ option readethers '1'
+ option leasefile '/tmp/dhcp.leases'
+ option localservice '1'
+ option ednspacket_max '1232'
+ option doh_backup_noresolv '-1'
+ option noresolv '1'
+ list doh_backup_server ''
+ list doh_backup_server '/mask.icloud.com/'
+ list doh_backup_server '/mask-h2.icloud.com/'
+ list doh_backup_server '/use-application-dns.net/'
+ list doh_backup_server '127.0.0.1#5054'
+ list doh_backup_server '127.0.0.1#5053'
+ list server '/mask.icloud.com/'
+ list server '/mask-h2.icloud.com/'
+ list server '/use-application-dns.net/'
+ list server '127.0.0.1#5054'
+ list server '127.0.0.1#5053'
+
+config dhcp 'lan'
+ option interface 'lan'
+ option start '100'
+ option limit '150'
+ option leasetime '12h'
+ option dhcpv4 'server'
+ option dhcpv6 'server'
+ option ra 'server'
+ option ra_slaac '1'
+ list ra_flags 'managed-config'
+ list ra_flags 'other-config'
+
+config dhcp 'wan'
+ option interface 'wan'
+ option ignore '1'
+
+config odhcpd 'odhcpd'
+ option maindhcp '0'
+ option leasefile '/tmp/hosts/odhcpd'
+ option leasetrigger '/usr/sbin/odhcpd-update'
+ option loglevel '4'
+
diff --git a/ext/openwrt/turret/files/etc/config/dropbear b/ext/openwrt/turret/files/etc/config/dropbear
new file mode 100644
index 0000000..95eb1d5
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/dropbear
@@ -0,0 +1,7 @@
+
+config dropbear
+ option Port '22'
+ option Interface 'lan'
+ option PasswordAuth 'off'
+ option RootPasswordAuth 'off'
+
diff --git a/ext/openwrt/turret/files/etc/config/firewall b/ext/openwrt/turret/files/etc/config/firewall
new file mode 100644
index 0000000..d4f7394
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/firewall
@@ -0,0 +1,131 @@
+
+config defaults
+ option syn_flood '1'
+ option input 'ACCEPT'
+ option output 'ACCEPT'
+ option forward 'REJECT'
+
+config zone
+ option name 'lan'
+ list network 'lan'
+ option input 'ACCEPT'
+ option output 'ACCEPT'
+ option forward 'ACCEPT'
+
+config zone
+ option name 'wan'
+ list network 'wan'
+ list network 'wan6'
+ option input 'REJECT'
+ option output 'ACCEPT'
+ option forward 'REJECT'
+ option masq '1'
+ option mtu_fix '1'
+
+config forwarding
+ option src 'lan'
+ option dest 'wan'
+
+config rule
+ option name 'Allow-DHCP-Renew'
+ option src 'wan'
+ option proto 'udp'
+ option dest_port '68'
+ option target 'ACCEPT'
+ option family 'ipv4'
+
+config rule
+ option name 'Allow-Ping'
+ option src 'wan'
+ option proto 'icmp'
+ option icmp_type 'echo-request'
+ option family 'ipv4'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-IGMP'
+ option src 'wan'
+ option proto 'igmp'
+ option family 'ipv4'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-DHCPv6'
+ option src 'wan'
+ option proto 'udp'
+ option dest_port '546'
+ option family 'ipv6'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-MLD'
+ option src 'wan'
+ option proto 'icmp'
+ option src_ip 'fe80::/10'
+ list icmp_type '130/0'
+ list icmp_type '131/0'
+ list icmp_type '132/0'
+ list icmp_type '143/0'
+ option family 'ipv6'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-ICMPv6-Input'
+ option src 'wan'
+ option proto 'icmp'
+ list icmp_type 'echo-request'
+ list icmp_type 'echo-reply'
+ list icmp_type 'destination-unreachable'
+ list icmp_type 'packet-too-big'
+ list icmp_type 'time-exceeded'
+ list icmp_type 'bad-header'
+ list icmp_type 'unknown-header-type'
+ list icmp_type 'router-solicitation'
+ list icmp_type 'neighbour-solicitation'
+ list icmp_type 'router-advertisement'
+ list icmp_type 'neighbour-advertisement'
+ option limit '1000/sec'
+ option family 'ipv6'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-ICMPv6-Forward'
+ option src 'wan'
+ option dest '*'
+ option proto 'icmp'
+ list icmp_type 'echo-request'
+ list icmp_type 'echo-reply'
+ list icmp_type 'destination-unreachable'
+ list icmp_type 'packet-too-big'
+ list icmp_type 'time-exceeded'
+ list icmp_type 'bad-header'
+ list icmp_type 'unknown-header-type'
+ option limit '1000/sec'
+ option family 'ipv6'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-IPSec-ESP'
+ option src 'wan'
+ option dest 'lan'
+ option proto 'esp'
+ option target 'ACCEPT'
+
+config rule
+ option name 'Allow-ISAKMP'
+ option src 'wan'
+ option dest 'lan'
+ option dest_port '500'
+ option proto 'udp'
+ option target 'ACCEPT'
+
+config redirect
+ option dest 'lan'
+ option target 'DNAT'
+ option name 'tf2'
+ option src 'wan'
+ option src_dport '37015'
+ option dest_ip '192.168.1.157'
+ option dest_port '37015'
+ option enabled '0'
+
diff --git a/ext/openwrt/turret/files/etc/config/https-dns-proxy b/ext/openwrt/turret/files/etc/config/https-dns-proxy
new file mode 100644
index 0000000..76e3c60
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/https-dns-proxy
@@ -0,0 +1,16 @@
+
+config main 'config'
+ option dnsmasq_config_update '*'
+ list force_dns_port '53'
+ list force_dns_port '853'
+ option procd_trigger_wan6 '0'
+ option force_dns '0'
+
+config https-dns-proxy
+ option bootstrap_dns '1.1.1.1,1.0.0.1'
+ option resolver_url 'https://cloudflare-dns.com/dns-query'
+ option listen_addr '127.0.0.1'
+ option listen_port '5054'
+ option user 'nobody'
+ option group 'nogroup'
+
diff --git a/ext/openwrt/turret/files/etc/config/luci b/ext/openwrt/turret/files/etc/config/luci
new file mode 100644
index 0000000..8eb8a9b
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/luci
@@ -0,0 +1,41 @@
+
+config core 'main'
+ option lang 'auto'
+ option mediaurlbase '/luci-static/bootstrap'
+ option resourcebase '/luci-static/resources'
+ option ubuspath '/ubus/'
+
+config extern 'flash_keep'
+ option uci '/etc/config/'
+ option dropbear '/etc/dropbear/'
+ option openvpn '/etc/openvpn/'
+ option passwd '/etc/passwd'
+ option opkg '/etc/opkg.conf'
+ option firewall '/etc/firewall.user'
+ option uploads '/lib/uci/upload/'
+
+config internal 'languages'
+
+config internal 'sauth'
+ option sessionpath '/tmp/luci-sessions'
+ option sessiontime '3600'
+
+config internal 'ccache'
+ option enable '1'
+
+config internal 'themes'
+ option Bootstrap '/luci-static/bootstrap'
+ option BootstrapDark '/luci-static/bootstrap-dark'
+ option BootstrapLight '/luci-static/bootstrap-light'
+
+config internal 'apply'
+ option rollback '90'
+ option holdoff '4'
+ option timeout '5'
+ option display '1.5'
+
+config internal 'diag'
+ option dns 'openwrt.org'
+ option ping 'openwrt.org'
+ option route 'openwrt.org'
+
diff --git a/ext/openwrt/turret/files/etc/config/network b/ext/openwrt/turret/files/etc/config/network
new file mode 100644
index 0000000..cb24fec
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/network
@@ -0,0 +1,30 @@
+
+config interface 'loopback'
+ option device 'lo'
+ option proto 'static'
+ option ipaddr '127.0.0.1'
+ option netmask '255.0.0.0'
+
+config globals 'globals'
+ option packet_steering '1'
+ option ula_prefix 'fd26:3166:dece::/48'
+
+config device
+ option name 'br-lan'
+ option type 'bridge'
+ list ports 'lan2'
+ list ports 'lan3'
+ list ports 'lan4'
+
+config interface 'lan'
+ option device 'br-lan'
+ option proto 'static'
+ option ipaddr '192.168.1.1'
+ option netmask '255.255.255.0'
+ option ip6assign '60'
+
+config interface 'wan'
+ option device 'lan1'
+ option proto 'dhcp'
+ option type 'bridge'
+
diff --git a/ext/openwrt/turret/files/etc/config/rpcd b/ext/openwrt/turret/files/etc/config/rpcd
new file mode 100644
index 0000000..176c643
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/rpcd
@@ -0,0 +1,10 @@
+config rpcd
+ option socket /var/run/ubus/ubus.sock
+ option timeout 30
+
+config login
+ option username 'root'
+ option password '$p$root'
+ list read '*'
+ list write '*'
+
diff --git a/ext/openwrt/turret/files/etc/config/system b/ext/openwrt/turret/files/etc/config/system
new file mode 100644
index 0000000..ee3415f
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/system
@@ -0,0 +1,16 @@
+
+config system
+ option hostname 'turret'
+ option timezone 'UTC'
+ option ttylogin '0'
+ option log_size '64'
+ option urandom_seed '0'
+ option compat_version '1.1'
+
+config timeserver 'ntp'
+ option enabled '1'
+ option enable_server '0'
+ list server '0.openwrt.pool.ntp.org'
+ list server '1.openwrt.pool.ntp.org'
+ list server '2.openwrt.pool.ntp.org'
+ list server '3.openwrt.pool.ntp.org'
diff --git a/ext/openwrt/turret/files/etc/config/ucitrack b/ext/openwrt/turret/files/etc/config/ucitrack
new file mode 100644
index 0000000..bb4cdbc
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/ucitrack
@@ -0,0 +1,56 @@
+config network
+ option init network
+ list affects dhcp
+
+config wireless
+ list affects network
+
+config firewall
+ option init firewall
+ list affects luci-splash
+ list affects qos
+ list affects miniupnpd
+
+config olsr
+ option init olsrd
+
+config dhcp
+ option init dnsmasq
+ list affects odhcpd
+
+config odhcpd
+ option init odhcpd
+
+config dropbear
+ option init dropbear
+
+config httpd
+ option init httpd
+
+config fstab
+ option exec '/sbin/block mount'
+
+config qos
+ option init qos
+
+config system
+ option init led
+ option exec '/etc/init.d/log reload'
+ list affects luci_statistics
+ list affects dhcp
+
+config luci_splash
+ option init luci_splash
+
+config upnpd
+ option init miniupnpd
+
+config ntpclient
+ option init ntpclient
+
+config samba
+ option init samba
+
+config tinyproxy
+ option init tinyproxy
+
diff --git a/ext/openwrt/turret/files/etc/config/uhttpd b/ext/openwrt/turret/files/etc/config/uhttpd
new file mode 100644
index 0000000..cb2ff71
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/uhttpd
@@ -0,0 +1,31 @@
+
+config uhttpd 'main'
+ list listen_http '0.0.0.0:80'
+ list listen_http '[::]:80'
+ list listen_https '0.0.0.0:443'
+ list listen_https '[::]:443'
+ option redirect_https '0'
+ option home '/www'
+ option rfc1918_filter '1'
+ option max_requests '3'
+ option max_connections '100'
+ option cert '/etc/uhttpd.crt'
+ option key '/etc/uhttpd.key'
+ option cgi_prefix '/cgi-bin'
+ list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
+ option script_timeout '60'
+ option network_timeout '30'
+ option http_keepalive '20'
+ option tcp_keepalive '1'
+ option ubus_prefix '/ubus'
+
+config cert 'defaults'
+ option days '730'
+ option key_type 'ec'
+ option bits '2048'
+ option ec_curve 'P-256'
+ option country 'ZZ'
+ option state 'Somewhere'
+ option location 'Unknown'
+ option commonname 'OpenWrt'
+
diff --git a/ext/openwrt/turret/files/etc/config/wireless b/ext/openwrt/turret/files/etc/config/wireless
new file mode 100644
index 0000000..115fc2c
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/config/wireless
@@ -0,0 +1,34 @@
+
+config wifi-device 'radio0'
+ option type 'mac80211'
+ option path '1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0'
+ option band '2g'
+ option disabled '0'
+ option cell_density '0'
+ option htmode 'HT20'
+ option channel 'auto'
+
+config wifi-iface 'default_radio0'
+ option device 'radio0'
+ option mode 'ap'
+ option ssid 'Box-2.4G'
+ option encryption 'psk2'
+ option key 'REPLACEME'
+ option network 'lan wan'
+
+config wifi-device 'radio1'
+ option type 'mac80211'
+ option path '1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0'
+ option band '5g'
+ option disabled '0'
+ option cell_density '0'
+ option htmode 'VHT80'
+ option channel 'auto'
+
+config wifi-iface 'default_radio1'
+ option device 'radio1'
+ option mode 'ap'
+ option ssid 'Box-5G'
+ option key 'REPLACEME'
+ option encryption 'psk2'
+ option network 'lan wan'
diff --git a/ext/openwrt/turret/files/etc/dropbear/authorized_keys b/ext/openwrt/turret/files/etc/dropbear/authorized_keys
new file mode 100644
index 0000000..495c605
--- /dev/null
+++ b/ext/openwrt/turret/files/etc/dropbear/authorized_keys
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIERx0I8DKtALZ9VrYnY1iBEpwl2pBlRiS8oJQvZwpl5e seth@glados
diff --git a/ext/terranix/cloud.nix b/ext/terranix/cloud.nix
new file mode 100644
index 0000000..5ee0113
--- /dev/null
+++ b/ext/terranix/cloud.nix
@@ -0,0 +1,7 @@
+{
+ terraform.cloud = {
+ hostname = "app.terraform.io";
+ organization = "getchoo";
+ workspaces.name = "flake";
+ };
+}
diff --git a/ext/terranix/cloudflare/default.nix b/ext/terranix/cloudflare/default.nix
new file mode 100644
index 0000000..80e8e39
--- /dev/null
+++ b/ext/terranix/cloudflare/default.nix
@@ -0,0 +1,21 @@
+{lib, ...}: {
+ imports = [
+ ./dns.nix
+ ./ruleset.nix
+ ./tunnels.nix
+ ];
+
+ resource = {
+ cloudflare_url_normalization_settings.incoming = {
+ scope = "incoming";
+ type = "cloudflare";
+ zone_id = lib.tfRef "var.zone_id";
+ };
+
+ cloudflare_bot_management.bots = {
+ enable_js = false;
+ fight_mode = false;
+ zone_id = lib.tfRef "var.zone_id";
+ };
+ };
+}
diff --git a/ext/terranix/cloudflare/dns.nix b/ext/terranix/cloudflare/dns.nix
new file mode 100644
index 0000000..9618019
--- /dev/null
+++ b/ext/terranix/cloudflare/dns.nix
@@ -0,0 +1,64 @@
+{lib, ...}: let
+ mkRecord = name: {
+ value,
+ type,
+ ...
+ } @ args:
+ {
+ name = args.name or name;
+ zone_id = lib.tfRef "var.zone_id";
+ ttl = 1;
+ inherit value type;
+ }
+ // lib.optionalAttrs (type != "TXT") {proxied = true;};
+
+ atlas_tunnel = lib.tfRef "data.cloudflare_tunnel.atlas-nginx.id" + ".cfargotunnel.com";
+in {
+ resource.cloudflare_record = builtins.mapAttrs mkRecord {
+ website = {
+ name = "@";
+ value = "website-86j.pages.dev";
+ type = "CNAME";
+ };
+
+ www = {
+ value = "mydadleft.me";
+ type = "CNAME";
+ };
+
+ api = {
+ value = "teawieapi.pages.dev";
+ type = "CNAME";
+ };
+
+ miniflux = {
+ value = atlas_tunnel;
+ type = "CNAME";
+ };
+
+ msix = {
+ value = atlas_tunnel;
+ type = "CNAME";
+ };
+
+ # prevent email spoofing
+
+ dmarc = {
+ name = "_dmarc";
+ value = "v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s;";
+ type = "TXT";
+ };
+
+ domainkey = {
+ name = "*._domainkey";
+ value = "v=DKIM1; p=";
+ type = "TXT";
+ };
+
+ email = {
+ name = "mydadleft.me";
+ value = "v=spf1 -all";
+ type = "TXT";
+ };
+ };
+}
diff --git a/ext/terranix/cloudflare/ruleset.nix b/ext/terranix/cloudflare/ruleset.nix
new file mode 100644
index 0000000..1be98aa
--- /dev/null
+++ b/ext/terranix/cloudflare/ruleset.nix
@@ -0,0 +1,64 @@
+{lib, ...}: {
+ resource.cloudflare_ruleset = {
+ default = {
+ kind = "zone";
+ name = "default";
+ phase = "http_config_settings";
+ zone_id = lib.tfRef "var.zone_id";
+
+ rules = [
+ {
+ action = "set_config";
+ action_parameters = {
+ automatic_https_rewrites = true;
+ email_obfuscation = true;
+ opportunistic_encryption = false;
+ };
+ description = "base redirects";
+ enabled = true;
+ expression = "true";
+ }
+ ];
+ };
+
+ redirect = {
+ kind = "zone";
+ name = "default";
+ phase = "http_request_dynamic_redirect";
+ zone_id = lib.tfRef "var.zone_id";
+
+ rules = [
+ {
+ action = "redirect";
+ action_parameters = {
+ from_value = {
+ preserve_query_string = false;
+ status_code = 301;
+ target_url = {
+ value = "https://www.youtube.com/watch?v=RvVdFXOFcjw";
+ };
+ };
+ };
+ description = "funny";
+ enabled = true;
+ expression = "(http.request.uri.path eq \"/hacks\" and http.host eq \"mydadleft.me\")";
+ }
+ {
+ action = "redirect";
+ action_parameters = {
+ from_value = {
+ preserve_query_string = false;
+ status_code = 301;
+ target_url = {
+ value = "https://www.youtube.com/watch?v=RvVdFXOFcjw";
+ };
+ };
+ };
+ description = "onlyfriends";
+ enabled = true;
+ expression = "(http.request.uri.path eq \"/onlyfriends\" and http.host eq \"mydadleft.me\")";
+ }
+ ];
+ };
+ };
+}
diff --git a/ext/terranix/cloudflare/tunnels.nix b/ext/terranix/cloudflare/tunnels.nix
new file mode 100644
index 0000000..bea9811
--- /dev/null
+++ b/ext/terranix/cloudflare/tunnels.nix
@@ -0,0 +1,11 @@
+{lib, ...}: {
+ data.cloudflare_tunnel =
+ lib.genAttrs
+ [
+ "atlas-nginx"
+ ]
+ (name: {
+ inherit name;
+ account_id = lib.tfRef "var.account_id";
+ });
+}
diff --git a/ext/terranix/default.nix b/ext/terranix/default.nix
new file mode 100644
index 0000000..b27e23d
--- /dev/null
+++ b/ext/terranix/default.nix
@@ -0,0 +1,20 @@
+{inputs, ...}: {
+ perSystem = {pkgs, ...}: {
+ terranix = {
+ builder = inputs.terranix.lib.terranixConfiguration;
+
+ package = pkgs.opentofu.withPlugins (plugins: [
+ plugins.cloudflare
+ plugins.tailscale
+ ]);
+
+ modules = [
+ ./cloudflare
+ ./tailscale
+ ./cloud.nix
+ ./vars.nix
+ ./versions.nix
+ ];
+ };
+ };
+}
diff --git a/ext/terranix/tailscale/acl.nix b/ext/terranix/tailscale/acl.nix
new file mode 100644
index 0000000..d27d3e1
--- /dev/null
+++ b/ext/terranix/tailscale/acl.nix
@@ -0,0 +1,25 @@
+{lib, ...}: {
+ resource.tailscale_acl.default = {
+ acl = toString (builtins.toJSON {
+ tagOwners = let
+ me = ["getchoo@github"];
+ tags = map (name: "tag:${name}") ["server" "personal" "gha"];
+ in
+ lib.genAttrs tags (_: me);
+
+ acls = let
+ mkAcl = action: src: dst: {inherit action src dst;};
+ in [
+ (mkAcl "accept" ["tag:personal"] ["*:*"])
+ (mkAcl "accept" ["tag:server" "tag:gha"] ["tag:server:*"])
+ ];
+
+ ssh = let
+ mkSshAcl = action: src: dst: users: {inherit action src dst users;};
+ in [
+ (mkSshAcl "accept" ["tag:personal"] ["tag:server" "tag:personal"] ["autogroup:nonroot" "root"])
+ (mkSshAcl "accept" ["tag:gha"] ["tag:server"] ["root"])
+ ];
+ });
+ };
+}
diff --git a/ext/terranix/tailscale/default.nix b/ext/terranix/tailscale/default.nix
new file mode 100644
index 0000000..2225fd5
--- /dev/null
+++ b/ext/terranix/tailscale/default.nix
@@ -0,0 +1,12 @@
+{lib, ...}: {
+ imports = [
+ ./acl.nix
+ ./devices.nix
+ ./dns.nix
+ ./tags.nix
+ ];
+
+ provider.tailscale = {
+ tailnet = lib.tfRef "var.tailnet";
+ };
+}
diff --git a/ext/terranix/tailscale/devices.nix b/ext/terranix/tailscale/devices.nix
new file mode 100644
index 0000000..44ee3f1
--- /dev/null
+++ b/ext/terranix/tailscale/devices.nix
@@ -0,0 +1,17 @@
+{lib, ...}: {
+ data.tailscale_device = let
+ toDevices = devices:
+ lib.genAttrs devices (name: {
+ name = "${name}.tailc59d6.ts.net";
+ wait_for = "60s";
+ });
+ in
+ toDevices [
+ "atlas"
+ "caroline"
+ "glados"
+ "glados-wsl"
+ "glados-windows"
+ "iphone-14"
+ ];
+}
diff --git a/ext/terranix/tailscale/dns.nix b/ext/terranix/tailscale/dns.nix
new file mode 100644
index 0000000..320a24b
--- /dev/null
+++ b/ext/terranix/tailscale/dns.nix
@@ -0,0 +1,5 @@
+{
+ resource.tailscale_dns_preferences.default = {
+ magic_dns = true;
+ };
+}
diff --git a/ext/terranix/tailscale/tags.nix b/ext/terranix/tailscale/tags.nix
new file mode 100644
index 0000000..a776756
--- /dev/null
+++ b/ext/terranix/tailscale/tags.nix
@@ -0,0 +1,16 @@
+{lib, ...}: {
+ resource.tailscale_device_tags = let
+ getDeviceID = device: lib.tfRef "data.tailscale_device.${device}.id";
+ toTags = n: v: {device_id = getDeviceID n;} // v;
+
+ tags = lib.genAttrs ["server" "personal" "gha"] (n: ["tag:${n}"]);
+ in
+ builtins.mapAttrs toTags {
+ atlas.tags = tags.server;
+ caroline.tags = tags.personal;
+ glados.tags = tags.personal;
+ glados-wsl.tags = tags.personal;
+ glados-windows.tags = tags.personal;
+ iphone-14.tags = tags.personal;
+ };
+}
diff --git a/ext/terranix/vars.nix b/ext/terranix/vars.nix
new file mode 100644
index 0000000..2f640c2
--- /dev/null
+++ b/ext/terranix/vars.nix
@@ -0,0 +1,11 @@
+{
+ variable = {
+ # cloudflare
+ zone_id.default = "53286ae07c44ed39e4b1249a2adb6d4d";
+ account_id.default = "44c47ae2d55db34c1bf2f378ea8202f1";
+ cf_domain.default = "mydadleft.me";
+
+ # tailscale
+ tailnet.default = "getchoo.github";
+ };
+}
diff --git a/ext/terranix/versions.nix b/ext/terranix/versions.nix
new file mode 100644
index 0000000..53bb5c6
--- /dev/null
+++ b/ext/terranix/versions.nix
@@ -0,0 +1,15 @@
+{lib, ...}: {
+ terraform.required_providers = let
+ registry = "registry.terraform.io";
+
+ fmtSource = _: value:
+ lib.recursiveUpdate value {
+ source = "${registry}/${value.source}";
+ };
+ in
+ lib.mapAttrs fmtSource {
+ cloudflare.source = "cloudflare/cloudflare";
+
+ tailscale.source = "tailscale/tailscale";
+ };
+}