Skip to content

Security and access

This page is for the person who has to approve Guardioz on a production server. It answers, in order: who connects to your database and with which rights, what the agent costs your database, how the agent runs on the host, why the installer needs administrator rights when the agent runs without them, and what leaves the server. It then covers how the agent proves which server it is, where the data is stored, and how it is deleted.

The installer creates one PostgreSQL role, guardioz_monitor, and grants it pg_monitor. pg_monitor is a role that PostgreSQL ships for monitoring. It allows reading the monitoring views and functions, the value of every setting, and every statistics view. That includes the settings and views that are otherwise visible only to a superuser. See Predefined Roles in the PostgreSQL 18 documentation.

The agent uses that role and no other. Four things limit what the role can do:

  • One grant. The installer grants pg_monitor and nothing else: no superuser, no right to create roles, and no rights on your tables beyond what PostgreSQL gives every role (PUBLIC). A role of that name that already exists on the instance is given a new password, the right to log in and the pg_monitor grant, and keeps whatever it already had.
  • Read-only sessions. The agent sets each of its own sessions to read-only when it connects, so PostgreSQL refuses a statement from the agent that would write. This is a property of the agent’s sessions, not of the role: a program that signs in with the role’s password gets an ordinary session. The password stays in the agent’s configuration file, which only root and the agent’s service can read.
  • A fixed set of statements. Every statement the agent runs against your data is a SELECT or a SHOW written out in the agent’s source. The database driver also sends the statements that make the session read-only and, on a server whose DateStyle is not ISO, set its date format; they change only the agent’s own session. The agent has no code path that takes a statement from Guardioz or from its configuration file. When it sends a snapshot, it reads from the answer only the status, the waiting time that Guardioz asks for after HTTP 503, and the reason that Guardioz gives when it refuses a snapshot, which the agent writes to its log. For the complete list of what it reads, see What the agent reads and sends.
  • The local socket. The agent connects over the local Unix socket, so Guardioz needs no network port open to your database. The only rule the installer can add to the PostgreSQL client authentication file (pg_hba.conf) is a rule for connections over that local socket. It adds no rule for connections over the network.

Each connection and each statement has a time limit. The agent waits a few seconds at most for a lock on a table. In the weekly size measurement it then records that table as not measured; in the daily catalog it leaves that database out of that collection. The numbers are on Limits.

The agent runs on your production server, so it is built to cost your database little. It collects about once an hour, not every few seconds. Guardioz is not real-time monitoring, and no email tells you that your database or your server stopped. The agent runs its read-only queries one at a time, each with a time limit, and it reads statistics and catalogs, never the rows of your tables. Its heaviest work, measuring the size of tables and indexes on disk, runs once a week, and the catalog of tables and indexes once a day (every hour during the first day after the registration). These two parts are the only ones that take a lock on your tables, and it is the lightest lock PostgreSQL has, held only while one object is read: it does not conflict with reads or writes.

The reasons for this design are in Why the agent collects once an hour. We have published no measurement of the agent’s load on a database, so this documentation gives no number for it.

The installer creates a system account for the agent’s service, and the agent runs under that account, not as root. On FreeBSD a supervising process stays under root, as the FreeBSD tab below explains. When an account with the name the installer uses already exists on the host, the installer uses it as it is and does not change it. That account needs a group with the same name, and on FreeBSD it has to be in that group: when it is not, the installer stops before it changes anything and says what to do. The service definition on the host names that account, and the section “Check it for yourself” says where that definition is.

The account owns nothing that decides which code runs or where the data goes; it owns only its schedule file:

  • The agent’s code belongs to root. The service account can read it and cannot change it.
  • The configuration file belongs to root, with mode 0640 and the service’s group. The service reads it and never writes it. Only the installation, which runs as root, writes it, so an agent under someone else’s control cannot change the address its data goes to.
  • The agent writes two things on your server: its own collection schedule, in a file under /var/lib/guardioz-agent, and its log output. The schedule file holds three timestamps. No rows and no collected statistics are written to disk on your server. The log can carry a PostgreSQL error message, and such a message can quote names and values. For how to read the log, see Manage the agent service.

The systemd unit restricts the process further:

  • It cannot gain new privileges, and it holds no Linux capabilities.
  • Apart from its own state directory, a private /tmp and /var/tmp that no other process sees, and the device directory /dev, which includes the shared memory directory /dev/shm, the filesystem is read-only for it, and home directories are read-only.
  • It cannot change kernel settings, load kernel modules or read kernel logs.
  • It cannot change control groups, the clock or the host name.
  • Its system calls are limited to the standard set for a service.
  • It can open only Unix, IPv4, IPv6 and netlink sockets.
  • It can start at most 32 tasks.

The unit also raises the agent’s out-of-memory score, so the kernel’s out-of-memory killer picks the agent before a process of similar size that keeps the default score, such as a PostgreSQL process.

When the service exits, systemd starts it again after 10 seconds. After 5 starts within 600 seconds systemd stops trying, and the service stays stopped until you clear the failed state with systemctl reset-failed and start it, or until the server restarts. No snapshot is sent while it is stopped. See Manage the agent service.

