summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseth <[email protected]>2023-12-11 19:08:10 -0500
committerseth <[email protected]>2023-12-12 22:43:30 -0500
commit03cea3ba8fea453fa5ca1611c7d8af152e2fcaaa (patch)
treec3f8895328329485714a5e51d928af1bf9892d46
parent988e00c510b1cc6b50e2211c4d0e8852463b1741 (diff)
start using opentofu
-rw-r--r--.env.template3
-rw-r--r--.envrc1
-rw-r--r--.github/dependabot.yml6
-rw-r--r--.github/workflows/deploy.yaml39
-rw-r--r--.gitignore4
-rw-r--r--.terraform.lock.hcl47
-rw-r--r--.terraformignore11
-rw-r--r--README.md1
-rw-r--r--dev.nix1
-rw-r--r--flake.lock30
-rw-r--r--flake.nix12
-rw-r--r--tofu/cloud.nix7
-rw-r--r--tofu/cloudflare/default.nix26
-rw-r--r--tofu/cloudflare/dns.nix64
-rw-r--r--tofu/cloudflare/ruleset.nix64
-rw-r--r--tofu/cloudflare/tunnels.nix11
-rw-r--r--tofu/default.nix54
-rw-r--r--tofu/deploy.nix15
-rw-r--r--tofu/tailscale/acl.nix27
-rw-r--r--tofu/tailscale/default.nix12
-rw-r--r--tofu/tailscale/devices.nix17
-rw-r--r--tofu/tailscale/dns.nix5
-rw-r--r--tofu/tailscale/tags.nix15
-rw-r--r--tofu/vars.nix11
-rw-r--r--tofu/versions.nix13
25 files changed, 493 insertions, 3 deletions
diff --git a/.env.template b/.env.template
new file mode 100644
index 0000000..4991713
--- /dev/null
+++ b/.env.template
@@ -0,0 +1,3 @@
+CLOUDFLARE_API_KEY=foo
+CLOUDFLARE_EMAIL=bar
+TAILSCALE_API_KEY=baz
diff --git a/.envrc b/.envrc
index 59dfc5d..eea1624 100644
--- a/.envrc
+++ b/.envrc
@@ -1,2 +1,3 @@
use flake
watch_file dev.nix
+dotenv_if_exists
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 1d662ce..2f4695a 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -6,3 +6,9 @@ updates:
interval: "weekly"
commit-message:
prefix: "actions"
+ - package-ecosystem: "terraform"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ commit-message:
+ prefix: "tofu"
diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index 34f4f26..0f3f1ed 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -1,4 +1,4 @@
-name: Deploy systems
+name: Deploy infrastructure
on:
check_suite:
@@ -6,7 +6,9 @@ on:
workflow_dispatch:
jobs:
- deploy:
+ nixos:
+ name: Deploy NixOS systems
+
runs-on: ubuntu-latest
concurrency:
@@ -46,3 +48,36 @@ jobs:
run: |
nix develop --accept-flake-config \
--command just deploy-all
+
+ opentofu:
+ name: Apply OpenTofu plan
+ needs: nixos
+
+ runs-on: ubuntu-latest
+
+ concurrency:
+ group: tofu
+ cancel-in-progress: true
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install Nix
+ uses: DeterminateSystems/nix-installer-action@v9
+
+ - name: Setup local Nix cache
+ uses: DeterminateSystems/magic-nix-cache-action@v2
+
+ - name: Setup OpenTofu
+ uses: opentofu/setup-opentofu@v1
+ with:
+ cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
+
+ - name: Setup OpenTofu cache
+ uses: terraform-cache/terraform-cache@v1
+
+ - name: Run plan
+ run: nix run .#plan
+
+ - name: Apply
+ run: tofu apply
diff --git a/.gitignore b/.gitignore
index a62b377..e45066e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,7 @@ repl-result-out*
.env*
!.envrc
!.env.template
+
+# opentofu
+.terraform/
+config.tf.json
diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl
new file mode 100644
index 0000000..4699bbf
--- /dev/null
+++ b/.terraform.lock.hcl
@@ -0,0 +1,47 @@
+# This file is maintained automatically by "tofu init".
+# Manual edits may be lost in future updates.
+
+provider "registry.opentofu.org/cloudflare/cloudflare" {
+ version = "4.20.0"
+ constraints = "~> 4.0"
+ hashes = [
+ "h1:KH92fiFCIurqU/qxsafm3mdnZSiXpr3fq9eoiLKiogo=",
+ "zh:22b06f598d4dac4131f69ca1c1e1ea5fd02d25019ccc99566d4ae8bf78e3996a",
+ "zh:29a85cf96a04f217a548a5e91c4e8eddd52563ce48872c44a449b2ade3a21260",
+ "zh:2ce0e98181c5a6b65a8ac930b816b94124fd7aee0ec4c5109a0a9acd28c3cf7b",
+ "zh:564f6396cf85b37a6a101d202bcc9e54590dbef27217c089c9f32a144f0a2b03",
+ "zh:618e2c40bc87bef36f12de8ec039faf973861d55c47bd125890737fbcb91fbee",
+ "zh:6e624f21eea8eeb25a13d96516a62f8879fd21ea21f17c0e933bccbc96da438e",
+ "zh:81ab073984a20c0a9480d98bf306d7f70bd781217bbaa68abd4ca1caab75db7d",
+ "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
+ "zh:9506a65591cc8cb0869f4023beb07ba6d02ddda073e17560867253d064cea308",
+ "zh:a4f9c859065ed8d626a479c68542153cd262d70551ae54bfe418092dc7e8d675",
+ "zh:a577841b5f33d556e2f1b2c453c78e7fa0c468edcad36b31d334f5671ce074cf",
+ "zh:ad17294bdfa79d117bda06cb21eb0a48f3785e45f2d4182a64f193466a34247a",
+ "zh:bb448bce29cb890b11fb48803d60367a34462bbe8954622e5424bedbcdf1477d",
+ "zh:e0749d864455a7b66953364371d715c94e44734cf8978a8c03ca2c73e212e88a",
+ "zh:e302c5222be4d5a1fcc59bff9e69c8f6dd7dff086b305af9b4fc9cbd2fd2c01c",
+ ]
+}
+
+provider "registry.opentofu.org/tailscale/tailscale" {
+ version = "0.13.13"
+ constraints = "0.13.13"
+ hashes = [
+ "h1:Fh799APNn48Jj2D29gcHh+HwLcA7wfAVIfMdkWyMoWw=",
+ "zh:07ee590ab8b568d65d52b401d15639ab0c23bda05e7b90f445a4159d7f9cecf8",
+ "zh:1bf72d550904475fbfc211295277d6afe0f3d0c98b89db7f718e2182febb0cd0",
+ "zh:26ef6e6f3a42cf5783d7aa5e1774b2fb86e0b01742349d4a5dee1164015163d9",
+ "zh:29c28fb821f6910cec4df54215b7338e180e44c0218ad16c63a0a8ecbb6307ab",
+ "zh:337d7548b8aeeeb7d6cd874601b237bb1db149c642fec416f2cb93513ac37070",
+ "zh:529f4fb1f54b3091ba32319ea766bfb7d49b7fb113d71bc89703155d8a1d5bdc",
+ "zh:541fafbe0124ceda9cf619d8248f6c1e7d5a45210604356f7896d447666f06ab",
+ "zh:5e1a66df1b891780a8aef54522ef1017952ca4f25103633d51b81bbe4b56b56a",
+ "zh:acdd72771d4cc7bb5465ea5d3eed56d86ee2b0b83b74549e8cd6dc4153222ef7",
+ "zh:beedd644c2db69829ec3850cd1aa3953c8c822820df16d97cf0c5b4891c03a2d",
+ "zh:c17fe2e6fe06f104d5150278500419f471d5d3b061dcd5673a6f6c915cc1cec0",
+ "zh:cc5805ae3f7f2495f7cf81655227fb68e18fc02d7fcc16896b57758a0f8611ae",
+ "zh:f18db5c7bf6707a5d358243a7dddfc69adf9b39ba0630206af5da6d89813b205",
+ "zh:f88f5b1e4c015b20a1bdf696df94f57bdfa69171ac0de149a586f89b17166010",
+ ]
+}
diff --git a/.terraformignore b/.terraformignore
new file mode 100644
index 0000000..c70390f
--- /dev/null
+++ b/.terraformignore
@@ -0,0 +1,11 @@
+result*
+repl-result-out*
+
+.pre-commit-config.yaml
+.direnv/
+.env*
+!.envrc
+!.env.template
+
+.terraform/
+.git/
diff --git a/README.md b/README.md
index 7f07641..ba9e4c9 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@ there are some amazing tools i use to make/manage this flake that i would highly
- [agenix](https://github.com/ryantm/agenix)
- [flake-parts](https://github.com/hercules-ci/flake-parts)
- [nixinate](https://github.com/MatthewCroughan/nixinate)
+- [terranix](https://github.com/terranix/terranix)
- [lanzaboote](https://github.com/nix-community/lanzaboote)
- [nixos-wsl](https://github.com/nix-community/nixos-wsl)
- [nix-openwrt-imagebuilder](https://github.com/astro/nix-openwrt-imagebuilder)
diff --git a/dev.nix b/dev.nix
index 86af47a..485ddae 100644
--- a/dev.nix
+++ b/dev.nix
@@ -33,6 +33,7 @@
fzf
just
jq
+ opentofu
]
++ lib.optional stdenv.isLinux inputs'.agenix.packages.agenix;
};
diff --git a/flake.lock b/flake.lock
index 3f624bf..c2670a1 100644
--- a/flake.lock
+++ b/flake.lock
@@ -555,7 +555,8 @@
"openwrt-imagebuilder": "openwrt-imagebuilder",
"parts": "parts",
"pre-commit": "pre-commit",
- "teawiebot": "teawiebot"
+ "teawiebot": "teawiebot",
+ "terranix": "terranix"
}
},
"rust-analyzer-src": {
@@ -644,6 +645,33 @@
"repo": "teawiebot",
"type": "github"
}
+ },
+ "terranix": {
+ "inputs": {
+ "bats-assert": [],
+ "bats-support": [],
+ "flake-utils": [
+ "pre-commit",
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "terranix-examples": []
+ },
+ "locked": {
+ "lastModified": 1695406838,
+ "narHash": "sha256-xiUfVD6rtsVWFotVtUW3Q1nQh4obKzgvpN1wqZuGXvM=",
+ "owner": "terranix",
+ "repo": "terranix",
+ "rev": "fc9077ca02ab5681935dbf0ecd725c4d889b9275",
+ "type": "github"
+ },
+ "original": {
+ "owner": "terranix",
+ "repo": "terranix",
+ "type": "github"
+ }
}
},
"root": "root",
diff --git a/flake.nix b/flake.nix
index 2e6ca6a..2ab2bc1 100644
--- a/flake.nix
+++ b/flake.nix
@@ -121,6 +121,17 @@
pre-commit.follows = "pre-commit";
};
};
+
+ terranix = {
+ url = "github:terranix/terranix";
+ inputs = {
+ nixpkgs.follows = "nixpkgs";
+ flake-utils.follows = "pre-commit/flake-utils";
+ terranix-examples.follows = "";
+ bats-support.follows = "";
+ bats-assert.follows = "";
+ };
+ };
};
outputs = {parts, ...} @ inputs:
@@ -131,6 +142,7 @@
./modules
./overlay
./systems
+ ./tofu
./users
./ci.nix
./dev.nix
diff --git a/tofu/cloud.nix b/tofu/cloud.nix
new file mode 100644
index 0000000..5ee0113
--- /dev/null
+++ b/tofu/cloud.nix
@@ -0,0 +1,7 @@
+{
+ terraform.cloud = {
+ hostname = "app.terraform.io";
+ organization = "getchoo";
+ workspaces.name = "flake";
+ };
+}
diff --git a/tofu/cloudflare/default.nix b/tofu/cloudflare/default.nix
new file mode 100644
index 0000000..c145cb0
--- /dev/null
+++ b/tofu/cloudflare/default.nix
@@ -0,0 +1,26 @@
+{lib, ...}: {
+ imports = [
+ ./dns.nix
+ ./ruleset.nix
+ ./tunnels.nix
+ ];
+
+ terraform.required_providers.cloudflare = {
+ source = "cloudflare/cloudflare";
+ version = "~> 4";
+ };
+
+ 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/tofu/cloudflare/dns.nix b/tofu/cloudflare/dns.nix
new file mode 100644
index 0000000..3371566
--- /dev/null
+++ b/tofu/cloudflare/dns.nix
@@ -0,0 +1,64 @@
+{lib, ...}: let
+ mkRecord = name: {
+ value,
+ type,
+ ...
+ } @ args:
+ {
+ name = args.name or name;
+ zone_id = "\${var.zone_id}";
+ inherit value type;
+ proxied = true;
+ }
+ // 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 = atlas_tunnel;
+ 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/tofu/cloudflare/ruleset.nix b/tofu/cloudflare/ruleset.nix
new file mode 100644
index 0000000..1be98aa
--- /dev/null
+++ b/tofu/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/tofu/cloudflare/tunnels.nix b/tofu/cloudflare/tunnels.nix
new file mode 100644
index 0000000..bea9811
--- /dev/null
+++ b/tofu/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/tofu/default.nix b/tofu/default.nix
new file mode 100644
index 0000000..4e6a425
--- /dev/null
+++ b/tofu/default.nix
@@ -0,0 +1,54 @@
+{inputs, ...}: {
+ perSystem = {
+ lib,
+ pkgs,
+ system,
+ ...
+ }: let
+ config = inputs.terranix.lib.terranixConfiguration {
+ inherit system;
+ modules = [
+ ./cloudflare
+ ./tailscale
+ ./cloud.nix
+ ./vars.nix
+ ./versions.nix
+ ];
+ };
+ in {
+ apps =
+ lib.genAttrs ["apply" "destroy" "plan"] (fn: {
+ type = "app";
+
+ program = pkgs.writeShellApplication {
+ name = fn;
+
+ runtimeInputs = [pkgs.opentofu];
+
+ text = ''
+ config_file="config.tf.json"
+ [ -e "$config_file" ] && rm -f "$config_file"
+ cp ${config} "$config_file"
+ tofu init && tofu ${fn}
+ '';
+ };
+ })
+ // {
+ tofu-config = {
+ type = "app";
+
+ program = pkgs.writeShellApplication {
+ name = "tofu-config";
+
+ runtimeInputs = [pkgs.opentofu];
+
+ text = ''
+ config_file="config.tf.json"
+ [ -e "$config_file" ] && rm -f "$config_file"
+ cp ${config} "$config_file"
+ '';
+ };
+ };
+ };
+ };
+}
diff --git a/tofu/deploy.nix b/tofu/deploy.nix
new file mode 100644
index 0000000..3f15713
--- /dev/null
+++ b/tofu/deploy.nix
@@ -0,0 +1,15 @@
+{
+ module.deploy_nixos = rec {
+ source = "github.com/nix-community/terraform-nixos//deploy_nixos?ref=646cacb12439ca477c05315a7bfd49e9832bc4e3";
+
+ build_on_target = "true";
+ flake = true;
+ hermetic = true;
+ ssh_agent = false;
+
+ nixos_config = "atlas";
+
+ target_user = "root";
+ target_host = nixos_config;
+ };
+}
diff --git a/tofu/tailscale/acl.nix b/tofu/tailscale/acl.nix
new file mode 100644
index 0000000..46503d8
--- /dev/null
+++ b/tofu/tailscale/acl.nix
@@ -0,0 +1,27 @@
+{lib, ...}: {
+ resource = {
+ tailscale_acl.main = {
+ 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/tofu/tailscale/default.nix b/tofu/tailscale/default.nix
new file mode 100644
index 0000000..2225fd5
--- /dev/null
+++ b/tofu/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/tofu/tailscale/devices.nix b/tofu/tailscale/devices.nix
new file mode 100644
index 0000000..44ee3f1
--- /dev/null
+++ b/tofu/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/tofu/tailscale/dns.nix b/tofu/tailscale/dns.nix
new file mode 100644
index 0000000..320a24b
--- /dev/null
+++ b/tofu/tailscale/dns.nix
@@ -0,0 +1,5 @@
+{
+ resource.tailscale_dns_preferences.default = {
+ magic_dns = true;
+ };
+}
diff --git a/tofu/tailscale/tags.nix b/tofu/tailscale/tags.nix
new file mode 100644
index 0000000..c519a25
--- /dev/null
+++ b/tofu/tailscale/tags.nix
@@ -0,0 +1,15 @@
+{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;
+ iphone-14.tags = tags.personal;
+ };
+}
diff --git a/tofu/vars.nix b/tofu/vars.nix
new file mode 100644
index 0000000..2f640c2
--- /dev/null
+++ b/tofu/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/tofu/versions.nix b/tofu/versions.nix
new file mode 100644
index 0000000..b563ce1
--- /dev/null
+++ b/tofu/versions.nix
@@ -0,0 +1,13 @@
+{
+ terraform.required_providers = {
+ cloudflare = {
+ source = "cloudflare/cloudflare";
+ version = "~> 4";
+ };
+
+ tailscale = {
+ source = "tailscale/tailscale";
+ version = "0.13.13";
+ };
+ };
+}