{
  name = "PostgreSQL";
  description = ''
    Runs a PostgreSQL database server on this host. 
    Other roles can use this role to create the required databases on this host through the
    `postgres` attribute. 
  '';

  nixosModule =
    {
      lib,
      pkgs,
      config,
      ...
    }:
    with lib;
    {
      options.postgres = {
        databases = mkOption {
          type = types.listOf types.str;
          default = [ ];
        };
      };
      config =
        let
          cfg = config.postgres;
        in
        {
          # Create the postgresql service
          services.postgresql = {
            enable = true;
            enableTCPIP = true;
            ensureDatabases = map (db: db) cfg.databases;
            ensureUsers = map (db: {
              name = db;
              ensureDBOwnership = true;
              ensureClauses.login = true;
            }) cfg.databases;
            identMap = ''
              # ArbitraryMapName systemUser DBUser
                 superuser_map      root      postgres
                 superuser_map      postgres  postgres
            '';

            authentication = pkgs.lib.mkOverride 10 ''
              # Allow local users to log into the database user with the same name
              local sameuser postgres     peer        map=superuser_map
              # Allow "md5" (password) authentication
              local   all   all                              md5
              host    all   all        0.0.0.0/0             md5
              host    all   all        127.0.0.1/32          md5
              host    all   all        ::1/128               md5
            '';
          };

          networking.firewall.allowedTCPPorts = [
            5432
          ];

          # Persist the database contents across reboots
          # TODO: This should be automatically backed up daily into the CEPH
          # cluster storage. It can't be on the cluster all the time, since
          # CEPH doesn't perform great with databases (according to people
          # online).
          environment.persistence."/persistent" = {
            directories = [
              {
                directory = "/var/lib/postgresql";
                user = "postgres";
                mode = "0700";
              }
            ];
          };

          # Create the required secret files
          sops.secrets = listToAttrs (
            map (db: {
              name = "postgres/${db}";
              value = {
                owner = "postgres";
              };
            }) cfg.databases
          );

          # Use the secret files from sops to set database user passwords
          systemd.services.postgresql.postStart = concatMapStrings (db: ''
            $PSQL -tA <<'EOF'
              DO $$
              DECLARE username TEXT;
              DECLARE password TEXT;
              BEGIN
                username := trim(both from replace('${db}', E'\n', '''));
                password := trim(both from replace(pg_read_file('${
                  (attrsets.getAttrFromPath [ "postgres/${db}" ] config.sops.secrets).path
                }'), E'\n', '''));
                EXECUTE format('ALTER ROLE %s WITH PASSWORD '''%s''';', username, password);
              END $$;
            EOF
          '') cfg.databases;
        };
    };
}