diff --git a/content/telegraf/controller/admin/audit-logs/_index.md b/content/telegraf/controller/admin/audit-logs/_index.md index 7dec5b70cc..836a39b5ed 100644 --- a/content/telegraf/controller/admin/audit-logs/_index.md +++ b/content/telegraf/controller/admin/audit-logs/_index.md @@ -60,7 +60,8 @@ Each entry records: - **Source**: IP address and user-agent of the request, where applicable. - **Outcome**: `Success`, `Failure`, or `Denied`. - **Timestamp**: when the event occurred, in UTC. -- **Sequence number, hash, and previous hash**: used to detect tampering. +- **Sequence number, hash, previous hash, and key fingerprint**: used to + detect tampering. ## Where audit logs are stored @@ -89,10 +90,38 @@ See [Audit logs in a cluster](/telegraf/controller/admin/high-availability/#audi ## Tamper detection -Each entry includes a SHA-256 hash that incorporates the entry's contents -and the hash of the previous entry, forming a chain. +Each entry includes an HMAC-SHA256 hash that incorporates the entry's +contents and the hash of the previous entry, forming a chain. +{{% product-name %}} computes the hash with a signing key that you configure +at startup and records a fingerprint of that key (the first 16 hexadecimal +characters of the key's SHA-256 digest) in the entry's `secretId` field. Sequence numbers are contiguous within and across monthly files. -Any modification, deletion, or out-of-order insertion breaks the chain. +Any modification, deletion, or out-of-order insertion breaks the chain, and +an entry re-sealed with a different key fails signature verification. + +{{% product-name %}} verifies the current month's chain when audit logging +starts and logs the result. +The `GET /api/audit-logger/verify` endpoint verifies every retained monthly +file on demand. +See [Verify integrity](/telegraf/controller/admin/audit-logs/view/#verify-integrity). + +> [!Important] +> #### The signing key is the trust boundary +> +> Anyone who can read the signing key can alter entries and re-sign the +> chain. +> Keep the key outside the audit log data directory, restrict who can read +> it, and forward audit events to an external destination that the +> {{% product-name %}} host cannot modify. +> See [Forward audit events](/telegraf/controller/admin/audit-logs/enable-configure/#forward-audit-events). + +Entries written by {{% product-name %}} 1.1 and earlier were signed with a +built-in key and carry the key fingerprint `123`. +Upgrading does not rewrite them. +The first entry signed with your key links to the last of those entries, so +the chain stays continuous, but verification reports them separately as +legacy entries because their signatures cannot prove that they were not +altered before the upgrade. In a high-availability cluster, each node maintains its own hash chain and sequence numbers, so events from different nodes merged into a single stream do @@ -107,11 +136,13 @@ Audit logging is part of [Telegraf Enterprise](/telegraf/enterprise/) and is unavailable in the free tier. With a valid license: -- Audit logging is **enabled at startup only** by setting `AUDIT_ENABLED`. +- Audit logging is **enabled at startup only** by setting `AUDIT_ENABLED` + and configuring a signing key. See [Enable and configure audit logging](/telegraf/controller/admin/audit-logs/enable-configure/). - Only the retention period is modifiable at runtime, from the **Settings** page. -- Only the **Owner** and **Administrator** roles can read audit log entries. +- Reading audit log entries requires the `audit:read` permission, which the + **Owner** and **Administrator** roles hold. See [View audit logs](/telegraf/controller/admin/audit-logs/view/). {{< children hlevel="h2" >}} diff --git a/content/telegraf/controller/admin/audit-logs/enable-configure.md b/content/telegraf/controller/admin/audit-logs/enable-configure.md index 5e8c578da5..30ad832217 100644 --- a/content/telegraf/controller/admin/audit-logs/enable-configure.md +++ b/content/telegraf/controller/admin/audit-logs/enable-configure.md @@ -2,9 +2,9 @@ title: Enable and configure audit logging list_title: Enable and configure audit logging description: > - Enable audit logging in Telegraf Controller at startup, configure the - retention period, and optionally forward audit events to syslog, a - webhook, or a file. + Enable audit logging in Telegraf Controller at startup with a signing key, + configure the retention period, and optionally forward audit events to + syslog, a webhook, or a file. aliases: - /telegraf/controller/audit-logs/enable-configure/ menu: @@ -17,9 +17,9 @@ related: - /telegraf/controller/telegraf-enterprise/apply-license/ --- -Enable audit logging in {{% product-name %}} at startup, change the -retention period as needed, and optionally forward events to external -destinations for long-term storage or SIEM integration. +Enable audit logging in {{% product-name %}} at startup with a signing key, +change the retention period as needed, and optionally forward events to +external destinations for long-term storage or SIEM integration. {{< telegraf/enterprise-feature "Audit logging" >}} @@ -33,6 +33,8 @@ destinations for long-term storage or SIEM integration. - A valid [Telegraf Enterprise license](/telegraf/enterprise/) applied to your {{% product-name %}} instance. +- A signing key of at least 32 characters. + See [Generate a signing key](#generate-a-signing-key). - Permission to modify the {{% product-name %}} startup environment (for example, the systemd unit file or startup environment). - The **Owner** or **Administrator** role to change the retention period @@ -43,12 +45,58 @@ destinations for long-term storage or SIEM integration. > > Per {{% product-name %}}'s security policy, settings that change the > application's security boundary, including whether audit logging is -> enabled and where audit events are forwarded, can only be changed at startup. +> enabled, the signing key, and where audit events are forwarded, can only be +> changed at startup. > Retention is the only audit setting that can be modified at runtime. ## Enable audit logging -Set `AUDIT_ENABLED` to `true` before starting {{% product-name %}}. +Audit logging requires two settings at startup: `AUDIT_ENABLED` set to +`true`, and a signing key of at least 32 characters that {{% product-name %}} +uses to sign each audit entry. +Provide the key in one of the following ways: + +- The `AUDIT_HMAC_KEY` environment variable, which holds the key itself. +- The `AUDIT_HMAC_KEY_FILE` environment variable or the + `--audit-hmac-key-file` command flag, which name a file that holds the key. + {{% product-name %}} trims surrounding whitespace, so a trailing newline + in the file is fine. + +If both are set, `AUDIT_HMAC_KEY` takes precedence. +{{% product-name %}} never writes the key to disk or to the database. + +### Generate a signing key + +Any random string of at least 32 characters works as a key. +To generate one and store it in a file: + +{{< code-tabs-wrapper >}} +{{% code-tabs %}} +[Linux/macOS](#) +[Windows (PowerShell)](#) +{{% /code-tabs %}} +{{% code-tab-content %}} + +```bash +openssl rand -base64 48 > /etc/telegraf-controller/audit-key +chmod 600 /etc/telegraf-controller/audit-key +``` + +{{% /code-tab-content %}} +{{% code-tab-content %}} + +```powershell +-join ((48..57 + 65..90 + 97..122) | Get-Random -Count 48 | ForEach-Object { [char]$_ }) | + Set-Content -NoNewline "C:\ProgramData\TelegrafController\audit-key" +``` + +{{% /code-tab-content %}} +{{< /code-tabs-wrapper >}} + +Store the file outside the audit log data directory and restrict read +access to the account that runs {{% product-name %}}. + +### Start {{% product-name %}} with audit logging enabled {{< tabs-wrapper >}} {{% tabs %}} @@ -59,12 +107,13 @@ Set `AUDIT_ENABLED` to `true` before starting {{% product-name %}}. {{% /tabs %}} {{% tab-content %}} -Add `AUDIT_ENABLED=true` to your systemd unit file (typically -`/etc/systemd/system/telegraf-controller.service`): +Add `AUDIT_ENABLED=true` and the key file path to your systemd unit file +(typically `/etc/systemd/system/telegraf-controller.service`): ```ini [Service] Environment=AUDIT_ENABLED=true +Environment=AUDIT_HMAC_KEY_FILE=/etc/telegraf-controller/audit-key ``` Reload systemd and restart the service: @@ -77,42 +126,55 @@ sudo systemctl restart telegraf-controller {{% /tab-content %}} {{% tab-content %}} -Set the variable, or pass `--audit-enabled` on the command line: +Set the variables, or pass `--audit-enabled` and `--audit-hmac-key-file` +on the command line: ```bash export AUDIT_ENABLED=true +export AUDIT_HMAC_KEY_FILE=/etc/telegraf-controller/audit-key telegraf_controller --no-interactive ``` ```bash -telegraf_controller --audit-enabled --no-interactive +telegraf_controller --audit-enabled \ + --audit-hmac-key-file=/etc/telegraf-controller/audit-key \ + --no-interactive ``` {{% /tab-content %}} {{% tab-content %}} -Set the variable in PowerShell, or pass `--audit-enabled` on the command line: +Set the variables in PowerShell, or pass `--audit-enabled` and +`--audit-hmac-key-file` on the command line: ```powershell $env:AUDIT_ENABLED="true" +$env:AUDIT_HMAC_KEY_FILE="C:\ProgramData\TelegrafController\audit-key" ./telegraf_controller.exe --no-interactive ``` ```powershell -./telegraf_controller.exe --audit-enabled --no-interactive +./telegraf_controller.exe --audit-enabled ` + --audit-hmac-key-file="C:\ProgramData\TelegrafController\audit-key" ` + --no-interactive ``` {{% /tab-content %}} {{% tab-content %}} -Pass `AUDIT_ENABLED=true` when starting the container: +Pass `AUDIT_ENABLED=true` and mount the key file read-only when starting +the container: ```bash docker run \ --env AUDIT_ENABLED=true \ + --env AUDIT_HMAC_KEY_FILE=/run/secrets/audit-key \ + --volume /etc/telegraf-controller/audit-key:/run/secrets/audit-key:ro \ influxdata/telegraf-controller:{{< latest-patch >}} ``` +The container runs as the `telegraf-controller` user (UID `10001`), so the +key file must be readable by that user. Include your standard container options, such as EULA acceptance, published ports, and the data volume. See [Run {{% product-name %}} in Docker](/telegraf/controller/install/docker/). @@ -125,9 +187,34 @@ After {{% product-name %}} starts: - The **Settings > Audit Logging** section displays as enabled. - Audit entries begin appearing in the platform data directory described in [Where audit logs are stored](/telegraf/controller/admin/audit-logs/#where-audit-logs-are-stored). +- The server log reports the result of the startup chain check. + See [Verify integrity](/telegraf/controller/admin/audit-logs/view/#verify-integrity). {{< img-hd src="/img/telegraf/controller-settings-audit-retention.png" alt="Telegraf Controller audit log retention dropdown" />}} +### Start without a key + +If `AUDIT_ENABLED` is `true` but no signing key is configured, or the key is +shorter than 32 characters, {{% product-name %}} starts with audit logging +disabled and logs the reason, for example: + +``` +Audit HMAC key is not configured: set AUDIT_HMAC_KEY or pass --audit-hmac-key-file; audit logging stays disabled +``` + +The **Settings > Audit Logging** section displays as disabled until you +restart with a key. + +When you start the executable in a terminal without `--no-interactive` and +no key is configured, {{% product-name %}} prompts for the key instead: + +``` +Audit log signing key (at least 32 characters, empty to start without audit logging): +``` + +Input is hidden, and the key applies to that run only. +Press Enter without a key to start with audit logging disabled. + ## Configure retention {{% product-name %}} keeps audit entries for 90 days (2160 hours) by default @@ -176,6 +263,12 @@ destinations in addition to writing it to local storage. Forwarders are configured **at startup only** and run independently, which lets you enable any combination of syslog, webhook, and file forwarders. +Every audit event is forwarded, including sign-in, sign-out, constant, and +agent-deletion events. +If a forwarder fails, {{% product-name %}} logs `Audit forward failed` with a +running failure count and keeps running. +The entry is still written to local storage. + ### Forward to syslog Forward audit events to a syslog server over TCP or UDP. @@ -229,6 +322,7 @@ term. To turn audit logging off, remove `AUDIT_ENABLED` (or set it to a value other than `true`) and restart {{% product-name %}}. +Starting without a signing key has the same effect. The startup-only policy applies in both directions: audit logging cannot be disabled from the UI. diff --git a/content/telegraf/controller/admin/audit-logs/view.md b/content/telegraf/controller/admin/audit-logs/view.md index 7f0208891a..85f33762be 100644 --- a/content/telegraf/controller/admin/audit-logs/view.md +++ b/content/telegraf/controller/admin/audit-logs/view.md @@ -2,8 +2,9 @@ title: View audit logs list_title: View audit logs description: > - Query Telegraf Controller audit logs through the audit log API. Read - access is restricted to Owners and Administrators. + Query Telegraf Controller audit logs and verify their integrity through + the audit log API. Read access requires the audit:read permission, which + Owners and Administrators hold. aliases: - /telegraf/controller/audit-logs/view/ menu: @@ -17,7 +18,8 @@ related: - /telegraf/controller/tokens/create/ --- -Use the {{% product-name %}} API to query and read audit entries. +Use the {{% product-name %}} API to query audit entries and verify that the +audit log has not been tampered with. {{< telegraf/enterprise-feature "Audit logging" >}} @@ -29,9 +31,14 @@ Use the {{% product-name %}} API to query and read audit entries. ## Prerequisites - Audit logging must be [enabled](/telegraf/controller/admin/audit-logs/enable-configure/). -- The **Owner** or **Administrator** role assigned to your account. -- An API token issued to a user with one of those roles. +- The `audit:read` permission, which the **Owner** and **Administrator** + roles hold. +- An API token with the `audit:read` permission, issued to a user with one + of those roles. See [Create an API token](/telegraf/controller/tokens/create/). + Administrator tokens created before {{% product-name %}} 1.2.0 do not + include `audit:read`; create a new token to read the audit log with one. + Owner tokens with full access are unaffected. ## Query the audit log API @@ -71,24 +78,81 @@ tamper-detection hash chain fields. "userAgent": "Mozilla/5.0 ...", "outcome": "Success", "hash": "f7c1...", - "prevHash": "a309..." + "prevHash": "a309...", + "secretId": "9f2c4b1e8a7d3c05" } ] ``` `actorType` is one of `User`, `Token`, or `System`. +`secretId` is the fingerprint of the key that signed the entry: the first 16 +hexadecimal characters of the key's SHA-256 digest, or `123` for entries +written before a signing key was configured. For the categories of events captured, see [What gets audited](/telegraf/controller/admin/audit-logs/#what-gets-audited). ## Verify integrity -The `hash` and `prevHash` fields form a SHA-256 chain across all entries. -To detect tampering, walk the result set in `seq` order and check that: +Send a `GET` request to `/api/audit-logger/verify` to check every retained +monthly audit file against the configured signing key. +The endpoint requires the same `audit:read` permission as the query endpoint. -1. Each entry's `prevHash` equals the previous entry's `hash`. -2. `seq` numbers are contiguous within and across monthly files. +```bash { placeholders="YOUR_TC_API_TOKEN" } +curl -H "Authorization: Bearer YOUR_TC_API_TOKEN" \ + "https://telegraf_controller.example.com/api/audit-logger/verify" +``` + +The response reports the overall result and one object per monthly file: + +```json +{ + "keyConfigured": true, + "currentKeyId": "9f2c4b1e8a7d3c05", + "valid": true, + "files": [ + { + "period": "2026-05", + "status": "valid", + "entries": 4827, + "firstSeq": 1, + "lastSeq": 4827, + "brokenAtSeq": null, + "reason": null, + "legacyEntries": 312, + "unverifiedEntries": 0, + "keyIds": ["123", "9f2c4b1e8a7d3c05"] + } + ] +} +``` + +- **keyConfigured** and **currentKeyId**: whether this node has a signing + key, and its fingerprint. +- **valid**: `false` if any file is `broken`. +- **status**: `valid`, `broken`, or `empty` for each file. +- **brokenAtSeq** and **reason**: the first entry that fails and why: + `signature does not match`, `does not link to the previous entry`, + `first entry does not start from genesis`, or `sequence gap after seq N`. +- **legacyEntries**: entries signed with the built-in key before a signing + key was configured (fingerprint `123`). + They are checked for chain continuity, but their signatures cannot prove + that they were not altered before the upgrade. +- **unverifiedEntries**: entries signed with a key this node does not have, + for example a key that has since been rotated. + Their fingerprints appear in `keyIds`. + They do not mark the file as `broken`. +- **firstSeq**: retention removes the oldest entries, so a file can start + after sequence `1`. + Verification starts from the first retained entry. + +{{% product-name %}} also verifies the current month's file when audit +logging starts and writes the result to the server log, for example: + +``` +Audit chain 2026-05 is broken at seq 1203: signature does not match +Audit chain 2026-05: 312 entries were signed with the built-in key before a key was configured +``` -If either check fails, an entry has been altered, removed, or inserted out -of order. +The first line is logged as an error, the second as a warning. For background on how the chain is constructed, see [Tamper detection](/telegraf/controller/admin/audit-logs/#tamper-detection). diff --git a/content/telegraf/controller/admin/high-availability/_index.md b/content/telegraf/controller/admin/high-availability/_index.md index eeb436a0c9..1e907dfbc0 100644 --- a/content/telegraf/controller/admin/high-availability/_index.md +++ b/content/telegraf/controller/admin/high-availability/_index.md @@ -188,6 +188,10 @@ interface and API traffic: | Unlicensed | No | No leader elected | No (returns 503) | Agent heartbeats are always accepted on every node, regardless of license state. +Scale limits apply to the cluster as a whole: before a node registers a new +agent, it checks the agent limit against the shared database, so a cluster +admits no more agents than a single node would. +See [Scale limits](/telegraf/controller/telegraf-enterprise/license-enforcement/#scale-limits). Licensing is checked when a node tries to acquire the lock, not continuously. A node that is already the leader when its license expires keeps the lock, but no @@ -204,6 +208,14 @@ chain, and forwards events to whatever destination that node is configured to use. Querying a node's [audit log API](/telegraf/controller/admin/audit-logs/view/) returns only that node's events. +Configure a [signing key](/telegraf/controller/admin/audit-logs/enable-configure/#enable-audit-logging) +on every node. +Each node signs its own entries with its own key, so the nodes can share one +key or use different keys. +If a node's key changes, entries signed with the previous key are reported +as unverified, not broken, when that node +[verifies its files](/telegraf/controller/admin/audit-logs/view/#verify-integrity). + To review activity across the whole cluster, forward each node's audit events to a shared destination, such as syslog or a webhook, and aggregate them there. See [Forward audit events](/telegraf/controller/admin/audit-logs/enable-configure/#forward-audit-events). diff --git a/content/telegraf/controller/admin/monitor.md b/content/telegraf/controller/admin/monitor.md index 1044a5ec8d..13da28f230 100644 --- a/content/telegraf/controller/admin/monitor.md +++ b/content/telegraf/controller/admin/monitor.md @@ -133,4 +133,8 @@ Each entry links to the page that explains how to fix the problem. See [Agent heartbeats return 401 Invalid token](/telegraf/controller/admin/troubleshoot/agents/#agent-heartbeats-return-401-invalid-token). - **License errors**. See [Troubleshoot licensing](/telegraf/controller/telegraf-enterprise/troubleshoot/). +- **Audit chain errors**, such as + `Audit chain 2026-05 is broken at seq 1203: signature does not match`, + which mean an audit file was altered. + See [Verify integrity](/telegraf/controller/admin/audit-logs/view/#verify-integrity). diff --git a/content/telegraf/controller/agents/heartbeat-data.md b/content/telegraf/controller/agents/heartbeat-data.md index 713047798f..4276e1d200 100644 --- a/content/telegraf/controller/agents/heartbeat-data.md +++ b/content/telegraf/controller/agents/heartbeat-data.md @@ -126,26 +126,28 @@ the `include` option. Optionally tune the sample with the ## Retrieve heartbeat data with the API -Both endpoints identify the agent by its reported agent ID (the heartbeat -plugin's `instance_id`) and require an API token with **read** permission on -the **Heartbeat** API. +Both endpoints identify the agent by its {{% product-name %}} agent `id`, +the identifier returned by `GET /api/agents`, not by the agent ID the +heartbeat plugin reports. +They require an API token with **read** permission on the **Agents** API and +return `404` for an unknown `id`. ### Latest heartbeat -`GET /api/heartbeat/agent/:agentId/latest-heartbeat` returns the most recent +`GET /api/agents/:id/heartbeat/latest` returns the most recent heartbeat snapshot, or `null` if none exists: when it was received, the reported statistics, how many log entries the agent reported and {{% product-name %}} stored, and the stored entries themselves. ```bash { placeholders="API_TOKEN|AGENT_ID" } -curl "https://telegraf-controller.example.com/api/heartbeat/agent/AGENT_ID/latest-heartbeat" \ +curl "https://telegraf-controller.example.com/api/agents/AGENT_ID/heartbeat/latest" \ -H "Authorization: Bearer API_TOKEN" ``` ### Statistics history -`GET /api/heartbeat/agent/:agentId/logs` returns the per-heartbeat statistics +`GET /api/agents/:id/heartbeat/logs` returns the per-heartbeat statistics series that backs the detail page's bar charts, oldest first. Each record carries a timestamp and the error, warning, and metric counts for that heartbeat. @@ -158,16 +160,16 @@ heartbeat. ```bash { placeholders="API_TOKEN|AGENT_ID" } -curl "https://telegraf-controller.example.com/api/heartbeat/agent/AGENT_ID/logs?limit=500" \ +curl "https://telegraf-controller.example.com/api/agents/AGENT_ID/heartbeat/logs?limit=500" \ -H "Authorization: Bearer API_TOKEN" ``` Replace the following: - {{% code-placeholder-key %}}`API_TOKEN`{{% /code-placeholder-key %}}: an - API token with read permission on the Heartbeat API + API token with read permission on the Agents API - {{% code-placeholder-key %}}`AGENT_ID`{{% /code-placeholder-key %}}: the - agent's reported agent ID + agent's `id` in {{% product-name %}}, as returned by `GET /api/agents` > [!Note] > Despite its path, the statistics history endpoint returns per-heartbeat diff --git a/content/telegraf/controller/agents/monitor.md b/content/telegraf/controller/agents/monitor.md index a08608ad42..9ef71be1fd 100644 --- a/content/telegraf/controller/agents/monitor.md +++ b/content/telegraf/controller/agents/monitor.md @@ -40,6 +40,32 @@ agents are hidden from the bar. For what each status means and how statuses are set, see [Set agent statuses](/telegraf/controller/agents/status/). +### Agent list columns + +The agent list has the following columns: + +- **Agent Details**: the agent's instance ID, or its hostname when the agent + did not report an instance ID. + Click **Show labels** above the list to show each agent's labels beside + its ID. +- **Telegraf Version**: the Telegraf version the agent reported. +- **Advisories**: the agent's security advisory exposure. + Requires a Telegraf Enterprise license. + See [Find affected agents on the Agents page](/telegraf/controller/security-advisories/view/#find-affected-agents-on-the-agents-page). +- **Status**: the agent's current status. +- **Last Reported**: when the agent last sent a heartbeat. + +Switch between two row layouts with the toggle above the list: + +- **Compact View** ({{% lucide "layout-grid" %}}) shows the version number + and the status as a colored dot. +- **Detailed View** ({{% lucide "layout-list" %}}) adds the agent's IP + address under its ID, shows the full version string the agent reported, + and shows the status as a labeled chip. + +Sort the list by **Agent Details**, **Status**, or **Last Reported** by +clicking a column header. Click the header again to reverse the sort order. + ## View fleet summary details Expand **More details** below the status bar to show three summary diff --git a/content/telegraf/controller/agents/reporting-rules.md b/content/telegraf/controller/agents/reporting-rules.md index f1d16e5f5f..7866a335f5 100644 --- a/content/telegraf/controller/agents/reporting-rules.md +++ b/content/telegraf/controller/agents/reporting-rules.md @@ -16,14 +16,17 @@ before {{% product-name %}} changes its status to **Not Reporting**. They can also automatically delete agents that haven't reported in a specified amount of time. -{{% product-name %}} requires a default reporting rule. Newly created agents -are automatically assigned to the current default reporting rule. +{{% product-name %}} requires exactly one default reporting rule. Newly +created agents are automatically assigned to the current default reporting +rule. On first run, {{% product-name %}} creates a default rule with a +one-hour not reporting threshold and auto-delete turned off. Manage reporting rules in the **Reporting Rules** section of {{% product-name "short" %}}, then assign them to agents from either the agent list or an agent details page. +- [How reporting rules work](#how-reporting-rules-work) - [Create a reporting rule](#create-a-reporting-rule) - [Update a reporting rule](#update-a-reporting-rule) - [Delete a reporting rule](#delete-a-reporting-rule) @@ -33,8 +36,30 @@ list or an agent details page. - [Assign a reporting rule to agents](#assign-a-reporting-rule-to-agents) - [From the agent list](#from-the-agent-list) - [From an agent details page](#from-an-agent-details-page) +- [Run a status check](#run-a-status-check) +## How reporting rules work + +A reporting rule has two thresholds, both measured from the agent's last +heartbeat: + +- **Not reporting threshold**: how long an agent can go without a heartbeat + before {{% product-name %}} marks it **Not Reporting**. +- **Auto-delete threshold** (optional): how much longer a **Not Reporting** + agent is kept. + {{% product-name %}} deletes the agent once its last heartbeat is older + than the two thresholds combined. + +{{% product-name %}} evaluates every rule once a minute. An agent that +resumes sending heartbeats returns to its reported status on the next +evaluation. + +Thresholds are stored as whole seconds from `1` to `2147483647`. +The web interface accepts durations such as `12h`, `7d`, or `3h 30m` and +converts them. The API rejects any other value, including `0`, with +`400 Bad Request`. + ## Create a reporting rule 1. In Telegraf Controller, go to **Reporting Rules**. @@ -43,10 +68,12 @@ list or an agent details page. - **Description**: Reporting rule description - **Not Reporting Threshold**: The maximum time an agent can go without reporting before {{% product-name "short" %}} assigns the "Not Reporting" - status. + status, as a duration such as `12h` or `7d`. - **Auto-delete agents**: Enable to automatically delete agents that haven't - reported in the defined auto-delete threshold. + reported in the defined **Auto-delete threshold**, counted from the end + of the not reporting threshold. - **Default Rule**: Enable to make the rule the default reporting rule. + The previous default rule stops being the default. 4. Save the rule. ## Update a reporting rule @@ -78,6 +105,13 @@ list or an agent details page. ## Set a default reporting rule +Exactly one rule is the default at any time. +Making another rule the default moves the default to that rule in one step. +You cannot turn **Default Rule** off on the current default rule; make +another rule the default instead. +Changing the default does not reassign agents that already have a rule; only +agents registered after the change receive the new default. + ### From the reporting rules list 1. In **Reporting Rules**, click the **More button ({{% lucide "ellipsis-vertical" %}})** @@ -106,3 +140,12 @@ list or an agent details page. agent and select **{{% lucide "eye" %}} View Details**. 2. In the **Reporting Rule** section, select **Change**. 3. Choose a rule and apply it. + +## Run a status check + +{{% product-name %}} evaluates reporting rules once a minute. To evaluate +them immediately, for example after changing a threshold, select +**{{% lucide "clock" %}} Run status check** on the **Reporting Rules** page. + +The same check is available from the API as `POST /api/agents/status-check`, +which requires the `agents:write` permission. diff --git a/content/telegraf/controller/config-groups/manage.md b/content/telegraf/controller/config-groups/manage.md index 83406a5474..0ee318bd26 100644 --- a/content/telegraf/controller/config-groups/manage.md +++ b/content/telegraf/controller/config-groups/manage.md @@ -25,6 +25,13 @@ labels, and lifecycle from the group detail page. **Configurations > Config Groups** in the navigation bar. 2. Click **{{% lucide "plus" %}} Add Config Group**. 3. Enter a group name and optional description. + Names are unique among configuration groups, matched exactly including + case, and can be up to 255 characters. + If the name is already taken, {{% product-name %}} reports + `Configuration group "" already exists` and the dialog stays open. + Through the API, the create request returns `409 Conflict` with + `"error": "config_group_name_taken"`. + A configuration group and a configuration can share a name. 4. _(Optional)_ To assign [aliases](/telegraf/controller/config-groups/aliases/) to the group, click **{{% lucide "plus" %}} Add Alias** and enter an alias that @@ -83,6 +90,9 @@ issues in the merged output are listed above the preview. On the group detail page, click the group name or description, enter a new value, and confirm. +Names are unique among configuration groups and can be up to 255 characters. +If another group already has the new name, the field stays open and shows +`Configuration group "" already exists`. ## Manage group labels diff --git a/content/telegraf/controller/configs/create.md b/content/telegraf/controller/configs/create.md index 7981412ccc..9a6c4df724 100644 --- a/content/telegraf/controller/configs/create.md +++ b/content/telegraf/controller/configs/create.md @@ -26,6 +26,13 @@ plugins. navigation bar. 2. Click **{{% lucide "plus" %}} Add Config**. 3. Enter a configuration name and optional description. + Names are unique among configurations, matched exactly including case, + and can be up to 255 characters. + If the name is already taken, {{% product-name %}} reports + `Configuration "" already exists` and the dialog stays open. + Through the API, the create request returns `409 Conflict` with + `"error": "config_name_taken"`. + A configuration and a configuration group can share a name. 4. _(Optional)_ To assign [aliases](/telegraf/controller/configs/aliases/) to the configuration, click **{{% lucide "plus" %}} Add Alias** and enter an alias that diff --git a/content/telegraf/controller/configs/update.md b/content/telegraf/controller/configs/update.md index 810f639bce..68ed64882b 100644 --- a/content/telegraf/controller/configs/update.md +++ b/content/telegraf/controller/configs/update.md @@ -40,6 +40,9 @@ compare, roll back, or prune versions, see 3. Under **Configuration Information**, click the text under **Name** or **Description**. The name or description will load into a form field. 4. Provide a new name or description and click **{{% lucide "check" %}}**. + Names are unique among configurations and can be up to 255 characters. + If another configuration already has the new name, the field stays open + and shows `Configuration "" already exists`. Name and description changes do not create a new configuration version. diff --git a/content/telegraf/controller/get-started.md b/content/telegraf/controller/get-started.md index e09101b37b..37918e99be 100644 --- a/content/telegraf/controller/get-started.md +++ b/content/telegraf/controller/get-started.md @@ -96,11 +96,14 @@ stdout and reports agent health back to {{% product-name %}}. url = "http://localhost:8000/agents/heartbeat" instance_id = "&{agent_id}" interval = "1m" - include = ["hostname", "statistics", "configs", "status"] + include = ["hostname", "statistics", "configs", "status", "logs"] # Include to authorize with Telegraf Controller # Note: If using Telegraf 1.38.x or earlier, use INFLUX_TOKEN token = "${TELEGRAF_CONTROLLER_TOKEN}" + [outputs.heartbeat.logs] + limit = 50 + [outputs.heartbeat.status] default = "ok" ``` @@ -127,11 +130,14 @@ stdout and reports agent health back to {{% product-name %}}. url = "http://localhost:8000/agents/heartbeat" instance_id = "&{agent_id}" interval = "1m" - include = ["hostname", "statistics", "configs", "status"] + include = ["hostname", "statistics", "configs", "status", "logs"] # Include to authorize with Telegraf Controller # Note: If using Telegraf 1.38.x or earlier, use INFLUX_TOKEN token = "${TELEGRAF_CONTROLLER_TOKEN}" + [outputs.heartbeat.logs] + limit = 50 + [outputs.heartbeat.status] default = "ok" ``` diff --git a/content/telegraf/controller/install/docker.md b/content/telegraf/controller/install/docker.md index 7b0aaba2f5..961c2db324 100644 --- a/content/telegraf/controller/install/docker.md +++ b/content/telegraf/controller/install/docker.md @@ -236,7 +236,7 @@ record and instance identity live in the data directory. The following `docker-compose.yml` runs {{% product-name %}} with a PostgreSQL database: -```yaml +```yaml { placeholders="postgres_user|postgres_password" } services: telegraf-controller: image: influxdata/telegraf-controller:{{< latest-patch >}} @@ -246,7 +246,7 @@ services: - "8000:8000" environment: TELEGRAF_CONTROLLER_EULA: accept - DATABASE_URL: postgresql://postgres:postgres@db:5432/telegraf_controller + DATABASE_URL: postgresql://postgres_user:postgres_password@db:5432/telegraf_controller volumes: - telegraf-controller:/var/lib/telegraf-controller restart: unless-stopped @@ -257,13 +257,13 @@ services: db: image: postgres:17-alpine environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres_user + POSTGRES_PASSWORD: postgres_password POSTGRES_DB: telegraf_controller volumes: - postgres-data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] + test: ["CMD-SHELL", "pg_isready -U postgres_user"] interval: 10s timeout: 5s retries: 5 @@ -274,6 +274,14 @@ volumes: postgres-data: ``` +Replace the following: + +- {{% code-placeholder-key %}}`postgres_user`{{% /code-placeholder-key %}} and + {{% code-placeholder-key %}}`postgres_password`{{% /code-placeholder-key %}}: + the username and password for the PostgreSQL `db` service. + The same values appear in `DATABASE_URL` so {{% product-name %}} can + connect to the database. + Start the services: ```bash diff --git a/content/telegraf/controller/reference/architecture.md b/content/telegraf/controller/reference/architecture.md index b9c3718cee..8012d3f614 100644 --- a/content/telegraf/controller/reference/architecture.md +++ b/content/telegraf/controller/reference/architecture.md @@ -276,11 +276,17 @@ Last-Modified: Mon, 05 Jan 2025 07:28:00 GMT ## Reporting Rules {{% product-name %}} uses reporting rules to determine when agents should be -marked as not reporting: - -- **Default Rule**: Created automatically on first run -- **Heartbeat Interval**: Expected frequency of agent heartbeats (default: 60s) -- **Threshold Multiplier**: How many intervals to wait before marking not_reporting (default: 3x) +marked as not reporting and when not reporting agents are deleted: + +- **Default rule**: Created automatically on first run (one-hour threshold, + no auto-delete) and assigned to newly registered agents. Exactly one rule + is the default at any time. +- **Not reporting threshold**: Seconds since the last heartbeat before an + agent is marked not reporting. +- **Auto-delete threshold**: Optional additional seconds after which a not + reporting agent is deleted. +- **Status check**: The heartbeat service evaluates every rule once a minute. + `POST /api/agents/status-check` runs the evaluation on demand. Access reporting rules via: diff --git a/content/telegraf/controller/reference/authentication-authorization.md b/content/telegraf/controller/reference/authentication-authorization.md index e40b89959e..a27d9833c7 100644 --- a/content/telegraf/controller/reference/authentication-authorization.md +++ b/content/telegraf/controller/reference/authentication-authorization.md @@ -34,6 +34,7 @@ This page is the reference for both. For task-based instructions, see - [Identity model](#identity-model) - [User roles](#user-roles) - [API tokens](#api-tokens) +- [Session-only endpoints](#session-only-endpoints) - [Endpoint authentication](#endpoint-authentication) - [License management](#license-management) @@ -116,7 +117,7 @@ additional administrative capabilities. | Role | Description | | :-------------- | :------------------------------------------------------------------------------------------------------------------- | | **Owner** | Full system access. Manages users, tokens, settings, and authentication providers. Only one owner exists at a time. Created during initial setup. | -| **Administrator** | Full system access. Same capabilities as the owner except cannot transfer ownership or modify LDAP/OIDC settings. | +| **Administrator** | Full system access. Same capabilities as the owner except cannot transfer ownership, modify LDAP/OIDC settings, or manage the license. Reads the audit log. | | **Manager** | Manages configurations, agents, labels, and reporting rules. Manages own API tokens. Cannot manage users or settings. | | **Viewer** | Read-only access to configurations, agents, labels, and reporting rules. Cannot manage tokens, users, or settings. | @@ -137,9 +138,22 @@ connections to {{% product-name %}}. Each token is scoped to the user who created it. The token's effective permissions are restricted to the creating user's role. A token cannot exceed the permissions of its owner. +When a token is created, the requested permissions are clamped to the +user's role: a wildcard such as `*:*` or `license:*` expands to the +permissions the role holds, and a request authenticated with a token cannot +create a token broader than itself. If a user's role changes to a role with less permissions, all of that user's existing tokens are automatically updated with restricted permissions or revoked to match the new role. +After an [ownership transfer](/telegraf/controller/users/transfer-ownership/), +the former owner's tokens are re-clamped to the **Administrator** role. + +Token management also depends on how the request is authenticated. +Owners and Administrators signed in with a session can list, revoke, +delete, and reassign any user's tokens. +A request authenticated with an API token manages only the tokens of the +user it belongs to, whatever its permissions, and cannot reassign tokens. +See [Token visibility](/telegraf/controller/tokens/#token-visibility). Tokens use the `tc-apiv1_` prefix, making them easy to identify in configuration files and scripts. @@ -152,6 +166,20 @@ API tokens are independent of the authentication provider that created the underlying user account. An LDAP user, an OIDC user, and a local user all issue tokens the same way. +## Session-only endpoints + +Endpoints that act on the signed-in user's own account or on instance +ownership accept only an interactive session, never an API token. +A request to one of these endpoints with an API token returns +`403 Forbidden` with the message `This endpoint requires an interactive +session`, even when the token holds the matching permissions. + +| Endpoint | Purpose | +| :---------------------------------------------------------------- | :------------------------------------------- | +| `PATCH /api/users/me` | Update the signed-in user's own profile | +| `PATCH /api/users/me/password` | Change the signed-in user's own password | +| `/api/users/transfer-owner` and its `pending`, `accept`, and `decline` routes | [Transfer ownership](/telegraf/controller/users/transfer-ownership/) | + ## Endpoint authentication By default, {{% product-name %}} requires authentication for API endpoints. diff --git a/content/telegraf/controller/reference/config-options.md b/content/telegraf/controller/reference/config-options.md index 84477f6e4d..1db8727462 100644 --- a/content/telegraf/controller/reference/config-options.md +++ b/content/telegraf/controller/reference/config-options.md @@ -142,6 +142,8 @@ telegraf_controller --no-interactive - [ha-poll-interval-ms](#ha-poll-interval-ms) - [Audit logging](#audit-logging) - [audit-enabled](#audit-enabled) + - [audit-hmac-key](#audit-hmac-key) + - [audit-hmac-key-file](#audit-hmac-key-file) - [audit-log-retention](#audit-log-retention) - [audit-syslog-host](#audit-syslog-host) - [audit-syslog-port](#audit-syslog-port) @@ -1194,6 +1196,8 @@ after startup require a restart. For a task-based walkthrough, see [Enable and configure audit logging](/telegraf/controller/admin/audit-logs/enable-configure/). - [audit-enabled](#audit-enabled) +- [audit-hmac-key](#audit-hmac-key) +- [audit-hmac-key-file](#audit-hmac-key-file) - [audit-log-retention](#audit-log-retention) - [audit-syslog-host](#audit-syslog-host) - [audit-syslog-port](#audit-syslog-port) @@ -1205,7 +1209,8 @@ after startup require a restart. For a task-based walkthrough, see #### audit-enabled Enable audit logging on startup. Audit logging requires a Telegraf -Enterprise license to take effect. +Enterprise license and a signing key ([`audit-hmac-key`](#audit-hmac-key) +or [`audit-hmac-key-file`](#audit-hmac-key-file)) to take effect. **Default:** `false` @@ -1215,6 +1220,36 @@ Enterprise license to take effect. --- +#### audit-hmac-key + +Key that signs each audit entry, at least 32 characters. +Audit logging stays disabled until a key is configured, even when +[`audit-enabled`](#audit-enabled) is set. +Takes precedence over [`audit-hmac-key-file`](#audit-hmac-key-file). +{{% product-name %}} never writes the key to disk or to the database. + +| Command flag | Environment variable | +| :----------- | :------------------- | +| _(none)_ | `AUDIT_HMAC_KEY` | + +--- + +#### audit-hmac-key-file + +Path to a file that holds the key that signs each audit entry +(at least 32 characters; surrounding whitespace is trimmed). +Audit logging stays disabled until a key is configured, even when +[`audit-enabled`](#audit-enabled) is set. +When the executable starts in a terminal without +[`--no-interactive`](#no-interactive) and no key is configured, +{{% product-name %}} prompts for the key at startup. + +| Command flag | Environment variable | +| :---------------------- | :-------------------- | +| `--audit-hmac-key-file` | `AUDIT_HMAC_KEY_FILE` | + +--- + #### audit-log-retention Sets the initial audit log retention period, in hours. diff --git a/content/telegraf/controller/telegraf-enterprise/license-enforcement.md b/content/telegraf/controller/telegraf-enterprise/license-enforcement.md index c6c5261e08..e246a599ae 100644 --- a/content/telegraf/controller/telegraf-enterprise/license-enforcement.md +++ b/content/telegraf/controller/telegraf-enterprise/license-enforcement.md @@ -36,7 +36,10 @@ them. ## Scale limits {{% product-name %}} enforces a maximum number of configurations and a -maximum number of reporting agents per instance. +maximum number of reporting agents per installation. +In a [high-availability cluster](/telegraf/controller/admin/high-availability/), +the limits apply to the cluster as a whole: every node counts against the +same database, so a cluster admits no more agents than a single node would. | Resource | Free tier | Telegraf Enterprise | | :------- | :-------: | :------------------ | @@ -66,6 +69,23 @@ cannot be overridden. and shows a tooltip explaining the limit. - The response includes an `X-Entitlement-Warning` header (see [Response headers](#response-headers)). +- The heartbeat endpoint returns `402 Payment Required` to an agent that is + not yet registered when the agent limit is reached. + Agents that are already registered keep reporting, and deleting agents + frees their slots immediately. + The response body identifies the limit: + + ```json + { + "success": false, + "error": "Agent entitlement limit reached (100/100). Upgrade to Telegraf Enterprise for higher limits.", + "error_type": "entitlement_limit_reached" + } + ``` + + An agent refused at the limit is remembered for 60 seconds, so its + retries are answered without a database lookup. + The **Agents** page shows the current agent count against the limit. A warning banner appears in the UI when usage reaches 80% of a limit so operators have advance notice before requests start being rejected. diff --git a/content/telegraf/controller/tokens/_index.md b/content/telegraf/controller/tokens/_index.md index ab23bf1138..d3a9fef718 100644 --- a/content/telegraf/controller/tokens/_index.md +++ b/content/telegraf/controller/tokens/_index.md @@ -57,6 +57,12 @@ access below your full role permissions. This lets you issue narrowly scoped tokens for specific tasks, such as a token that can only register agents or a token limited to read-only access. +Requested permissions are clamped to your role. +A wildcard such as `*:*` or `license:*` expands to the permissions your role +holds, so an Administrator who requests `license:*` receives `license:read`. +A request authenticated with an API token cannot create a token with +permissions beyond its own. + ## Token states Tokens exist in one of two states: @@ -70,17 +76,21 @@ Any agent or client using a revoked token immediately loses access. ## Token visibility -Your role determines which tokens you can view and manage: +Your role and how you authenticate determine which tokens you can view and +manage: -| Role | Token visibility | -|:------------------|:----------------------------------| -| **Owner** | All tokens across all users | -| **Administrator** | All tokens across all users | -| **Manager** | Only their own tokens | -| **Viewer** | Cannot manage tokens | +| Role | Signed in with a session | Authenticated with an API token | +|:------------------|:----------------------------|:--------------------------------| +| **Owner** | All tokens across all users | Only their own tokens | +| **Administrator** | All tokens across all users | Only their own tokens | +| **Manager** | Only their own tokens | Only their own tokens | +| **Viewer** | Cannot manage tokens | Cannot manage tokens | > [!Note] -> **Owner** and **Administrator** users can revoke any token in the organization, +> **Owner** and **Administrator** users signed in to the web interface can +> list, revoke, delete, and reassign any token in the organization, > including tokens belonging to other users. +> A request authenticated with an API token manages only the tokens of the +> user it belongs to, whatever its permissions, and cannot reassign tokens. {{< children hlevel="h2" >}} diff --git a/content/telegraf/controller/tokens/reassign.md b/content/telegraf/controller/tokens/reassign.md index db01927e86..785c6cff4c 100644 --- a/content/telegraf/controller/tokens/reassign.md +++ b/content/telegraf/controller/tokens/reassign.md @@ -16,8 +16,10 @@ external clients using the token. > [!Important] > #### Required permissions > -> To reassign an API token, you must have the **Owner** or **Administrator** -> role in {{% product-name %}}. +> To reassign an API token, you must be signed in to {{% product-name %}} +> with the **Owner** or **Administrator** role. +> Requests authenticated with an API token cannot reassign tokens and +> receive a `403 Forbidden` response. ## Reassign a token diff --git a/content/telegraf/controller/users/transfer-ownership.md b/content/telegraf/controller/users/transfer-ownership.md index 7f53daa3b8..3921132f3a 100644 --- a/content/telegraf/controller/users/transfer-ownership.md +++ b/content/telegraf/controller/users/transfer-ownership.md @@ -2,11 +2,15 @@ title: Transfer ownership description: > Transfer the Telegraf Controller owner role to another administrator. + The owner requests the transfer and the administrator accepts it. menu: telegraf_controller: name: Transfer ownership parent: Manage users weight: 104 +related: + - /telegraf/controller/reference/authentication-authorization/ + - /telegraf/controller/reference/api/ --- The **Owner** role grants full administrative access to {{% product-name %}}, @@ -14,16 +18,55 @@ including the ability to manage all users, tokens, and settings. Only one owner can exist at a time. The current owner can transfer ownership to any active administrator. +An ownership transfer is a two-step handoff: the owner requests the transfer, +and the target administrator accepts it. Nothing changes until the target +accepts. + +- [Prerequisites and restrictions](#prerequisites-and-restrictions) +- [How a transfer works](#how-a-transfer-works) +- [Request the transfer](#request-the-transfer) +- [Accept the transfer](#accept-the-transfer) +- [Decline or cancel a request](#decline-or-cancel-a-request) +- [What happens when the transfer is accepted](#what-happens-when-the-transfer-is-accepted) + ## Prerequisites and restrictions -- Only the current **Owner** can transfer ownership. +- Only the current **Owner** can request a transfer, and only the current + **Owner** can cancel one. - The target user must have the **Administrator** role and be in an active state. - If the target user is a **Manager** or **Viewer**, you must first promote them to **Administrator**. See [Change a user's role](/telegraf/controller/users/update/#change-a-users-role). - You cannot transfer ownership to yourself. +- The target must accept the request before it expires. +- Every transfer operation requires a signed-in session. + API tokens cannot request, accept, decline, or cancel a transfer. + See [Session-only endpoints](/telegraf/controller/reference/authentication-authorization/#session-only-endpoints). + +## How a transfer works + +1. The owner requests a transfer to an administrator. + The request is **pending** and expires after 72 hours by default. + Only one request can be pending at a time; a new request cancels the + previous one. +2. The target administrator accepts or declines the request, or the owner + cancels it. + A request that reaches its expiry time expires on its own. +3. When the target accepts, the roles swap in a single operation. + See [What happens when the transfer is accepted](#what-happens-when-the-transfer-is-accepted). + +> [!Important] +> #### The web interface does not show pending requests +> +> In {{% product-name %}} 1.2, the web interface can only request a +> transfer. After you confirm the request, the dialog reports the transfer as +> complete and returns you to the sign-in page, but you remain the owner until +> the target accepts. +> The target accepts, declines, and the owner cancels through the +> [{{% product-name %}} API](/telegraf/controller/reference/api/), as +> described below. -## Transfer the owner role +## Request the transfer 1. Navigate to the **Users** page or the target user's detail page. 2. Choose the target **Administrator** from the list (if not already selected). @@ -34,24 +77,101 @@ administrator. {{< img-hd src="/img/telegraf/controller-transfer-ownership.png" alt="Telegraf Controller transfer ownership confirmation" />}} -## What happens during transfer +{{% product-name %}} records the request and returns you to the sign-in page. +Sign in again if you need to keep working; your role has not changed yet. +Tell the target administrator that a request is waiting for them. + +To set a different expiry, request the transfer from the API instead. +`POST /api/users/transfer-owner` accepts the target's user ID and an optional +`expiresInHours` from `1` to `168`: + +```json +{ + "targetUserId": "01HZ8R5T4VX9YQK0M2N3P4Q5R6", + "expiresInHours": 24 +} +``` + +## Accept the transfer + +The target administrator accepts the request through the API from their own +signed-in session. +The easiest way is the +[interactive API reference](/telegraf/controller/reference/api/#explore-the-interactive-api-reference), +which sends requests with your browser session. + +1. Sign in to {{% product-name %}} as the target administrator and open + `/api/docs`. +2. Send `GET /api/users/transfer-owner/pending` to see the waiting request. + A `404` response means no request is pending for your account. + + ```json + { + "id": "6f1c2a9e-3b4d-4c5e-8f70-1a2b3c4d5e6f", + "fromUserId": "01HZ8R5T4VX9YQK0M2N3P4Q5R6", + "fromUsername": "alice", + "toUserId": "01J0ABCDEF1234567890GHJKLM", + "expiresAt": "2026-05-30T18:42:11.512Z", + "createdAt": "2026-05-27T18:42:11.512Z", + "requiresRecoveryPassword": true + } + ``` + +3. Send `POST /api/users/transfer-owner/accept`. + If `requiresRecoveryPassword` is `true`, your account signs in through + LDAP or OIDC and has no local password, so the request body must include a + recovery password that meets the + [password complexity requirements](/telegraf/controller/settings/#password-complexity-requirements): + + ```json { placeholders="RECOVERY_PASSWORD" } + { "recoveryPassword": "RECOVERY_PASSWORD" } + ``` + + Replace {{% code-placeholder-key %}}`RECOVERY_PASSWORD`{{% /code-placeholder-key %}} + with the password to use if your identity provider becomes unavailable. + If `requiresRecoveryPassword` is `false`, send an empty JSON object. + + A `204` response means the transfer is complete. + +4. Sign out and sign in again so that your session reflects the **Owner** + role. + +The owner account always keeps a local password so that it can sign in when +an external provider is unreachable. +See [Owner account behavior](/telegraf/controller/reference/authentication-authorization/#owner-account-behavior). + +## Decline or cancel a request + +- **Target administrator**: send `POST /api/users/transfer-owner/decline` + from your signed-in session to decline the request. +- **Owner**: send `DELETE /api/users/transfer-owner/pending` from your + signed-in session to cancel the request you made. + +Both return `204`. A declined, cancelled, or expired request cannot be +accepted; the owner must make a new request. + +## What happens when the transfer is accepted -When you confirm the transfer, {{% product-name %}} performs an atomic operation -that updates both accounts simultaneously: +When the target accepts, {{% product-name %}} performs an atomic operation +that updates both accounts together: - The current owner is demoted to **Administrator**. - The target user is promoted to **Owner**. -- Both users' sessions are destroyed -- both must log in again. -- The operation is atomic: both changes succeed together or neither takes effect. +- If the target supplied a recovery password, it becomes the local password of + the new owner account. +- The former owner's API tokens are re-clamped to the **Administrator** + role's permissions. +- The operation is atomic: all changes succeed together or none takes effect. > [!Tip] > #### Coordinate ownership transfers > -> Coordinate with the target user before transferring ownership. Both accounts -> are logged out immediately after the transfer completes. +> Coordinate with the target user before requesting a transfer. +> The request expires if it is not accepted in time, and both of you should +> sign in again once it completes. > [!Warning] > #### You cannot reclaim the Owner role yourself > -> Once transferred, you cannot reclaim the **Owner** role yourself. The new -> owner must transfer it back to you. +> Once the transfer is accepted, you cannot reclaim the **Owner** role +> yourself. The new owner must transfer it back to you.