After it starts the service, the installer reads the user id of the running process and confirms that it is the service account, not root.

The one privileged thing the agent needs is permission to pass through the PostgreSQL data directory. It needs that to measure free space on the disk that holds the transaction log (pg_wal), and, where a directory above the data directory is closed to other accounts, as on the Red Hat family, also on the disk that holds the data directory. The installer grants exactly that, with access-control list entries: on the data directory and, on Linux, on each directory above it that would otherwise block the account. The account can enter those directories, and cannot list or read what is inside. The owner and the group of each directory stay as they are, and the installer runs no chmod. Where the access-control list has the POSIX form, on Linux and on FreeBSD with UFS, ls -l shows its mask in the group column, as --x for a directory whose group had no permissions; the group of the directory gains no permission. Each entry goes into the install manifest with the command that removes it.

You can install without this grant, and the agent then records the disk figures of the transaction-log directory, and in that Red Hat layout those of the data directory too, as not measured. Without the figures of the data directory, Guardioz makes no max_wal_size recommendation. For the option, where it goes in the install command, and every other change the installer makes, see What the installer changes on your server.

Why the installer needs administrator rights

Section titled “Why the installer needs administrator rights”

The installer needs administrator rights, and the agent runs without them. You use those rights when you install, update or remove the agent, and when you start a collection by hand. During the installation the installer runs the agent’s registration with those rights, and that run also collects and sends the first snapshot. The service process that collects after that does not have them.

The installer needs them because what it sets up belongs to the operating system or to the account that owns PostgreSQL. These actions need administrator rights:

  • creating the system account that the agent’s service runs under;
  • putting the agent’s code under /opt/guardioz-agent and its configuration file under /etc/guardioz-agent, both owned by root;
  • writing the service definition, and starting the service;
  • running psql as the operating-system account that owns PostgreSQL, when that is the account that can create the monitoring role;
  • adding the access-control list entries on the PostgreSQL data directory, and the two lines in pg_hba.conf when the monitoring role cannot log in over the local socket.

For every change, and how each one is recorded, see What the installer changes on your server.

Installing with administrator rights is what allows the agent to run without them. A program that is installed from an ordinary account belongs to that account, so the running program can rewrite its own code and its own configuration file. Here root owns both. The running agent cannot change the code it executes, and it cannot change the address its data goes to.

The installer keeps its use of those rights narrow, and it shows it:

  • From an account that uses sudo, the installer runs under your account and puts sudo only in front of the steps that need it. Before it changes anything, it prints which of the two ways it runs: Running as root., or a line that names your account and says that it uses sudo for the steps that need administrator rights.
  • After it starts the service, the installer reads the account of the running agent process and confirms that it is the service account, not root. The update script makes the same check after it restarts a service.

PostgreSQL from your system’s packages is installed and run the same way: the package is installed with administrator rights, and the server runs under its own account, usually postgres, without them. The PostgreSQL documentation gives the reason in The PostgreSQL User Account: “it is advisable that this user account not own the PostgreSQL executable files, to ensure that a compromised server process could not modify those executables.” The agent follows that advice point by point:

What the PostgreSQL documentation advises for the server What the Guardioz installer does for the agent
“it is advisable to run PostgreSQL under a separate user account”, one that is not “shared with other daemons” It creates a system account for the agent’s service, or uses an existing account of that name as it is.
The account does “not own the PostgreSQL executable files” The agent’s code and its configuration file belong to root. The service account reads them and cannot change them.
“Pre-packaged versions of PostgreSQL will typically create a suitable user account automatically during package installation.” The installer creates the account during the installation. That is one of the steps that need administrator rights.

On Linux, you can see both accounts on your own server. The first command prints the account that PostgreSQL runs under. The second prints the account of the running agent process, followed by its command line. Replace 5432 with the port of your PostgreSQL instance. On a Linux system with default settings, neither command needs administrator rights.

Terminal window
ps -o user= -C postgres | sort -u
ps -o user=,args= -p "$(systemctl show -p MainPID --value guardioz-agent-5432)"

Every connection starts on your side. Guardioz opens no connection to your server, the agent listens on no port, and no inbound port is needed.

What Where it goes When
One snapshot, as one HTTPS request app.guardioz.com, port 443/TCP After each collection
The registration request app.guardioz.com, port 443/TCP Once, during the installation
The installer’s own requests: the agent source, and the message that the service started app.guardioz.com, port 443/TCP During the installation

During the installation the server also reaches package repositories: the one that supplies the agent’s Python libraries, and your system’s package repository when the installer has to add a package it needs. Those destinations are on Requirements.

The address the agent sends to is a setting in its configuration file, /etc/guardioz-agent/config-5432.yaml. Replace 5432 with the port of your PostgreSQL instance. You can read that file as root at any time and confirm where the data goes. See Agent configuration.

Nothing is queued on your server: a snapshot that does not arrive is dropped, after at most three attempts, and the next collection takes fresh data.

