Schedule icon
FluxQuery icon
Script icon
If icon
Switch icon
Loop icon
Request icon
Log icon
SlackIncomingWebhook icon

InfluxDB Bucket Retention Sentinel

Audit InfluxDB buckets for infinite retention with Flux buckets(), alert on breach, and optionally bound retention via the REST API.

Categories
DataInfrastructure

InfluxDB documents retention period 0 as a deliberate, named setting: infinite retention, data kept forever. That is sometimes exactly what you want - and sometimes a bucket created for a quick test that nobody ever bounded, quietly accumulating data and cost indefinitely. Nothing in InfluxDB itself flags that for you. This blueprint runs Flux's own buckets() introspection function, finds every bucket with retentionPeriod == 0, alerts Slack on breach, and can bound that bucket's retention to a configured number of days through InfluxDB's own REST API - never deleting existing data, only shortening the window going forward.

How it works

  1. periodic_retention_check (io.kestra.plugin.core.trigger.Schedule) runs every 6 hours, always forcing auto_remediate: "false" and dry_run: "true" through its own inputs: override regardless of this flow's defaults. Shipped disabled so you can validate a manual run first.
  2. audit_bucket_retention (io.kestra.plugin.influxdb.FluxQuery) runs buckets() with fetchType: STORE, returning a uri to the stored result - each row carrying name, id, organizationID, retentionPolicy, and retentionPeriod (nanoseconds).
  3. evaluate_retention_risk (io.kestra.plugin.scripts.python.Script) reads that stored result and collects every bucket whose retentionPeriod is exactly 0, emitting infinite_count and infinite_buckets through Kestra.outputs.
  4. evaluate_retention_gate (io.kestra.plugin.core.flow.If) flags a breach whenever infinite_count > max_infinite_retention_buckets.
    • then (breach): route_remediation (io.kestra.plugin.core.flow.Switch on auto_remediate) either considers remediation ("true", gated again by dry_run through check_dry_run) or only logs that remediation is disabled ("false"). When both gates allow it, bound_bucket_retention (io.kestra.plugin.core.flow.Loop) runs patch_bucket_retention (io.kestra.plugin.core.http.Request, PATCH /api/v2/buckets/{id}) for each flagged bucket, setting retentionRules to remediation_retention_days. alert_retention_risk always fires to Slack regardless of which path ran.
    • else (compliant): log_retention_healthy records a clean check.
  5. log_audit_complete always runs last, printing the headline numbers regardless of which branch fired.
  6. The errors block alerts Slack separately if the flow itself fails - an unreachable instance or an invalid token must not read as "no breach".

What you get

  • A concrete, named list of infinite-retention buckets, computed from InfluxDB's own buckets() function, not inferred from dashboards or configuration files.
  • Remediation that only ever shortens the retention window going forward through InfluxDB's own documented API; no existing data point is deleted by this flow.
  • Two independent gates (auto_remediate, dry_run) between "breach detected" and "retention actually bounded".
  • A final status log every run, breach or not, so the execution history doubles as a retention-posture trend for the organization.

Who it's for

  • Platform and observability teams running self-hosted InfluxDB who need to catch a bucket nobody ever bounded before storage cost or a compliance review catches it instead.
  • SREs standing up a new InfluxDB organization who want this as a pre-production gate.
  • Anyone evaluating the InfluxDB plugin who wants a worked example of FluxQuery against Flux's own introspection functions, beyond writing and reading measurement data.

Why orchestrate this with Kestra

buckets() is a live, read-only snapshot; running it by hand in the InfluxDB UI answers one moment in time and fixes nothing. Kestra supplies the schedule, the risk classification as a first-class branch, two independent authorization gates before anything is patched, and an execution history that shows exactly when a bucket was created with infinite retention and whether it was bounded.

Prerequisites

  • A reachable InfluxDB v2 instance and a token with rights to query buckets and, if remediation runs, patch them.
  • A Slack incoming webhook for alerts.

