From 784e35bf553bc7f426aa2f663db6d32121431590 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Sun, 26 Dec 2021 22:37:57 -0500 Subject: feat(grfn/bbbg): Production deployment Start of a production deployment of the app with nixos+terraform, using provisioners and null-resources to provision nixos machines a'la espes. Change-Id: I2ddaed76d0037dadbf9fc9e2ee27e9e67a852228 Reviewed-on: https://cl.tvl.fyi/c/depot/+/4695 Reviewed-by: grfn Autosubmit: grfn Tested-by: BuildkiteCI --- users/grfn/bbbg/default.nix | 5 +- users/grfn/bbbg/shell.nix | 9 ++ users/grfn/bbbg/tf.nix | 93 ++++++++++++++++ users/grfn/secrets/bbbg.age | 20 ++-- users/grfn/secrets/cloudflare.age | 16 +-- users/grfn/secrets/secrets.nix | 3 +- users/grfn/terraform/globals.nix | 24 ++++ users/grfn/terraform/nixosMachine.nix | 203 ++++++++++++++++++++++++++++++++++ users/grfn/terraform/workspace.nix | 104 +++++++++++++++++ 9 files changed, 458 insertions(+), 19 deletions(-) create mode 100644 users/grfn/bbbg/tf.nix create mode 100644 users/grfn/terraform/globals.nix create mode 100644 users/grfn/terraform/nixosMachine.nix create mode 100644 users/grfn/terraform/workspace.nix diff --git a/users/grfn/bbbg/default.nix b/users/grfn/bbbg/default.nix index 90f112bf2866..5b5b4badbf4b 100644 --- a/users/grfn/bbbg/default.nix +++ b/users/grfn/bbbg/default.nix @@ -1,4 +1,4 @@ -{ depot, pkgs, ... }: +args@{ depot, pkgs, ... }: with pkgs.lib; @@ -12,6 +12,7 @@ in rec { meta.targets = [ "db-util" "server" + "tf" ]; depsPaths = deps.makePaths {}; @@ -75,4 +76,6 @@ in rec { server = pkgs.writeShellScriptBin "bbbg-server" '' exec ${pkgs.openjdk17_headless}/bin/java -jar ${server-jar} "$@" ''; + + tf = import ./tf.nix args; } diff --git a/users/grfn/bbbg/shell.nix b/users/grfn/bbbg/shell.nix index 195562519ed4..48bcd73759d0 100644 --- a/users/grfn/bbbg/shell.nix +++ b/users/grfn/bbbg/shell.nix @@ -11,6 +11,15 @@ mkShell { openjdk11_headless postgresql_12 nix-prefetch-git + (writeShellScriptBin "terraform" '' + set -e + module=$(nix-build ~/code/depot -A users.grfn.bbbg.tf.module) + rm -f ~/tfstate/bbbg/*.json + cp ''${module}/*.json ~/tfstate/bbbg + exec ${depot.users.grfn.bbbg.tf.terraform}/bin/terraform \ + -chdir=/home/grfn/tfstate/bbbg \ + "$@" + '') ]; PGHOST = "localhost"; diff --git a/users/grfn/bbbg/tf.nix b/users/grfn/bbbg/tf.nix new file mode 100644 index 000000000000..71f07d343501 --- /dev/null +++ b/users/grfn/bbbg/tf.nix @@ -0,0 +1,93 @@ +{ depot, ... }: + +let + inherit (depot.users.grfn) + terraform + ; + +in terraform.workspace "bbbg" { + plugins = (p: with p; [ + aws + cloudflare + ]); +} { + machine = terraform.nixosMachine { + name = "bbbg"; + instanceType = "t3a.small"; + rootVolumeSizeGb = 250; + extraIngressPorts = [ 80 443 ]; + configuration = { pkgs, lib, config, depot, ... }: { + imports = [ + ./module.nix + "${depot.third_party.agenix.src}/modules/age.nix" + ]; + + services.openssh.enable = true; + + services.nginx = { + enable = true; + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + }; + + networking.firewall.enable = false; + + programs.zsh.enable = true; + + users.users.grfn = { + isNormalUser = true; + initialPassword = "password"; + extraGroups = [ + "wheel" + "networkmanager" + "audio" + "docker" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ + depot.users.grfn.keys.main + ]; + }; + + security.sudo.extraRules = [{ + groups = ["wheel"]; + commands = [{ command = "ALL"; options = ["NOPASSWD"]; }]; + }]; + + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + + age.secrets = { + bbbg.file = + depot.users.grfn.secrets."bbbg.age"; + }; + + services.bbbg.enable = true; + services.bbbg.database.enable = true; + services.bbbg.proxy.enable = true; + services.bbbg.domain = "bbbg.gws.fyi"; + + security.acme.email = "root@gws.fyi"; + security.acme.acceptTerms = true; + }; + }; + + dns = { + data.cloudflare_zone.gws-fyi = { + name = "gws.fyi"; + }; + + resource.cloudflare_record.bbbg = { + zone_id = "\${data.cloudflare_zone.gws-fyi.id}"; + name = "bbbg"; + type = "A"; + value = "\${aws_instance.bbbg_machine.public_ip}"; + proxied = false; + }; + }; +} diff --git a/users/grfn/secrets/bbbg.age b/users/grfn/secrets/bbbg.age index d2d4c7362597..6c15dcdf7361 100644 --- a/users/grfn/secrets/bbbg.age +++ b/users/grfn/secrets/bbbg.age @@ -1,10 +1,12 @@ age-encryption.org/v1 --> ssh-ed25519 CpJBgQ dHPaZt3ZRV6rBPQrqiEpKXd48OjUC1joVIm/ZHcimVQ -Q8JwGJ91nsxspJFwZaq2BENdJYHxdHG30Ef0/Cae58M --> ssh-ed25519 LfBFbQ oN98wLqM69Kv2Ldg31v0eBNtfpNP4nbyqAC+gCOT3yI -U8weIdIqhGs2eoKXqCxO8zHe2Ddo5fVJ5ZYua/hcBs8 --> \Z^u8-grease ., ,^=lH#0> +P=Z," d -fwUdQTFyoVYOmMUWN2nQ9JWg+Mj0iF325eJaEYkWTNvDZfUGioravnCEQxAErbAN -S1v0wgUUM8/ja3uI ---- erMVG5PLHMBECjcKtR+OLq5hYa+6dS4gPsQ5CzQByQ0 -S8Y"g|DZ0X 1gg|.]&m=4O-T=Em8(\bD~~+ha~ReW#-5bfO`m4 <'|U8"\ө3$@ϔ8;|:u WKz@%#NE?+!1xN8h> \ No newline at end of file +-> ssh-ed25519 CpJBgQ 6vLlq2WEcn6TE0rgahQyl7CYhCF3uiBD3hOnZkHswmM +BSUiKPdDWMhYbi/+j9Kw5YDEOvjaickYQuhpWkhLktQ +-> ssh-ed25519 LfBFbQ mQJfyk35Ghd7UWouPlq4kTIFFwlRGh24r0kvJUgUbBw +eYpBJEG9Cdc2qHI0maFpp9/2o30R0KGLRSQ7DzsVaZ0 +-> ssh-ed25519 lZtaEQ npyXpqTMWITvRVfPwEQ1rXJ0sxnJvurLOfeiE07m92E +oCXVRGOegBgQUJof8UHJsDdMyNsx6X575Rd4mWZ9LRk +-> ;^O0_l-grease +sseb4RnQz93Wlgs5B0PE+j7AzFyMkzHjFbn9sCn0UA +--- Bqq0uedob5/kJOSoavN7Aq1fH7QVNW134M3uS6u2lFA +r3?ujF !_R/#BQ +Nה"V1mwly's P^6K{ t 3m%'zOo8^SJxꨯR=ŕzEz*Ѥ>g뻐 %>\)Lj05VQ8/HXOGs7gDGIsNpiuYFj?x;] \ No newline at end of file diff --git a/users/grfn/secrets/cloudflare.age b/users/grfn/secrets/cloudflare.age index 1c9fa3ca6bf6..e2f6e9360385 100644 --- a/users/grfn/secrets/cloudflare.age +++ b/users/grfn/secrets/cloudflare.age @@ -1,9 +1,9 @@ age-encryption.org/v1 --> ssh-ed25519 CpJBgQ w4W+pzmVIEMF0uZN7KZMAppJaLjEeDKoe7i9LGayKDQ -Rd8k+3csmbZQIrp09ZUfCAOZVwI0BZ6hCBN3nkZQMp4 --> ssh-ed25519 LfBFbQ dyv1splvcftMd1zWDkPBfsgvXxH5neZlO7ZjrhyzNHI -N/kqc/luOl8lsZcbaxF8/3ULsL78zvZhkiCarohe+G4 --> \w7t-grease lo&b JZpCA -nN2lH0W9+zulMjZMLPMk61+xsrQ ---- voTpUbu8OiJQyuKB7tIOvlErgY0jg2w7N3MehD5FIdM -&czl |KM~2eUN8P~}*hSYJJ FɊoc=L`zO7KgZ.aXD HЦ878 \ No newline at end of file +-> ssh-ed25519 CpJBgQ tWx7wXCFjOOfD0wKRHHvLUdR+SF0i43xvnQG9GKurnk +NRh7kSn7wqw80Y9EFr9Ccft+zYMadXZhYNPEaQlQXtQ +-> ssh-ed25519 LfBFbQ SPQMLC3Ehw00IG1CcbcLFZI2tHy89fjRgVgH4Iw2iBM +oo2gT9472/DFRoZ6TYxhnM9ylRUNzoS8mLQYvn+4OSM +-> D[7+*-grease `>j ~Jk Dz%o vaKET3 +TkKVm8IpqfiVzETAi9+zuUtCdkReB+lHtthwNw +--- 3iOmY4TNICMi/Fz7k8pmoZlFym9uQBWNtHNlizoAMaM +ZPzQ65AT I;;Зy5]k^!`t$RւtK) $scratch/id_rsa.pem + chmod 0600 $scratch/id_rsa.pem + + export NIX_SSHOPTS="\ + -o StrictHostKeyChecking=no\ + -o UserKnownHostsFile=/dev/null\ + -o GlobalKnownHostsFile=/dev/null\ + -o IdentityFile=$scratch/id_rsa.pem" + + nix-build ${drvPath} + nix-copy-closure \ + --to ${targetUser}@''${${machineResource}.public_ip} \ + ${osRootPath} \ + --gzip \ + --use-substitutes + ''; + } + + # activate it + { + remote-exec.inline = [ + # semicolons mandatory + '' + set -e; + nix-env --profile /nix/var/nix/profiles/system --set ${osRootPath}; + ${osRootPath}/bin/switch-to-configuration switch; + '' + ]; + } + ]; + }; + } + + { + resource.aws_security_group_rule = builtins.listToAttrs (map (port: { + name = "ingress_${toString port}"; + value = { + provider = "aws.${region}"; + security_group_id = securityGroupId'; + type = "ingress"; + protocol = "TCP"; + from_port = port; + to_port = port; + cidr_blocks = ["0.0.0.0/0"]; + ipv6_cidr_blocks = []; + description = null; + prefix_list_ids = null; + self = null; + }; + }) extraIngressPorts); + } +] diff --git a/users/grfn/terraform/workspace.nix b/users/grfn/terraform/workspace.nix new file mode 100644 index 000000000000..c2a0fdb97793 --- /dev/null +++ b/users/grfn/terraform/workspace.nix @@ -0,0 +1,104 @@ +{ pkgs, depot, ... }: +name: { plugins }: module_tf: + +let + + inherit (pkgs) lib runCommandNoCC writeText writeScript; + inherit (lib) filterAttrsRecursive; + + allPlugins = (p: plugins p ++ (with p; [ + external + local + tls + p.null + ])); + + tf = pkgs.terraform.withPlugins allPlugins; + + cleanTerraform = filterAttrsRecursive (k: _: ! (builtins.elem k [ + "__readTree" + "__readTreeChildren" + ])); + + plugins_tf = { + terraform.required_providers = (builtins.listToAttrs (map (p: { + name = lib.last (lib.splitString "/" p.provider-source-address); + value = { + source = p.provider-source-address; + version = p.version; + }; + }) (allPlugins pkgs.terraform.plugins))); + }; + + + module_tf' = module_tf // { + inherit (depot.users.grfn.terraform) globals; + plugins = plugins_tf; + }; + + module = runCommandNoCC "module" {} '' + mkdir $out + ${lib.concatStrings (lib.mapAttrsToList (k: config_tf: + (let + # TODO: filterAttrsRecursive? + configJson = writeText "${k}.tf.json" + (builtins.toJSON (cleanTerraform config_tf)); + in '' + ${pkgs.jq}/bin/jq . ${configJson} > $out/${lib.escapeShellArg k}.tf.json + '')) + (cleanTerraform module_tf'))} + ''; + + + tfcmd = writeScript "${name}-tfcmd" '' + set -e + dir="''${TF_STATE_ROOT:-$HOME/tfstate}/${name}" + cd "$dir" + rm -f *.json + cp ${module}/*.json . + exec ${tf}/bin/terraform "$(basename "$0")" + ''; + + init = writeScript "${name}-init" '' + set -e + dir="''${TF_STATE_ROOT:-$HOME/tfstate}/${name}" + [ -d "$dir" ] || mkdir -p "$dir" + cd "$dir" + rm -f *.json + cp ${module}/*.json . + exec ${tf}/bin/terraform init + ''; + + # TODO: import (-config) + tfcmds = runCommandNoCC "${name}-tfcmds" {} '' + mkdir -p $out/bin + ln -s ${init} $out/bin/init + ln -s ${tfcmd} $out/bin/validate + ln -s ${tfcmd} $out/bin/plan + ln -s ${tfcmd} $out/bin/apply + ln -s ${tfcmd} $out/bin/destroy + ''; + +in { + inherit name module; + terraform = tf; + cmds = tfcmds; + + # run = { + # init = depot.nix.nixRunWrapper "init" tfcmds; + # validate = depot.nix.nixRunWrapper "validate" tfcmds; + # plan = depot.nix.nixRunWrapper "plan" tfcmds; + # apply = depot.nix.nixRunWrapper "apply" tfcmds; + # destroy = depot.nix.nixRunWrapper "destroy" tfcmds; + # }; + + test = runCommandNoCC "${name}-test" {} '' + set -e + export TF_STATE_ROOT=$(pwd) + ${tfcmds}/bin/init + ${tfcmds}/bin/validate + touch $out + ''; + + meta.targets = [ "module" "test" ]; +} -- cgit 1.4.1