Before you begin
Check these requirements first, because a mismatch here fails later in a way that is hard to read:How it works
The agent signs a connection token locally using the IAM credentials it already holds, then presents that token to PostgreSQL as the password. The token is valid for 15 minutes and the agent mints a new one for each connection. Two consequences are worth knowing up front:- Token minting is not logged in CloudTrail. The token is signed on the client side, so no AWS API call is made and no event is recorded. You can audit the connection landing in your PostgreSQL logs instead.
- The IAM policy controls who, not where. IAM database authentication ignores
aws:SourceIp,aws:SourceVpcandaws:SourceVpcein a policy condition. Use security groups to restrict the network path.
Step 1: Turn on IAM database authentication
Your database has to accept IAM tokens before any of the following matters. Without this, the token is signed correctly and then rejected at login. In the AWS console, go to Modify, then Database authentication, and choose Password and IAM database authentication. For a DB instance, you can also use the CLI:Step 2: Create the database role
Connect as your master user and create theatatus role. Run this once per cluster:
pg_monitor is the built-in read-only monitoring role. Without it the agent sees only its own session in pg_stat_activity, and the query text of every other session is redacted to <insufficient privilege>.
The agent opens a connection per database it collects from. Roles inherit CONNECT from PUBLIC by default. If you have revoked that, grant it back for each database you want monitored:
The username in the agent config, the username in the IAM policy, and the PostgreSQL role name must match exactly, including their case. The username is signed into the token, so a case mismatch fails as an authentication error with no hint about the cause.
Step 3: Allow the agent to connect
The identity the agent runs as needs permission to open an IAM-authenticated connection as theatatus role. Attach this policy to the agent’s EC2 instance role, ECS task role, or EKS pod role:
<RESOURCE_ID> is the database resource id, not the database name. Find it under Configuration in the RDS console:
On ECS Fargate, attach this to the task role, not the execution role. The execution role is used by ECS before your container starts, to pull the image and read secrets. The process inside the container picks up the task role, so that is the identity that signs the token.
Step 4: Configure the agent
Edit/etc/atatus-infra-agent/conf.d/postgresql.d/postgresql.yml and add an aws: block:
Set
instance_endpoint explicitly whenever hosts: is not the real RDS endpoint, such as a CNAME, an IP address, or a connection pooler. AWS rejects a token presented to a host it was not signed for.
Restart the agent to pick up the change:
This restarts the agent on the host, not your database. It is safe to run
at any time: the only effect is a gap in collection of a few seconds, and your
databases keep serving throughout. The commands that restart a database are
called out separately, and none of them are required by the agent.
TLS
TLS is mandatory under managed authentication and defaults toverify-full. The token is a bearer credential, so a connection that can fall back to plaintext would hand it to anyone on the network path. The agent does not let you turn TLS off here.
You do not need to install a certificate. The agent ships the Amazon RDS certificate bundle and trusts it alongside the system store, which matters because the RDS authorities are a private PKI that is in no operating system trust store.
verify-ca and require are also accepted. Point ssl_root_cert at a PEM file only if you terminate TLS with your own certificate authority:
verify-ca checks the certificate chain but not the server hostname, so it is only as strong as its trust store. Pinned to the Amazon RDS authorities, it still trusts any RDS instance in any AWS account. Prefer verify-full, and use verify-ca only with your own ssl_root_cert.Monitor several databases with one agent
One agent can collect from any number of PostgreSQL databases. You do not need an agent per database, and the databases do not have to share a region, an account, or a set of credentials. There are three ways to arrange it. They can be mixed in the same setup.One entry per database
metrics is a list, so add an entry for each database. This is the clearest option and the one to reach for by default, because every setting is scoped to its own database:
aws block, the databases can sit in different regions, and with role_arn they can sit in different AWS accounts. Each entry can also use a different authentication method, so one database can use a password while another uses IAM tokens.
Several hosts in one entry
When databases share the same credentials and region, list them under a singlehosts entry:
hosts is shared, so this works only when the username, the region and the authentication method are the same for all of them.
Each host still needs its own rds-db:connect permission, because the resource id differs per database. Grant them in one policy:
One file per database
The agent reads every.yml file under conf.d/postgresql.d/, not only postgresql.yml. Give each database its own file when you want them managed separately, for example by different teams or by a configuration management tool:
metrics list and is loaded independently, so a mistake in one file is easier to find than a mistake in a long combined file.
Only files ending in
.yml are read. postgresql.yml.template is ignored because of its suffix, which is why the shipped template does not start collecting on its own. Renaming a file to orders.yml.disabled is a quick way to turn one database off without deleting its config.Things to watch
Keep these in mind as the number of databases grows:- Every database role has to be set up separately. Steps 2 and 3 above are per database, so create the
atatusrole and grantrds_iamon each one. - The agent opens a connection per database it collects from. Check
max_connectionson your smaller instances before you add many databases to one agent. - Security groups are per database. The agent host needs a path to each one on port 5432.
- Restart once, after all the edits. The agent reads the whole
conf.dtree at startup.
Monitoring a database in another AWS account
RDS has no resource-based policy, so the only workable shape is a role in the database’s account that the agent assumes. The agent’s own credentials are used only to callsts:AssumeRole. The token is then signed with the temporary credentials that role returns.
Add role_arn to the managed_authentication block:
external_id only if the trust policy requires one. In the database owner’s CloudTrail, the agent appears with the role session name atatus-infra-agent.
Confirm the assume works from the agent host before you restart the agent:
Running the agent outside AWS
With no credential fields set, the agent uses the standard AWS credential chain: environment variables, then the shared config file, then the EC2, ECS or EKS role. That is the best setup inside AWS, because no key is written to disk. On a host outside AWS, supply credentials explicitly. They are used only to sign the token, or to assume the role above:Set it up with Terraform
Everything on this page can be provisioned instead of configured by hand: an EC2 host running the agent, therds-db:connect policy with the resource id
resolved at apply time, the security group rule, and optionally the database
role itself created at first boot.
That has its own page, including the DocumentDB half and how to run both
engines from one host:
The working Terraform is at
atatus-database-monitoring-sample.
Troubleshooting
Work through these in order. Each step rules out one layer, so you do not have to guess which one is at fault.Check the agent version
Managed authentication needs 4.3.0 or higher. An older agent ignores theaws: block without complaining:
Check the agent is running and loaded your config
Turn up the log level
The default log level iswarning, which hides the messages that show the integration starting up. Set log_level: info in /etc/atatus-infra-agent/atatus.yml, restart, and read the log:
Prove the token works on its own
This is the single most useful check, because it splits the problem cleanly in half. Run it on the agent host, so it uses the same identity the agent uses:Query metrics are empty
If the agent connects but you see no queries,pg_stat_statements is most likely not loaded. It is a shared library that has to be loaded when the server starts, so CREATE EXTENSION on its own is not enough:
pg_stat_statements. If it does not, set shared_preload_libraries = pg_stat_statements in your parameter group and reboot the instance. This is a static parameter, so applying the parameter group without a reboot does nothing, CREATE EXTENSION still succeeds, and query metrics stay empty with no error.
On Aurora,
shared_preload_libraries is set in the DB cluster parameter group, not the DB parameter group. Recent Aurora PostgreSQL versions already include pg_stat_statements in their default cluster parameter group, so check the current value before you create a custom group.