Skip to content

Security

Everything security-related about Katalogue is on this page: the measures to take when deploying it, what personal data it holds and where, and what protects it against a compromised dependency.

Read through the Architecture section first to get an understanding for the topology. If you are deploying Katalogue, work through the checklist below as part of that deployment.

For how the protections themselves work — the token types, what is hashed and what is encrypted, the security headers and the rate limiting tiers — see Security Mechanisms on the Architecture page.

The following measures should be taken to make Katalogue as secure as possible in a production scenario. Coincidentially, most of these actions also reduce the management burden for Katalogue admins.

  1. Set the ENCRYPTION_KEY config variable to a long, cryptographically random string. Store it safely.
  2. Secure database user accounts:
    1. Make sure the katalogue_superuser database user only have the default permissions and a strong password.
    2. Make sure admin database users are few and have strong passwords. Ideally, avoid the default postgres username.
  3. Configure Cookies and CORS properly.
  4. Deploy Katalogue behind a VPN/firewall, never expose it to the internet.
  5. Ensure all communication between services is enforced to HTTPS.
  6. Use externally provisioned users provisioned through user groups, not local users nor individually added external users. This relieves Katalogue from storing user account passwords and automates user role assignments.
    1. Go through the security hardening steps for the app registration in Azure.
    2. Disable local user authentication (Settings -> Authentication and uncheck Enable Local Authentication). This disables the feature to create and use local user accounts in Katalogue.
    3. If local user authentication cannot be disabled, make sure to update the admin user’s default password.
  7. Restrict the user account permissions for accounts used in datasource connections to ingest metadata from source systems to only have read access to the required resources/tables.
  8. Enable password manager integration for datasource connections and store all datasource connection passwords there. This relieves Katalogue from storing user account passwords.
  9. Inject all configuration parameters that are secrets as environment variables/secrets in the startup phase of Docker containers. Do not store secrets in the appsettings.json config file. Configuration cannot be injected during the Docker build stage: the .dockerignore files exclude real appsettings files from the build context, because anything copied into an image is readable by anyone who can pull it.
  10. If the REST API service is enabled, consider using an externally provided signing key for access token signing. This relieves Katalogue from storing the private key.
  11. Review the rate limiting configuration and tighten the defaults if Katalogue is exposed to a broad or untrusted network.
  12. Limit the number of Katalogue admin users to as few as possible.
  13. Documentation & Processes:
    1. Document your deployment.
    2. Store all passwords in keyvaults or other safe places.
    3. Setup backup & restore processes for the database.
    4. Integrate logging with central logging functions.

If all of the steps above are followed, the only secrets Katalogue need to handle are the following:

  • ENCRYPTION_KEY - The Encryption key used to encrypt JWT cookies for authenticating requests from the frontend service.
  • REPOSITORY_PASSWORD - The repository database user password.
  • OIDC_CLIENT_SECRET - The Microsoft Entra Id app registration’s client secret.

Personally Identifiable Information in Katalogue is mainly related to users and user accounts. This data is deleted when the user is deleted from Katalogue, with a few exceptions:

  • Deleted, externally provisioned users from e.g. Microsoft Entra Id is deleted in Katalogue when a sync task is run. However, if the user is assigned to assets in Katalogue, as e.g. owner of the asset, the user is only disabled until all assets have been transferred to another user.
  • Local users must be deleted manually in Katalogue.
  • The changelog table is a complete log of all data changes that ever happened in Katalogue. Deleted users will remain in this table. Katalogue has no functionality for cleansing the changelog, so removing them is currently a matter of writing custom SQL against the repository database to null out the values.
  • The username (with the default attribute mapping to Microsoft Entra Id, this will be the email address) of the user that last made a change to an asset is stored in the modified_by_user_username column in all asset tables. This is not deleted when the user is deleted.

These are the main tables in the Katalogue repository database that store data that might be defined as PII in your organization:

TableDescriptionPII data stored
public.userMain user table with user informationsource id, name, username, email, photo, title, department
public.changelogHistory table with snapshots of all changes to the user tablesource id, name, username, email, photo, title, department
stage.raw_userStage table to handle user syncing. This table is truncated at the beginning of the sync task, but data is kept until the next sync job starts for debugging purposes.source id, name, username, email, photo, title, department
stage.raw_user_group_memberStage table to handle user group membership syncing. This table is truncated at the beginning of the sync task, but data is kept until the next sync job starts for debugging purposes.user source id (or attribute that is mapped to the Katalogue user source id) from Microsoft Entra Id.
public.http_requestLog table to log all http requests to the backend api. Logging to this table is disabled by default.username, IP address

