Unverified Commit b10e1459 authored by Florian Klink's avatar Florian Klink Committed by GitHub
Browse files

Improve systemd creds support for radicle (#475836)

parents ec6997a0 914bb2e6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -308,3 +308,5 @@ See <https://github.com/NixOS/nixpkgs/issues/481673>.
    ```

    **Do not set this globally!** This makes your setup inherently less secure.

- `services.radicle` now supports importing the private key and passphrase as systemd creds.
+0 −4
Original line number Diff line number Diff line
@@ -3,12 +3,8 @@
let
  inherit (systemdUtils.lib)
    assertValueOneOf
    automountConfig
    checkUnitConfig
    makeJobScript
    mountConfig
    serviceConfig
    unitConfig
    unitNameType
    ;

+49 −20
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
  config,
  lib,
  pkgs,
  utils,
  ...
}:
let
@@ -15,6 +16,11 @@ let
    RAD_HOME = HOME;
  };

  credentials = {
    privateKey = "xyz.radicle.node.secret";
    privateKeyPassphrase = "xyz.radicle.node.passphrase";
  };

  # Convenient wrapper to run `rad` in the namespaces of `radicle-node.service`
  rad-system = pkgs.writeShellScriptBin "rad-system" ''
    set -o allexport
@@ -131,16 +137,34 @@ in
    services.radicle = {
      enable = lib.mkEnableOption "Radicle Seed Node";
      package = lib.mkPackageOption pkgs "radicle-node" { };
      privateKeyFile = lib.mkOption {
        # Note that a key encrypted by systemd-creds is not a path but a str.
        type = with lib.types; either path str;
      privateKey = lib.mkOption {
        type = with lib.types; nullOr (either path str);
        default = null;
        description = ''
          Absolute file path to an SSH private key,
          An SSH private key (as an absolute file path or Systemd credential name),
          usually generated by `rad auth`.

          If it contains a colon (`:`) the string before the colon
          is taken as the credential name
          and the string after as a path encrypted with `systemd-creds`.
          If set to the default value of `null`, radicle will import the private key from a credential
          named `${credentials.privateKey}`.

          If configured as a credential name it will be imported via `ImportCredential=` in the service configuration.
          Refer to the systemd-creds documentation for more details <https://systemd.io/CREDENTIALS/>
        '';
      };
      privateKeyPassphrase = lib.mkOption {
        type = with lib.types; nullOr str;
        default = null;
        description = ''
          A passphrase for an SSH private key (as a Systemd credential name),
          usually provided on generation of the key with `rad auth`.

          If set to the default value of `null`, radicle will optionally import the passphrase from a
          credential named `${credentials.privateKeyPassphrase}`.

          If the passphrase is not set, radicle will prompt for it.

          If configured as a credential name it will be imported via `ImportCredential=` in the service configuration.
          Refer to the systemd-creds documentation for more details <https://systemd.io/CREDENTIALS/>
        '';
      };
      publicKey = lib.mkOption {
@@ -304,23 +328,28 @@ in
          # Give only access to the private key to radicle-node.
          {
            serviceConfig =
              let
                keyCred = builtins.split ":" "${cfg.privateKeyFile}";
              in
              if lib.length keyCred > 1 then
              if cfg.privateKey == null then
                {
                  LoadCredentialEncrypted = [ cfg.privateKeyFile ];
                  # Note that neither %d nor ${CREDENTIALS_DIRECTORY} works in BindReadOnlyPaths=
                  BindReadOnlyPaths = [
                    "/run/credentials/radicle-node.service/${lib.head keyCred}:${env.RAD_HOME}/keys/radicle"
                  ];
                  ImportCredential = [ credentials.privateKey ];
                }
              else if lib.types.path.check cfg.privateKey then
                {
                  LoadCredential = [ "${credentials.privateKey}:${cfg.privateKey}" ];
                }
              else
                {
                  LoadCredential = [ "radicle:${cfg.privateKeyFile}" ];
                  BindReadOnlyPaths = [
                    "/run/credentials/radicle-node.service/radicle:${env.RAD_HOME}/keys/radicle"
                  ];
                  ImportCredential = [ "${cfg.privateKey}:${credentials.privateKey}" ];
                };
          }
          {
            serviceConfig =
              if cfg.privateKeyPassphrase == null then
                {
                  ImportCredential = [ credentials.privateKeyPassphrase ];
                }
              else
                {
                  ImportCredential = [ "${cfg.privateKeyPassphrase}:${credentials.privateKeyPassphrase}" ];
                };
          }
        ];
+4 −1
Original line number Diff line number Diff line
@@ -19,9 +19,12 @@ in
  meta.maintainers = with lib.maintainers; [ defelo ];

  nodes.seed = {
    virtualisation.credentials = {
      "xyz.radicle.node.secret".source = "${seed-ssh-keys.snakeOilEd25519PrivateKey}";
    };

    services.radicle = {
      enable = true;
      privateKeyFile = seed-ssh-keys.snakeOilEd25519PrivateKey;
      publicKey = seed-ssh-keys.snakeOilEd25519PublicKey;
      node.openFirewall = true;
      settings = {
+4 −1
Original line number Diff line number Diff line
@@ -76,9 +76,12 @@ in
      {
        imports = [ commonHostConfig ];

        virtualisation.credentials = {
          "xyz.radicle.node.secret".source = "${seed-ssh-keys.snakeOilEd25519PrivateKey}";
        };

        services.radicle = {
          enable = true;
          privateKeyFile = seed-ssh-keys.snakeOilEd25519PrivateKey;
          publicKey = seed-ssh-keys.snakeOilEd25519PublicKey;
          node = {
            openFirewall = true;
Loading