From bb71e44614f25b299041dbdb46eb908dd908ac4c Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 21 Apr 2026 09:57:35 -0400 Subject: [PATCH] Write per-minion telegraf creds to each minion's own pillar file pillar/top.sls only distributes postgres.auth to manager-class roles, so sensors / heavynodes / searchnodes / receivers / fleet / idh / hypervisor / desktop minions never received the postgres telegraf password they need to write metrics. Broadcasting the aggregate postgres.auth pillar to every role would leak the so_postgres admin password and every other minion's cred. Fan out per-minion credentials into each minion's own pillar file at /opt/so/saltstack/local/pillar/minions/.sls. That file is already distributed by pillar/top.sls exclusively to the matching minion via `- minions.{{ grains.id }}`, so each minion sees only its own postgres.telegraf.{user,pass} and nothing else. - salt/postgres/auth.sls: after writing the manager-scoped aggregate pillar, fan the per-minion creds out via so-yaml.py replace for every up-minion. Creates the minion pillar file if missing. Requires postgres_auth_pillar so the manager pillar lands first. - salt/telegraf/etc/telegraf.conf: consume postgres:telegraf:user and postgres:telegraf:pass directly from the minion's own pillar instead of walking postgres:auth:users which isn't visible off the manager. --- salt/postgres/auth.sls | 29 +++++++++++++++++++++++++++++ salt/telegraf/etc/telegraf.conf | 9 ++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/salt/postgres/auth.sls b/salt/postgres/auth.sls index 3da1bcde0..0b94ece99 100644 --- a/salt/postgres/auth.sls +++ b/salt/postgres/auth.sls @@ -49,6 +49,35 @@ postgres_auth_pillar: pass: "{{ entry.pass }}" {% endfor %} - show_changes: False + + {# Fan each minion's telegraf cred out to its own pillar file. The minions/ + .sls file is only served to that specific minion via pillar/top.sls + (`- minions.{{ grains.id }}`), so sensors, heavynodes, etc. see their own + credential without the admin password or anyone else's. Run per up-minion + so we have the original minion id (not just the safe-normalized version). #} + {% for mid in up_minions %} + {%- set safe = mid | replace('.','_') | replace('-','_') | lower %} + {%- set key = 'telegraf_' ~ safe %} + {%- set entry = telegraf_users.get(key) %} + {%- if entry %} + +postgres_telegraf_minion_pillar_{{ safe }}: + cmd.run: + - name: | + set -e + PILLAR_FILE=/opt/so/saltstack/local/pillar/minions/{{ mid }}.sls + if [ ! -f "$PILLAR_FILE" ]; then + echo '{}' > "$PILLAR_FILE" + chown socore:socore "$PILLAR_FILE" 2>/dev/null || true + chmod 640 "$PILLAR_FILE" + fi + /usr/sbin/so-yaml.py replace "$PILLAR_FILE" postgres.telegraf.user '{{ entry.user }}' + /usr/sbin/so-yaml.py replace "$PILLAR_FILE" postgres.telegraf.pass '{{ entry.pass }}' + - require: + - file: postgres_auth_pillar + + {%- endif %} + {% endfor %} {% else %} {{sls}}_state_not_allowed: diff --git a/salt/telegraf/etc/telegraf.conf b/salt/telegraf/etc/telegraf.conf index ee13e33d0..001a61d93 100644 --- a/salt/telegraf/etc/telegraf.conf +++ b/salt/telegraf/etc/telegraf.conf @@ -10,9 +10,12 @@ {%- set LOGSTASH_ENABLED = LOGSTASH_MERGED.enabled %} {%- set TG_OUT = TELEGRAFMERGED.output | upper %} {%- set PG_HOST = GLOBALS.manager_ip %} -{%- set PG_SAFE = GLOBALS.minion_id | replace('.','_') | replace('-','_') | lower %} -{%- set PG_USER = 'so_telegraf_' ~ PG_SAFE %} -{%- set PG_PASS = salt['pillar.get']('postgres:auth:users:telegraf_' ~ PG_SAFE ~ ':pass', '') %} +{#- Per-minion telegraf creds are written into the minion's own pillar file + (/opt/so/saltstack/local/pillar/minions/.sls) by postgres.auth on the + manager. Each minion only sees its own password — the aggregate map in + postgres:auth:users is manager-scoped. #} +{%- set PG_USER = salt['pillar.get']('postgres:telegraf:user', '') %} +{%- set PG_PASS = salt['pillar.get']('postgres:telegraf:pass', '') %} # Global tags can be specified here in key="value" format. [global_tags] role = "{{ GLOBALS.role.split('-') | last }}"