tailscale proxy: collect sanitized Telemt active IP list
Telemt's Prometheus endpoint exposes only active-IP counts, while its loopback control API includes both the address list and sensitive proxy links. Add a root systemd timer that enters the Telemt container network namespace, filters the API response in memory, and publishes only username/address rows through the Zabbix agent key telemt.active_ips.list.\n\nThe collector refreshes every 30 seconds, writes atomically with root:zabbix 0640 permissions, and leaves the control API unexposed. Document the host installation and recommend one-day Zabbix history because client IP addresses are sensitive operational data.
This commit is contained in:
@@ -48,3 +48,27 @@ Cockpit. The Telemt application whitelist permits only the client-02 Zabbix
|
|||||||
server (`192.168.0.34/32`). In Zabbix, import Telemt's upstream
|
server (`192.168.0.34/32`). In Zabbix, import Telemt's upstream
|
||||||
`tools/zbx_telemt_template.yaml`, link it to the Docker host, and set
|
`tools/zbx_telemt_template.yaml`, link it to the Docker host, and set
|
||||||
`{$TELEMT_URL}` to the URL above.
|
`{$TELEMT_URL}` to the URL above.
|
||||||
|
|
||||||
|
Prometheus deliberately exposes only active-IP counts. The files in
|
||||||
|
`zabbix/` add the text key `telemt.active_ips.list` without publishing
|
||||||
|
Telemt's control API. A root timer enters only the container's network
|
||||||
|
namespace, reads `/v1/users`, discards links/secrets in memory, and writes a
|
||||||
|
sanitized username/IP list readable by the Zabbix agent:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
install -o root -g root -m 0755 zabbix/zabbix-telemt-active-ips \
|
||||||
|
/usr/local/libexec/zabbix-telemt-active-ips
|
||||||
|
install -o root -g root -m 0644 zabbix/zabbix-telemt-active-ips.service \
|
||||||
|
zabbix/zabbix-telemt-active-ips.timer /etc/systemd/system/
|
||||||
|
install -o root -g root -m 0644 zabbix/telemt-active-ips.conf \
|
||||||
|
/etc/zabbix/zabbix_agent2.d/telemt-active-ips.conf
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now zabbix-telemt-active-ips.timer
|
||||||
|
systemctl start zabbix-telemt-active-ips.service
|
||||||
|
systemctl restart zabbix-agent2
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a Zabbix agent item on `Fedora Kirochnaya` with key
|
||||||
|
`telemt.active_ips.list`, information type **Text**, a 30-second update
|
||||||
|
interval, and one-day history. IP addresses are operationally sensitive; do
|
||||||
|
not retain this item longer or expose it on unrestricted dashboards.
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Sanitized by zabbix-telemt-active-ips.service; contains no proxy secrets.
|
||||||
|
UserParameter=telemt.active_ips.list,cat /var/lib/zabbix/telemt-active-ips.txt
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
container_name="ts-lan-telemt"
|
||||||
|
output_dir="/var/lib/zabbix"
|
||||||
|
json_target="${output_dir}/telemt-active-ips.json"
|
||||||
|
text_target="${output_dir}/telemt-active-ips.txt"
|
||||||
|
|
||||||
|
install -d -o root -g zabbix -m 0750 "${output_dir}"
|
||||||
|
|
||||||
|
container_pid="$(docker inspect --format '{{.State.Pid}}' "${container_name}")"
|
||||||
|
if [[ -z "${container_pid}" || "${container_pid}" == "0" ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
json_tmp="$(mktemp "${output_dir}/.telemt-active-ips.json.XXXXXX")"
|
||||||
|
text_tmp="$(mktemp "${output_dir}/.telemt-active-ips.txt.XXXXXX")"
|
||||||
|
trap 'rm -f "${json_tmp}" "${text_tmp}"' EXIT
|
||||||
|
|
||||||
|
# The API response also contains proxy links and secrets. Filter it in-memory
|
||||||
|
# and persist only the username and current active IP address list.
|
||||||
|
nsenter -t "${container_pid}" -n \
|
||||||
|
curl --fail --silent --show-error --max-time 5 \
|
||||||
|
http://127.0.0.1:9091/v1/users |
|
||||||
|
jq --compact-output '{
|
||||||
|
users: [
|
||||||
|
.data[]
|
||||||
|
| {
|
||||||
|
username,
|
||||||
|
active_unique_ips: (.active_unique_ips_list // [])
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}' > "${json_tmp}"
|
||||||
|
|
||||||
|
{
|
||||||
|
active_count="$(jq '[.users[].active_unique_ips[]] | length' "${json_tmp}")"
|
||||||
|
printf 'Active IP addresses: %s\n' "${active_count}"
|
||||||
|
jq --raw-output '
|
||||||
|
[
|
||||||
|
.users[] as $user
|
||||||
|
| $user.active_unique_ips[]
|
||||||
|
| "\($user.username) | \(.)"
|
||||||
|
]
|
||||||
|
| if length == 0 then ["No active IP addresses"] else . end
|
||||||
|
| .[]
|
||||||
|
' "${json_tmp}"
|
||||||
|
} > "${text_tmp}"
|
||||||
|
|
||||||
|
chown root:zabbix "${json_tmp}" "${text_tmp}"
|
||||||
|
chmod 0640 "${json_tmp}" "${text_tmp}"
|
||||||
|
mv -f "${json_tmp}" "${json_target}"
|
||||||
|
mv -f "${text_tmp}" "${text_target}"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Collect sanitized Telemt active IP addresses for Zabbix
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/libexec/zabbix-telemt-active-ips
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
PrivateTmp=true
|
||||||
|
NoNewPrivileges=true
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Refresh sanitized Telemt active IP addresses for Zabbix
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=30s
|
||||||
|
OnUnitActiveSec=30s
|
||||||
|
AccuracySec=2s
|
||||||
|
Unit=zabbix-telemt-active-ips.service
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
Reference in New Issue
Block a user