Unverified Commit a95a5308 authored by Leona Maroni's avatar Leona Maroni
Browse files

nixos/gitlab: add activeRecord key files

GitLab 17.11 started using rails activeRecord encryption for some values.
Introduce new key files. This is breaking for unstable/25.05.

Also add a test to prevent this from happening unnoticed in the future.

For the future there should also be an option to set multiple activeRecord
keys for rotation.
parent 2e2cab78
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -333,6 +333,8 @@

- The behavior of the `networking.nat.externalIP` and `networking.nat.externalIPv6` options has been changed. `networking.nat.forwardPorts` now only forwards packets destined for the specified IP addresses.

- `services.gitlab` now requires the setting of `activeRecordPrimaryKeyFile`, `activeRecordDeterministicKeyFile`, `activeRecordSaltFile` as GitLab introduced Rails ActiveRecord encryption.

- `python3Packages.bpycv` has been removed due to being incompatible with Blender 4 and unmaintained.

- `python3Packages.jaeger-client` was removed because it was deprecated upstream. [OpenTelemetry](https://opentelemetry.io) is the recommended replacement.
+64 −2
Original line number Diff line number Diff line
@@ -907,6 +907,50 @@ in
        '';
      };

      secrets.activeRecordPrimaryKeyFile = mkOption {
        type = with types; nullOr path;
        default = null;
        description = ''
          A file containing the secret used to encrypt some rails data
          in the DB. This should not be the same as `services.gitlab.secrets.activeRecordDeterministicKeyFile`!

          Make sure the secret is at ideally 32 characters and all random,
          no regular words or you'll be exposed to dictionary attacks.

          This should be a string, not a nix path, since nix paths are
          copied into the world-readable nix store.
        '';
      };

      secrets.activeRecordDeterministicKeyFile = mkOption {
        type = with types; nullOr path;
        default = null;
        description = ''
          A file containing the secret used to encrypt some rails data in a deterministic way
          in the DB. This should not be the same as `services.gitlab.secrets.activeRecordPrimaryKeyFile`!

          Make sure the secret is at ideally 32 characters and all random,
          no regular words or you'll be exposed to dictionary attacks.

          This should be a string, not a nix path, since nix paths are
          copied into the world-readable nix store.
        '';
      };

      secrets.activeRecordSaltFile = mkOption {
        type = with types; nullOr path;
        default = null;
        description = ''
          A file containing the salt for active record encryption in the DB.

          Make sure the secret is at ideally 32 characters and all random,
          no regular words or you'll be exposed to dictionary attacks.

          This should be a string, not a nix path, since nix paths are
          copied into the world-readable nix store.
        '';
      };

      extraShellConfig = mkOption {
        type = types.attrs;
        default = { };
@@ -1180,6 +1224,18 @@ in
        assertion = cfg.secrets.jwsFile != null;
        message = "services.gitlab.secrets.jwsFile must be set!";
      }
      {
        assertion = cfg.secrets.activeRecordPrimaryKeyFile != null;
        message = "services.gitlab.secrets.activeRecordPrimaryKeyFile must be set!";
      }
      {
        assertion = cfg.secrets.activeRecordDeterministicKeyFile != null;
        message = "services.gitlab.secrets.activeRecordDeterministicKeyFile must be set!";
      }
      {
        assertion = cfg.secrets.activeRecordSaltFile != null;
        message = "services.gitlab.secrets.activeRecordSaltFile must be set!";
      }
      {
        assertion = versionAtLeast postgresqlPackage.version "14.9";
        message = "PostgreSQL >= 14.9 is required to run GitLab 17. Follow the instructions in the manual section for upgrading PostgreSQL here: https://nixos.org/manual/nixos/stable/index.html#module-services-postgres-upgrading";
@@ -1480,11 +1536,17 @@ in
            db="$(<'${cfg.secrets.dbFile}')"
            otp="$(<'${cfg.secrets.otpFile}')"
            jws="$(<'${cfg.secrets.jwsFile}')"
            export secret db otp jws
            arprimary="$(<'${cfg.secrets.activeRecordPrimaryKeyFile}')"
            ardeterministic="$(<'${cfg.secrets.activeRecordDeterministicKeyFile}')"
            arsalt="$(<'${cfg.secrets.activeRecordSaltFile}')"
            export secret db otp jws arprimary ardeterministic arsalt
            jq -n '{production: {secret_key_base: $ENV.secret,
                    otp_key_base: $ENV.otp,
                    db_key_base: $ENV.db,
                    openid_connect_signing_key: $ENV.jws}}' \
                    openid_connect_signing_key: $ENV.jws,
                    active_record_encryption_primary_key: $ENV.arprimary,
                    active_record_encryption_deterministic_key: $ENV.ardeterministic,
                    active_record_encryption_key_derivation_salt: $ENV.arsalt}}' \
               > '${cfg.statePath}/config/secrets.yml'
          )

+10 −0
Original line number Diff line number Diff line
@@ -106,6 +106,9 @@ in
            otpFile = pkgs.writeText "otpsecret" "Riew9mue";
            dbFile = pkgs.writeText "dbsecret" "we2quaeZ";
            jwsFile = pkgs.runCommand "oidcKeyBase" { } "${pkgs.openssl}/bin/openssl genrsa 2048 > $out";
            activeRecordPrimaryKeyFile = pkgs.writeText "arprimary" "vsaYPZjTRxcbG7W6gNr95AwBmzFUd4Eu";
            activeRecordDeterministicKeyFile = pkgs.writeText "ardeterministic" "kQarv9wb2JVP7XzLTh5f6DFcMHms4nEC";
            activeRecordSaltFile = pkgs.writeText "arsalt" "QkgR9CfFU3MXEWGqa7LbP24AntK5ZeYw";
          };

          registry = {
@@ -477,6 +480,9 @@ in
      gitlab.start()
    ''
    + waitForServices
    + ''
      gitlab.succeed("cp /var/gitlab/state/config/secrets.yml /root/gitlab-secrets.yml")
    ''
    + test true
    + ''
      gitlab.systemctl("start gitlab-backup.service")
@@ -496,5 +502,9 @@ in
      gitlab.systemctl("start gitlab.target")
    ''
    + waitForServices
    + ''
      with subtest("Check that no secrets were auto-generated as these would be non-persistent"):
          gitlab.succeed("diff -u /root/gitlab-secrets.yml /var/gitlab/state/config/secrets.yml")
    ''
    + test false;
}