aboutsummaryrefslogtreecommitdiff
path: root/nix
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-02-09 12:09:49 +0100
committerAlex Auvolat <alex@adnab.me>2022-02-09 12:09:49 +0100
commitf03cafd49b48eabc4743b3a3791fd22f19cb0de1 (patch)
treee31d1c68502e4ee2f8f4dc67235eac0e220b2fbd /nix
parentcce5cd17f5429295eb2165480ca941dd3f49b788 (diff)
downloadnixcfg-f03cafd49b48eabc4743b3a3791fd22f19cb0de1.tar.gz
nixcfg-f03cafd49b48eabc4743b3a3791fd22f19cb0de1.zip
Modularize and prepare to support multiple clusters
Diffstat (limited to 'nix')
-rw-r--r--nix/deuxfleurs.nix185
1 files changed, 185 insertions, 0 deletions
diff --git a/nix/deuxfleurs.nix b/nix/deuxfleurs.nix
new file mode 100644
index 0000000..9b8013c
--- /dev/null
+++ b/nix/deuxfleurs.nix
@@ -0,0 +1,185 @@
+{ config, pkgs, ... }:
+
+let
+ cfg = config.deuxfleurs;
+in
+ with builtins;
+ with pkgs.lib;
+{
+ options.deuxfleurs =
+ let wg_node = with types; submodule {
+ options = {
+ hostname = mkOption {
+ type = str;
+ description = "Host name";
+ };
+ IP = mkOption {
+ type = str;
+ description = "IP Address";
+ };
+ publicKey = mkOption {
+ type = str;
+ description = "Public key";
+ };
+ endpoint = mkOption {
+ type = nullOr str;
+ description = "Wireguard endpoint on the public Internet";
+ };
+ };
+ };
+ in
+ {
+ # Parameters that may vary between nodes
+ site_name = mkOption {
+ description = "Site (availability zone) on which this node is deployed";
+ type = types.str;
+ };
+ vpn_ip = mkOption {
+ description = "IP address of this node on the Wireguard VPN";
+ type = types.str;
+ };
+ vpn_listen_port = mkOption {
+ description = "Port for incoming Wireguard VPN connections";
+ type = types.port;
+ };
+ is_raft_server = mkOption {
+ description = "Make this node a RAFT server for the Nomad and Consul deployments";
+ type = types.bool;
+ default = false;
+ };
+
+ # Parameters common to all nodes
+ cluster_name = mkOption {
+ description = "Name of this Deuxfleurs deployment";
+ type = types.str;
+ };
+ cluster_nodes = mkOption {
+ description = "Nodes that are part of the cluster";
+ type = types.listOf wg_node;
+ };
+ admin_nodes = mkOption {
+ description = "Machines that are part of the Wireguard VPN for administration purposes";
+ type = types.listOf wg_node;
+ };
+ admin_accounts = mkOption {
+ description = "List of users having an admin account on cluster nodes, maps user names to a list of authorized SSH keys";
+ type = types.attrsOf (types.listOf types.str);
+ };
+ };
+
+ config = {
+ # Configure admin accounts on all nodes
+ users.users = builtins.mapAttrs (name: publicKeys: {
+ isNormalUser = true;
+ extraGroups = [ "wheel" ];
+ openssh.authorizedKeys.keys = publicKeys;
+ }) cfg.admin_accounts;
+
+ # Configure Wireguard VPN between all nodes
+ networking.wireguard.interfaces.wg0 = {
+ ips = [ "${cfg.vpn_ip}/16" ];
+ listenPort = cfg.vpn_listen_port;
+ privateKeyFile = "/root/wireguard-keys/private";
+ peers = map ({ publicKey, endpoint, IP, ... }: {
+ publicKey = publicKey;
+ allowedIPs = [ "${IP}/32" ];
+ endpoint = endpoint;
+ persistentKeepalive = 25;
+ }) (cfg.cluster_nodes ++ cfg.admin_nodes);
+ };
+
+ networking.firewall.allowedUDPPorts = [ cfg.vpn_listen_port ];
+
+ # Configure /etc/hosts to link all hostnames to their Wireguard IP
+ networking.extraHosts = builtins.concatStringsSep "\n" (map
+ ({ hostname, IP, ...}: "${IP} ${hostname}")
+ (cfg.cluster_nodes ++ cfg.admin_nodes));
+
+ # Enable Hashicorp Consul & Nomad
+ services.consul.enable = true;
+ services.consul.extraConfig =
+ (if cfg.is_raft_server
+ then {
+ server = true;
+ bootstrap_expect = 3;
+ }
+ else {}) //
+ {
+ datacenter = cfg.cluster_name;
+ node_meta = {
+ "site" = cfg.site_name;
+ };
+ ui = true;
+ bind_addr = cfg.vpn_ip;
+
+ ports.http = -1;
+ addresses.https = "0.0.0.0";
+ ports.https = 8501;
+
+ retry_join = map (node_info: node_info.IP) cfg.cluster_nodes;
+
+ ca_file = "/var/lib/consul/pki/consul-ca.crt";
+ cert_file = "/var/lib/consul/pki/consul2022.crt";
+ key_file = "/var/lib/consul/pki/consul2022.key";
+ verify_incoming = true;
+ verify_outgoing = true;
+ verify_server_hostname = true;
+ };
+
+ services.nomad.enable = true;
+ services.nomad.package = pkgs.nomad_1_1;
+ services.nomad.settings =
+ (if cfg.is_raft_server
+ then { server = {
+ enabled = true;
+ bootstrap_expect = 3;
+ }; }
+ else {}) //
+ {
+ region = cfg.cluster_name;
+ datacenter = cfg.site_name;
+ advertise = {
+ rpc = cfg.vpn_ip;
+ http = cfg.vpn_ip;
+ serf = cfg.vpn_ip;
+ };
+ consul = {
+ address = "localhost:8501";
+ ca_file = "/var/lib/nomad/pki/consul2022.crt";
+ cert_file = "/var/lib/nomad/pki/consul2022-client.crt";
+ key_file = "/var/lib/nomad/pki/consul2022-client.key";
+ ssl = true;
+ };
+ client = {
+ enabled = true;
+ network_interface = "wg0";
+ meta = {
+ "site" = cfg.site_name;
+ };
+ };
+ tls = {
+ http = true;
+ rpc = true;
+ ca_file = "/var/lib/nomad/pki/nomad-ca.crt";
+ cert_file = "/var/lib/nomad/pki/nomad2022.crt";
+ key_file = "/var/lib/nomad/pki/nomad2022.key";
+ verify_server_hostname = true;
+ verify_https_client = true;
+ };
+ plugin = [
+ {
+ docker = [
+ {
+ config = [
+ {
+ volumes.enabled = true;
+ allow_privileged = true;
+ }
+ ];
+ }
+ ];
+ }
+ ];
+ };
+ };
+}