Commit 914bb2e6 authored by Elias Vasylenko's avatar Elias Vasylenko
Browse files

nixos/radicle: Update radicle to support systemd creds more completely via ImportCredential

By default it will look for the cred names supported by the upstream package, but alternate cred names can be chosen to produce a rename on the ImportCredential.
parent 3a813e37
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -306,3 +306,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