MetricHarborDocs

Credentials

MetricHarbor stores the name of a credential and the shape of it. It never stores the secret, and there is no field in the API in which to put one — offer it a password and it refuses the request.

The secret lives on your agent, encrypted, on your machine. A full dump of MetricHarbor's database is not a route into your infrastructure.

This is a real security property and it costs you something: you declare a credential in the web interface and then supply it on the host. The three mechanisms below exist to make that bearable.

The kinds

Kind You enter The agent prompts for
ssh_key username private key, passphrase
ssh_password username password
database_password username password
basic_auth username password
bearer_token — token
kubeconfig context kubeconfig
snmp_v2c — community
snmp_v3 username, security level, auth and privacy protocols auth passphrase, privacy passphrase

The split is the point: everything in the middle column is configuration, so MetricHarbor knows it and can show it to you. Everything in the right-hand column is a secret, so it only ever exists on your host.

1. Declare it, then run one command

In Credentials → Declare credential, pick a kind and give it a name you will be willing to retype — ssh-monitor, postgres-monitor. The detail page then shows the exact command, filled in:

runuser -u metricharbor -- metricharbor-agent cred add postgres-monitor --type database_password

Running these commands

runuser is used here rather than sudo deliberately. It comes from util-linux, which is essential on every distribution these packages target; sudo is not installed by default on a minimal Debian, and some hardened builds remove it on purpose. If you have sudo and prefer it, sudo -u metricharbor … does the same thing.

Not su - metricharbor either way: that account has a nologin shell on purpose, so su refuses it with "This account is currently not available."

Running these as plain root works too — the agent gives the files it writes to whoever owns the credential store, so the service can still read them. Preferring the service account is tidier, not required.

You are prompted for the password. A secret is never a command-line argument. /proc/<pid>/cmdline is world-readable and shell history is a file on disk, so there is no --password= form of this command, by design. Use the prompt, --password-file, a creds.d drop file, or cred import.

Not stdin. Piping a secret in is refused rather than accepted quietly — reading a line unechoed is impossible when stdin is a pipe, and the alternative is echoing the secret:

$ echo 'hunter2' | metricharbor-agent cred add db --type database_password
error: a secret cannot be typed when stdin is not a terminal; use --<field>-file,
       the creds.d drop file, or cred import

2. Let the agent generate it — SSH only

SSH keys are the one kind where the secret does not exist yet, and nobody should be moving private keys around:

runuser -u metricharbor -- metricharbor-agent cred new-ssh ssh-monitor --username monitor

The keypair is created on that host. The private half never exists anywhere else — not in MetricHarbor, not in a browser, not in a paste buffer. The command prints the public key to add to ~monitor/.ssh/authorized_keys on the hosts you want monitored.

--restrict emits a command= forced-command prefix, limiting the key to the collector's own commands. Worth using: it means a stolen key from that host cannot be used for a shell.

3. A file drop, for configuration management

/etc/metricharbor/creds.d/postgres-monitor.cred    # mode 0600

Dropped in plaintext by Ansible or Puppet, then encrypted and shredded by the agent on its next start, so a fleet rollout needs no second step. Use this if you already manage secrets with ansible-vault or similar and do not want to shell out to a CLI.

Checking it worked

metricharbor-agent cred list      # names only; it will not print a secret
metricharbor-agent check          # config parses, credentials resolve, targets answer

In the web interface, each credential shows one of three states:

  • held — one or more agents report holding a secret under that name.
  • not on any agent — no agent has it. Any target that needs it is collecting nothing. This is the single worst failure in the design, because it produces silence rather than an error, so the page shows it in red with the command to fix it.
  • unknown — no agent has reported in yet, so what they hold is not known. Not the same as broken; telling you to go fix a file on a host that has simply not checked in yet would waste your time.

Moving credentials between hosts

The encryption key is bound to the machine, so copying creds.d/ to a replacement host will not decrypt. That is deliberate — a stolen disk image is not a stolen credential — and it is why export exists:

runuser -u metricharbor -- metricharbor-agent cred export --out creds.mhbackup
# Passphrase: ********   (yours, not the machine key — this bundle is portable)

runuser -u metricharbor -- metricharbor-agent cred import creds.mhbackup    # on the new host

The same bundle is how one credential reaches a fleet. A database password often serves twenty hosts: enter it once, export, and distribute the bundle with whatever you already use for secrets. Backup, host migration and fleet rollout are the same two commands, and the secret still never touches MetricHarbor.

What is protected, and what is not

Be clear about this, because it is easy to over-read.

The at-rest encryption protects backups, disk images and stray copies. It does not protect against root on that host: if an attacker is root, they own the credentials regardless of what any software does.

What you get is a smaller blast radius in both directions. If one agent host is compromised, the attacker gets the credentials on that host — which is why per-agent credentials and new-ssh --restrict are worth the effort — and nothing on your other agents, and nothing in MetricHarbor beyond that one agent's ingest token. If MetricHarbor is compromised, an attacker gets no credential of yours at all.