diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result diff --git a/README.md b/README.md index e005679..db47956 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# config-core-services-01 +# NixOS configuration of klubrz's machines diff --git a/krops.nix b/krops.nix new file mode 100644 index 0000000..174498a --- /dev/null +++ b/krops.nix @@ -0,0 +1,24 @@ +let + krops = builtins.fetchGit { + url = "https://cgit.krebsco.de/krops/"; + }; + lib = import "${krops}/lib"; + pkgs = import "${krops}/pkgs" {}; + source = machine: lib.evalSource [ + { + config.file = toString ./machines; + nixos-config.symlink = "config/${machine}/configuration.nix"; + nixpkgs.git = { + clean.exclude = [ "/.version-suffix" ]; + ref = "973910f5c31b9ba6c171c33a8bd7199990b14c72"; # nixos-21.05 + url = https://github.com/NixOS/nixpkgs; + }; + } + ]; +in + { + core-services-01 = pkgs.krops.writeDeploy "deploy-core-services-01" { + source = source "core-services-01"; + target = "root@core01.internal.rz.ens.wtf"; + }; + } diff --git a/machines/core-services-01/acme-dns.nix b/machines/core-services-01/acme-dns.nix new file mode 100644 index 0000000..82d3ff1 --- /dev/null +++ b/machines/core-services-01/acme-dns.nix @@ -0,0 +1,26 @@ +{ config, ... }: +let + my = config.my; +in +{ + services.acme-dns = { + enable = true; + domain = "acme.${my.subZone}"; + nsname = "acme.${my.subZone}"; + nsadmin = my.emailWithDot; + dns.listen = "[${my.ipv6.acme}]"; # :-). + records = [ + "acme.${my.subZone}. AAAA ${my.ipv6.acme}" + "acme.${my.subZone}. NS acme.${my.subZone}." + ]; + }; + + services.nginx.enable = true; + services.nginx.virtualHosts."acme.${my.subZone}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:8090"; + }; + }; +} diff --git a/machines/core-services-01/acme-ssl.nix b/machines/core-services-01/acme-ssl.nix new file mode 100644 index 0000000..2403cd6 --- /dev/null +++ b/machines/core-services-01/acme-ssl.nix @@ -0,0 +1,14 @@ +{ config, lib, ... }: + +let + my = config.my; +in +{ + security.acme.acceptTerms = true; + security.acme.email = my.email; + + security.acme.server = + if my.acmeStaging + then "https://acme-staging-v02.api.letsencrypt.org/directory" + else null; +} diff --git a/machines/core-services-01/configuration.nix b/machines/core-services-01/configuration.nix new file mode 100644 index 0000000..691cd3f --- /dev/null +++ b/machines/core-services-01/configuration.nix @@ -0,0 +1,92 @@ +{ config, pkgs, lib, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ./nur.nix + ./rz.nix + ./monitoring.nix + ./programs.nix + ./system.nix + ./acme-ssl.nix + ./dns.nix + ./netboot-server.nix + ./qemu.nix + ./gitea.nix + ./dokuwiki.nix + ./nginx.nix + ./keycloak.nix + ./acme-dns.nix + ./secrets + # TODO push to gitea + # TODO ./gotify.nix + # TODO(Raito): ./backups.nix + # TODO(Raito): ./snmp.nix + # TODO(Raito): ./sflow.nix? + ]; + + # Use the systemd-boot EFI boot loader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + boot.initrd.supportedFilesystems = [ "zfs" ]; + boot.supportedFilesystems = [ "zfs" ]; + + networking.hostName = "klubrz-core-services-01"; + networking.hostId = "64838310"; + + time.timeZone = "Europe/Paris"; + + # The global useDHCP flag is deprecated, therefore explicitly set to false here. + # Per-interface useDHCP will be mandatory in the future, so this generated config + # replicates the default behaviour. + networking.useDHCP = false; + # Adieu, hackENS — networking.interfaces.ens18.useDHCP = true; + networking.interfaces.ens19.useDHCP = true; + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + console = { + font = "Lat2-Terminus16"; + keyMap = "us"; + }; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + programs.mtr.enable = true; + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + + # List services that you want to enable: + + 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/hackens-milieu.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 = "20.09"; # Did you read the comment? +} diff --git a/machines/core-services-01/dns.nix b/machines/core-services-01/dns.nix new file mode 100644 index 0000000..2161481 --- /dev/null +++ b/machines/core-services-01/dns.nix @@ -0,0 +1,28 @@ +{ config, lib, ... }: + +with lib; + +let + dns = import (builtins.fetchTarball "https://github.com/kirelagin/dns.nix/archive/master.tar.gz"); + my = config.my; +in +{ + services.unbound = { + enable = true; + settings = { + server = { + access-control = [ "127.0.0.0/8 allow" "::1/128 allow" ] ++ map (v: "${v} allow") my.privateRanges; + interface = [ "127.0.0.1" ] ++ my.ipv4; + }; + }; + }; + services.nsd = { + enable = true; + interfaces = my.ipv6.standard; + zones = { + ${my.subZone} = { + data = dns.lib.toString my.subZone (import ./subZone.nix { inherit dns config; }); + }; + }; + }; +} diff --git a/machines/core-services-01/dokuwiki.nix b/machines/core-services-01/dokuwiki.nix new file mode 100644 index 0000000..a0be037 --- /dev/null +++ b/machines/core-services-01/dokuwiki.nix @@ -0,0 +1,33 @@ +{ config, ... }: + +let + my = config.my; +in +{ + services.dokuwiki."wiki.${my.subZone}" = { + enable = true; + hostName = "wiki.${my.subZone}"; + acl = '' + * @ALL 1 + * @admin 16 + ''; + nginx = { + enableACME = true; + forceSSL = true; + }; + }; + + /* + services.nginx = { + enable = true; + + virtualHosts."wiki.${my.subZone}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "htttp://127.0.0.1:${toString port}"; + }; + }; + }; + */ +} diff --git a/machines/core-services-01/gitea.nix b/machines/core-services-01/gitea.nix new file mode 100644 index 0000000..afe9a5b --- /dev/null +++ b/machines/core-services-01/gitea.nix @@ -0,0 +1,29 @@ +{ config, ... }: + +let + my = config.my; + port = 3000; +in +{ + services.gitea = { + enable = true; + domain = "git.${my.subZone}"; + rootUrl = "https://git.${my.subZone}/"; + httpAddress = "127.0.0.1"; + httpPort = port; + database.type = "postgres"; + disableRegistration = true; + }; + + services.nginx = { + enable = true; + + virtualHosts."git.${my.subZone}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + }; + }; + }; +} diff --git a/machines/core-services-01/hardware-configuration.nix b/machines/core-services-01/hardware-configuration.nix new file mode 100644 index 0000000..d4aca08 --- /dev/null +++ b/machines/core-services-01/hardware-configuration.nix @@ -0,0 +1,35 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "rpool/root/nixos"; + fsType = "zfs"; + }; + + fileSystems."/home" = + { device = "rpool/home"; + fsType = "zfs"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/56B8-1FC0"; + fsType = "vfat"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/0fe95042-8197-4969-a549-65565cf70171"; } + ]; + +} diff --git a/machines/core-services-01/keycloak.nix b/machines/core-services-01/keycloak.nix new file mode 100644 index 0000000..8886a75 --- /dev/null +++ b/machines/core-services-01/keycloak.nix @@ -0,0 +1,27 @@ +{ config, ... }: +let + my = config.my; + port = 8080; +in +{ + services.keycloak = { + enable = true; + initialAdminPassword = "changemeasap"; + database.createLocally = true; + database.passwordFile = config.age.secrets.keycloakDatabasePasswordFile.path; + frontendUrl = "https://auth.${my.subZone}/auth/"; + forceBackendUrlToFrontendUrl = true; + httpPort = toString port; + extraConfig = { + "subsystem=undertow"."server=default-server"."http-listener=default".proxy-address-forwarding = true; + }; + }; + + services.nginx.virtualHosts."auth.${my.subZone}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + }; + }; +} diff --git a/machines/core-services-01/monitoring.nix b/machines/core-services-01/monitoring.nix new file mode 100644 index 0000000..8316012 --- /dev/null +++ b/machines/core-services-01/monitoring.nix @@ -0,0 +1,44 @@ +{ config, pkgs, ... }: +let + my = config.my; + realm = "ClubReseau"; +in +{ + services.netdata.enable = true; + + services.oauth2_proxy = { + enable = true; + keyFile = config.age.secrets.oauth2ProxyKeyFile.path; + provider = "keycloak"; + email.domains = [ "*" ]; + setXauthrequest = true; + scope = "profile"; + loginURL = "https://auth.${my.subZone}/auth/realms/${realm}/protocol/openid-connect/auth"; + redeemURL = "https://auth.${my.subZone}/auth/realms/${realm}/protocol/openid-connect/token"; + profileURL = "https://auth.${my.subZone}/auth/realms/${realm}/protocol/openid-connect/userinfo"; + validateURL = "https://auth.${my.subZone}/auth/realms/${realm}/protocol/openid-connect/userinfo"; + redirectURL = "https://monitoring.${my.subZone}/oauth2/callback"; + reverseProxy = true; + passHostHeader = true; + + nginx = { + virtualHosts = [ "monitoring.${my.subZone}" ]; + }; + }; + + services.nginx = { + enable = true; + + virtualHosts."monitoring.${my.subZone}" = { + enableACME = true; + forceSSL = true; + + locations."/".proxyPass = "http://localhost:19999"; + }; + }; + + # services.smartd = { + # enable = true; + # extraOptions = [ "-A /var/log/smartd/" ]; # For netdata + # }; +} diff --git a/machines/core-services-01/my.nix b/machines/core-services-01/my.nix new file mode 100644 index 0000000..5a83031 --- /dev/null +++ b/machines/core-services-01/my.nix @@ -0,0 +1,95 @@ +{ config, lib, ... }: + +with lib; +with types; +let + cfg = config.my; + mkAddress = addr: let + splitted = lib.splitString "/" addr; + elemAt = builtins.elemAt splitted; + in + { address = (elemAt 0); prefixLength = lib.toInt (elemAt 1); }; +in +{ + options.my = { + email = mkOption { + description = "Admin email"; + type = str; + default = ""; + example = "clipper@ens.fr"; + }; + + emailWithDot = mkOption { + description = "Admin email with dots"; + type = str; + default = lib.replaceStrings ["@"] ["."] cfg.email; + example = "clipper.ens.fr"; + }; + + acmeStaging = mkOption { + description = "Enable staging servers"; + type = bool; + default = false; + }; + + subZone = mkOption { + description = "Sub zone for hosting the services"; + type = str; + default = ""; + example = "ens.pizza"; + }; + + ipv4 = mkOption { + description = "Public IPv4 addresses without prefix"; + type = listOf str; + example = [ "192.186.1.153" ]; + default = map (v: (mkAddress v).address) cfg.ipv4Full; + }; + + ipv4Full = mkOption { + description = "Public IPv4 addresses with prefix"; + type = listOf str; + default = []; + example = [ "192.186.1.153/24" ]; + }; + + ipv6.standard = mkOption { + description = "Public IPv6 addresses for standard services without prefix"; + type = listOf str; + example = [ "2001:470:1f13:21d:f515:b348:cd48:e064" ]; + default = map (v: (mkAddress v).address) cfg.ipv6.standardFull; + }; + + ipv6.standardFull = mkOption { + description = "Public IPv6 addresses for standard services with prefix"; + type = listOf str; + example = [ "2001:470:1f13:21d:f515:b348:cd48:e064/64" ]; + }; + + ipv6.acme = mkOption { + description = "Public IPv6 address for ACME services (acme-dns) without prefi"; + type = str; + default = (mkAddress cfg.ipv6.acmeFull).address; + example = "2001:470:1f13:21d:f515:b348:cd48:e064/64"; + }; + + ipv6.acmeFull = mkOption { + description = "Public IPv6 address for ACME services (acme-dns) with prefix"; + type = str; + example = "2001:470:1f13:21d:f515:b348:cd48:e064/64"; + }; + + privateRanges = mkOption { + description = "Internal management ranges for access control"; + type = listOf str; + example = [ "10.1.0.0/22" ]; + }; + }; + + config = { + networking.interfaces.ens19 = { + ipv4.addresses = map mkAddress cfg.ipv4Full; + ipv6.addresses = map mkAddress (cfg.ipv6.standardFull ++ [ cfg.ipv6.acmeFull ]); + }; + }; +} diff --git a/machines/core-services-01/netboot-server.nix b/machines/core-services-01/netboot-server.nix new file mode 100644 index 0000000..ac0bd87 --- /dev/null +++ b/machines/core-services-01/netboot-server.nix @@ -0,0 +1,45 @@ +{ pkgs, config, ... }: +let + bootSystem = import { + configuration = { config, pkgs, lib, ... }: with lib; { + imports = [ + + ]; + # Early init the serial console + boot.kernelParams = [ "console=tty1" "console=ttyS0,115200" ]; + + ## Some useful options for setting up a new system + services.getty.autologinUser = mkForce "root"; + # Enable sshd wich gets disabled by netboot-minimal.nix + systemd.services.sshd.wantedBy = mkOverride 0 [ "multi-user.target" ]; + users.users.root.openssh.authorizedKeys.keyFiles = [ + ./pubkeys/gdd.keys + ./pubkeys/raito.keys + ./pubkeys/hackens-milieu.keys + ]; + programs.mosh.enable = true; + + console.keyMap = "us"; + }; + }; + netboot = pkgs.symlinkJoin { + name = "netboot"; + paths = with bootSystem.config.system.build; [ + netbootRamdisk + kernel + netbootIpxeScript + ]; + preferLocalBuild = true; + }; +in { + services.pixiecore = { + enable = true; + kernel = "${netboot}/bzImage"; + initrd = "${netboot}/initrd"; + cmdLine = "init=${bootSystem.config.system.build.toplevel}/init loglevel=4"; + debug = true; + dhcpNoBind = true; + port = 64172; + statusPort = 64172; + }; +} diff --git a/machines/core-services-01/nginx.nix b/machines/core-services-01/nginx.nix new file mode 100644 index 0000000..5bf0bcc --- /dev/null +++ b/machines/core-services-01/nginx.nix @@ -0,0 +1,9 @@ +{ ... }: +{ + services.nginx = { + recommendedTlsSettings = true; + recommendedProxySettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + }; +} diff --git a/machines/core-services-01/nix/sources.json b/machines/core-services-01/nix/sources.json new file mode 100644 index 0000000..359fd04 --- /dev/null +++ b/machines/core-services-01/nix/sources.json @@ -0,0 +1,32 @@ +{ + "agenix": { + "branch": "master", + "description": "age-encrypted secrets for NixOS", + "homepage": "", + "owner": "ryantm", + "repo": "agenix", + "rev": "fb00f178b3a49a39cc964049075439b575d36d60", + "sha256": "0rb99dbwnaf8sgjbshwk1bizs51jild3zg61a5yqw3h0vcxalzrp", + "type": "tarball", + "url": "https://github.com/ryantm/agenix/archive/fb00f178b3a49a39cc964049075439b575d36d60.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "klubrz-nur": { + "branch": "main", + "repo": "https://git.rz.ens.wtf/Klub-RZ/nur", + "rev": "48597e362c87365976ebc0168fb0e5678aa3865d", + "type": "git" + }, + "niv": { + "branch": "master", + "description": "Easy dependency management for Nix projects", + "homepage": "https://github.com/nmattia/niv", + "owner": "nmattia", + "repo": "niv", + "rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070", + "sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx", + "type": "tarball", + "url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/machines/core-services-01/nix/sources.nix b/machines/core-services-01/nix/sources.nix new file mode 100644 index 0000000..1938409 --- /dev/null +++ b/machines/core-services-01/nix/sources.nix @@ -0,0 +1,174 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + if spec ? ref then spec.ref else + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + in + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else {}; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/machines/core-services-01/nur.nix b/machines/core-services-01/nur.nix new file mode 100644 index 0000000..119c503 --- /dev/null +++ b/machines/core-services-01/nur.nix @@ -0,0 +1,17 @@ +{ lib, pkgs, ... }: +let + nivSources = import ./nix/sources.nix; + rz-src = nivSources.klubrz-nur; + rz-no-pkgs = (import nivSources.klubrz-nur {}); +in +{ + nixpkgs.config.packageOverrides = { + rz = import rz-src { inherit pkgs; }; + }; + + imports = [ + "${nivSources.agenix}/modules/age.nix" + ] ++ lib.attrValues rz-no-pkgs.modules; + + nixpkgs.overlays = []; +} diff --git a/machines/core-services-01/programs.nix b/machines/core-services-01/programs.nix new file mode 100644 index 0000000..9250d40 --- /dev/null +++ b/machines/core-services-01/programs.nix @@ -0,0 +1,23 @@ +{ pkgs, ... }: +let pkgsList = with pkgs; [ + nix-prefetch-git + dnsutils + + unzip + zip + ripgrep + + niv + nixfmt + ]; +in +{ + imports = [ + ./vim.nix + ]; + programs.tmux.enable = true; + programs.wireshark.enable = true; + programs.mosh.enable = true; + + environment.systemPackages = pkgsList; +} diff --git a/machines/core-services-01/pubkeys/gdd.keys b/machines/core-services-01/pubkeys/gdd.keys new file mode 100644 index 0000000..b5d4e40 --- /dev/null +++ b/machines/core-services-01/pubkeys/gdd.keys @@ -0,0 +1,2 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICE7TN5NQKGojNGIeTFiHjLHTDQGT8i05JFqX/zLW2zc +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIFbkPWWZzOBaRdx4+7xQUgxDwuncSl2fxAeVuYfVUPZ diff --git a/machines/core-services-01/pubkeys/hackens-milieu.keys b/machines/core-services-01/pubkeys/hackens-milieu.keys new file mode 100644 index 0000000..c79c039 --- /dev/null +++ b/machines/core-services-01/pubkeys/hackens-milieu.keys @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3+w4+nyJG8lr2mh0S9Zf8j2/6H5smlO87s6KNLlhkF hackens@hackens-milieu diff --git a/machines/core-services-01/pubkeys/raito.keys b/machines/core-services-01/pubkeys/raito.keys new file mode 100644 index 0000000..0f48a59 --- /dev/null +++ b/machines/core-services-01/pubkeys/raito.keys @@ -0,0 +1,4 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcEkYM1r8QVNM/G5CxJInEdoBCWjEHHDdHlzDYNSUIdHHsn04QY+XI67AdMCm8w30GZnLUIj5RiJEWXREUApby0GrfxGGcy8otforygfgtmuUKAUEHdU2MMwrQI7RtTZ8oQ0USRGuqvmegxz3l5caVU7qGvBllJ4NUHXrkZSja2/51vq80RF4MKkDGiz7xUTixI2UcBwQBCA/kQedKV9G28EH+1XfvePqmMivZjl+7VyHsgUVj9eRGA1XWFw59UPZG8a7VkxO/Eb3K9NF297HUAcFMcbY6cPFi9AaBgu3VC4eetDnoN/+xT1owiHi7BReQhGAy/6cdf7C/my5ehZwD +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKIIcqryU28FkV+UpiTnGCOfwKO5jFhkdvU7a7Ew2KoZ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMLf6B8VV//BhOWihYK8Zy1CJ3sg4w2bP0aBO0VPs4hS +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE0xMwWedkKosax9+7D2OlnMxFL/eV4CvFZLsbLptpXr diff --git a/machines/core-services-01/qemu.nix b/machines/core-services-01/qemu.nix new file mode 100644 index 0000000..729cdcd --- /dev/null +++ b/machines/core-services-01/qemu.nix @@ -0,0 +1,4 @@ +{ pkgs, ... }: +{ + services.qemuGuest.enable = true; +} diff --git a/machines/core-services-01/rz.nix b/machines/core-services-01/rz.nix new file mode 100644 index 0000000..4f096e4 --- /dev/null +++ b/machines/core-services-01/rz.nix @@ -0,0 +1,18 @@ +{ lib, ... }: + +{ + imports = [ ./my.nix ]; + + my = { + email = "club-reseau@lists.ens.psl.eu"; + acmeStaging = false; + subZone = "rz.ens.wtf"; + ipv6.standardFull = [ + "2001:470:1f13:187:fd34:80c3:a761:ff2/64" + ]; + ipv6.acmeFull = "2001:470:1f13:187:a039:c3ff:fe4f:8661/64"; + ipv4Full = [ "10.1.1.20/24" ]; + + privateRanges = [ "10.1.0.0/22 "]; + }; +} diff --git a/machines/core-services-01/secrets/default.nix b/machines/core-services-01/secrets/default.nix new file mode 100644 index 0000000..4459bf2 --- /dev/null +++ b/machines/core-services-01/secrets/default.nix @@ -0,0 +1,5 @@ +{ ... }: +{ + age.secrets.keycloakDatabasePasswordFile.file = ./keycloakDatabasePasswordFile.age; + age.secrets.oauth2ProxyKeyFile.file = ./oauth2ProxyKeyFile.age; +} diff --git a/machines/core-services-01/secrets/keycloakDatabasePasswordFile.age b/machines/core-services-01/secrets/keycloakDatabasePasswordFile.age new file mode 100644 index 0000000..4a352ab --- /dev/null +++ b/machines/core-services-01/secrets/keycloakDatabasePasswordFile.age @@ -0,0 +1,26 @@ +age-encryption.org/v1 +-> ssh-ed25519 lHr4YQ FHOLoe1idBzwzFB5v1UqrVIgIjmyVMqhC60F+7bsslY ++4jeqlOONU712hstLOOU59dHgx48CB3+Z4xn1faH8Q0 +-> ssh-ed25519 Wu8JLQ hqwTH7IVS1GTep9tNy6vrUUVtPcVXBxDnJj77S+l/Ek +gmnQhE5wnxQgEhyE18RKKemMQr4ewtRkQRt0bJo8O7Y +-> ssh-ed25519 cvTB5g bw+GZVk23ok4lgUF86PqTkZOM7BPNY7foMYYMZSEemU +6BAoCmLYb1oJwPPW3X2AaS3ZOttSxAykOeKIJM/03+k +-> ssh-ed25519 /vwQcQ Kqg5WdWhAuxCxMgWPpXWk77utvbIbBdcZXNSOF+a938 +4361sLVjBWOoWqTl7sIktNiulSU4gHnD2Q5gjDkZ2po +-> ssh-ed25519 reTIKw abLB9hwppWQhlkAHx3AiFgePvigajethU03CjTu6SUg +sueQMp1LPmF4h1EPsyGrSDH6RoXVXoWm1i3OISZlyPw +-> ssh-ed25519 85WiGg T6amGqzBiF7BLhnhPrz8BCu/NDikWBDnRv+UL2Y8mXs +xghk5e+D3O4rX4FT4TNu/bowSj7HCn3Wi4E6F7pseiw +-> ssh-rsa krWCLQ +KDsZM/5myCVtb7RL9Mo1F2WUKzBPhwillBvrIONZKH0dh3mCMjeVfyYTto1NxKxp +GsvYltgLbDggo3ittwQedB9s/JXL5z0+f3DroKVJzw82ti6w3SMpvKiCR2x+5DjH +D4Wzt/CQFujxAMOghKQGlFuCM6nVkpmL9ucgUPEp7ApbNWuc4patJgLpvkE0yj7X +Q4ScTPg86Oh5RFf4Qwa3QhG7IdnIoSSJxK+rK5qZb2vPST9zc2OKZKQXOh2h6hBy +tEAhRYBTu6oqprwYlEWL7dCsbBeHjLmBE6Zvovp51PizZhzub1jCh/fuka1VTFSq +f1oWAdTS3Ow5gXWKoH5TkQ +-> +_u~Wjak-grease cU8 ?4 8Y(inxl+ +h+7nxip00iflkCYBX2HvbHYc0SjsLvn4WVYUPzhDGjyauwARfA5zCfuIbGnEcxzF +FOWG9QQzr90JDCkonUjGTJ3N+ykLpiYCvLDJgXZB4MVEONyutwM +--- dZ6ca/xXQAOh82oeOyV/EkjTzK+oUj0YgzGTqyzJ8Rs +a™éæ OvF·âŒžú‘ÞñÃúÓÊ› +¤¦ÄÃJF¾»ÈÐßjëjŒ+ \ No newline at end of file diff --git a/machines/core-services-01/secrets/oauth2ProxyKeyFile.age b/machines/core-services-01/secrets/oauth2ProxyKeyFile.age new file mode 100644 index 0000000..eb729b2 Binary files /dev/null and b/machines/core-services-01/secrets/oauth2ProxyKeyFile.age differ diff --git a/machines/core-services-01/secrets/secrets.nix b/machines/core-services-01/secrets/secrets.nix new file mode 100644 index 0000000..dca2f64 --- /dev/null +++ b/machines/core-services-01/secrets/secrets.nix @@ -0,0 +1,13 @@ +let + pkgs = import {}; + lib = pkgs.lib; + readPubkeys = user: builtins.filter (k: k != "") (lib.splitString "\n" (builtins.readFile (../pubkeys + "/${user}.keys"))); + superadmins = (readPubkeys "raito") ++ (readPubkeys "gdd"); + core-services-01 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrnZxP4OUGDzd1uykMghzFNLH0Fg42hH+0qxif6O6oU"; + systems = [ core-services-01 ]; +in + { + "keycloakDatabasePasswordFile.age".publicKeys = superadmins ++ systems; + "oauth2ProxyKeyFile.age".publicKeys = superadmins ++ systems; + } + diff --git a/machines/core-services-01/subZone.nix b/machines/core-services-01/subZone.nix new file mode 100644 index 0000000..c9417d9 --- /dev/null +++ b/machines/core-services-01/subZone.nix @@ -0,0 +1,56 @@ +{ config, dns, ... }: + +with dns.lib.combinators; + +let + my = config.my; + delegateACMEDNSChallenge = acme: { _acme-challenge.CNAME = [ acme ]; }; +in +with my.ipv6; # contains { standard, acme } +{ + SOA = { + nameServer = "ns1.${my.subZone}."; + adminEmail = my.email; + serial = 2021072400; # Y M D Version + }; + + NS = [ + "ns1.${my.subZone}." + ]; + + AAAA = standard; + + CAA = letsEncrypt my.email; + + subdomains = { + git.AAAA = standard; + wiki.AAAA = standard; + monitoring.AAAA = standard; + auth.AAAA = standard; + push.AAAA = standard; + ns1.AAAA = standard; + + # Délégation de sous zone à he.gdd pour la certification HE. + gdd.subdomains.he = { + NS = [ "ns1.he.gdd.${my.subZone}." ]; + subdomains.ns1.AAAA = [ "2001:470:1f13:187:b80d:21ff:fe43:f1a5" ]; + }; + + acme = { + NS = [ "acme.${my.subZone}." ]; + AAAA = [ acme ]; + }; + + internal.subdomains = { + core01 = { + A = [ "10.1.1.20" ]; + }; + pve01 = { + A = [ "10.1.1.10" ]; + subdomains = { + idrac.A = [ "10.1.2.20" ]; + } // delegateACMEDNSChallenge "7c663a49-151c-4eea-a34f-725ff9f19d41.acme.rz.ens.wtf."; + }; + }; + }; +} diff --git a/machines/core-services-01/system.nix b/machines/core-services-01/system.nix new file mode 100644 index 0000000..31a6994 --- /dev/null +++ b/machines/core-services-01/system.nix @@ -0,0 +1,28 @@ +{ pkgs, ... }: +{ + # Auto upgrades + system.autoUpgrade = { + enable = true; + allowReboot = false; + }; + + # Auto GC and store optimizations + nix = { + trustedUsers = [ "root" "gab" ]; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 90d"; + }; + optimise.automatic = true; + extraOptions = '' + min-free = ${toString (100 * 1024 * 1024)} + max-free = ${toString (1024 * 1024 * 1024)} + ''; + }; + + services.locate = { + enable = true; + interval = "04:05"; + }; +} diff --git a/machines/core-services-01/vim.nix b/machines/core-services-01/vim.nix new file mode 100644 index 0000000..bed8752 --- /dev/null +++ b/machines/core-services-01/vim.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: +{ + environment.variables = { EDITOR = "vim"; }; + + environment.systemPackages = with pkgs; [ + nixfmt + git + (neovim.override { + vimAlias = true; + configure = { + packages.myPlugins = with pkgs.vimPlugins; { + start = [ vim-lastplace vim-nix ]; + opt = []; + }; + customRC = '' + set encoding=utf-8 + set wildmenu + + set nocompatible + set backspace=indent,eol,start + set cursorline + hi CursorLine term=bold cterm=bold ctermbg=darkgrey + set number + set relativenumber + set tabstop=4 + set expandtab + ''; + }; + } + )]; +}