A snapshot carries statistics, catalog facts, the value of every PostgreSQL setting except six that the agent masks, the statement each session is running or, when it is idle, ran last, and a profile of the machine. Some of that can carry text from your own systems, so read the full list before you choose the first server to monitor. See What the agent reads and sends.

Why the agent sends data out and Guardioz never connects in

Section titled “Why the agent sends data out and Guardioz never connects in”

A monitoring service can work in one of two ways. The service connects in to your database and reads the statistics itself, or an agent on your server reads them and sends them out. Guardioz uses the second way, because opening an outbound connection from a database server is safer than opening a way in to a database. The differences are concrete:

The agent sends data out (Guardioz) A service connects in to your database
Network One outbound HTTPS connection to app.guardioz.com. PostgreSQL keeps listening only where it listened before. The database port must be reachable from outside your network.
Firewall No inbound rule. An inbound rule for the database port, which someone must keep correct.
Database credentials The monitoring role’s password stays in a file on your server. The service must store a credential that can sign in to your database.
What the service holds that can reach your database Nothing: no password and no network path. A working credential and a network path.

This design has a cost, and it is the agent: you install a program on the server that runs PostgreSQL. That is why the rest of this page says what that program can do and cannot do, and why its source code is on your server for you to read.

The same reasoning is why the agent runs on the same server as PostgreSQL. See Requirements.

Registration returns one collector key for the server. The agent stores it in its configuration file and sends it in the X-Collector-Key header of every snapshot. Four facts follow from that:

  • Guardioz stores only the SHA-256 hash of the key, and compares hashes. The key itself is not in the Guardioz database.
  • A key belongs to exactly one server, so a snapshot can land only on that server.
  • Running the installer again on a host that still holds a working key for this server replaces that key. The old key then stops working at once.
  • Deleting the server in Guardioz deletes its key. The agent on the host keeps running, and every request it sends is refused with HTTP 401. Its log then carries Authentication failed (HTTP 401). Check collector_key. For how to read the log, see Manage the agent service.

The install command carries a different secret, a one-time setup token. It is valid for 60 minutes and works once. See Limits.

Guardioz has no field for the password of a monitored database. The registration request carries the setup token, the host name, the port, the PostgreSQL version, the name of the monitoring role and the list of database names. On a later run it also carries the collector key that the host already holds. It carries no password, and Guardioz stores none for your database.

The monitoring role’s password is generated on your server and written into the agent’s configuration file on that host.

Your own Guardioz password is stored as a bcrypt hash. For sessions and how they end, see Manage your account.

Your monitoring data is stored in the European Union. The database that holds it, and its backups, are in Poland, where the company is registered, so EU data protection law (GDPR) applies. Guardioz shows a sentence to the same effect on the registration page.

The legal documents are on guardioz.com: the Terms of Service, the Privacy Policy, the Data Processing Agreement, the Service Provider List and the Agent Software Licence.

Each server belongs to one organization. Guardioz reads a server by its identifier together with the organization of the signed-in user. A server of another organization answers 404: the API with Server not found, and the web application with The page you are looking for does not exist. Neither says whether the server exists. A collector key authenticates one server of one organization.

Each account has exactly one organization, and today you cannot add another person to your organization. The account that created the organization is the only one that sees its servers. See Manage your account.

Guardioz deletes no monitoring data automatically today. The snapshots and findings of a server stay for as long as that server exists in Guardioz.

  • Deleting a server deletes, from the Guardioz database, that server, its collector key and everything collected from it: its snapshots, its findings, its machine profile and the records of its analysis runs. Copies in our database backups expire on their own, after up to about 36 days. Notification e-mails that were already sent, and error reports already passed to our error-monitoring provider, are not recalled. Request logs and the other copies that the Terms of Service, clause 16.7, name are not reached by a deletion either. See Manage your servers.
  • The agent on the host is not touched by that. It keeps collecting and its requests are refused. Remove it from the server as a separate step. See Remove Guardioz from a server.
  • Deleting your account also deletes your organization and every server in it, each the same way as deleting that server, together with your user and the ways to sign in with it. The agents on those servers are refused from then on. See Manage your account.

You do not have to take this page on trust. Each statement it makes about your server can be confirmed on that server.

What you want to confirm Where to look
Which statements the agent runs /opt/guardioz-agent/guardioz_agent/, readable by every account. See What the agent reads and sends.
What the install command will do, before you run it Download the script and read it. See Install the agent.
Which changes the installer made /etc/guardioz-agent/install-manifest.txt, which lists the changes the installer made, each with the command that reverses it or a note on how to reverse it. A new password given to a monitoring role that already existed is not listed, because it cannot be reversed. See What the installer changes on your server.
Where the agent sends data, and how it connects to PostgreSQL The agent’s configuration file. See Agent configuration.
Which account the agent’s process runs as right now On Linux, the second command in Why the installer needs administrator rights.
Which account the service runs as, and how it is restricted The service definition on the host: /etc/systemd/system/guardioz-agent-5432.service on Linux, /usr/local/etc/rc.d/guardioz_agent_5432 on FreeBSD. Replace 5432 with the port of your PostgreSQL instance.