diff options
33 files changed, 1144 insertions, 220 deletions
| @@ -94,6 +94,18 @@ | |||
| 94 | "type": "github" | 94 | "type": "github" |
| 95 | } | 95 | } |
| 96 | }, | 96 | }, |
| 97 | "leapseconds": { | ||
| 98 | "flake": false, | ||
| 99 | "locked": { | ||
| 100 | "narHash": "sha256-VCE0xQRXz833Qann3dgKU2wHPRZDdSN4/M+0nd3yYl4=", | ||
| 101 | "type": "file", | ||
| 102 | "url": "https://www.ietf.org/timezones/data/leap-seconds.list" | ||
| 103 | }, | ||
| 104 | "original": { | ||
| 105 | "type": "file", | ||
| 106 | "url": "https://www.ietf.org/timezones/data/leap-seconds.list" | ||
| 107 | } | ||
| 108 | }, | ||
| 97 | "mach-nix": { | 109 | "mach-nix": { |
| 98 | "inputs": { | 110 | "inputs": { |
| 99 | "flake-utils": "flake-utils", | 111 | "flake-utils": "flake-utils", |
| @@ -197,6 +209,7 @@ | |||
| 197 | "deploy-rs": "deploy-rs", | 209 | "deploy-rs": "deploy-rs", |
| 198 | "flake-compat": "flake-compat", | 210 | "flake-compat": "flake-compat", |
| 199 | "home-manager": "home-manager", | 211 | "home-manager": "home-manager", |
| 212 | "leapseconds": "leapseconds", | ||
| 200 | "mach-nix": "mach-nix", | 213 | "mach-nix": "mach-nix", |
| 201 | "nixpkgs": "nixpkgs", | 214 | "nixpkgs": "nixpkgs", |
| 202 | "nvfetcher": "nvfetcher", | 215 | "nvfetcher": "nvfetcher", |
| @@ -66,6 +66,11 @@ | |||
| 66 | pypi-deps-db.follows = "pypi-deps-db"; | 66 | pypi-deps-db.follows = "pypi-deps-db"; |
| 67 | }; | 67 | }; |
| 68 | }; | 68 | }; |
| 69 | |||
| 70 | leapseconds = { | ||
| 71 | url = "https://www.ietf.org/timezones/data/leap-seconds.list"; | ||
| 72 | flake = false; | ||
| 73 | }; | ||
| 69 | }; | 74 | }; |
| 70 | 75 | ||
| 71 | outputs = { self, nixpkgs, home-manager, sops-nix, deploy-rs, nvfetcher, ... }@inputs: | 76 | outputs = { self, nixpkgs, home-manager, sops-nix, deploy-rs, nvfetcher, ... }@inputs: |
| @@ -210,11 +215,7 @@ | |||
| 210 | 215 | ||
| 211 | apps = foldr recursiveUpdate {} [activateNixosConfigurations activateHomeManagerConfigurations]; | 216 | apps = foldr recursiveUpdate {} [activateNixosConfigurations activateHomeManagerConfigurations]; |
| 212 | 217 | ||
| 213 | devShells = forAllSystems (system: systemPkgs: { default = import ./shell.nix { | 218 | devShells = forAllSystems (system: systemPkgs: { default = import ./shell.nix ({ inherit system; } // inputs); }); |
| 214 | pkgs = self.legacyPackages.${system}; | ||
| 215 | deploy-rs = deploy-rs.packages.${system}.deploy-rs; | ||
| 216 | nvfetcher = nvfetcher.defaultPackage.${system}; | ||
| 217 | };}); | ||
| 218 | 219 | ||
| 219 | templates.default = { | 220 | templates.default = { |
| 220 | path = ./.; | 221 | path = ./.; |
diff --git a/hosts/surtr/prometheus/tls.crt b/hosts/surtr/prometheus/tls.crt index ba958f40..d81f429f 100644 --- a/hosts/surtr/prometheus/tls.crt +++ b/hosts/surtr/prometheus/tls.crt | |||
| @@ -1,10 +1,13 @@ | |||
| 1 | -----BEGIN CERTIFICATE----- | 1 | -----BEGIN CERTIFICATE----- |
| 2 | MIIBXzCCARGgAwIBAgIBATAFBgMrZXAwHzEdMBsGA1UEAwwUcHJvbWV0aGV1cy55 | 2 | MIIB5TCCAWWgAwIBAgIPQAAAAGNpYE436fsCRvVfMAUGAytlcTAfMR0wGwYDVQQD |
| 3 | Z2dkcmFzaWwwIBcNMjIwNDA4MjAwMzU1WhgPMjA5MDA0MjYyMDAzNTVaMBoxGDAW | 3 | DBRwcm9tZXRoZXVzLnlnZ2RyYXNpbDAeFw0yMjExMDcxOTM5NDFaFw0zMjExMDcx |
| 4 | BgNVBAMMD3N1cnRyLnlnZ2RyYXNpbDAqMAUGAytlcAMhAAJd8I32X/z9J0cO2Oz+ | 4 | OTQ0NDFaMBoxGDAWBgNVBAMMD3N1cnRyLnlnZ2RyYXNpbDAqMAUGAytlcAMhAAJd |
| 5 | 4KAoIJq0igdMdbLBA+8WO+vgo3UwczAMBgNVHRMBAf8EAjAAMEQGA1UdEQQ9MDuC | 5 | 8I32X/z9J0cO2Oz+4KAoIJq0igdMdbLBA+8WO+vgo4G8MIG5MB8GA1UdIwQYMBaA |
| 6 | GnByb21ldGhldXMuc3VydHIueWdnZHJhc2lsgh1wcm9tZXRoZXVzLnN1cnRyLnln | 6 | FObrhCUDCZk6/JeeDMNWl8WeLr+MMB0GA1UdDgQWBBQ3na09y/kUWmnN4nHYCJeT |
| 7 | Z2RyYXNpbC5saTAdBgNVHQ4EFgQUN52tPcv5FFppzeJx2AiXk6UgPDgwBQYDK2Vw | 7 | pSA8ODAOBgNVHQ8BAf8EBAMCBeAwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggr |
| 8 | A0EAPN9zhaeBB2C1TursdARH0jVBz9g0dRhP7sO5ZG0K+xp24paLXiTF1rYub24p | 8 | BgEFBQcDAjBEBgNVHREEPTA7ghpwcm9tZXRoZXVzLnN1cnRyLnlnZ2RyYXNpbIId |
| 9 | /yZw71p7M0BAE+hJqYBzYo5YBQ== | 9 | cHJvbWV0aGV1cy5zdXJ0ci55Z2dkcmFzaWwubGkwBQYDK2VxA3MAYHd3I/Mg/t34 |
| 10 | zdcxrIKOAKJ9ZVVoP0msk/viKrZ4b+Q9rKSNEnkyk0y56Z7FlLDxGLScaemqQ3uA | ||
| 11 | 5hjhdTci/xd4xYX/edLw1AWGRs2kBe3vs2WOmrdcKa849vdMH27G/P/+bgbdofCN | ||
| 12 | fukxYHzpESYA | ||
| 10 | -----END CERTIFICATE----- | 13 | -----END CERTIFICATE----- |
diff --git a/hosts/vidhar/borg/default.nix b/hosts/vidhar/borg/default.nix index 7672de18..80ce9c7e 100644 --- a/hosts/vidhar/borg/default.nix +++ b/hosts/vidhar/borg/default.nix | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | { config, pkgs, lib, flakeInputs, ... }: | 1 | { config, pkgs, lib, flakeInputs, utils, ... }: |
| 2 | 2 | ||
| 3 | with lib; | 3 | with lib; |
| 4 | 4 | ||
| @@ -21,60 +21,26 @@ let | |||
| 21 | ServerAliveCountMax 30 | 21 | ServerAliveCountMax 30 |
| 22 | ''; | 22 | ''; |
| 23 | 23 | ||
| 24 | copyService = { repo, repoEscaped }: let | 24 | checkBorgUnit = { |
| 25 | serviceName = "copy-borg@${repoEscaped}"; | ||
| 26 | in nameValuePair serviceName { | ||
| 27 | serviceConfig = { | 25 | serviceConfig = { |
| 28 | Type = "oneshot"; | 26 | Type = "oneshot"; |
| 29 | ExecStart = "${copyBorg}/bin/copy_borg --verbosity 3 ${escapeShellArg repo} yggdrasil.borgbase:repo"; | 27 | ExecStart = "${pkgs.borgbackup}/bin/borg ${utils.escapeSystemdExecArgs [ |
| 30 | TimeoutStartSec = "8h"; | 28 | "--lock-wait" "3600" |
| 31 | # User = "borg"; | 29 | "--progress" |
| 32 | # Group = "borg"; | 30 | "check" |
| 33 | # StateDirectory = "borg"; | 31 | "--verify-data" |
| 34 | RuntimeDirectory = "copy-borg"; | 32 | ]} %I"; |
| 35 | Environment = [ | 33 | Environment = [ |
| 36 | "BORG_RSH=\"${pkgs.openssh}/bin/ssh -F ${pkgs.writeText "config" sshConfig}\"" | ||
| 37 | "BORG_BASE_DIR=/var/lib/borg" | 34 | "BORG_BASE_DIR=/var/lib/borg" |
| 38 | "BORG_CONFIG_DIR=/var/lib/borg/config" | 35 | "BORG_CONFIG_DIR=/var/lib/borg/config" |
| 39 | "BORG_CACHE_DIR=/var/lib/borg/cache" | 36 | "BORG_CACHE_DIR=/var/lib/borg/cache" |
| 40 | "BORG_SECURITY_DIR=/var/lib/borg/security" | 37 | "BORG_SECURITY_DIR=/var/lib/borg/security" |
| 41 | "BORG_KEYS_DIR=/var/lib/borg/keys" | 38 | "BORG_KEYS_DIR=/var/lib/borg/keys" |
| 42 | "BORG_KEY_FILE=${config.sops.secrets."yggdrasil.borgkey".path}" | ||
| 43 | "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes" | ||
| 44 | "BORG_HOSTNAME_IS_UNIQUE=yes" | 39 | "BORG_HOSTNAME_IS_UNIQUE=yes" |
| 40 | "BORG_RSH=\"${pkgs.openssh}/bin/ssh -F ${pkgs.writeText "config" sshConfig}\"" | ||
| 45 | ]; | 41 | ]; |
| 46 | |||
| 47 | LogRateLimitIntervalSec = 0; | ||
| 48 | }; | 42 | }; |
| 49 | }; | 43 | }; |
| 50 | |||
| 51 | copyBorg = flakeInputs.mach-nix.lib.${config.nixpkgs.system}.buildPythonPackage rec { | ||
| 52 | pname = "copy-borg"; | ||
| 53 | src = ./copy; | ||
| 54 | version = "0.0.0"; | ||
| 55 | ignoreDataOutdated = true; | ||
| 56 | |||
| 57 | requirements = '' | ||
| 58 | humanize | ||
| 59 | tqdm | ||
| 60 | python-dateutil | ||
| 61 | xdg | ||
| 62 | python-unshare | ||
| 63 | pyprctl | ||
| 64 | halo | ||
| 65 | ''; | ||
| 66 | postInstall = '' | ||
| 67 | wrapProgram $out/bin/copy_borg \ | ||
| 68 | --prefix PATH : ${makeBinPath (with pkgs; [util-linux borgbackup])}:${config.security.wrapperDir} | ||
| 69 | ''; | ||
| 70 | |||
| 71 | providers.python-unshare = "nixpkgs"; | ||
| 72 | overridesPre = [ | ||
| 73 | (self: super: { python-unshare = super.python-unshare.overrideAttrs (oldAttrs: { name = "python-unshare-0.2.1"; version = "0.2.1"; }); }) | ||
| 74 | ]; | ||
| 75 | |||
| 76 | # _.tomli.buildInputs.add = with pkgs."python3Packages"; [ flit-core ]; | ||
| 77 | }; | ||
| 78 | in { | 44 | in { |
| 79 | config = { | 45 | config = { |
| 80 | services.borgsnap = { | 46 | services.borgsnap = { |
| @@ -85,7 +51,15 @@ in { | |||
| 85 | keyfile = config.sops.secrets."yggdrasil.borgkey".path; | 51 | keyfile = config.sops.secrets."yggdrasil.borgkey".path; |
| 86 | }; | 52 | }; |
| 87 | 53 | ||
| 88 | systemd.services = listToAttrs (map copyService [{ repo = "/srv/backup/borg/jotnar"; repoEscaped = "srv-backup-borg-jotnar"; }]); | 54 | services.copyborg.jotnar = { |
| 55 | from = "/srv/backup/borg/jotnar"; | ||
| 56 | to = "yggdrasil.borgbase:repo"; | ||
| 57 | inherit sshConfig; | ||
| 58 | keyfile = config.sops.secrets."yggdrasil.borgkey".path; | ||
| 59 | timerOptions.timerConfig = { | ||
| 60 | OnCalendar = "*-*-* 00/4:00:00 Europe/Berlin"; | ||
| 61 | }; | ||
| 62 | }; | ||
| 89 | 63 | ||
| 90 | services.borgbackup.repos.jotnar = { | 64 | services.borgbackup.repos.jotnar = { |
| 91 | path = "/srv/backup/borg/jotnar"; | 65 | path = "/srv/backup/borg/jotnar"; |
| @@ -95,6 +69,27 @@ in { | |||
| 95 | in filter (v: v != null) (mapAttrsToList toAuthKey (builtins.readDir dir)); | 69 | in filter (v: v != null) (mapAttrsToList toAuthKey (builtins.readDir dir)); |
| 96 | }; | 70 | }; |
| 97 | 71 | ||
| 72 | systemd.services."check-borg@${utils.escapeSystemdPath "/srv/backup/borg/jotnar"}" = checkBorgUnit; | ||
| 73 | systemd.services."check-borg@${utils.escapeSystemdPath "yggdrasil.borgbase:repo"}" = recursiveUpdate checkBorgUnit { | ||
| 74 | serviceConfig = { | ||
| 75 | Environment = checkBorgUnit.serviceConfig.Environment ++ [ | ||
| 76 | "BORG_KEY_FILE=${config.sops.secrets."yggdrasil.borgkey".path}" | ||
| 77 | ]; | ||
| 78 | }; | ||
| 79 | }; | ||
| 80 | systemd.timers."check-borg@${utils.escapeSystemdPath "/srv/backup/borg/jotnar"}" = { | ||
| 81 | wantedBy = [ "timers.target" ]; | ||
| 82 | timerConfig = { | ||
| 83 | OnCalendar = "Sun *-*-02..08 01:30:00 Europe/Berlin"; | ||
| 84 | }; | ||
| 85 | }; | ||
| 86 | systemd.timers."check-borg@${utils.escapeSystemdPath "yggdrasil.borgbase:repo"}" = { | ||
| 87 | wantedBy = [ "timers.target" ]; | ||
| 88 | timerConfig = { | ||
| 89 | OnCalendar = "Sun *-*-02..08 01:30:00 Europe/Berlin"; | ||
| 90 | }; | ||
| 91 | }; | ||
| 92 | |||
| 98 | boot.postBootCommands = mkBefore '' | 93 | boot.postBootCommands = mkBefore '' |
| 99 | ${pkgs.findutils}/bin/find /srv/backup/borg -type d -empty -delete | 94 | ${pkgs.findutils}/bin/find /srv/backup/borg -type d -empty -delete |
| 100 | ''; | 95 | ''; |
| @@ -123,13 +118,5 @@ in { | |||
| 123 | group = "borg"; | 118 | group = "borg"; |
| 124 | mode = "0400"; | 119 | mode = "0400"; |
| 125 | }; | 120 | }; |
| 126 | |||
| 127 | systemd.timers."copy-borg@srv-backup-borg-jotnar" = { | ||
| 128 | wantedBy = ["multi-user.target"]; | ||
| 129 | |||
| 130 | timerConfig = { | ||
| 131 | OnCalendar = "*-*-* 00/4:00:00 Europe/Berlin"; | ||
| 132 | }; | ||
| 133 | }; | ||
| 134 | }; | 121 | }; |
| 135 | } | 122 | } |
diff --git a/hosts/vidhar/borg/pyprctl-packages.nix b/hosts/vidhar/borg/pyprctl-packages.nix deleted file mode 100644 index d3b4256a..00000000 --- a/hosts/vidhar/borg/pyprctl-packages.nix +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | # Generated by pip2nix 0.8.0.dev1 | ||
| 2 | # See https://github.com/nix-community/pip2nix | ||
| 3 | |||
| 4 | { pkgs, fetchurl, fetchgit, fetchhg }: | ||
| 5 | |||
| 6 | self: super: { | ||
| 7 | "pyprctl" = super.buildPythonPackage rec { | ||
| 8 | pname = "pyprctl"; | ||
| 9 | version = "0.1.3"; | ||
| 10 | src = fetchurl { | ||
| 11 | url = "https://files.pythonhosted.org/packages/bf/5e/62765de39bbce8111fb1f4453a4a804913bf49179fa265fb713ed66c9d15/pyprctl-0.1.3-py3-none-any.whl"; | ||
| 12 | sha256 = "1pgif990r92za5rx12mjnq5iiz72d455v0wrawzb73q79w8ya0k3"; | ||
| 13 | }; | ||
| 14 | format = "wheel"; | ||
| 15 | doCheck = false; | ||
| 16 | buildInputs = []; | ||
| 17 | checkInputs = []; | ||
| 18 | nativeBuildInputs = []; | ||
| 19 | propagatedBuildInputs = []; | ||
| 20 | }; | ||
| 21 | } | ||
diff --git a/hosts/vidhar/prometheus/ca/.gitignore b/hosts/vidhar/prometheus/ca/.gitignore deleted file mode 100644 index 7c894574..00000000 --- a/hosts/vidhar/prometheus/ca/.gitignore +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | ca.key | ||
| 2 | ca.cnf | ||
| 3 | *.old \ No newline at end of file | ||
diff --git a/hosts/vidhar/prometheus/ca/ca.crt b/hosts/vidhar/prometheus/ca/ca.crt index 922fed28..8cfea666 100644 --- a/hosts/vidhar/prometheus/ca/ca.crt +++ b/hosts/vidhar/prometheus/ca/ca.crt | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | -----BEGIN CERTIFICATE----- | 1 | -----BEGIN CERTIFICATE----- |
| 2 | MIIBsjCCAWSgAwIBAgIUOzZ8XcFb8XtI2yyWp4S/WMD6QxQwBQYDK2VwMB8xHTAb | 2 | MIIBrjCCAS6gAwIBAgIUYV3YPBx91CbgMpOGb5HKMZ2hzRUwBQYDK2VxMB8xHTAb |
| 3 | BgNVBAMMFHByb21ldGhldXMueWdnZHJhc2lsMCAXDTIyMDQwODE5NDgwMFoYDzIw | 3 | BgNVBAMMFHByb21ldGhldXMueWdnZHJhc2lsMB4XDTIyMTEwNzE5MjgzNFoXDTMy |
| 4 | OTAwNDI2MTk0ODAwWjAfMR0wGwYDVQQDDBRwcm9tZXRoZXVzLnlnZ2RyYXNpbDAq | 4 | MTEwNzE5MzMzNFowHzEdMBsGA1UEAwwUcHJvbWV0aGV1cy55Z2dkcmFzaWwwQzAF |
| 5 | MAUGAytlcAMhAOoxPLBH6pnCRtE7V5gejM92gg1vLNLHw3rFIXXchOJmo4GvMIGs | 5 | BgMrZXEDOgAVqcV3KGDhcbQt/UR3Yv6OuAGc+Kc8hrDHjAV8K9GTjahc/d49NK2v |
| 6 | MB0GA1UdDgQWBBRnwBkgZFnueEa7aV8aEAoMRzW4CTBaBgNVHSMEUzBRgBRnwBkg | 6 | FAz0uK8YidIaTVJZjzHhTgCjYzBhMB8GA1UdIwQYMBaAFObrhCUDCZk6/JeeDMNW |
| 7 | ZFnueEa7aV8aEAoMRzW4CaEjpCEwHzEdMBsGA1UEAwwUcHJvbWV0aGV1cy55Z2dk | 7 | l8WeLr+MMB0GA1UdDgQWBBTm64QlAwmZOvyXngzDVpfFni6/jDAOBgNVHQ8BAf8E |
| 8 | cmFzaWyCFDs2fF3BW/F7SNsslqeEv1jA+kMUMA8GA1UdEwEB/wQFMAMBAf8wCwYD | 8 | BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXEDcwAFAqBlI7SpHaSE+0mMzx5x |
| 9 | VR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQEAwICBDAFBgMrZXADQQD9AC2OHtzW8QSC | 9 | 0M6T3iJtLxP36Qz5MHx3vvcbbx1eJhZWKewuyz+9LXaCkf8Jpd5AFoC+HhoikVSz |
| 10 | HU/4rGdRWRqr3pfclKXimSWaAXMPly2M1qehPI402lhQrIAVF+D1pi/EAGJfbbzF | 10 | 46yVzmTBt6TISc4bh+eiWcXEKFbxEbXkwqZd2m/oHI4Em4qnDKp96FcOfq6RQ8pR |
| 11 | aurykEMB | 11 | AwA= |
| 12 | -----END CERTIFICATE----- | 12 | -----END CERTIFICATE----- |
diff --git a/hosts/vidhar/prometheus/ca/ca.key b/hosts/vidhar/prometheus/ca/ca.key new file mode 100644 index 00000000..32c4330a --- /dev/null +++ b/hosts/vidhar/prometheus/ca/ca.key | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:yk8nI2Zz2F3XnBM9dqnA3UoWTTCGJLMZUYjpo+SW+ARmZVgYdcqHZunhoGRQP/r6qrIUvM/2Yl85Uosw43jllILCNESH17Gi6uI0gD9OE8I14oll8wCL+/GvP/IuU//1NEAeLF9cz8MBWPE0WW2wQk5DF4ikl+z3/McG+kaqeU+ka6aMmjIjUstjR2vCf+pfZN3KswylcLaeuvXP,iv:ByEIQCxQwjynCFxGZdYtg+nx9mFmwbqHL3iBhzLbKIQ=,tag:jIc+KcfbSmiZqM6Z2xIa0g==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": null, | ||
| 9 | "lastmodified": "2022-11-07T19:33:34Z", | ||
| 10 | "mac": "ENC[AES256_GCM,data:UE1+0M15ZBgsKOfEmz8DMeQsmzkRxcN5cjdpMswzc6vIgo6sRN4ArdtDKqAMcFtFhzokSZin6OIizsk6KLlsts5sgVHQHXKrqssc016OADRg4BoC9zM/MGLUXOHndrRSPGSQgRDCeVwmR9C5iE18VZ/NCcZtoztHt6DPt3xmGpo=,iv:JB6CTWUyyDpjciKfYugf78Xo+jDKCH3+tL8p9G7M5y0=,tag:n73uY6cX5EV6Rjq1/HM8kw==,type:str]", | ||
| 11 | "pgp": [ | ||
| 12 | { | ||
| 13 | "created_at": "2022-11-07T19:33:34Z", | ||
| 14 | "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DXxoViZlp6dISAQdAJxBqRR1DzDPs/sQgfZNaKZTWH+mbdQo9mpGRWcWkm1ww\nOjVRJjiBDyeItfbOS9hnEOJKwKUIk1tH7F5m+U5daFLSw/Ct/xzJ7iyphcfRzNFN\n0l4BHF6sMyoPFpSGpE+0d4IRqfDPF3t9d3NL1lAGV75MoEho38ptNCbAn32kWpZ9\n7/Vk3L+oR/3xhLAwm3/7JDed01zNnKRaxFh3zpYfwZWhMtEdoUoEIkojufEJ64s2\n=KZjL\n-----END PGP MESSAGE-----\n", | ||
| 15 | "fp": "30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "unencrypted_suffix": "_unencrypted", | ||
| 19 | "version": "3.7.3" | ||
| 20 | } | ||
| 21 | } \ No newline at end of file | ||
diff --git a/hosts/vidhar/prometheus/ca/ca.key.sops b/hosts/vidhar/prometheus/ca/ca.key.sops deleted file mode 100644 index 5313056e..00000000 --- a/hosts/vidhar/prometheus/ca/ca.key.sops +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:XW6h0psHOSV0cR03vRg479A5XRM7KfiBfVgvm4QlxCZzhkk5U1ToDJIaCxqKpxlEu8wm79wmz+/CmSLDEBcs7x05a5vBDt81mlWJ49PolOrG9bL9Qkyq5u8sB8HWXRXxCP5kg2su+n9NqdHX9AIhYCXy7VJDuGo=,iv:v661AhF2Q/O+a7JtwHtnSkSI0mL8ltu5rPny8vWCL/Q=,tag:c7b0a6o6y/MI5vG85uFuUg==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": null, | ||
| 9 | "lastmodified": "2022-04-08T20:12:22Z", | ||
| 10 | "mac": "ENC[AES256_GCM,data:W/IF6WgTscbkcMUTR3aeqM/H/UwgFgILDbKBxYJQxcFtt4kq3UqzSd/e0hk5NQ9IkagAC4X0gZDuzco2mc7caUGyzMKRdA2ekgcdDwzruQ4i+UYyr80dFhqHpV+aksdZJVR+dJzkmIRmza3Ia5e/X01XNIbIrU13JKYm9jCskd0=,iv:2g+UFcSTxcTrf+toi4BDVvAaY5ydk7yRnhpQ/rrNvVo=,tag:3X01wEqL/Q8cIiF+DEMnpg==,type:str]", | ||
| 11 | "pgp": [ | ||
| 12 | { | ||
| 13 | "created_at": "2022-04-08T20:12:22Z", | ||
| 14 | "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DXxoViZlp6dISAQdADN+s7UQS8hEBc2mMRovD/zKuIoIAS3swLpP6ul9kRGMw\nDCUvOL41sxXmuodi4Pg69YB2YcL47Fod7nQWUYaK8L3CuyjWUq1cxomlYtTd03eH\n0l4BiyWTuZ+1OG4Xng8B4zdcM5jWfeTRWupDIXcnPFjwz47FetmrcCAaROKYL87e\nAjK76Y6gR/gSj0GTTAUIfKFpqsqAdBAf6oBekQcPgeqcrJcZ2ZZFWzmswGBvcGjs\n=gqhG\n-----END PGP MESSAGE-----\n", | ||
| 15 | "fp": "30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "unencrypted_suffix": "_unencrypted", | ||
| 19 | "version": "3.7.2" | ||
| 20 | } | ||
| 21 | } \ No newline at end of file | ||
diff --git a/hosts/vidhar/prometheus/ca/certs/01.pem b/hosts/vidhar/prometheus/ca/certs/01.pem deleted file mode 100644 index 81abe0b7..00000000 --- a/hosts/vidhar/prometheus/ca/certs/01.pem +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | Certificate: | ||
| 2 | Data: | ||
| 3 | Version: 3 (0x2) | ||
| 4 | Serial Number: 1 (0x1) | ||
| 5 | Signature Algorithm: ED25519 | ||
| 6 | Issuer: CN=prometheus.yggdrasil | ||
| 7 | Validity | ||
| 8 | Not Before: Apr 8 20:03:55 2022 GMT | ||
| 9 | Not After : Apr 26 20:03:55 2090 GMT | ||
| 10 | Subject: CN=surtr.yggdrasil | ||
| 11 | Subject Public Key Info: | ||
| 12 | Public Key Algorithm: ED25519 | ||
| 13 | ED25519 Public-Key: | ||
| 14 | pub: | ||
| 15 | 02:5d:f0:8d:f6:5f:fc:fd:27:47:0e:d8:ec:fe:e0: | ||
| 16 | a0:28:20:9a:b4:8a:07:4c:75:b2:c1:03:ef:16:3b: | ||
| 17 | eb:e0 | ||
| 18 | X509v3 extensions: | ||
| 19 | X509v3 Basic Constraints: critical | ||
| 20 | CA:FALSE | ||
| 21 | X509v3 Subject Alternative Name: | ||
| 22 | DNS:prometheus.surtr.yggdrasil, DNS:prometheus.surtr.yggdrasil.li | ||
| 23 | X509v3 Subject Key Identifier: | ||
| 24 | 37:9D:AD:3D:CB:F9:14:5A:69:CD:E2:71:D8:08:97:93:A5:20:3C:38 | ||
| 25 | Signature Algorithm: ED25519 | ||
| 26 | 3c:df:73:85:a7:81:07:60:b5:4e:ea:ec:74:04:47:d2:35:41: | ||
| 27 | cf:d8:34:75:18:4f:ee:c3:b9:64:6d:0a:fb:1a:76:e2:96:8b: | ||
| 28 | 5e:24:c5:d6:b6:2e:6f:6e:29:ff:26:70:ef:5a:7b:33:40:40: | ||
| 29 | 13:e8:49:a9:80:73:62:8e:58:05 | ||
| 30 | -----BEGIN CERTIFICATE----- | ||
| 31 | MIIBXzCCARGgAwIBAgIBATAFBgMrZXAwHzEdMBsGA1UEAwwUcHJvbWV0aGV1cy55 | ||
| 32 | Z2dkcmFzaWwwIBcNMjIwNDA4MjAwMzU1WhgPMjA5MDA0MjYyMDAzNTVaMBoxGDAW | ||
| 33 | BgNVBAMMD3N1cnRyLnlnZ2RyYXNpbDAqMAUGAytlcAMhAAJd8I32X/z9J0cO2Oz+ | ||
| 34 | 4KAoIJq0igdMdbLBA+8WO+vgo3UwczAMBgNVHRMBAf8EAjAAMEQGA1UdEQQ9MDuC | ||
| 35 | GnByb21ldGhldXMuc3VydHIueWdnZHJhc2lsgh1wcm9tZXRoZXVzLnN1cnRyLnln | ||
| 36 | Z2RyYXNpbC5saTAdBgNVHQ4EFgQUN52tPcv5FFppzeJx2AiXk6UgPDgwBQYDK2Vw | ||
| 37 | A0EAPN9zhaeBB2C1TursdARH0jVBz9g0dRhP7sO5ZG0K+xp24paLXiTF1rYub24p | ||
| 38 | /yZw71p7M0BAE+hJqYBzYo5YBQ== | ||
| 39 | -----END CERTIFICATE----- | ||
diff --git a/hosts/vidhar/prometheus/ca/certs/02.pem b/hosts/vidhar/prometheus/ca/certs/02.pem deleted file mode 100644 index d908ca7d..00000000 --- a/hosts/vidhar/prometheus/ca/certs/02.pem +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | Certificate: | ||
| 2 | Data: | ||
| 3 | Version: 3 (0x2) | ||
| 4 | Serial Number: 2 (0x2) | ||
| 5 | Signature Algorithm: ED25519 | ||
| 6 | Issuer: CN=prometheus.yggdrasil | ||
| 7 | Validity | ||
| 8 | Not Before: Apr 8 20:07:13 2022 GMT | ||
| 9 | Not After : Apr 26 20:07:13 2090 GMT | ||
| 10 | Subject: CN=vidhar.yggdrasil | ||
| 11 | Subject Public Key Info: | ||
| 12 | Public Key Algorithm: ED25519 | ||
| 13 | ED25519 Public-Key: | ||
| 14 | pub: | ||
| 15 | 13:84:a6:01:07:7a:5e:8d:2b:8d:83:ee:73:1d:c6: | ||
| 16 | b8:9a:ad:b9:3d:40:51:ec:2c:f3:52:7d:81:90:e7: | ||
| 17 | ac:88 | ||
| 18 | X509v3 extensions: | ||
| 19 | X509v3 Basic Constraints: critical | ||
| 20 | CA:FALSE | ||
| 21 | X509v3 Subject Alternative Name: | ||
| 22 | DNS:prometheus.vidhar.yggdrasil | ||
| 23 | X509v3 Subject Key Identifier: | ||
| 24 | 44:AA:8E:CC:AB:C9:A7:D1:A1:D0:FA:7F:DB:87:1E:08:AA:6E:4D:59 | ||
| 25 | Signature Algorithm: ED25519 | ||
| 26 | 47:65:87:17:50:96:77:56:20:ac:9e:f4:e4:6d:19:6d:b7:24: | ||
| 27 | 11:af:0c:c3:f3:fd:75:19:d9:77:06:41:79:7f:a5:00:0c:18: | ||
| 28 | ee:82:3e:9e:09:61:34:cf:8f:f5:83:d1:5d:b2:e4:42:b6:3f: | ||
| 29 | 9c:b6:5a:f3:40:92:e6:8f:24:0f | ||
| 30 | -----BEGIN CERTIFICATE----- | ||
| 31 | MIIBQTCB9KADAgECAgECMAUGAytlcDAfMR0wGwYDVQQDDBRwcm9tZXRoZXVzLnln | ||
| 32 | Z2RyYXNpbDAgFw0yMjA0MDgyMDA3MTNaGA8yMDkwMDQyNjIwMDcxM1owGzEZMBcG | ||
| 33 | A1UEAwwQdmlkaGFyLnlnZ2RyYXNpbDAqMAUGAytlcAMhABOEpgEHel6NK42D7nMd | ||
| 34 | xriarbk9QFHsLPNSfYGQ56yIo1cwVTAMBgNVHRMBAf8EAjAAMCYGA1UdEQQfMB2C | ||
| 35 | G3Byb21ldGhldXMudmlkaGFyLnlnZ2RyYXNpbDAdBgNVHQ4EFgQURKqOzKvJp9Gh | ||
| 36 | 0Pp/24ceCKpuTVkwBQYDK2VwA0EAR2WHF1CWd1YgrJ705G0ZbbckEa8Mw/P9dRnZ | ||
| 37 | dwZBeX+lAAwY7oI+nglhNM+P9YPRXbLkQrY/nLZa80CS5o8kDw== | ||
| 38 | -----END CERTIFICATE----- | ||
diff --git a/hosts/vidhar/prometheus/ca/index.txt b/hosts/vidhar/prometheus/ca/index.txt deleted file mode 100644 index 41ebb0f4..00000000 --- a/hosts/vidhar/prometheus/ca/index.txt +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | V 20900426200355Z 01 unknown /CN=surtr.yggdrasil | ||
| 2 | V 20900426200713Z 02 unknown /CN=vidhar.yggdrasil | ||
diff --git a/hosts/vidhar/prometheus/ca/index.txt.attr b/hosts/vidhar/prometheus/ca/index.txt.attr deleted file mode 100644 index 8f7e63a3..00000000 --- a/hosts/vidhar/prometheus/ca/index.txt.attr +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | unique_subject = yes | ||
diff --git a/hosts/vidhar/prometheus/ca/serial b/hosts/vidhar/prometheus/ca/serial deleted file mode 100644 index 75016ea3..00000000 --- a/hosts/vidhar/prometheus/ca/serial +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | 03 | ||
diff --git a/hosts/vidhar/prometheus/tls.crt b/hosts/vidhar/prometheus/tls.crt index 792ed542..6516f185 100644 --- a/hosts/vidhar/prometheus/tls.crt +++ b/hosts/vidhar/prometheus/tls.crt | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | -----BEGIN CERTIFICATE----- | 1 | -----BEGIN CERTIFICATE----- |
| 2 | MIIBQTCB9KADAgECAgECMAUGAytlcDAfMR0wGwYDVQQDDBRwcm9tZXRoZXVzLnln | 2 | MIIByDCCAUigAwIBAgIPQAAAAGNpXrc6y389EXtIMAUGAytlcTAfMR0wGwYDVQQD |
| 3 | Z2RyYXNpbDAgFw0yMjA0MDgyMDA3MTNaGA8yMDkwMDQyNjIwMDcxM1owGzEZMBcG | 3 | DBRwcm9tZXRoZXVzLnlnZ2RyYXNpbDAeFw0yMjExMDcxOTMyNTRaFw0zMjExMDcx |
| 4 | A1UEAwwQdmlkaGFyLnlnZ2RyYXNpbDAqMAUGAytlcAMhABOEpgEHel6NK42D7nMd | 4 | OTM3NTRaMBsxGTAXBgNVBAMMEHZpZGhhci55Z2dkcmFzaWwwKjAFBgMrZXADIQAT |
| 5 | xriarbk9QFHsLPNSfYGQ56yIo1cwVTAMBgNVHRMBAf8EAjAAMCYGA1UdEQQfMB2C | 5 | hKYBB3pejSuNg+5zHca4mq25PUBR7CzzUn2BkOesiKOBnjCBmzAfBgNVHSMEGDAW |
| 6 | G3Byb21ldGhldXMudmlkaGFyLnlnZ2RyYXNpbDAdBgNVHQ4EFgQURKqOzKvJp9Gh | 6 | gBTm64QlAwmZOvyXngzDVpfFni6/jDAdBgNVHQ4EFgQURKqOzKvJp9Gh0Pp/24ce |
| 7 | 0Pp/24ceCKpuTVkwBQYDK2VwA0EAR2WHF1CWd1YgrJ705G0ZbbckEa8Mw/P9dRnZ | 7 | CKpuTVkwDgYDVR0PAQH/BAQDAgXgMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI |
| 8 | dwZBeX+lAAwY7oI+nglhNM+P9YPRXbLkQrY/nLZa80CS5o8kDw== | 8 | KwYBBQUHAwIwJgYDVR0RBB8wHYIbcHJvbWV0aGV1cy52aWRoYXIueWdnZHJhc2ls |
| 9 | MAUGAytlcQNzAIPNcNWqVX4Ie971O/S2DL0HMFmPbR331U4snLBqPGWC1/j9NV4O | ||
| 10 | cxJvLo8Hzb4I0BXn/nZbyk/ogCCJU69BVeK378qgLo68DIZ4TA3ka5ZPNRSt464Q | ||
| 11 | NvbkDhtFVVxM04xUjI4dOeE9jczG9nN3jHESAA== | ||
| 9 | -----END CERTIFICATE----- | 12 | -----END CERTIFICATE----- |
diff --git a/hosts/vidhar/borg/copy/copy_borg/__main__.py b/modules/borgcopy/copy/copy_borg/__main__.py index 5b374d99..5b374d99 100755 --- a/hosts/vidhar/borg/copy/copy_borg/__main__.py +++ b/modules/borgcopy/copy/copy_borg/__main__.py | |||
diff --git a/hosts/vidhar/borg/copy/setup.py b/modules/borgcopy/copy/setup.py index f77d9560..f77d9560 100644 --- a/hosts/vidhar/borg/copy/setup.py +++ b/modules/borgcopy/copy/setup.py | |||
diff --git a/modules/borgcopy/default.nix b/modules/borgcopy/default.nix new file mode 100644 index 00000000..eae07dc8 --- /dev/null +++ b/modules/borgcopy/default.nix | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | { config, pkgs, lib, utils, flakeInputs, ... }: | ||
| 2 | |||
| 3 | with lib; | ||
| 4 | |||
| 5 | let | ||
| 6 | copyBorg = flakeInputs.mach-nix.lib.${config.nixpkgs.system}.buildPythonPackage rec { | ||
| 7 | pname = "copy-borg"; | ||
| 8 | src = ./copy; | ||
| 9 | version = "0.0.0"; | ||
| 10 | ignoreDataOutdated = true; | ||
| 11 | |||
| 12 | requirements = '' | ||
| 13 | humanize | ||
| 14 | tqdm | ||
| 15 | python-dateutil | ||
| 16 | xdg | ||
| 17 | python-unshare | ||
| 18 | pyprctl | ||
| 19 | halo | ||
| 20 | ''; | ||
| 21 | postInstall = '' | ||
| 22 | wrapProgram $out/bin/copy_borg \ | ||
| 23 | --prefix PATH : ${makeBinPath (with pkgs; [util-linux borgbackup])}:${config.security.wrapperDir} | ||
| 24 | ''; | ||
| 25 | |||
| 26 | providers.python-unshare = "nixpkgs"; | ||
| 27 | overridesPre = [ | ||
| 28 | (self: super: { python-unshare = super.python-unshare.overrideAttrs (oldAttrs: { name = "python-unshare-0.2.1"; version = "0.2.1"; }); }) | ||
| 29 | ]; | ||
| 30 | |||
| 31 | # _.tomli.buildInputs.add = with pkgs."python3Packages"; [ flit-core ]; | ||
| 32 | }; | ||
| 33 | |||
| 34 | copyService = name: opts: nameValuePair "copy-borg@${utils.escapeSystemdPath name}" { | ||
| 35 | serviceConfig = { | ||
| 36 | Type = "oneshot"; | ||
| 37 | ExecStart = "${copyBorg}/bin/copy_borg --verbosity ${toString opts.verbosity} ${utils.escapeSystemdExecArgs [opts.from opts.to]}"; | ||
| 38 | TimeoutStartSec = "8h"; | ||
| 39 | # User = "borg"; | ||
| 40 | # Group = "borg"; | ||
| 41 | # StateDirectory = "borg"; | ||
| 42 | RuntimeDirectory = "copy-borg"; | ||
| 43 | Environment = [ | ||
| 44 | "BORG_BASE_DIR=/var/lib/borg" | ||
| 45 | "BORG_CONFIG_DIR=/var/lib/borg/config" | ||
| 46 | "BORG_CACHE_DIR=/var/lib/borg/cache" | ||
| 47 | "BORG_SECURITY_DIR=/var/lib/borg/security" | ||
| 48 | "BORG_KEYS_DIR=/var/lib/borg/keys" | ||
| 49 | ] | ||
| 50 | ++ optional opts.unknownUnencryptedRepoAccessOk "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes" | ||
| 51 | ++ optional opts.hostnameIsUnique "BORG_HOSTNAME_IS_UNIQUE=yes" | ||
| 52 | ++ optional (!(isNull opts.sshConfig)) "BORG_RSH=\"${pkgs.openssh}/bin/ssh -F ${pkgs.writeText "config" opts.sshConfig}\"" | ||
| 53 | ++ optional (!(isNull opts.keyfile)) "BORG_KEY_FILE=${opts.keyfile}"; | ||
| 54 | |||
| 55 | LogRateLimitIntervalSec = 0; | ||
| 56 | }; | ||
| 57 | }; | ||
| 58 | copyTimer = name: opts: nameValuePair "copy-borg@${utils.escapeSystemdPath name}" (recursiveUpdate { | ||
| 59 | wantedBy = [ "timers.target" ]; | ||
| 60 | |||
| 61 | timerConfig = { | ||
| 62 | Unit = "copy-borg@${utils.escapeSystemdPath name}.service"; | ||
| 63 | }; | ||
| 64 | } opts.timerOptions); | ||
| 65 | |||
| 66 | cfg = config.services.copyborg; | ||
| 67 | in { | ||
| 68 | options = { | ||
| 69 | services.copyborg = mkOption { | ||
| 70 | type = types.attrsOf (types.submodule { | ||
| 71 | options = { | ||
| 72 | from = mkOption { | ||
| 73 | type = types.str; | ||
| 74 | }; | ||
| 75 | to = mkOption { | ||
| 76 | type = types.str; | ||
| 77 | }; | ||
| 78 | |||
| 79 | verbosity = mkOption { | ||
| 80 | type = types.int; | ||
| 81 | default = 3; | ||
| 82 | }; | ||
| 83 | |||
| 84 | sshConfig = mkOption { | ||
| 85 | type = with types; nullOr str; | ||
| 86 | default = null; | ||
| 87 | }; | ||
| 88 | |||
| 89 | keyfile = mkOption { | ||
| 90 | type = with types; nullOr str; | ||
| 91 | default = null; | ||
| 92 | }; | ||
| 93 | |||
| 94 | unknownUnencryptedRepoAccessOk = mkOption { | ||
| 95 | type = types.bool; | ||
| 96 | default = false; | ||
| 97 | }; | ||
| 98 | hostnameIsUnique = mkOption { | ||
| 99 | type = types.bool; | ||
| 100 | default = true; | ||
| 101 | }; | ||
| 102 | |||
| 103 | timerOptions = mkOption { | ||
| 104 | # type = types.submodule utils.systemdUtils.unitOptions.stage2TimerOptions; | ||
| 105 | type = types.attrs; | ||
| 106 | default = { | ||
| 107 | wantedBy = ["timers.target"]; | ||
| 108 | }; | ||
| 109 | }; | ||
| 110 | }; | ||
| 111 | }); | ||
| 112 | default = {}; | ||
| 113 | }; | ||
| 114 | }; | ||
| 115 | |||
| 116 | config = { | ||
| 117 | systemd.services = mapAttrs' copyService cfg; | ||
| 118 | systemd.timers = mapAttrs' copyTimer cfg; | ||
| 119 | }; | ||
| 120 | } | ||
diff --git a/modules/borgsnap/default.nix b/modules/borgsnap/default.nix index f4c0eec4..0a674e64 100644 --- a/modules/borgsnap/default.nix +++ b/modules/borgsnap/default.nix | |||
| @@ -74,6 +74,15 @@ in { | |||
| 74 | type = with types; listOf str; | 74 | type = with types; listOf str; |
| 75 | default = []; | 75 | default = []; |
| 76 | }; | 76 | }; |
| 77 | |||
| 78 | unknownUnencryptedRepoAccessOk = mkOption { | ||
| 79 | type = types.bool; | ||
| 80 | default = false; | ||
| 81 | }; | ||
| 82 | hostnameIsUnique = mkOption { | ||
| 83 | type = types.bool; | ||
| 84 | default = true; | ||
| 85 | }; | ||
| 77 | }; | 86 | }; |
| 78 | }; | 87 | }; |
| 79 | 88 | ||
| @@ -95,9 +104,10 @@ in { | |||
| 95 | "BORG_CACHE_DIR=/var/lib/borg/cache" | 104 | "BORG_CACHE_DIR=/var/lib/borg/cache" |
| 96 | "BORG_SECURITY_DIR=/var/lib/borg/security" | 105 | "BORG_SECURITY_DIR=/var/lib/borg/security" |
| 97 | "BORG_KEYS_DIR=/var/lib/borg/keys" | 106 | "BORG_KEYS_DIR=/var/lib/borg/keys" |
| 98 | "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes" | 107 | ] |
| 99 | "BORG_HOSTNAME_IS_UNIQUE=yes" | 108 | ++ optional cfg.unknownUnencryptedRepoAccessOk "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes" |
| 100 | ] ++ optional (!(isNull cfg.sshConfig)) "BORG_RSH=\"${pkgs.openssh}/bin/ssh -F ${pkgs.writeText "config" cfg.sshConfig}\"" | 109 | ++ optional cfg.hostnameIsUnique "BORG_HOSTNAME_IS_UNIQUE=yes" |
| 110 | ++ optional (!(isNull cfg.sshConfig)) "BORG_RSH=\"${pkgs.openssh}/bin/ssh -F ${pkgs.writeText "config" cfg.sshConfig}\"" | ||
| 101 | ++ optional (!(isNull cfg.keyfile)) "BORG_KEY_FILE=${cfg.keyfile}"; | 111 | ++ optional (!(isNull cfg.keyfile)) "BORG_KEY_FILE=${cfg.keyfile}"; |
| 102 | RuntimeDirectory = "zfssnap-prune"; | 112 | RuntimeDirectory = "zfssnap-prune"; |
| 103 | }; | 113 | }; |
diff --git a/modules/zfssnap/zfssnap/zfssnap/__main__.py b/modules/zfssnap/zfssnap/zfssnap/__main__.py index 274317e2..2ff8b309 100644 --- a/modules/zfssnap/zfssnap/zfssnap/__main__.py +++ b/modules/zfssnap/zfssnap/zfssnap/__main__.py | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | #!@python@/bin/python | ||
| 2 | |||
| 3 | import csv | 1 | import csv |
| 4 | import subprocess | 2 | import subprocess |
| 5 | import io | 3 | import io |
diff --git a/overlays/matrix-synapse/1.70.1/default.nix b/overlays/matrix-synapse/1.70.1/default.nix new file mode 100644 index 00000000..0c026914 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/default.nix | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | { lib, stdenv, fetchFromGitHub, python3, openssl, rustPlatform | ||
| 2 | , enableSystemd ? stdenv.isLinux, nixosTests | ||
| 3 | , enableRedis ? true | ||
| 4 | , callPackage | ||
| 5 | }: | ||
| 6 | |||
| 7 | let | ||
| 8 | plugins = python3.pkgs.callPackage ./plugins { }; | ||
| 9 | tools = callPackage ./tools { }; | ||
| 10 | in | ||
| 11 | with python3.pkgs; | ||
| 12 | buildPythonApplication rec { | ||
| 13 | pname = "matrix-synapse"; | ||
| 14 | version = "1.70.1"; | ||
| 15 | format = "pyproject"; | ||
| 16 | |||
| 17 | src = fetchFromGitHub { | ||
| 18 | owner = "matrix-org"; | ||
| 19 | repo = "synapse"; | ||
| 20 | rev = "v${version}"; | ||
| 21 | hash = "sha256-/clEY3sabaDEOAAowQ896vYOvzf5Teevoa7ZkzWw+fY="; | ||
| 22 | }; | ||
| 23 | |||
| 24 | cargoDeps = rustPlatform.fetchCargoTarball { | ||
| 25 | inherit src; | ||
| 26 | name = "${pname}-${version}"; | ||
| 27 | hash = "sha256-9wxWxrn+uPcz60710DROhDqNC6FvTtnqzWiWRk8kl6A="; | ||
| 28 | }; | ||
| 29 | |||
| 30 | postPatch = '' | ||
| 31 | # Remove setuptools_rust from runtime dependencies | ||
| 32 | # https://github.com/matrix-org/synapse/blob/v1.69.0/pyproject.toml#L177-L185 | ||
| 33 | sed -i '/^setuptools_rust =/d' pyproject.toml | ||
| 34 | ''; | ||
| 35 | |||
| 36 | nativeBuildInputs = [ | ||
| 37 | poetry-core | ||
| 38 | rustPlatform.cargoSetupHook | ||
| 39 | setuptools-rust | ||
| 40 | ] ++ (with rustPlatform.rust; [ | ||
| 41 | cargo | ||
| 42 | rustc | ||
| 43 | ]); | ||
| 44 | |||
| 45 | buildInputs = [ openssl ]; | ||
| 46 | |||
| 47 | propagatedBuildInputs = [ | ||
| 48 | authlib | ||
| 49 | bcrypt | ||
| 50 | bleach | ||
| 51 | canonicaljson | ||
| 52 | daemonize | ||
| 53 | frozendict | ||
| 54 | ijson | ||
| 55 | jinja2 | ||
| 56 | jsonschema | ||
| 57 | lxml | ||
| 58 | matrix-common | ||
| 59 | msgpack | ||
| 60 | netaddr | ||
| 61 | phonenumbers | ||
| 62 | pillow | ||
| 63 | prometheus-client | ||
| 64 | psutil | ||
| 65 | psycopg2 | ||
| 66 | pyasn1 | ||
| 67 | pydantic | ||
| 68 | pyjwt | ||
| 69 | pymacaroons | ||
| 70 | pynacl | ||
| 71 | pyopenssl | ||
| 72 | pysaml2 | ||
| 73 | pyyaml | ||
| 74 | requests | ||
| 75 | setuptools | ||
| 76 | signedjson | ||
| 77 | sortedcontainers | ||
| 78 | treq | ||
| 79 | twisted | ||
| 80 | typing-extensions | ||
| 81 | unpaddedbase64 | ||
| 82 | ] ++ lib.optional enableSystemd systemd | ||
| 83 | ++ lib.optionals enableRedis [ hiredis txredisapi ]; | ||
| 84 | |||
| 85 | checkInputs = [ mock parameterized openssl ]; | ||
| 86 | |||
| 87 | doCheck = !stdenv.isDarwin; | ||
| 88 | |||
| 89 | checkPhase = '' | ||
| 90 | runHook preCheck | ||
| 91 | |||
| 92 | # remove src module, so tests use the installed module instead | ||
| 93 | rm -rf ./synapse | ||
| 94 | |||
| 95 | PYTHONPATH=".:$PYTHONPATH" ${python3.interpreter} -m twisted.trial -j $NIX_BUILD_CORES tests | ||
| 96 | |||
| 97 | runHook postCheck | ||
| 98 | ''; | ||
| 99 | |||
| 100 | passthru.tests = { inherit (nixosTests) matrix-synapse; }; | ||
| 101 | passthru.plugins = plugins; | ||
| 102 | passthru.tools = tools; | ||
| 103 | passthru.python = python3; | ||
| 104 | |||
| 105 | meta = with lib; { | ||
| 106 | homepage = "https://matrix.org"; | ||
| 107 | description = "Matrix reference homeserver"; | ||
| 108 | license = licenses.asl20; | ||
| 109 | maintainers = teams.matrix.members; | ||
| 110 | }; | ||
| 111 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/plugins/default.nix b/overlays/matrix-synapse/1.70.1/plugins/default.nix new file mode 100644 index 00000000..e67d9075 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/plugins/default.nix | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | { callPackage }: | ||
| 2 | |||
| 3 | { | ||
| 4 | matrix-synapse-ldap3 = callPackage ./ldap3.nix { }; | ||
| 5 | matrix-synapse-mjolnir-antispam = callPackage ./mjolnir-antispam.nix { }; | ||
| 6 | matrix-synapse-pam = callPackage ./pam.nix { }; | ||
| 7 | matrix-synapse-shared-secret-auth = callPackage ./shared-secret-auth.nix { }; | ||
| 8 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/plugins/ldap3.nix b/overlays/matrix-synapse/1.70.1/plugins/ldap3.nix new file mode 100644 index 00000000..394c0f5e --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/plugins/ldap3.nix | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | { isPy3k, buildPythonPackage, fetchPypi, service-identity, ldap3, twisted, ldaptor, mock }: | ||
| 2 | |||
| 3 | buildPythonPackage rec { | ||
| 4 | pname = "matrix-synapse-ldap3"; | ||
| 5 | version = "0.1.5"; | ||
| 6 | |||
| 7 | src = fetchPypi { | ||
| 8 | inherit pname version; | ||
| 9 | sha256 = "9fdf8df7c8ec756642aa0fea53b31c0b2f1924f70d7f049a2090b523125456fe"; | ||
| 10 | }; | ||
| 11 | |||
| 12 | propagatedBuildInputs = [ service-identity ldap3 twisted ]; | ||
| 13 | |||
| 14 | # ldaptor is not ready for py3 yet | ||
| 15 | doCheck = !isPy3k; | ||
| 16 | checkInputs = [ ldaptor mock ]; | ||
| 17 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/plugins/mjolnir-antispam.nix b/overlays/matrix-synapse/1.70.1/plugins/mjolnir-antispam.nix new file mode 100644 index 00000000..7372c2f7 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/plugins/mjolnir-antispam.nix | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | { lib, buildPythonPackage, fetchFromGitHub, matrix-synapse }: | ||
| 2 | |||
| 3 | buildPythonPackage rec { | ||
| 4 | pname = "matrix-synapse-mjolnir-antispam"; | ||
| 5 | version = "1.5.0"; | ||
| 6 | |||
| 7 | src = fetchFromGitHub { | ||
| 8 | owner = "matrix-org"; | ||
| 9 | repo = "mjolnir"; | ||
| 10 | rev = "refs/tags/v${version}"; | ||
| 11 | sha256 = "sha256-YmP+r9W5e63Aw66lSQeTTbYwSF/vjPyHkoehJxtcRNw="; | ||
| 12 | }; | ||
| 13 | |||
| 14 | sourceRoot = "./source/synapse_antispam"; | ||
| 15 | |||
| 16 | propagatedBuildInputs = [ matrix-synapse ]; | ||
| 17 | |||
| 18 | doCheck = false; # no tests | ||
| 19 | pythonImportsCheck = [ "mjolnir" ]; | ||
| 20 | |||
| 21 | meta = with lib; { | ||
| 22 | description = "AntiSpam / Banlist plugin to be used with mjolnir"; | ||
| 23 | longDescription = '' | ||
| 24 | Primarily meant to block invites from undesired homeservers/users, | ||
| 25 | Mjolnir's Synapse module is a way to interpret ban lists and apply | ||
| 26 | them to your entire homeserver. | ||
| 27 | ''; | ||
| 28 | homepage = "https://github.com/matrix-org/mjolnir#synapse-module"; | ||
| 29 | license = licenses.asl20; | ||
| 30 | maintainers = with maintainers; [ jojosch ]; | ||
| 31 | }; | ||
| 32 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/plugins/pam.nix b/overlays/matrix-synapse/1.70.1/plugins/pam.nix new file mode 100644 index 00000000..a14fe6d6 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/plugins/pam.nix | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | { buildPythonPackage, fetchFromGitHub, twisted, python-pam }: | ||
| 2 | |||
| 3 | buildPythonPackage rec { | ||
| 4 | pname = "matrix-synapse-pam"; | ||
| 5 | version = "0.1.3"; | ||
| 6 | |||
| 7 | src = fetchFromGitHub { | ||
| 8 | owner = "14mRh4X0r"; | ||
| 9 | repo = "matrix-synapse-pam"; | ||
| 10 | rev = "v${version}"; | ||
| 11 | sha256 = "0jgz49cwiyih5cg3hr4byva04zjnq8aj7rima9874la9fc5sd2wf"; | ||
| 12 | }; | ||
| 13 | |||
| 14 | propagatedBuildInputs = [ twisted python-pam ]; | ||
| 15 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/plugins/shared-secret-auth.nix b/overlays/matrix-synapse/1.70.1/plugins/shared-secret-auth.nix new file mode 100644 index 00000000..a6e22db3 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/plugins/shared-secret-auth.nix | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | { lib, buildPythonPackage, fetchFromGitHub, matrix-synapse, twisted }: | ||
| 2 | |||
| 3 | buildPythonPackage rec { | ||
| 4 | pname = "matrix-synapse-shared-secret-auth"; | ||
| 5 | version = "2.0.2"; | ||
| 6 | |||
| 7 | src = fetchFromGitHub { | ||
| 8 | owner = "devture"; | ||
| 9 | repo = "matrix-synapse-shared-secret-auth"; | ||
| 10 | rev = version; | ||
| 11 | sha256 = "sha256-qzXKwTEOMtdvsxoU3Xh3vQyhK+Q18LfkeSts7EyDIXE="; | ||
| 12 | }; | ||
| 13 | |||
| 14 | doCheck = false; | ||
| 15 | pythonImportsCheck = [ "shared_secret_authenticator" ]; | ||
| 16 | |||
| 17 | buildInputs = [ matrix-synapse ]; | ||
| 18 | propagatedBuildInputs = [ twisted ]; | ||
| 19 | |||
| 20 | meta = with lib; { | ||
| 21 | description = "Shared Secret Authenticator password provider module for Matrix Synapse"; | ||
| 22 | homepage = "https://github.com/devture/matrix-synapse-shared-secret-auth"; | ||
| 23 | license = licenses.agpl3Plus; | ||
| 24 | maintainers = with maintainers; [ sumnerevans ]; | ||
| 25 | }; | ||
| 26 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/tools/default.nix b/overlays/matrix-synapse/1.70.1/tools/default.nix new file mode 100644 index 00000000..defc35bc --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/tools/default.nix | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | { callPackage }: | ||
| 2 | { | ||
| 3 | rust-synapse-compress-state = callPackage ./rust-synapse-compress-state.nix { }; | ||
| 4 | |||
| 5 | synadm = callPackage ./synadm.nix { }; | ||
| 6 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/tools/rust-synapse-compress-state.nix b/overlays/matrix-synapse/1.70.1/tools/rust-synapse-compress-state.nix new file mode 100644 index 00000000..fcf123d6 --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/tools/rust-synapse-compress-state.nix | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | { lib, rustPlatform, python3, fetchFromGitHub, pkg-config, openssl }: | ||
| 2 | |||
| 3 | rustPlatform.buildRustPackage rec { | ||
| 4 | pname = "rust-synapse-compress-state"; | ||
| 5 | version = "0.1.3"; | ||
| 6 | |||
| 7 | src = fetchFromGitHub { | ||
| 8 | owner = "matrix-org"; | ||
| 9 | repo = pname; | ||
| 10 | rev = "v${version}"; | ||
| 11 | sha256 = "sha256-SSfVtG8kwHarVbB1O7xC2SSbUpPGYMHTMyoxu8mpEk0="; | ||
| 12 | }; | ||
| 13 | |||
| 14 | cargoSha256 = "sha256-PG+UeovhJMsIlm5dOYdtMxbUxZjwG3V59kAcB9aFP5c="; | ||
| 15 | |||
| 16 | cargoBuildFlags = [ | ||
| 17 | "--all" | ||
| 18 | ]; | ||
| 19 | |||
| 20 | nativeBuildInputs = [ python3 pkg-config ]; | ||
| 21 | |||
| 22 | buildInputs = [ openssl ]; | ||
| 23 | |||
| 24 | meta = with lib; { | ||
| 25 | description = "A tool to compress some state in a Synapse instance's database"; | ||
| 26 | homepage = "https://github.com/matrix-org/rust-synapse-compress-state"; | ||
| 27 | license = licenses.asl20; | ||
| 28 | maintainers = with maintainers; [ hexa maralorn ]; | ||
| 29 | }; | ||
| 30 | } | ||
diff --git a/overlays/matrix-synapse/1.70.1/tools/synadm.nix b/overlays/matrix-synapse/1.70.1/tools/synadm.nix new file mode 100644 index 00000000..5075e42e --- /dev/null +++ b/overlays/matrix-synapse/1.70.1/tools/synadm.nix | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | { lib | ||
| 2 | , python3Packages | ||
| 3 | }: | ||
| 4 | |||
| 5 | with python3Packages; buildPythonApplication rec { | ||
| 6 | pname = "synadm"; | ||
| 7 | version = "0.36"; | ||
| 8 | format = "setuptools"; | ||
| 9 | |||
| 10 | src = fetchPypi { | ||
| 11 | inherit pname version; | ||
| 12 | sha256 = "sha256-OMXUbfAC927qJw0B5sq1lGJQRkFAUdohIOkCYUbZumI="; | ||
| 13 | }; | ||
| 14 | |||
| 15 | postPatch = '' | ||
| 16 | substituteInPlace setup.py \ | ||
| 17 | --replace "Click>=7.0,<8.0" "Click" | ||
| 18 | ''; | ||
| 19 | |||
| 20 | propagatedBuildInputs = [ | ||
| 21 | click | ||
| 22 | click-option-group | ||
| 23 | dnspython | ||
| 24 | tabulate | ||
| 25 | pyyaml | ||
| 26 | requests | ||
| 27 | ]; | ||
| 28 | |||
| 29 | checkPhase = '' | ||
| 30 | runHook preCheck | ||
| 31 | export HOME=$TMPDIR | ||
| 32 | $out/bin/synadm -h > /dev/null | ||
| 33 | runHook postCheck | ||
| 34 | ''; | ||
| 35 | |||
| 36 | meta = with lib; { | ||
| 37 | description = "Command line admin tool for Synapse"; | ||
| 38 | longDescription = '' | ||
| 39 | A CLI tool to help admins of Matrix Synapse homeservers | ||
| 40 | conveniently issue commands available via its admin API's | ||
| 41 | (matrix-org/synapse@master/docs/admin_api) | ||
| 42 | ''; | ||
| 43 | homepage = "https://github.com/JOJ0/synadm"; | ||
| 44 | license = licenses.gpl3Plus; | ||
| 45 | maintainers = with maintainers; [ hexa ]; | ||
| 46 | }; | ||
| 47 | } | ||
diff --git a/overlays/matrix-synapse/default.nix b/overlays/matrix-synapse/default.nix new file mode 100644 index 00000000..9db73e35 --- /dev/null +++ b/overlays/matrix-synapse/default.nix | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | { final, prev, ... }: { | ||
| 2 | matrix-synapse = final.callPackage ./1.70.1/default.nix {}; | ||
| 3 | } | ||
| @@ -1,8 +1,29 @@ | |||
| 1 | { pkgs ? import <nixpkgs> {}, deploy-rs, nvfetcher }: | 1 | { system, self, deploy-rs, nvfetcher, mach-nix, leapseconds, ... }: |
| 2 | let | 2 | let |
| 3 | tai64dec = pkgs.writeShellScriptBin "tai64dec" '' | 3 | pkgs = self.legacyPackages.${system}; |
| 4 | echo $((16#$(${pkgs.daemontools}/bin/tai64n <<<"" | ${pkgs.coreutils}/bin/tail -c +2 | ${pkgs.coreutils}/bin/head -c 16))) | 4 | |
| 5 | ''; | 5 | ca = mach-nix.lib.${system}.buildPythonPackage { |
| 6 | pname = "ca"; | ||
| 7 | src = ./tools/ca; | ||
| 8 | version = "0.0.0"; | ||
| 9 | ignoreDataOutdated = true; | ||
| 10 | |||
| 11 | requirements = '' | ||
| 12 | cryptography >=38.0.0 | ||
| 13 | fqdn | ||
| 14 | atomicwrites | ||
| 15 | leapseconddata | ||
| 16 | xkcdpass | ||
| 17 | ''; | ||
| 18 | |||
| 19 | _.cryptography.buildInputs = with pkgs; [ openssl ]; | ||
| 20 | |||
| 21 | postInstall = '' | ||
| 22 | wrapProgram $out/bin/ca \ | ||
| 23 | --set-default LEAPSECONDS_FILE ${leapseconds} \ | ||
| 24 | --prefix PATH : ${pkgs.lib.makeBinPath (with pkgs; [sops])} | ||
| 25 | ''; | ||
| 26 | }; | ||
| 6 | in pkgs.mkShell { | 27 | in pkgs.mkShell { |
| 7 | name = "nixos"; | 28 | name = "nixos"; |
| 8 | nativeBuildInputs = with pkgs; [ | 29 | nativeBuildInputs = with pkgs; [ |
| @@ -10,10 +31,10 @@ in pkgs.mkShell { | |||
| 10 | wireguard-tools | 31 | wireguard-tools |
| 11 | gup | 32 | gup |
| 12 | nftables | 33 | nftables |
| 13 | deploy-rs | 34 | deploy-rs.packages.${system}.deploy-rs |
| 14 | tai64dec | ||
| 15 | knot-dns | 35 | knot-dns |
| 16 | yq | 36 | yq |
| 17 | nvfetcher | 37 | nvfetcher.defaultPackage.${system} |
| 38 | ca | ||
| 18 | ]; | 39 | ]; |
| 19 | } | 40 | } |
diff --git a/tools/ca/ca/__main__.py b/tools/ca/ca/__main__.py new file mode 100644 index 00000000..e3e4bbe6 --- /dev/null +++ b/tools/ca/ca/__main__.py | |||
| @@ -0,0 +1,568 @@ | |||
| 1 | import sys, os | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import argparse | ||
| 5 | |||
| 6 | from inspect import signature | ||
| 7 | |||
| 8 | from enum import Enum, auto | ||
| 9 | from contextlib import contextmanager | ||
| 10 | |||
| 11 | from cryptography import __version__ as cryptography_version | ||
| 12 | from cryptography.hazmat.backends import openssl | ||
| 13 | from cryptography import x509 | ||
| 14 | from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID, ExtensionOID | ||
| 15 | from cryptography.hazmat.primitives import serialization, hashes | ||
| 16 | from cryptography.hazmat.primitives.serialization import PrivateFormat, pkcs12 | ||
| 17 | from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey | ||
| 18 | from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey | ||
| 19 | from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey | ||
| 20 | from cryptography.hazmat.primitives.asymmetric import rsa | ||
| 21 | from pathlib import Path | ||
| 22 | from atomicwrites import atomic_write | ||
| 23 | from fqdn import FQDN | ||
| 24 | from datetime import datetime, timedelta, timezone | ||
| 25 | from math import ceil, ldexp | ||
| 26 | import re | ||
| 27 | from getpass import getpass | ||
| 28 | from itertools import count | ||
| 29 | from tempfile import TemporaryFile | ||
| 30 | import subprocess | ||
| 31 | import json | ||
| 32 | from leapseconddata import LeapSecondData | ||
| 33 | |||
| 34 | |||
| 35 | class KeyType(Enum): | ||
| 36 | ED448 = 'ed448' | ||
| 37 | ED25519 = 'ed25519' | ||
| 38 | RSA4096 = 'rsa4096' | ||
| 39 | RSA2048 = 'rsa2048' | ||
| 40 | |||
| 41 | def generate(self): | ||
| 42 | match self: | ||
| 43 | case KeyType.ED448: | ||
| 44 | return Ed448PrivateKey.generate() | ||
| 45 | case KeyType.ED25519: | ||
| 46 | return Ed25519PrivateKey.generate() | ||
| 47 | case KeyType.RSA4096: | ||
| 48 | return rsa.generate_private_key( | ||
| 49 | public_exponent = 65537, | ||
| 50 | key_size = 4096, | ||
| 51 | ) | ||
| 52 | case KeyType.RSA2048: | ||
| 53 | return rsa.generate_private_key( | ||
| 54 | public_exponent = 65537, | ||
| 55 | key_size = 2048, | ||
| 56 | ) | ||
| 57 | |||
| 58 | def aligned(self, key): | ||
| 59 | match self: | ||
| 60 | case KeyType.ED448: | ||
| 61 | return isinstance(key, Ed448PrivateKey) | ||
| 62 | case KeyType.ED25519: | ||
| 63 | return isinstance(key, Ed25519PrivateKey) | ||
| 64 | case KeyType.RSA4096: | ||
| 65 | return isinstance(key, RSAPrivateKey) and key.key_size == 4096 | ||
| 66 | case KeyType.RSA2048: | ||
| 67 | return isinstance(key, RSAPrivateKey) and key.key_size == 2048 | ||
| 68 | |||
| 69 | def __str__(self): | ||
| 70 | return self.value | ||
| 71 | |||
| 72 | @classmethod | ||
| 73 | def from_string(cls, s): | ||
| 74 | try: | ||
| 75 | return cls(s) | ||
| 76 | except KeyError: | ||
| 77 | raise ValueError() | ||
| 78 | |||
| 79 | class ValidFQDN(FQDN): | ||
| 80 | def __init__(self, *args, **kwds): | ||
| 81 | super().__init__(*args, **kwds) | ||
| 82 | |||
| 83 | if not self.is_valid: | ||
| 84 | raise ValueError(f'‘{self}’ is not valid') | ||
| 85 | |||
| 86 | def duration(inp_str): | ||
| 87 | delta = timedelta() | ||
| 88 | |||
| 89 | item_re = re.compile(r'\W*(?P<value>\d+)\W*(?P<unit>(?i:d|h|m(?!s)|s|ms|µs))') | ||
| 90 | |||
| 91 | match = item_re.match(inp_str) | ||
| 92 | while match: | ||
| 93 | val = int(match.group('value')) | ||
| 94 | unit = match.group('unit').lower() | ||
| 95 | |||
| 96 | if unit == 'd': | ||
| 97 | delta += timedelta(days=val) | ||
| 98 | elif unit == 'h': | ||
| 99 | delta += timedelta(hours=val) | ||
| 100 | elif unit == 'm': | ||
| 101 | delta += timedelta(minutes=val) | ||
| 102 | elif unit == 's': | ||
| 103 | delta += timedelta(seconds=val) | ||
| 104 | elif unit == 'ms': | ||
| 105 | delta += timedelta(milliseconds=val) | ||
| 106 | elif unit == 'µs' or unit == 'us': | ||
| 107 | delta += timedelta(microseconds=val) | ||
| 108 | else: | ||
| 109 | raise ValueError(f'Unknown time unit ‘{unit:s}’') | ||
| 110 | |||
| 111 | inp_str = inp_str[match.end():] | ||
| 112 | match = item_re.match(inp_str) | ||
| 113 | else: | ||
| 114 | if re.match('\w', inp_str): | ||
| 115 | raise ValueError(f'Parsing of duration resulted in leftovers: ‘{inp_str:s}’') | ||
| 116 | |||
| 117 | return delta | ||
| 118 | |||
| 119 | @contextmanager | ||
| 120 | def umask(desired_umask): | ||
| 121 | """ A little helper to safely set and restore umask(2). """ | ||
| 122 | try: | ||
| 123 | prev_umask = os.umask(0) | ||
| 124 | os.umask(prev_umask | desired_umask) | ||
| 125 | yield | ||
| 126 | finally: | ||
| 127 | os.umask(prev_umask) | ||
| 128 | |||
| 129 | class BooleanAction(argparse.Action): | ||
| 130 | def __init__(self, option_strings, dest, nargs=None, **kwargs): | ||
| 131 | super(BooleanAction, self).__init__(option_strings, dest, nargs=0, **kwargs) | ||
| 132 | |||
| 133 | def __call__(self, parser, namespace, values, option_string=None): | ||
| 134 | setattr(namespace, self.dest, False if option_string.startswith('--no') else True) | ||
| 135 | |||
| 136 | |||
| 137 | def load_key(keyfile, prompt='CA private key password: '): | ||
| 138 | key = None | ||
| 139 | with open(keyfile, 'rb') as f: | ||
| 140 | is_sops = False | ||
| 141 | try: | ||
| 142 | sops_json = json.load(f) | ||
| 143 | is_sops = 'sops' in sops_json | ||
| 144 | except json.JSONDecodeError: | ||
| 145 | pass | ||
| 146 | |||
| 147 | f.seek(0) | ||
| 148 | |||
| 149 | if not is_sops: | ||
| 150 | try: | ||
| 151 | key = serialization.load_pem_private_key(f.read(), password=None) | ||
| 152 | except TypeError: | ||
| 153 | pw = getpass(prompt=prompt) | ||
| 154 | key = serialization.load_pem_private_key(f.read(), password=bytes(pw, sys.stdin.encoding)) | ||
| 155 | else: | ||
| 156 | cmd = ['sops', '-d', f'/dev/fd/{f.fileno()}'] | ||
| 157 | with subprocess.Popen(cmd, stdout=subprocess.PIPE, pass_fds=(f.fileno(),)) as proc: | ||
| 158 | key = serialization.load_pem_private_key(proc.stdout.read(), password=None) | ||
| 159 | ret = proc.wait() | ||
| 160 | if ret != 0: | ||
| 161 | raise subprocess.CalledProcessErrror(ret, cmd) | ||
| 162 | |||
| 163 | return key | ||
| 164 | |||
| 165 | def mv_bak(path): | ||
| 166 | global logger | ||
| 167 | |||
| 168 | bak_path = path.parent / f'{path.name}.bak' | ||
| 169 | for n in count(2): | ||
| 170 | if not bak_path.exists(): | ||
| 171 | break | ||
| 172 | bak_path = path.parent / f'{path.name}.bak{n}' | ||
| 173 | |||
| 174 | logger.warn('Renaming ‘%s’ to ‘%s’...', path, bak_path) | ||
| 175 | path.rename(bak_path) | ||
| 176 | |||
| 177 | def tai64nint(dt): | ||
| 178 | global leapsecond_data | ||
| 179 | |||
| 180 | have_data = False | ||
| 181 | try: | ||
| 182 | have_data = bool(leapsecond_data) | ||
| 183 | except NameError: | ||
| 184 | pass | ||
| 185 | |||
| 186 | if not have_data: | ||
| 187 | leapsecond_data = LeapSecondData.from_file(Path(os.getenv('LEAPSECONDS_FILE'))) | ||
| 188 | |||
| 189 | tai_dt = leapsecond_data.to_tai(dt) | ||
| 190 | seconds = int(tai_dt.timestamp()) | ||
| 191 | nanoseconds = int((tai_dt.timestamp() - seconds) / 1e-9) | ||
| 192 | seconds += int(ldexp(1, 62)) | ||
| 193 | return seconds << 32 | nanoseconds | ||
| 194 | |||
| 195 | def write_genkey(key_type, sops, keyfile): | ||
| 196 | if keyfile.exists(): | ||
| 197 | raise ValueError(f'Keyfile exists: {keyfile}') | ||
| 198 | |||
| 199 | key = None | ||
| 200 | |||
| 201 | def genkey(fh): | ||
| 202 | nonlocal key, key_type | ||
| 203 | |||
| 204 | logger.debug('Generating new privkey...') | ||
| 205 | key = key_type.generate() | ||
| 206 | priv_bytes = key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()) | ||
| 207 | fh.write(priv_bytes) | ||
| 208 | |||
| 209 | if not sops: | ||
| 210 | with umask(0o0177), atomic_write(keyfile, overwrite=False, mode='wb') as fh: | ||
| 211 | logger.info('Writing new privkey to ‘%s’...', keyfile) | ||
| 212 | genkey(fh) | ||
| 213 | logger.debug('Adjusting permissions for ‘%s’...', keyfile) | ||
| 214 | os.chmod(keyfile, 0o0400) | ||
| 215 | else: | ||
| 216 | with TemporaryFile(mode='wb') as tf: | ||
| 217 | genkey(tf) | ||
| 218 | tf.seek(0) | ||
| 219 | |||
| 220 | with umask(0o0177), atomic_write(keyfile, overwrite=False, mode='wb') as fh: | ||
| 221 | logger.info('Encrypting new privkey to ‘%s’...', keyfile) | ||
| 222 | subprocess.run(['sops', '-e', f'/dev/fd/{tf.fileno()}'], stdout=fh, pass_fds=(tf.fileno(),), check=True) | ||
| 223 | logger.debug('Adjusting permissions for ‘%s’...', keyfile) | ||
| 224 | os.chmod(keyfile, 0o0400) | ||
| 225 | |||
| 226 | return key | ||
| 227 | |||
| 228 | def initca(ca_cert, ca_key, key_type, subject, clock_skew, validity, sops): | ||
| 229 | global logger | ||
| 230 | |||
| 231 | key = None | ||
| 232 | try: | ||
| 233 | key = load_key(ca_key) | ||
| 234 | logger.info('Successfully loaded privkey from ‘%s’', ca_key) | ||
| 235 | |||
| 236 | if not key_type.aligned(key): | ||
| 237 | logger.warn('Private key ‘%s’ does not align with requested type %s', ca_key, key_type) | ||
| 238 | |||
| 239 | try: | ||
| 240 | mv_bak(ca_key) | ||
| 241 | except FileNotFoundError: | ||
| 242 | pass | ||
| 243 | try: | ||
| 244 | mv_bak(ca_cert) | ||
| 245 | except FileNotFoundError: | ||
| 246 | pass | ||
| 247 | |||
| 248 | raise FileNotFoundError(f'Key does not align with requested type: {ca_key}') | ||
| 249 | except FileNotFoundError: | ||
| 250 | key = write_genkey(key_type, sops, ca_key) | ||
| 251 | |||
| 252 | cert = None | ||
| 253 | try: | ||
| 254 | with open(ca_cert, 'rb') as fh: | ||
| 255 | cert = x509.load_pem_x509_certificate(fh.read()) | ||
| 256 | logger.info('Successfully loaded certificate from ‘%s’', ca_cert) | ||
| 257 | except FileNotFoundError: | ||
| 258 | logger.debug('Generating new certificate...') | ||
| 259 | |||
| 260 | now = datetime.utcnow() | ||
| 261 | name = x509.Name([ | ||
| 262 | x509.NameAttribute(NameOID.COMMON_NAME, subject.relative) | ||
| 263 | ]) | ||
| 264 | |||
| 265 | cert = x509.CertificateBuilder().subject_name( | ||
| 266 | name | ||
| 267 | ).public_key( | ||
| 268 | key.public_key() | ||
| 269 | ).serial_number( | ||
| 270 | x509.random_serial_number() | ||
| 271 | ).not_valid_before( | ||
| 272 | now - clock_skew | ||
| 273 | ).not_valid_after( | ||
| 274 | now + validity | ||
| 275 | ).issuer_name( | ||
| 276 | name | ||
| 277 | ).add_extension( | ||
| 278 | x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key()), | ||
| 279 | False | ||
| 280 | ).add_extension( | ||
| 281 | x509.SubjectKeyIdentifier.from_public_key(key.public_key()), | ||
| 282 | False | ||
| 283 | ).add_extension( | ||
| 284 | x509.KeyUsage(digital_signature=True, content_commitment=False, key_encipherment=False, data_encipherment=False, key_agreement=False, key_cert_sign=True, crl_sign=True, encipher_only=False, decipher_only=False), | ||
| 285 | True | ||
| 286 | ).add_extension( | ||
| 287 | x509.BasicConstraints(ca=True, path_length=None), | ||
| 288 | True | ||
| 289 | ).sign(key, None if isinstance(key, Ed25519PrivateKey) or isinstance(key, Ed448PrivateKey) else hashes.SHA512()) | ||
| 290 | |||
| 291 | with umask(0o0133), atomic_write(ca_cert, overwrite=False, mode='wb') as cf: | ||
| 292 | logger.info('Writing new certificate to ‘%s’...', ca_cert) | ||
| 293 | cf.write(cert.public_bytes(serialization.Encoding.PEM)) | ||
| 294 | logger.debug('Adjusting permissions for ‘%s’...', ca_cert) | ||
| 295 | os.chmod(ca_cert, 0o0444) | ||
| 296 | |||
| 297 | def signcsr(ca_cert, ca_key, clock_skew, validity, subject, alternative_name, ignore_alternative_names, csr, output): | ||
| 298 | csr_bytes = None | ||
| 299 | try: | ||
| 300 | csr_bytes = csr.read() | ||
| 301 | except AttributeError: | ||
| 302 | csr_bytes = csr | ||
| 303 | |||
| 304 | csr = x509.load_pem_x509_csr(csr_bytes) | ||
| 305 | if not subject: | ||
| 306 | common_name_attrs = csr.subject.get_attributes_for_oid(NameOID.COMMON_NAME) | ||
| 307 | if len(common_name_attrs) != 1: | ||
| 308 | raise InvalidParamsError('Invalid name structure in CSR') | ||
| 309 | subject = common_name_attrs[0].value.lower() | ||
| 310 | logger.warn('Using subject common name from csr: %s', subject) | ||
| 311 | name = x509.Name([ | ||
| 312 | x509.NameAttribute(NameOID.COMMON_NAME, subject) | ||
| 313 | ]) | ||
| 314 | |||
| 315 | if not ignore_alternative_names: | ||
| 316 | ext = csr.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME) | ||
| 317 | csr_alt_names = ext.value.get_values_for_type(x509.DNSName) | ||
| 318 | logger.warn('Using alternative names from csr: %s', csr_alt_names) | ||
| 319 | alternative_name = list(set(alternative_name) | set(csr_alt_names)) | ||
| 320 | |||
| 321 | ca_key = load_key(ca_key) | ||
| 322 | with open(ca_cert, 'rb') as fh: | ||
| 323 | ca_cert = x509.load_pem_x509_certificate(fh.read()) | ||
| 324 | |||
| 325 | now = datetime.now(tz=timezone.utc) | ||
| 326 | cert = x509.CertificateBuilder().subject_name( | ||
| 327 | name | ||
| 328 | ).public_key( | ||
| 329 | csr.public_key() | ||
| 330 | ).serial_number( | ||
| 331 | (tai64nint(now) << 24) | (x509.random_serial_number() & int(ldexp(1, 24) - 1)) | ||
| 332 | ).not_valid_before( | ||
| 333 | now - clock_skew | ||
| 334 | ).not_valid_after( | ||
| 335 | now + validity | ||
| 336 | ).issuer_name( | ||
| 337 | ca_cert.subject | ||
| 338 | ).add_extension( | ||
| 339 | x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_cert.public_key()), | ||
| 340 | False | ||
| 341 | ).add_extension( | ||
| 342 | x509.SubjectKeyIdentifier.from_public_key(csr.public_key()), | ||
| 343 | False | ||
| 344 | ).add_extension( | ||
| 345 | x509.KeyUsage(digital_signature=True, content_commitment=True, key_encipherment=True, data_encipherment=False, key_agreement=False, key_cert_sign=False, crl_sign=False, encipher_only=False, decipher_only=False), | ||
| 346 | True | ||
| 347 | ).add_extension( | ||
| 348 | x509.BasicConstraints(ca=False, path_length=None), | ||
| 349 | True | ||
| 350 | ).add_extension( | ||
| 351 | x509.ExtendedKeyUsage([ExtendedKeyUsageOID.CLIENT_AUTH]), | ||
| 352 | False | ||
| 353 | ) | ||
| 354 | |||
| 355 | if alternative_name: | ||
| 356 | cert = cert.add_extension( | ||
| 357 | x509.SubjectAlternativeName( | ||
| 358 | list(map(x509.DNSName, alternative_name)) | ||
| 359 | ), | ||
| 360 | False | ||
| 361 | ) | ||
| 362 | |||
| 363 | cert = cert.sign(ca_key, None if isinstance(ca_key, Ed25519PrivateKey) or isinstance(ca_key, Ed448PrivateKey) else hashes.SHA256()) | ||
| 364 | |||
| 365 | output = output.with_suffix('.crt') | ||
| 366 | |||
| 367 | try: | ||
| 368 | mv_bak(output) | ||
| 369 | except FileNotFoundError: | ||
| 370 | pass | ||
| 371 | with umask(0o0133), atomic_write(output, overwrite=False, mode='wb') as cf: | ||
| 372 | logger.info('Writing new certificate to ‘%s’...', output) | ||
| 373 | cf.write(cert.public_bytes(serialization.Encoding.PEM)) | ||
| 374 | logger.debug('Adjusting permissions for ‘%s’...', output) | ||
| 375 | os.chmod(output, 0o0444) | ||
| 376 | |||
| 377 | def new_client(ca_cert, ca_key, key_type, clock_skew, validity, subject, alternative_name, sops, output): | ||
| 378 | key_file = output.with_suffix('.key') | ||
| 379 | cert_file = output.with_suffix('.crt') | ||
| 380 | |||
| 381 | key = None | ||
| 382 | try: | ||
| 383 | key = load_key(key_file) | ||
| 384 | logger.info('Successfully loaded privkey from ‘%s’', key_file) | ||
| 385 | |||
| 386 | if not key_type.aligned(key): | ||
| 387 | logger.warn('Private key ‘%s’ does not align with requested type %s', key_file, key_type) | ||
| 388 | |||
| 389 | try: | ||
| 390 | mv_bak(key_file) | ||
| 391 | except FileNotFoundError: | ||
| 392 | pass | ||
| 393 | try: | ||
| 394 | mv_bak(cert_file) | ||
| 395 | except FileNotFoundError: | ||
| 396 | pass | ||
| 397 | |||
| 398 | raise FileNotFoundError(f'Key does not align with requested type: {key_file}') | ||
| 399 | except FileNotFoundError: | ||
| 400 | key = write_genkey(key_type, sops, key_file) | ||
| 401 | |||
| 402 | csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ | ||
| 403 | x509.NameAttribute(NameOID.COMMON_NAME, subject) | ||
| 404 | ])) | ||
| 405 | if alternative_name: | ||
| 406 | csr = csr.add_extension( | ||
| 407 | x509.SubjectAlternativeName( | ||
| 408 | list(map(x509.DNSName, alternative_name)) | ||
| 409 | ), | ||
| 410 | False | ||
| 411 | ) | ||
| 412 | |||
| 413 | return signcsr( | ||
| 414 | ca_cert=ca_cert, | ||
| 415 | ca_key=ca_key, | ||
| 416 | clock_skew=clock_skew, | ||
| 417 | validity=validity, | ||
| 418 | subject=None, | ||
| 419 | alternative_name=[], | ||
| 420 | ignore_alternative_names=False, | ||
| 421 | output=cert_file, | ||
| 422 | csr=csr.sign( | ||
| 423 | key, | ||
| 424 | None if isinstance(key, Ed25519PrivateKey) or isinstance(key, Ed448PrivateKey) else hashes.SHA256(), | ||
| 425 | ).public_bytes(serialization.Encoding.PEM) | ||
| 426 | ) | ||
| 427 | |||
| 428 | def to_pkcs12(random_password, filename, output): | ||
| 429 | key_file = filename.with_suffix('.key') | ||
| 430 | cert_file = filename.with_suffix('.crt') | ||
| 431 | |||
| 432 | if not output: | ||
| 433 | output = filename.with_suffix('.p12') | ||
| 434 | |||
| 435 | key = load_key(key_file) | ||
| 436 | logger.info('Successfully loaded privkey from ‘%s’', key_file) | ||
| 437 | cert = None | ||
| 438 | with open(cert_file, mode='rb') as fh: | ||
| 439 | cert = x509.load_pem_x509_certificate(fh.read()) | ||
| 440 | logger.info('Successfully loaded certificate from ‘%s’', cert_file) | ||
| 441 | |||
| 442 | with umask(0o0177), atomic_write(output, overwrite=False, mode='wb') as fh: | ||
| 443 | logger.info('Writing to ‘%s’...', output) | ||
| 444 | common_name_attrs = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) | ||
| 445 | if len(common_name_attrs) != 1: | ||
| 446 | raise InvalidParamsError('Invalid name structure in cert') | ||
| 447 | subject = common_name_attrs[0].value.lower() | ||
| 448 | |||
| 449 | pw = None | ||
| 450 | if not random_password: | ||
| 451 | pw2 = None | ||
| 452 | while not pw2 or pw2 != pw: | ||
| 453 | pw = getpass(prompt='Password: ') | ||
| 454 | if not pw: | ||
| 455 | pw = None | ||
| 456 | break | ||
| 457 | else: | ||
| 458 | pw2 = getpass(prompt='Repeat password: ') | ||
| 459 | else: | ||
| 460 | from xkcdpass import xkcd_password as xp | ||
| 461 | ws = xp.generate_wordlist(wordfile=xp.locate_wordfile()) | ||
| 462 | pw = xp.generate_xkcdpassword(ws, numwords=12) | ||
| 463 | print(f'Password: {pw}', file=sys.stderr) | ||
| 464 | |||
| 465 | encryption = None | ||
| 466 | if pw: | ||
| 467 | encryption = PrivateFormat.PKCS12.encryption_builder().kdf_rounds( | ||
| 468 | 500000 | ||
| 469 | ).key_cert_algorithm( | ||
| 470 | pkcs12.PBES.PBESv2SHA256AndAES256CBC | ||
| 471 | ).hmac_hash( | ||
| 472 | hashes.SHA256() | ||
| 473 | ).build(bytes(pw, 'utf-8')) | ||
| 474 | fh.write(pkcs12.serialize_key_and_certificates( | ||
| 475 | bytes(subject, 'utf-8'), | ||
| 476 | key, | ||
| 477 | cert, | ||
| 478 | None, | ||
| 479 | encryption, | ||
| 480 | )) | ||
| 481 | logger.debug('Adjusting permissions for ‘%s’...', output) | ||
| 482 | os.chmod(output, 0o0400) | ||
| 483 | |||
| 484 | |||
| 485 | def main(): | ||
| 486 | global logger | ||
| 487 | logger = logging.getLogger(__name__) | ||
| 488 | console_handler = logging.StreamHandler() | ||
| 489 | console_handler.setFormatter( logging.Formatter('[%(levelname)s](%(name)s): %(message)s') ) | ||
| 490 | if sys.stderr.isatty(): | ||
| 491 | console_handler.setFormatter( logging.Formatter('%(asctime)s [%(levelname)s](%(name)s): %(message)s') ) | ||
| 492 | logger.addHandler(console_handler) | ||
| 493 | |||
| 494 | # log uncaught exceptions | ||
| 495 | def log_exceptions(type, value, tb): | ||
| 496 | global logger | ||
| 497 | |||
| 498 | logger.error(value) | ||
| 499 | sys.__excepthook__(type, value, tb) # calls default excepthook | ||
| 500 | |||
| 501 | sys.excepthook = log_exceptions | ||
| 502 | |||
| 503 | |||
| 504 | parser = argparse.ArgumentParser(prog='ca', formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| 505 | parser.add_argument('--verbosity', dest='log_level', action='append', type=int) | ||
| 506 | parser.add_argument('--verbose', '-v', dest='log_level', action='append_const', const=1) | ||
| 507 | parser.add_argument('--quiet', '-q', dest='log_level', action='append_const', const=-1) | ||
| 508 | subparsers = parser.add_subparsers(help='Subcommands', required=True) | ||
| 509 | |||
| 510 | subparser = subparsers.add_parser('init', aliases=['initca', 'init-ca', 'ca'], formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| 511 | subparser.add_argument('--ca-cert', type=Path, default=Path('ca.crt')) | ||
| 512 | subparser.add_argument('--ca-key', type=Path, default=Path('ca.key')) | ||
| 513 | subparser.add_argument('--key-type', type=KeyType.from_string, choices=list(KeyType), default=KeyType.ED448.value) | ||
| 514 | subparser.add_argument('--clock-skew', metavar='DURATION', type=duration, default=timedelta(minutes=5)) | ||
| 515 | subparser.add_argument('--validity', metavar='DURATION', type=duration, default=timedelta(days=ceil(365.2425*10))) | ||
| 516 | subparser.add_argument('--sops', '--no-sops', action=BooleanAction, default=True) | ||
| 517 | subparser.add_argument('--subject', metavar='FQDN', type=ValidFQDN, required=True) | ||
| 518 | subparser.set_defaults(cmd=initca) | ||
| 519 | |||
| 520 | subparser = subparsers.add_parser('sign', aliases=['signcsr', 'sign-csr'], formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| 521 | subparser.add_argument('--ca-cert', type=Path, default=Path('ca.crt')) | ||
| 522 | subparser.add_argument('--ca-key', type=Path, default=Path('ca.key')) | ||
| 523 | subparser.add_argument('--clock-skew', metavar='DURATION', type=duration, default=timedelta(minutes=5)) | ||
| 524 | subparser.add_argument('--validity', metavar='DURATION', type=duration, default=timedelta(days=ceil(365.2425*10))) | ||
| 525 | subparser.add_argument('--subject', metavar='CN', type=str, required=False) | ||
| 526 | subparser.add_argument('--ignore-alternative-names', '--no-ignore-alternative-names', action=BooleanAction, default=True) | ||
| 527 | subparser.add_argument('--alternative-name', metavar='CN', type=str, action='append') | ||
| 528 | subparser.add_argument('--output', type=Path, required=True) | ||
| 529 | subparser.add_argument('csr', metavar='FILE', type=argparse.FileType(mode='rb')) | ||
| 530 | subparser.set_defaults(cmd=signcsr) | ||
| 531 | |||
| 532 | subparser = subparsers.add_parser('new-client', aliases=['new', 'new-client', 'client'], formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| 533 | subparser.add_argument('--ca-cert', type=Path, default=Path('ca.crt')) | ||
| 534 | subparser.add_argument('--ca-key', type=Path, default=Path('ca.key')) | ||
| 535 | subparser.add_argument('--key-type', type=KeyType.from_string, choices=list(KeyType), default=KeyType.ED25519.value) | ||
| 536 | subparser.add_argument('--clock-skew', metavar='DURATION', type=duration, default=timedelta(minutes=5)) | ||
| 537 | subparser.add_argument('--validity', metavar='DURATION', type=duration, default=timedelta(days=ceil(365.2425*10))) | ||
| 538 | subparser.add_argument('--sops', '--no-sops', action=BooleanAction, default=True) | ||
| 539 | subparser.add_argument('--subject', metavar='CN', type=str, required=True) | ||
| 540 | subparser.add_argument('--alternative-name', metavar='CN', type=str, action='append') | ||
| 541 | subparser.add_argument('--output', type=Path, required=True) | ||
| 542 | subparser.set_defaults(cmd=new_client) | ||
| 543 | |||
| 544 | subparser = subparsers.add_parser('pkcs12', aliases=['p12', 'pfx'], formatter_class=argparse.ArgumentDefaultsHelpFormatter) | ||
| 545 | subparser.add_argument('--random-password', '--no-random-password', action=BooleanAction, default=True) | ||
| 546 | subparser.add_argument('--output', type=Path) | ||
| 547 | subparser.add_argument('filename', metavar='BASENAME', type=Path) | ||
| 548 | subparser.set_defaults(cmd=to_pkcs12) | ||
| 549 | |||
| 550 | args = parser.parse_args() | ||
| 551 | |||
| 552 | |||
| 553 | LOG_LEVELS = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] | ||
| 554 | DEFAULT_LOG_LEVEL = logging.INFO | ||
| 555 | log_level = LOG_LEVELS.index(DEFAULT_LOG_LEVEL) | ||
| 556 | |||
| 557 | for adjustment in args.log_level or (): | ||
| 558 | log_level = min(len(LOG_LEVELS) - 1, max(log_level - adjustment, 0)) | ||
| 559 | logger.setLevel(LOG_LEVELS[log_level]) | ||
| 560 | |||
| 561 | |||
| 562 | logger.debug('Using cryptography %s (%s)', cryptography_version, openssl.backend.openssl_version_text()) | ||
| 563 | |||
| 564 | |||
| 565 | args.cmd(**{ k: v for k, v in vars(args).items() if k in signature(args.cmd).parameters.keys() }) | ||
| 566 | |||
| 567 | if __name__ == '__main__': | ||
| 568 | sys.exit(main()) | ||
diff --git a/tools/ca/setup.py b/tools/ca/setup.py new file mode 100644 index 00000000..3342a7a6 --- /dev/null +++ b/tools/ca/setup.py | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | from setuptools import setup | ||
| 2 | |||
| 3 | setup(name='ca', | ||
| 4 | packages=['ca'], | ||
| 5 | entry_points={ | ||
| 6 | 'console_scripts': [ | ||
| 7 | 'ca=ca.__main__:main' | ||
| 8 | ], | ||
| 9 | }, | ||
| 10 | ) | ||
