From 6774129851ce47a9ab62cf8d909895e52dc02adb Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Wed, 1 Jan 2025 02:58:19 +0100 Subject: [PATCH] feat(hosts/bagel-box): enable secrets-agent on this machine And we use it for RabbitMQ mTLS authentication. Signed-off-by: Raito Bezarius --- hosts/bagel-box/default.nix | 9 ++++++ services/ofborg/default.nix | 55 ++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/hosts/bagel-box/default.nix b/hosts/bagel-box/default.nix index a7abf5f..1743493 100644 --- a/hosts/bagel-box/default.nix +++ b/hosts/bagel-box/default.nix @@ -52,6 +52,15 @@ # FIXME: plug into our prometheus stack. stats.enable = true; }; + + secrets-agent = { + enable = true; + methods.token = { + enable = true; + tenancy = "floral"; + identifier = "bagel-box"; + }; + }; }; bagel.sysadmin.enable = true; diff --git a/services/ofborg/default.nix b/services/ofborg/default.nix index fff6b20..7d4fc8d 100644 --- a/services/ofborg/default.nix +++ b/services/ofborg/default.nix @@ -21,8 +21,7 @@ let RuntimeDirectory = "ofborg"; WorkingDirectory = "/var/lib/ofborg"; LoadCredential = - optional (hasAttr "rabbitmq-password" config.age.secrets) "rabbitmq-password:${config.age.secrets.rabbitmq-password.path}" - ++ optional (hasAttr "gerrit-event-listener-ssh-key" config.age.secrets) "gerrit-ssh-key:${config.age.secrets.gerrit-event-listener-ssh-key.path}"; + optional (hasAttr "gerrit-event-listener-ssh-key" config.age.secrets) "gerrit-ssh-key:${config.age.secrets.gerrit-event-listener-ssh-key.path}"; Environment = [ "XDG_STATE_HOME=/run/ofborg" ]; @@ -45,6 +44,20 @@ in { settings = mkOption { type = generators.type; }; + + pki = { + cacertFile = mkOption { + type = types.path; + description = "CA certificate file for mTLS in OfBorg"; + default = config.bagel.pki.cacertFile; + }; + rootPath = mkOption { + type = types.str; + description = "Root mountpoint for PKI issuing in the Vault cluster"; + example = "floral_systems/v1/infra/v1"; + default = config.bagel.pki.rootPath; + }; + }; }; config = mkMerge [ @@ -97,27 +110,37 @@ in { }; } (mkIf cfg.rabbitmq.enable { - age.secrets.rabbitmq-password.file = ../../secrets/floral/rabbitmq-password.age; - services.nginx.enable = true; + systemd.services.rabbitmq.vault = { + # TODO: Reloading implies rabbitmqctl eval -n [target-node@hostname] 'ssl:clear_pem_cache().' + template = '' + {{ with pkiCert "${cfg.pki.rootPath}/issue/rabbitmq-server" "common_name=${amqpHost}" }} + {{ scratch.MapSet "secrets" "server.pem" .Data.Cert }} + {{ scratch.MapSet "secrets" "server.key" .Data.Key }} + {{ end }} + {{ scratch.Get "secrets" | explodeMap | toJSON }} + ''; + secrets = { + "server.pem" = {}; + "server.key" = {}; + }; + }; services.rabbitmq = { enable = true; configItems = { "listeners.tcp" = "none"; "listeners.ssl.default" = builtins.toString amqpPort; - "ssl_options.certfile" = "${config.security.acme.certs.${amqpHost}.directory}/cert.pem"; - "ssl_options.keyfile" = "${config.security.acme.certs.${amqpHost}.directory}/key.pem"; + # TODO(upstream): this should accept path as well… + "ssl_options.cacertfile" = "${cfg.pki.cacertFile}"; + "ssl_options.certfile" = "/run/credentials/rabbitmq.service/server.pem"; + "ssl_options.keyfile" = "/run/credentials/rabbitmq.service/server.key"; + "ssl_options.verify" = "verify_peer"; + # TODO(upstream): … + "ssl_options.fail_if_no_peer_cert" = "true"; + # TLS authentication via X.509 + "auth_mechanisms.1" = "EXTERNAL"; + "ssl_cert_login_from" = "common_name"; }; }; - - security.acme.certs.${amqpHost} = { - webroot = "/var/lib/acme/.challenges"; - group = "rabbitmq"; - }; - services.nginx.virtualHosts.${amqpHost}.locations."/.well-known/acme-challenge".root = - "/var/lib/acme/.challenges"; - systemd.services.rabbitmq.requires = ["acme-finished-${amqpHost}.target"]; - - networking.firewall.allowedTCPPorts = [ amqpPort ]; }) (mkIf cfg.pastebin.enable { systemd.services.ofborg-pastebin = mkOfborgWorker "pastebin-worker" { };