Local testing: docker run -d --name influxdb-retention-sentinel -p 8087:8086 influxdb:2 docker network connect YOUR_KESTRA_NETWORK influxdb-retention-sentinel (only needed if the Kestra Worker runs in a separate Docker network than this container; set INFLUXDB_URL to http://influxdb-retention-sentinel:8086 from inside that network, or http://localhost:8087 from the host). Complete the container's first-run setup (org, bucket, token) via influx setup or the UI before running this flow; a freshly-created bucket with no retention flag set is exactly the infinite-retention case this blueprint audits.

Secrets

  • INFLUXDB_URL: InfluxDB base URL, matching this plugin's own documented connection pattern (see influxdb-load-query-data.yaml).
  • INFLUXDB_TOKEN: InfluxDB API token used both by FluxQuery and, if remediation runs, the REST API patch - must have read access to buckets and, for remediation, write/admin access.
  • SLACK_WEBHOOK_URL: Slack incoming webhook used by alert_retention_risk and the errors block.
  • In Kestra OSS (no Enterprise secrets backend), secrets are supplied as environment variables prefixed SECRET_, base64-encoded, and read back in flows with {{ secret('NAME') }} - for example SECRET_INFLUXDB_TOKEN=$(echo -n '<your-influxdb-token>' | base64). This keeps credentials out of the flow YAML but, per Kestra's own documentation, offers no encryption at rest or access control beyond the host environment; use the Enterprise secrets backend for stronger guarantees.

Inputs

  • influxdb_org (STRING, default my-org): organization whose buckets are audited.
  • max_infinite_retention_buckets (INT, default 0): breach threshold; 0 means any infinite-retention bucket at all breaches.
  • remediation_retention_days (INT, default 90): bounded retention applied when remediation runs.
  • auto_remediate (SELECT: "false", "true"; default "false"): must be "true" for the patch to even be considered.
  • dry_run (SELECT: "true", "false"; default "true"): must be explicitly "false", together with auto_remediate: "true", for the bucket to actually be patched.

Outputs

  • outputs.audit_bucket_retention.uri: the raw stored buckets() result for every run.
  • outputs.evaluate_retention_risk.vars.infinite_count / .infinite_buckets: the computed risk result for every run.

Quick start

  1. Start InfluxDB locally with the command above and complete first-run setup, leaving the created bucket's retention unbounded (the default for a fresh bucket created without specifying one).
  2. Add the INFLUXDB_URL, INFLUXDB_TOKEN, and SLACK_WEBHOOK_URL secrets.
  3. Run the flow manually with the defaults (auto_remediate: "false") and confirm alert_retention_risk fires naming the expected bucket, and that log_remediation_disabled logs without patching anything.
  4. Run once with auto_remediate: "true" and dry_run: "true" and confirm log_dry_run_remediation describes the patch without applying it.
  5. Run once with auto_remediate: "true" and dry_run: "false" and confirm via the InfluxDB UI or GET /api/v2/buckets/{id} that the bucket's retentionRules now shows everySeconds matching remediation_retention_days * 86400.
  6. Enable periodic_retention_check once you trust the check; it always runs in the safe auto_remediate: "false" / dry_run: "true" mode regardless of what you leave the flow's own defaults set to.

How to extend

  • Loop over several influxdb_org values with io.kestra.plugin.core.flow.Loop (ForEach is deprecated) to sweep a multi-org instance in one run.
  • Extend evaluate_retention_risk to also flag buckets above a maximum retention ceiling, not just infinite ones, for organizations with an upper-bound compliance policy instead of (or in addition to) a lower bound.
  • Route the remediation branch through a Pause approval task instead of (or alongside) the static auto_remediate input, for a human-reviewed patch on production organizations.
  • Exclude InfluxDB's own system buckets (_monitoring, _tasks) from the audit by filtering on name in evaluate_retention_risk, if your organization's policy only targets user-created buckets.

Pitfalls

  • This plugin has no structured bucket-management task. Verified task list: FluxQuery, InfluxQLQuery, Load, Write (plus a FluxTrigger trigger) - none expose bucket retention as a settable property. Remediation calls InfluxDB's own documented PATCH /api/v2/buckets/{id} REST endpoint directly through the core io.kestra.plugin.core.http.Request task instead.
  • The API token header scheme is Authorization: Token <token>, not Bearer. Verified from InfluxDB's own API authentication documentation; using Bearer here would authenticate against the wrong scheme and fail.
  • The exact JSON shape of FluxQuery's STORE output was not confirmed against a live instance. evaluate_retention_risk's script defensively handles both a bare row list and a {"rows": [...]}-wrapped shape, but this has not been exercised against a running InfluxDB server in this environment.
  • retentionPeriod == 0 is InfluxDB's own documented meaning for infinite retention, confirmed from the InfluxDB v2 API reference's equivalent everySeconds field ("0 represents infinite retention") - this is not an assumption invented for this blueprint.
  • auto_remediate and dry_run are independent gates, not a single boolean. Both must be "true"/"false" respectively for the patch Loop to run; setting only one leaves the other still blocking.
  • Switch case keys "true"/"false" are quoted strings. auto_remediate renders as the literal string "true" or "false"; unquoted true:/false: YAML map keys would parse as booleans instead and would not match.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.