diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore index b2be92b..726d2d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ result +.direnv diff --git a/hive.nix b/hive.nix new file mode 100644 index 0000000..fdc3708 --- /dev/null +++ b/hive.nix @@ -0,0 +1,57 @@ +let + sources = import ./npins; + metadata = import ./meta; + + lib = import (sources.nix-lib + "/trivial.nix"); + + mkNode = node: { name, nodes, ... }: { + # Import the base configuration for each node + imports = builtins.map (lib.mkRel ./machines/${node}) [ + "_configuration.nix" + "_hardware-configuration.nix" + ]; + + # Include default secrets + # dgn-secrets.sources = [ ./machines/${node}/secrets ]; + + # Deployment config is specified in meta.nodes.${node}.deployment + inherit (metadata.nodes.${node}) deployment; + + # Set NIX_PATH to the patched version of nixpkgs + nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ]; + + # Use the stateVersion declared in the metadata + system.stateVersion = metadata.nodes.${node}.stateVersion; + }; + + mkNixpkgs = node: + let version = "nixos-${metadata.nodes.${node}.nixpkgs}"; in + (import sources.${version} { }).applyPatches { + name = "${version}-patched"; + src = sources.${version}; + patches = (import ./nix-patches).${version} or [ ]; + }; + + mkNixpkgs' = node: import (mkNixpkgs node) { }; + + mkArgs = node: { + nix-lib = import sources.nix-lib { inherit ((mkNixpkgs' node)) lib; keysRoot = ./keys; }; + }; + + nodes = builtins.attrNames metadata.nodes; +in + +{ + meta = { + nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes; + + specialArgs = { inherit sources; meta = metadata; }; + + nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes; + }; + + defaults = { ... }: { + # Import the default modules + imports = [ ./modules ]; + }; +} // (lib.mapSingleFuse mkNode nodes) diff --git a/machines/core-services-01/configuration.nix b/machines/core-services-01/_configuration.nix similarity index 70% rename from machines/core-services-01/configuration.nix rename to machines/core-services-01/_configuration.nix index ac0021a..9bcee06 100644 --- a/machines/core-services-01/configuration.nix +++ b/machines/core-services-01/_configuration.nix @@ -2,9 +2,6 @@ { imports = [ - # Include the results of the hardware scan. - ./hardware-configuration.nix - ./acme-dns.nix ./acme-ssl.nix ./backups.nix @@ -77,28 +74,11 @@ services.zfs.autoScrub.enable = true; - # Enable the OpenSSH daemon. - services.openssh.enable = true; - users.users.root.openssh.authorizedKeys.keyFiles = [ - ../pubkeys/gdd.keys - ../pubkeys/raito.keys - ../pubkeys/mrf.keys - ../pubkeys/hubrecht.keys - ../pubkeys/sinavir.keys - ]; - # Open ports in the firewall. # networking.firewall.allowedTCPPorts = [ ... ]; # networking.firewall.allowedUDPPorts = [ ... ]; # Or disable the firewall altogether. networking.firewall.enable = false; - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "22.05"; # Did you read the comment? - environment.variables.NIX_PATH = lib.mkForce "/var/src"; + system.stateVersion = "22.05"; } diff --git a/machines/core-services-01/hardware-configuration.nix b/machines/core-services-01/_hardware-configuration.nix similarity index 100% rename from machines/core-services-01/hardware-configuration.nix rename to machines/core-services-01/_hardware-configuration.nix diff --git a/machines/public-cof/configuration.nix b/machines/public-cof/_configuration.nix similarity index 77% rename from machines/public-cof/configuration.nix rename to machines/public-cof/_configuration.nix index 6bd8454..a831791 100644 --- a/machines/public-cof/configuration.nix +++ b/machines/public-cof/_configuration.nix @@ -3,7 +3,6 @@ { imports = [ - ./hardware-configuration.nix ./programs.nix ./system.nix ./acme.nix @@ -49,15 +48,5 @@ enableSSHSupport = true; }; - # Enable the OpenSSH daemon. - services.openssh.enable = true; - users.users.root.openssh.authorizedKeys.keyFiles = [ - ../pubkeys/gdd.keys - ../pubkeys/raito.keys - ../pubkeys/mrf.keys - ../pubkeys/sinavir.keys - ../pubkeys/hubrecht.keys - ]; - system.stateVersion = "21.05"; } diff --git a/machines/public-cof/hardware-configuration.nix b/machines/public-cof/_hardware-configuration.nix similarity index 100% rename from machines/public-cof/hardware-configuration.nix rename to machines/public-cof/_hardware-configuration.nix diff --git a/machines/remote-builder-01/configuration.nix b/machines/remote-builder-01/_configuration.nix similarity index 69% rename from machines/remote-builder-01/configuration.nix rename to machines/remote-builder-01/_configuration.nix index 286062b..d5906a8 100644 --- a/machines/remote-builder-01/configuration.nix +++ b/machines/remote-builder-01/_configuration.nix @@ -2,7 +2,6 @@ { imports = [ - ./hardware-configuration.nix ./system.nix # TODO monitoring ]; @@ -59,28 +58,11 @@ services.zfs.autoScrub.enable = true; - # Enable the OpenSSH daemon. - services.openssh.enable = true; - users.users.root.openssh.authorizedKeys.keyFiles = [ - ../pubkeys/gdd.keys - ../pubkeys/raito.keys - ../pubkeys/sinavir.keys - ../pubkeys/remote-builders.keys - ]; - # Open ports in the firewall. # networking.firewall.allowedTCPPorts = [ ... ]; # networking.firewall.allowedUDPPorts = [ ... ]; # Or disable the firewall altogether. networking.firewall.enable = false; - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "21.05"; # Did you read the comment? - + system.stateVersion = "21.05"; } - diff --git a/machines/remote-builder-01/hardware-configuration.nix b/machines/remote-builder-01/_hardware-configuration.nix similarity index 100% rename from machines/remote-builder-01/hardware-configuration.nix rename to machines/remote-builder-01/_hardware-configuration.nix diff --git a/meta/default.nix b/meta/default.nix new file mode 100644 index 0000000..a6ccb51 --- /dev/null +++ b/meta/default.nix @@ -0,0 +1,5 @@ +let + nodes = import ./nodes.nix; +in + +{ inherit nodes; } diff --git a/meta/nodes.nix b/meta/nodes.nix new file mode 100644 index 0000000..c017cc4 --- /dev/null +++ b/meta/nodes.nix @@ -0,0 +1,64 @@ +### +# File specifying all the deployement options for the nodes administrated by the dgnum. +# +# Node metadata template is: +# +# NODE_NAME = { +# adminGroups = []; # List of groups that have root access +# admins = []; # List of individuals that have root access +# deployment = {}; # Colmena deployment options +# nixpkgs = "unstable" or "22.11"; # nixpkgs version +# } + +let + mkNode = _: attrs: { + access = [ ]; + + deployment = { }; + + nixpkgs = "23.05"; + } // attrs; +in + +builtins.mapAttrs mkNode { + core-services-01 = { + admins = [ + "gdd" + "hubrecht" + "mrf" + "raito" + "sinavir" + ]; + + deployment.targetHost = "core01.rz.ens.wtf"; + + stateVersion = "22.05"; + }; + + remote-builder-01 = { + admins = [ + "gdd" + "raito" + "sinavir" + "remote-builders" + ]; + + deployment.targetHost = "nix01.builders.rz.ens.wtf"; + + stateVersion = "21.05"; + }; + + public-cof = { + admins = [ + "gdd" + "hubrecht" + "mrf" + "raito" + "sinavir" + ]; + + deployment.targetHost = "beta.rz.ens.wtf"; + + stateVersion = "21.05"; + }; +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..bc98724 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,11 @@ +{ nix-lib, sources, ... }: + +{ + imports = (nix-lib.mkImports ./. [ + "krz-access-control" + "krz-ssh" + ]) ++ [ + # TODO: Switch to global version of agenix via npins + # "${sources.agenix}/modules/age.nix" + ]; +} diff --git a/modules/krz-access-control.nix b/modules/krz-access-control.nix new file mode 100644 index 0000000..55fd2a3 --- /dev/null +++ b/modules/krz-access-control.nix @@ -0,0 +1,46 @@ +{ config, lib, nix-lib, meta, name, ... }: + +let + inherit (lib) + mkDefault + mkEnableOption + mkIf + mkOption + + types; + + nodeMeta = meta.nodes.${name}; + inherit (nodeMeta) admins; + + cfg = config.krz-access-control; +in + +{ + options.krz-access-control = { + enable = mkEnableOption "DGNum access control." // { default = true; }; + + users = mkOption { + type = with types; attrsOf (listOf str); + default = { }; + description = '' + Attribute set describing which member has access to which user on the node. + Members must be declared in `meta/members.nix`. + ''; + example = '' + { + user1 = [ "member1" "member2" ]; + } + ''; + }; + }; + + config = mkIf cfg.enable { + # Admins have root access to the node + krz-access-control.users.root = mkDefault admins; + + users.users = builtins.mapAttrs + (u: members: { openssh.authorizedKeys.keys = nix-lib.getAllKeys members; }) + cfg.users; + }; +} + diff --git a/modules/krz-ssh.nix b/modules/krz-ssh.nix new file mode 100644 index 0000000..4124ada --- /dev/null +++ b/modules/krz-ssh.nix @@ -0,0 +1,25 @@ +{ config, lib, ... }: + +let + inherit (lib) + mkEnableOption + mkIf; + + cfg = config.krz-ssh; +in + +{ + options.krz-ssh = { + enable = mkEnableOption "ssh default configuration." // { default = true; }; + }; + + config = mkIf cfg.enable { + services.openssh = { + enable = true; + + settings.PasswordAuthentication = false; + }; + + programs.mosh.enable = true; + }; +} diff --git a/nix-patches/default.nix b/nix-patches/default.nix new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/nix-patches/default.nix @@ -0,0 +1 @@ +{} diff --git a/npins/default.nix b/npins/default.nix new file mode 100644 index 0000000..4a7c372 --- /dev/null +++ b/npins/default.nix @@ -0,0 +1,47 @@ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + mkSource = spec: + assert spec ? type; let + path = + if spec.type == "Git" then mkGitSource spec + else if spec.type == "GitRelease" then mkGitSource spec + else if spec.type == "PyPi" then mkPyPiSource spec + else if spec.type == "Channel" then mkChannelSource spec + else builtins.throw "Unknown source type ${spec.type}"; + in + spec // { outPath = path; }; + + mkGitSource = { repository, revision, url ? null, hash, ... }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null then + (builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + }) + else assert repository.type == "Git"; builtins.fetchGit { + url = repository.url; + rev = revision; + # hash = hash; + }; + + mkPyPiSource = { url, hash, ... }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = { url, hash, ... }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; +in +if version == 3 then + builtins.mapAttrs (_: mkSource) data.pins +else + throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/npins/sources.json b/npins/sources.json new file mode 100644 index 0000000..1df8536 --- /dev/null +++ b/npins/sources.json @@ -0,0 +1,43 @@ +{ + "pins": { + "agenix": { + "type": "GitRelease", + "repository": { + "type": "Git", + "url": "https://github.com/ryantm/agenix" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "0.13.0", + "revision": "9c9fbfb94b2d545c7f0b78da0254ea0041595795", + "url": null, + "hash": "0k6aggy3lhqv6j11cvi4gr0i3jps8hlf262xl9ji3ffxwas46p54" + }, + "nix-lib": { + "type": "GitRelease", + "repository": { + "type": "Git", + "url": "https://git.hubrecht.ovh/hubrecht/nix-lib" + }, + "pre_releases": false, + "version_upper_bound": null, + "version": "0.1.1", + "revision": "5db2443e2cb18335375ad84ffbc066a239c054de", + "url": null, + "hash": "18xzi2yn2vk7zq79pgz8z2s1ijhyjcx5866mp21rrdi9gz37yiif" + }, + "nixos-23.05": { + "type": "Channel", + "name": "nixos-23.05", + "url": "https://releases.nixos.org/nixos/23.05/nixos-23.05.2162.6da4bc6cb07/nixexprs.tar.xz", + "hash": "198wbl9b7j3k51n0rxs09vy6x535ysqv6kbxf42d9yqr49d2n9vc" + }, + "nixpkgs": { + "type": "Channel", + "name": "nixpkgs-unstable", + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-23.11pre506668.af8cd5ded77/nixexprs.tar.xz", + "hash": "0in8bgah6hz47lsa3ka2fslwks174maqdzy8mcmsj0q4wrv8h2s9" + } + }, + "version": 3 +} \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..e29954b --- /dev/null +++ b/shell.nix @@ -0,0 +1,15 @@ +let + sources = import ./npins; + pkgs = import sources.nixpkgs { }; +in + +pkgs.mkShell { + packages = with pkgs; [ + npins + colmena + nixos-generators + ] ++ (builtins.map (p: callPackage p { }) [ + ]); + + allowSubstitutes = false; +}