In addition to this, logs may contain PII data. Katalogue rotates the file logs regularly (every 14 days by default) but logs captured by external logging tools or console logs stored in the container service might store PII data for a long time.

Finally, Katalogue may also store PII data if such data has been entered in any of the metadata attributes, like table descriptions, synced with Katalogue, or if someone enters PII data in descriptions in Katalogue. Detecting and handling such data is not considered to be part of the application but should rather be controlled by policy and processes.

Katalogue is a Node.js application and depends on packages from the public npm registry. There have been attacks that compromise a maintainer’s account, publish a poisoned version of a legitimate package, and execute malicious code on every machine that installs it.

  1. Dependency install scripts are disabled. The payload in these attacks is delivered through an npm lifecycle script — a preinstall or postinstall entry that runs automatically as part of npm install. Every Katalogue package directory carries an .npmrc with ignore-scripts=true, and both Dockerfiles pass --ignore-scripts explicitly. Nothing a compromised dependency declares will run at install time.
  2. Dependencies are installed from committed lockfiles. Builds and deployments use npm ci, which installs the exact versions recorded in package-lock.json. Resolving a newer version is a deliberate, reviewed step rather than something an install can do on its own.
  3. No secrets reach the build. All files that might contain secrets are excluded from the Docker build context, and configuration is supplied at container startup. The backend image also leaves out the utils operator tooling, so a running container carries no utility for encrypting or generating keys with its own ENCRYPTION_KEY.
  4. The frontend build runs with no network access. Disabling install scripts does not stop a bundler from executing webpack loaders and Babel plugins out of node_modules while it compiles, so a compromised build dependency does get to run at that point. Every package it needs is already installed by then, so the frontend image builds with --network=none: nothing can be sent out, and no second-stage payload can be fetched.

Installing the dependencies and changing which dependencies you have are two different operations, and they use different commands.

  • To install, always use npm ci. It installs exactly the versions recorded in package-lock.json and never resolves anything newer, so the result is reproducible. Keep the lockfile under version control, and do not use npm install for this.
  • To add or upgrade a dependency, use npm install <package>. This is the one case where npm install is correct, because npm ci cannot change the lockfile. Let the new version age first — npm install <package> --before=<date> resolves to what was published before that date. Note that --before applies to everything it resolves, not only the named package, so check what changed afterwards.
  • Review the package-lock.json diff on dependency changes. Updating everything at once produces a diff too large to read, which is exactly how an unexpected package slips through.
  • Run npm audit signatures to verify that installed packages match what the registry signed.

Understand what a successful attack would reach, because that determines what you must rotate.

ENCRYPTION_KEY protects everything Katalogue encrypts at rest. Code running inside the API process can use it to decrypt every stored datasource connection password, every setting marked as secret (OIDC_CLIENT_SECRET, MAIL_PASSWORD, REST_API_OIDC_SIGNING_KEY), and to read or forge session cookies. Local user account passwords and REST API client secrets are hashed rather than encrypted, and are not recoverable.

This is the reason for two recommendations in the checklist above. Using password manager integration for datasource connections means those credentials never sit in the repository database at all. Supplying secrets as Docker secrets rather than environment variables means they are not sitting in process.env, which is the first thing an infostealer reads.

A database backup carries the same reach. It contains every encrypted secret in the repository database, and ENCRYPTION_KEY is what turns those back into usable credentials — so a backup and the key together are equivalent to the live database. Keep them apart: a backup stored alongside the key, or in a location the key is also available from, is a single place to compromise rather than two.

Assume that anything the affected machine could read has been taken, and that removing the package afterwards does not undo it.

  1. Treat the developer workstation, build agent or container as compromised. Rebuild it rather than cleaning it.
  2. Rotate REPOSITORY_PASSWORD, OIDC_CLIENT_SECRET and MAIL_PASSWORD, and rotate the REST API signing key from Settings.
  3. Re-provision every datasource connection password, at the source systems as well as in Katalogue.
  4. Rotate any credential that was present in the environment but not owned by Katalogue — cloud CLI tokens, container registry logins, SSH keys, CI secrets.
  5. ENCRYPTION_KEY cannot currently be rotated once encrypted data exists. If it was exposed, the encrypted values in the repository database must be treated as compromised and re-created after redeploying with a new key.
  6. Review your source systems, and Katalogue’s own record of what happened, for access you cannot account for. Katalogue keeps two: the Changelog, which records every data change and who made it, and the public.http_request table, which records every request to the backend API. HTTP request logging is disabled by default, so if you want it available during an incident it has to be switched on beforehand.