diff --git a/Zabbix-fix.md b/Zabbix-fix.md new file mode 100644 index 0000000..d269063 --- /dev/null +++ b/Zabbix-fix.md @@ -0,0 +1,342 @@ +# Zabbix Auto-Registration Deployment + +Deployment scripts and documentation for Zabbix Agent 2 with PSK-encrypted auto-registration against `zabbix.snarfnet.net`. + +## Overview + +This project automates the end-to-end setup of Zabbix active agent auto-registration: + +1. **Server-side:** Creates auto-registration actions via the Zabbix API so new agents are automatically assigned to host groups and linked to templates. +2. **Agent-side:** Installs and configures Zabbix Agent 2 with PSK encryption on Linux (x86_64 and ARM) and Windows hosts. + +When an agent starts with `ServerActive` and `HostMetadata` configured, it reaches out to the Zabbix server on port 10051. The server matches the metadata against auto-registration action conditions and automatically adds the host. + +## Scripts + +| File | Purpose | +|------|---------| +| `configure_server_autoregistration.sh` | Creates host groups and auto-registration actions on the Zabbix server via API | +| `deploy_zabbix_agent_linux.sh` | Agent install for Linux x86_64 (RHEL, Debian, Ubuntu) | +| `deploy_zabbix_agent_linux_arm.sh` | Agent install for Linux ARM (aarch64, armhf, Raspberry Pi) | +| `deploy_zabbix_agent_windows.ps1` | Agent install for Windows x86_64 | + +## Prerequisites + +- **Zabbix Server 7.0** running and accessible +- **PSK encryption** already configured on the server (Administration → General → Autoregistration) +- **Port 10051/TCP** exposed and reachable from agent hosts (see [Kubernetes Exposure](#kubernetes-exposure) if running in k8s) +- `curl` and `jq` on the machine running the server config script +- `openssl` on agent hosts (for PSK key generation if not providing one) + +--- + +## Step 1: Expose Zabbix Server Trapper Port (Kubernetes) + +If your Zabbix server runs in Kubernetes, port 10051 must be exposed externally for agents to connect. The web UI (443) is not sufficient — agents need the trapper port. + +### Ports Required + +| Port | Service | Direction | Purpose | +|------|---------|-----------|---------| +| **10051/TCP** | zabbix-server | Inbound from agents | Active check-ins, auto-registration | +| 443/TCP | zabbix-web | Inbound from users | Web UI and API | + +### Option A: LoadBalancer Service (recommended) + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: zabbix-server-trapper + namespace: zabbix +spec: + type: LoadBalancer + selector: + app: zabbix-server # match your pod labels + ports: + - name: trapper + port: 10051 + targetPort: 10051 + protocol: TCP +``` + +### Option B: NodePort Service + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: zabbix-server-trapper + namespace: zabbix +spec: + type: NodePort + selector: + app: zabbix-server # match your pod labels + ports: + - name: trapper + port: 10051 + targetPort: 10051 + nodePort: 30051 + protocol: TCP +``` + +With NodePort, update agent `ServerActive` to use `:30051` or put a load balancer in front. + +### Option C: Nginx Ingress TCP Passthrough + +Add to the ingress controller's TCP ConfigMap: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: tcp-services + namespace: ingress-nginx +data: + "10051": "zabbix/zabbix-server:10051" +``` + +Ensure the ingress controller's Service also exposes port 10051. + +### DNS Considerations + +Make sure `zabbix.snarfnet.net` resolves to the IP where port 10051 is exposed. If the web UI and trapper are on different IPs, either: +- Point the main DNS record to the trapper LB and use a separate record for the web UI +- Or update `ServerActive` in agent configs to a dedicated trapper hostname + +### Verify Connectivity + +From an agent host: + +```bash +nc -zv zabbix.snarfnet.net 10051 +``` + +Expected: `Connection to zabbix.snarfnet.net 10051 port [tcp/*] succeeded!` + +If you get "connection refused" — the port isn't exposed or the trapper process isn't running. + +--- + +## Step 2: Configure Server Auto-Registration Actions + +Run the server configuration script to create host groups and auto-registration actions: + +```bash +bash configure_server_autoregistration.sh -u Admin -p 'your_zabbix_admin_password' +``` + +### What it does + +1. Authenticates with the Zabbix API at `https://zabbix.snarfnet.net/api_jsonrpc.php` +2. Finds or creates host groups: `Linux servers`, `Windows servers` +3. Looks up templates: `Linux by Zabbix agent active`, `Windows by Zabbix agent active` +4. Creates two auto-registration actions (skips if they already exist) + +### Actions Created + +| Action | Condition | Operations | +|--------|-----------|------------| +| Auto-register Linux hosts | Host metadata contains `Linux` | Add to group `Linux servers`, link template `Linux by Zabbix agent active` | +| Auto-register Windows hosts | Host metadata contains `Windows` | Add to group `Windows servers`, link template `Windows by Zabbix agent active` | + +### Options + +``` +-u Zabbix API username (required) +-p Zabbix API password (required) +-s Zabbix API URL (default: https://zabbix.snarfnet.net/api_jsonrpc.php) +-h Show help +``` + +### Notes + +- The API user must have **Super admin** role to create actions +- PSK configuration is assumed to already be in place (Administration → General → Autoregistration) +- The script is idempotent — safe to run multiple times + +--- + +## Step 3: Deploy Agents + +### Generate a Shared PSK Key + +All agents must use the same PSK key that's configured on the server: + +```bash +openssl rand -hex 32 +``` + +### Linux x86_64 + +```bash +# Auto-generate PSK (prints key at end) +sudo bash deploy_zabbix_agent_linux.sh + +# With a specific PSK +sudo bash deploy_zabbix_agent_linux.sh "your_64_char_hex_psk_here" +``` + +**Supports:** RHEL/CentOS/Rocky/Alma 8+, Ubuntu, Debian + +**What it does:** +1. Detects OS family (RHEL or Debian-based) +2. Adds the Zabbix 7.0 repository and installs `zabbix-agent2` +3. Writes PSK file with restricted permissions (640, root:zabbix) +4. Configures `ServerActive=zabbix.snarfnet.net`, `HostMetadata=Linux`, TLS PSK settings +5. Enables and starts the `zabbix-agent2` service + +### Linux ARM (Raspberry Pi, aarch64, armhf) + +```bash +# Auto-generate PSK +sudo bash deploy_zabbix_agent_linux_arm.sh + +# With a specific PSK +sudo bash deploy_zabbix_agent_linux_arm.sh "your_64_char_hex_psk_here" +``` + +**Supports:** Raspberry Pi OS, Ubuntu ARM, Debian ARM, any aarch64/armhf/armv6l Linux with systemd + +**What it does:** +1. Detects architecture (aarch64, armv7l, armv6l) +2. Tries package manager install (apt on Debian/Ubuntu/Raspbian) +3. Falls back to pre-compiled static binary tarball from Zabbix CDN +4. Creates systemd service unit for binary installs +5. Creates `zabbix` user if needed +6. Writes PSK file and agent configuration +7. Enables and starts the service + +### Windows + +```powershell +# Run as Administrator + +# Auto-generate PSK +.\deploy_zabbix_agent_windows.ps1 + +# With a specific PSK +.\deploy_zabbix_agent_windows.ps1 -PskKey "your_64_char_hex_psk_here" +``` + +**Supports:** Windows Server 2016+, Windows 10/11 (x86_64) + +**What it does:** +1. Downloads Zabbix Agent 2 MSI from official CDN +2. Installs silently to `C:\Program Files\Zabbix Agent 2` +3. Writes PSK file with ACL-restricted permissions (Administrators + SYSTEM only) +4. Writes agent config with `HostMetadata=Windows` and TLS PSK settings +5. Adds Windows Firewall rule for port 10050 inbound (Domain/Private profiles) +6. Sets service to automatic start and starts it + +--- + +## Configuration Reference + +| Setting | Value | +|---------|-------| +| Zabbix Server | `zabbix.snarfnet.net` | +| PSK Identity | `PSK_autoregister` | +| Host Metadata (Linux) | `Linux` | +| Host Metadata (Windows) | `Windows` | +| PSK File (Linux) | `/etc/zabbix/zabbix_agent2.psk` | +| PSK File (Windows) | `C:\Program Files\Zabbix Agent 2\zabbix_agent2.psk` | +| Agent Config (Linux) | `/etc/zabbix/zabbix_agent2.conf` | +| Agent Config (Windows) | `C:\Program Files\Zabbix Agent 2\zabbix_agent2.conf` | +| Trapper Port | 10051 (agent → server, active checks + registration) | +| Agent Port | 10050 (server → agent, passive checks) | + +--- + +## Security Notes + +- PSK key must be **identical** on the server and all agents using the same identity +- PSK files are permission-locked (640 on Linux, ACL-restricted on Windows) +- Use unique PSK identities per environment to segment (e.g., `PSK_prod`, `PSK_dev`) +- Rotate PSK keys by updating the server autoregistration config and redeploying agents +- The server config script does **not** modify PSK settings — manage those separately in the Zabbix UI + +--- + +## Troubleshooting + +### Connectivity Test + +```bash +# From agent → server (must succeed for auto-registration) +nc -zv zabbix.snarfnet.net 10051 +``` + +```powershell +Test-NetConnection -ComputerName zabbix.snarfnet.net -Port 10051 +``` + +### Agent Logs + +```bash +# Linux +journalctl -u zabbix-agent2 --since "5 minutes ago" +tail -f /var/log/zabbix/zabbix_agent2.log +grep -iE "error|failed|denied|psk|tls" /var/log/zabbix/zabbix_agent2.log +``` + +```powershell +# Windows +Get-Content "C:\Program Files\Zabbix Agent 2\zabbix_agent2.log" -Tail 50 +Select-String -Path "C:\Program Files\Zabbix Agent 2\zabbix_agent2.log" -Pattern "error|failed|denied|psk|tls" +``` + +### Server Logs (on Zabbix server) + +```bash +tail -f /var/log/zabbix/zabbix_server.log | grep -i "autoregistration\|psk\|tls\|cannot" +``` + +### Common Issues + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `connection refused` on 10051 | Port not exposed (Kubernetes) or trapper not running | Expose port 10051 via LoadBalancer/NodePort; check `StartTrappers` in server config | +| `connection timed out` on 10051 | Firewall blocking traffic | Open outbound 10051 on agent host; open inbound 10051 on server/cluster | +| `TLS handshake failed` | PSK key or identity mismatch | Verify key matches exactly; check for trailing newlines in PSK file | +| Agent connects but host doesn't appear | Auto-registration action missing or disabled | Run `configure_server_autoregistration.sh`; verify actions are enabled in UI | +| Action exists but doesn't trigger | HostMetadata doesn't match condition | Verify agent config has `HostMetadata=Linux` or `HostMetadata=Windows` | +| Hostname conflict | Host with same name already exists | Delete/rename existing host in Zabbix, or change `HostnameItem` | +| Script creates actions with invalid JSON | Log messages captured in variables | Fixed in current version — `log()` writes to stderr | + +### Verify Agent Config + +```bash +# Linux — confirm critical settings +grep -E "^Server=|^ServerActive=|^HostMetadata=|^TLS" /etc/zabbix/zabbix_agent2.conf + +# Check PSK file has no trailing newline +cat -A /etc/zabbix/zabbix_agent2.psk +# Should end with $ immediately after hex string, no extra lines +``` + +### Verify Server Actions via API + +```bash +# Get auth token +TOKEN=$(curl -s -X POST https://zabbix.snarfnet.net/api_jsonrpc.php \ + -H "Content-Type: application/json-rpc" \ + -d '{"jsonrpc":"2.0","method":"user.login","params":{"username":"Admin","password":"YOUR_PASS"},"id":1}' \ + | jq -r '.result') + +# List autoregistration actions +curl -s -X POST https://zabbix.snarfnet.net/api_jsonrpc.php \ + -H "Content-Type: application/json-rpc" \ + -d "{\"jsonrpc\":\"2.0\",\"method\":\"action.get\",\"params\":{\"filter\":{\"eventsource\":\"2\"}},\"auth\":\"${TOKEN}\",\"id\":2}" \ + | jq '.result[] | {name, status}' +``` + +--- + +## Deployment Order Summary + +1. **Expose port 10051** on your Kubernetes cluster (LoadBalancer/NodePort/Ingress TCP) +2. **Verify connectivity** from an agent host: `nc -zv zabbix.snarfnet.net 10051` +3. **Run server config script** to create auto-registration actions +4. **Deploy agents** with the shared PSK key +5. **Verify** hosts appear in Zabbix UI under their respective host groups diff --git a/zabbix-autoregister/README.md b/zabbix-autoregister/README.md new file mode 100644 index 0000000..d269063 --- /dev/null +++ b/zabbix-autoregister/README.md @@ -0,0 +1,342 @@ +# Zabbix Auto-Registration Deployment + +Deployment scripts and documentation for Zabbix Agent 2 with PSK-encrypted auto-registration against `zabbix.snarfnet.net`. + +## Overview + +This project automates the end-to-end setup of Zabbix active agent auto-registration: + +1. **Server-side:** Creates auto-registration actions via the Zabbix API so new agents are automatically assigned to host groups and linked to templates. +2. **Agent-side:** Installs and configures Zabbix Agent 2 with PSK encryption on Linux (x86_64 and ARM) and Windows hosts. + +When an agent starts with `ServerActive` and `HostMetadata` configured, it reaches out to the Zabbix server on port 10051. The server matches the metadata against auto-registration action conditions and automatically adds the host. + +## Scripts + +| File | Purpose | +|------|---------| +| `configure_server_autoregistration.sh` | Creates host groups and auto-registration actions on the Zabbix server via API | +| `deploy_zabbix_agent_linux.sh` | Agent install for Linux x86_64 (RHEL, Debian, Ubuntu) | +| `deploy_zabbix_agent_linux_arm.sh` | Agent install for Linux ARM (aarch64, armhf, Raspberry Pi) | +| `deploy_zabbix_agent_windows.ps1` | Agent install for Windows x86_64 | + +## Prerequisites + +- **Zabbix Server 7.0** running and accessible +- **PSK encryption** already configured on the server (Administration → General → Autoregistration) +- **Port 10051/TCP** exposed and reachable from agent hosts (see [Kubernetes Exposure](#kubernetes-exposure) if running in k8s) +- `curl` and `jq` on the machine running the server config script +- `openssl` on agent hosts (for PSK key generation if not providing one) + +--- + +## Step 1: Expose Zabbix Server Trapper Port (Kubernetes) + +If your Zabbix server runs in Kubernetes, port 10051 must be exposed externally for agents to connect. The web UI (443) is not sufficient — agents need the trapper port. + +### Ports Required + +| Port | Service | Direction | Purpose | +|------|---------|-----------|---------| +| **10051/TCP** | zabbix-server | Inbound from agents | Active check-ins, auto-registration | +| 443/TCP | zabbix-web | Inbound from users | Web UI and API | + +### Option A: LoadBalancer Service (recommended) + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: zabbix-server-trapper + namespace: zabbix +spec: + type: LoadBalancer + selector: + app: zabbix-server # match your pod labels + ports: + - name: trapper + port: 10051 + targetPort: 10051 + protocol: TCP +``` + +### Option B: NodePort Service + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: zabbix-server-trapper + namespace: zabbix +spec: + type: NodePort + selector: + app: zabbix-server # match your pod labels + ports: + - name: trapper + port: 10051 + targetPort: 10051 + nodePort: 30051 + protocol: TCP +``` + +With NodePort, update agent `ServerActive` to use `:30051` or put a load balancer in front. + +### Option C: Nginx Ingress TCP Passthrough + +Add to the ingress controller's TCP ConfigMap: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: tcp-services + namespace: ingress-nginx +data: + "10051": "zabbix/zabbix-server:10051" +``` + +Ensure the ingress controller's Service also exposes port 10051. + +### DNS Considerations + +Make sure `zabbix.snarfnet.net` resolves to the IP where port 10051 is exposed. If the web UI and trapper are on different IPs, either: +- Point the main DNS record to the trapper LB and use a separate record for the web UI +- Or update `ServerActive` in agent configs to a dedicated trapper hostname + +### Verify Connectivity + +From an agent host: + +```bash +nc -zv zabbix.snarfnet.net 10051 +``` + +Expected: `Connection to zabbix.snarfnet.net 10051 port [tcp/*] succeeded!` + +If you get "connection refused" — the port isn't exposed or the trapper process isn't running. + +--- + +## Step 2: Configure Server Auto-Registration Actions + +Run the server configuration script to create host groups and auto-registration actions: + +```bash +bash configure_server_autoregistration.sh -u Admin -p 'your_zabbix_admin_password' +``` + +### What it does + +1. Authenticates with the Zabbix API at `https://zabbix.snarfnet.net/api_jsonrpc.php` +2. Finds or creates host groups: `Linux servers`, `Windows servers` +3. Looks up templates: `Linux by Zabbix agent active`, `Windows by Zabbix agent active` +4. Creates two auto-registration actions (skips if they already exist) + +### Actions Created + +| Action | Condition | Operations | +|--------|-----------|------------| +| Auto-register Linux hosts | Host metadata contains `Linux` | Add to group `Linux servers`, link template `Linux by Zabbix agent active` | +| Auto-register Windows hosts | Host metadata contains `Windows` | Add to group `Windows servers`, link template `Windows by Zabbix agent active` | + +### Options + +``` +-u Zabbix API username (required) +-p Zabbix API password (required) +-s Zabbix API URL (default: https://zabbix.snarfnet.net/api_jsonrpc.php) +-h Show help +``` + +### Notes + +- The API user must have **Super admin** role to create actions +- PSK configuration is assumed to already be in place (Administration → General → Autoregistration) +- The script is idempotent — safe to run multiple times + +--- + +## Step 3: Deploy Agents + +### Generate a Shared PSK Key + +All agents must use the same PSK key that's configured on the server: + +```bash +openssl rand -hex 32 +``` + +### Linux x86_64 + +```bash +# Auto-generate PSK (prints key at end) +sudo bash deploy_zabbix_agent_linux.sh + +# With a specific PSK +sudo bash deploy_zabbix_agent_linux.sh "your_64_char_hex_psk_here" +``` + +**Supports:** RHEL/CentOS/Rocky/Alma 8+, Ubuntu, Debian + +**What it does:** +1. Detects OS family (RHEL or Debian-based) +2. Adds the Zabbix 7.0 repository and installs `zabbix-agent2` +3. Writes PSK file with restricted permissions (640, root:zabbix) +4. Configures `ServerActive=zabbix.snarfnet.net`, `HostMetadata=Linux`, TLS PSK settings +5. Enables and starts the `zabbix-agent2` service + +### Linux ARM (Raspberry Pi, aarch64, armhf) + +```bash +# Auto-generate PSK +sudo bash deploy_zabbix_agent_linux_arm.sh + +# With a specific PSK +sudo bash deploy_zabbix_agent_linux_arm.sh "your_64_char_hex_psk_here" +``` + +**Supports:** Raspberry Pi OS, Ubuntu ARM, Debian ARM, any aarch64/armhf/armv6l Linux with systemd + +**What it does:** +1. Detects architecture (aarch64, armv7l, armv6l) +2. Tries package manager install (apt on Debian/Ubuntu/Raspbian) +3. Falls back to pre-compiled static binary tarball from Zabbix CDN +4. Creates systemd service unit for binary installs +5. Creates `zabbix` user if needed +6. Writes PSK file and agent configuration +7. Enables and starts the service + +### Windows + +```powershell +# Run as Administrator + +# Auto-generate PSK +.\deploy_zabbix_agent_windows.ps1 + +# With a specific PSK +.\deploy_zabbix_agent_windows.ps1 -PskKey "your_64_char_hex_psk_here" +``` + +**Supports:** Windows Server 2016+, Windows 10/11 (x86_64) + +**What it does:** +1. Downloads Zabbix Agent 2 MSI from official CDN +2. Installs silently to `C:\Program Files\Zabbix Agent 2` +3. Writes PSK file with ACL-restricted permissions (Administrators + SYSTEM only) +4. Writes agent config with `HostMetadata=Windows` and TLS PSK settings +5. Adds Windows Firewall rule for port 10050 inbound (Domain/Private profiles) +6. Sets service to automatic start and starts it + +--- + +## Configuration Reference + +| Setting | Value | +|---------|-------| +| Zabbix Server | `zabbix.snarfnet.net` | +| PSK Identity | `PSK_autoregister` | +| Host Metadata (Linux) | `Linux` | +| Host Metadata (Windows) | `Windows` | +| PSK File (Linux) | `/etc/zabbix/zabbix_agent2.psk` | +| PSK File (Windows) | `C:\Program Files\Zabbix Agent 2\zabbix_agent2.psk` | +| Agent Config (Linux) | `/etc/zabbix/zabbix_agent2.conf` | +| Agent Config (Windows) | `C:\Program Files\Zabbix Agent 2\zabbix_agent2.conf` | +| Trapper Port | 10051 (agent → server, active checks + registration) | +| Agent Port | 10050 (server → agent, passive checks) | + +--- + +## Security Notes + +- PSK key must be **identical** on the server and all agents using the same identity +- PSK files are permission-locked (640 on Linux, ACL-restricted on Windows) +- Use unique PSK identities per environment to segment (e.g., `PSK_prod`, `PSK_dev`) +- Rotate PSK keys by updating the server autoregistration config and redeploying agents +- The server config script does **not** modify PSK settings — manage those separately in the Zabbix UI + +--- + +## Troubleshooting + +### Connectivity Test + +```bash +# From agent → server (must succeed for auto-registration) +nc -zv zabbix.snarfnet.net 10051 +``` + +```powershell +Test-NetConnection -ComputerName zabbix.snarfnet.net -Port 10051 +``` + +### Agent Logs + +```bash +# Linux +journalctl -u zabbix-agent2 --since "5 minutes ago" +tail -f /var/log/zabbix/zabbix_agent2.log +grep -iE "error|failed|denied|psk|tls" /var/log/zabbix/zabbix_agent2.log +``` + +```powershell +# Windows +Get-Content "C:\Program Files\Zabbix Agent 2\zabbix_agent2.log" -Tail 50 +Select-String -Path "C:\Program Files\Zabbix Agent 2\zabbix_agent2.log" -Pattern "error|failed|denied|psk|tls" +``` + +### Server Logs (on Zabbix server) + +```bash +tail -f /var/log/zabbix/zabbix_server.log | grep -i "autoregistration\|psk\|tls\|cannot" +``` + +### Common Issues + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `connection refused` on 10051 | Port not exposed (Kubernetes) or trapper not running | Expose port 10051 via LoadBalancer/NodePort; check `StartTrappers` in server config | +| `connection timed out` on 10051 | Firewall blocking traffic | Open outbound 10051 on agent host; open inbound 10051 on server/cluster | +| `TLS handshake failed` | PSK key or identity mismatch | Verify key matches exactly; check for trailing newlines in PSK file | +| Agent connects but host doesn't appear | Auto-registration action missing or disabled | Run `configure_server_autoregistration.sh`; verify actions are enabled in UI | +| Action exists but doesn't trigger | HostMetadata doesn't match condition | Verify agent config has `HostMetadata=Linux` or `HostMetadata=Windows` | +| Hostname conflict | Host with same name already exists | Delete/rename existing host in Zabbix, or change `HostnameItem` | +| Script creates actions with invalid JSON | Log messages captured in variables | Fixed in current version — `log()` writes to stderr | + +### Verify Agent Config + +```bash +# Linux — confirm critical settings +grep -E "^Server=|^ServerActive=|^HostMetadata=|^TLS" /etc/zabbix/zabbix_agent2.conf + +# Check PSK file has no trailing newline +cat -A /etc/zabbix/zabbix_agent2.psk +# Should end with $ immediately after hex string, no extra lines +``` + +### Verify Server Actions via API + +```bash +# Get auth token +TOKEN=$(curl -s -X POST https://zabbix.snarfnet.net/api_jsonrpc.php \ + -H "Content-Type: application/json-rpc" \ + -d '{"jsonrpc":"2.0","method":"user.login","params":{"username":"Admin","password":"YOUR_PASS"},"id":1}' \ + | jq -r '.result') + +# List autoregistration actions +curl -s -X POST https://zabbix.snarfnet.net/api_jsonrpc.php \ + -H "Content-Type: application/json-rpc" \ + -d "{\"jsonrpc\":\"2.0\",\"method\":\"action.get\",\"params\":{\"filter\":{\"eventsource\":\"2\"}},\"auth\":\"${TOKEN}\",\"id\":2}" \ + | jq '.result[] | {name, status}' +``` + +--- + +## Deployment Order Summary + +1. **Expose port 10051** on your Kubernetes cluster (LoadBalancer/NodePort/Ingress TCP) +2. **Verify connectivity** from an agent host: `nc -zv zabbix.snarfnet.net 10051` +3. **Run server config script** to create auto-registration actions +4. **Deploy agents** with the shared PSK key +5. **Verify** hosts appear in Zabbix UI under their respective host groups diff --git a/zabbix-autoregister/configure_server_autoregistration.sh b/zabbix-autoregister/configure_server_autoregistration.sh new file mode 100644 index 0000000..a4b4f9e --- /dev/null +++ b/zabbix-autoregister/configure_server_autoregistration.sh @@ -0,0 +1,330 @@ +#!/bin/bash +# +# Zabbix Server Auto-Registration Configuration Script +# Creates auto-registration actions via the Zabbix API. +# Target server: zabbix.snarfnet.net +# +# Usage: bash configure_server_autoregistration.sh -u -p +# +# Prerequisites: curl, jq +# +set -euo pipefail + +# --- Defaults --- +ZABBIX_URL="https://zabbix.snarfnet.net/api_jsonrpc.php" +API_USER="" +API_PASSWORD="" +AUTH_TOKEN="" + +# --- Parse Arguments --- +usage() { + cat << EOF +Usage: $0 -u -p [-s ] + +Options: + -u Zabbix API username (e.g., Admin) + -p Zabbix API password + -s Zabbix API URL (default: ${ZABBIX_URL}) + -h Show this help + +Example: + $0 -u Admin -p zabbix +EOF + exit 1 +} + +while getopts "u:p:s:h" opt; do + case ${opt} in + u) API_USER="${OPTARG}" ;; + p) API_PASSWORD="${OPTARG}" ;; + s) ZABBIX_URL="${OPTARG}" ;; + h) usage ;; + *) usage ;; + esac +done + +if [ -z "${API_USER}" ] || [ -z "${API_PASSWORD}" ]; then + echo "ERROR: -u and -p are required." + usage +fi + +# --- Functions --- + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2; } + +api_call() { + local payload="$1" + local response + response=$(curl -s -X POST "${ZABBIX_URL}" \ + -H "Content-Type: application/json-rpc" \ + -d "${payload}") + + # Check for errors + local error + error=$(echo "${response}" | jq -r '.error // empty') + if [ -n "${error}" ]; then + log "ERROR: API call failed:" + echo "${response}" | jq '.error' >&2 + return 1 + fi + + echo "${response}" +} + +authenticate() { + log "Authenticating with Zabbix API..." + local response + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"user.login\", + \"params\": { + \"username\": \"${API_USER}\", + \"password\": \"${API_PASSWORD}\" + }, + \"id\": 1 + }") + + AUTH_TOKEN=$(echo "${response}" | jq -r '.result') + if [ -z "${AUTH_TOKEN}" ] || [ "${AUTH_TOKEN}" = "null" ]; then + log "ERROR: Authentication failed. Check username/password." + exit 1 + fi + log "Authenticated successfully." +} + +get_or_create_hostgroup() { + local group_name="$1" + + # Try to find existing group + local response + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"hostgroup.get\", + \"params\": { + \"filter\": { + \"name\": [\"${group_name}\"] + } + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 3 + }") + + local groupid + groupid=$(echo "${response}" | jq -r '.result[0].groupid // empty') + + if [ -n "${groupid}" ]; then + log " Found host group '${group_name}' (ID: ${groupid})" + echo "${groupid}" + return + fi + + # Create the group + log " Creating host group '${group_name}'..." + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"hostgroup.create\", + \"params\": { + \"name\": \"${group_name}\" + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 4 + }") + + groupid=$(echo "${response}" | jq -r '.result.groupids[0] // empty') + if [ -z "${groupid}" ]; then + log "ERROR: Failed to create host group '${group_name}'." + echo "${response}" | jq . >&2 + exit 1 + fi + + log " Created host group '${group_name}' (ID: ${groupid})" + echo "${groupid}" +} + +get_template_id() { + local template_name="$1" + + local response + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"template.get\", + \"params\": { + \"filter\": { + \"host\": [\"${template_name}\"] + } + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 5 + }") + + local templateid + templateid=$(echo "${response}" | jq -r '.result[0].templateid // empty') + + if [ -z "${templateid}" ]; then + # Try searching by visible name + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"template.get\", + \"params\": { + \"search\": { + \"name\": \"${template_name}\" + } + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 6 + }") + templateid=$(echo "${response}" | jq -r '.result[0].templateid // empty') + fi + + if [ -z "${templateid}" ]; then + log " WARNING: Template '${template_name}' not found. Skipping template link." + echo "" + return + fi + + log " Found template '${template_name}' (ID: ${templateid})" + echo "${templateid}" +} + +create_autoregistration_action() { + local action_name="$1" + local metadata_value="$2" + local groupid="$3" + local templateid="$4" + + # Check if action already exists + local response + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"action.get\", + \"params\": { + \"filter\": { + \"name\": \"${action_name}\", + \"eventsource\": \"2\" + } + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 7 + }") + + local existing + existing=$(echo "${response}" | jq -r '.result[0].actionid // empty') + if [ -n "${existing}" ]; then + log " Action '${action_name}' already exists (ID: ${existing}). Skipping." + return + fi + + # Build operations array + local operations="[ + { + \"operationtype\": \"4\", + \"opgroup\": [ + { + \"groupid\": \"${groupid}\" + } + ] + }" + + # Add template link if we have a template ID + if [ -n "${templateid}" ]; then + operations="${operations}, + { + \"operationtype\": \"6\", + \"optemplate\": [ + { + \"templateid\": \"${templateid}\" + } + ] + }" + fi + + operations="${operations}]" + + # Create the action + log " Creating auto-registration action '${action_name}'..." + response=$(api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"action.create\", + \"params\": { + \"name\": \"${action_name}\", + \"eventsource\": \"2\", + \"status\": \"0\", + \"filter\": { + \"evaltype\": \"0\", + \"conditions\": [ + { + \"conditiontype\": \"24\", + \"operator\": \"2\", + \"value\": \"${metadata_value}\" + } + ] + }, + \"operations\": ${operations} + }, + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 8 + }") + + local actionid + actionid=$(echo "${response}" | jq -r '.result.actionids[0] // empty') + if [ -n "${actionid}" ]; then + log " Created action '${action_name}' (ID: ${actionid})" + else + log " ERROR: Failed to create action '${action_name}'." + echo "${response}" | jq . >&2 + fi +} + +logout() { + api_call "{ + \"jsonrpc\": \"2.0\", + \"method\": \"user.logout\", + \"params\": [], + \"auth\": \"${AUTH_TOKEN}\", + \"id\": 99 + }" > /dev/null 2>&1 || true + log "Logged out." +} + +# --- Main --- + +log "=== Zabbix Server Auto-Registration Configuration ===" +log "Server: ${ZABBIX_URL}" + +# Check dependencies +for cmd in curl jq; do + if ! command -v "${cmd}" &> /dev/null; then + log "ERROR: '${cmd}' is required but not installed." + exit 1 + fi +done + +# Authenticate +authenticate + +# Get/create host groups +log "Setting up host groups..." +LINUX_GROUP_ID=$(get_or_create_hostgroup "Linux servers") +WINDOWS_GROUP_ID=$(get_or_create_hostgroup "Windows servers") + +# Find templates +log "Looking up templates..." +LINUX_TEMPLATE_ID=$(get_template_id "Linux by Zabbix agent active") +WINDOWS_TEMPLATE_ID=$(get_template_id "Windows by Zabbix agent active") + +# Create auto-registration actions +log "Creating auto-registration actions..." +create_autoregistration_action "Auto-register Linux hosts" "Linux" "${LINUX_GROUP_ID}" "${LINUX_TEMPLATE_ID}" +create_autoregistration_action "Auto-register Windows hosts" "Windows" "${WINDOWS_GROUP_ID}" "${WINDOWS_TEMPLATE_ID}" + +# Logout +logout + +log "" +log "=== Configuration Complete ===" +log "" +log "Summary:" +log " - Linux hosts with metadata 'Linux' → group 'Linux servers' + template" +log " - Windows hosts with metadata 'Windows' → group 'Windows servers' + template" +log "" +log "Agents configured with the matching PSK key should now auto-register." diff --git a/zabbix-autoregister/deploy_zabbix_agent_linux.sh b/zabbix-autoregister/deploy_zabbix_agent_linux.sh new file mode 100644 index 0000000..9a470e3 --- /dev/null +++ b/zabbix-autoregister/deploy_zabbix_agent_linux.sh @@ -0,0 +1,157 @@ +#!/bin/bash +# +# Zabbix Agent 2 Deployment Script - Linux +# Installs and configures Zabbix Agent 2 with PSK auto-registration +# Target server: zabbix.snarfnet.net +# +# Usage: sudo bash deploy_zabbix_agent_linux.sh [psk_key] +# psk_key - (optional) 128-char hex PSK. If omitted, one is generated. +# +set -euo pipefail + +ZABBIX_SERVER="zabbix.snarfnet.net" +PSK_IDENTITY="PSK_autoregister" +PSK_FILE="/etc/zabbix/zabbix_agent2.psk" +AGENT_CONF="/etc/zabbix/zabbix_agent2.conf" +HOST_METADATA="Linux" + +# --- Functions --- + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } + +detect_os() { + if [ -f /etc/os-release ]; then + . /etc/os-release + OS_ID="${ID}" + OS_VERSION="${VERSION_ID%%.*}" + else + log "ERROR: Cannot detect OS. /etc/os-release not found." + exit 1 + fi +} + +install_agent_rhel() { + local major_ver="$1" + log "Installing Zabbix Agent 2 on RHEL/CentOS ${major_ver}..." + + # Install Zabbix repo + rpm -Uvh "https://repo.zabbix.com/zabbix/7.0/rhel/${major_ver}/x86_64/zabbix-release-latest-7.0.el${major_ver}.noarch.rpm" 2>/dev/null || true + dnf clean all + dnf install -y zabbix-agent2 zabbix-agent2-plugin-* +} + +install_agent_debian() { + local codename="$1" + log "Installing Zabbix Agent 2 on Debian/Ubuntu (${codename})..." + + wget -q "https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest+ubuntu_all.deb" -O /tmp/zabbix-release.deb + dpkg -i /tmp/zabbix-release.deb + apt-get update + apt-get install -y zabbix-agent2 zabbix-agent2-plugin-* + rm -f /tmp/zabbix-release.deb +} + +install_agent() { + detect_os + case "${OS_ID}" in + rhel|centos|rocky|alma|fedora) + install_agent_rhel "${OS_VERSION}" + ;; + debian|ubuntu) + local codename + codename=$(lsb_release -cs 2>/dev/null || echo "jammy") + install_agent_debian "${codename}" + ;; + *) + log "ERROR: Unsupported OS '${OS_ID}'. Install zabbix-agent2 manually, then re-run." + exit 1 + ;; + esac +} + +generate_psk() { + openssl rand -hex 32 +} + +configure_agent() { + local psk_key="$1" + + log "Writing PSK to ${PSK_FILE}..." + echo "${psk_key}" > "${PSK_FILE}" + chmod 640 "${PSK_FILE}" + chown root:zabbix "${PSK_FILE}" + + log "Configuring ${AGENT_CONF}..." + cp "${AGENT_CONF}" "${AGENT_CONF}.bak.$(date +%s)" + + # Apply configuration + sed -i "s|^Server=.*|Server=${ZABBIX_SERVER}|" "${AGENT_CONF}" + sed -i "s|^ServerActive=.*|ServerActive=${ZABBIX_SERVER}|" "${AGENT_CONF}" + sed -i "s|^Hostname=.*|# Hostname=|" "${AGENT_CONF}" + + # Add/update settings that may not exist + grep -q "^HostnameItem=" "${AGENT_CONF}" && \ + sed -i "s|^HostnameItem=.*|HostnameItem=system.hostname|" "${AGENT_CONF}" || \ + echo "HostnameItem=system.hostname" >> "${AGENT_CONF}" + + grep -q "^HostMetadata=" "${AGENT_CONF}" && \ + sed -i "s|^HostMetadata=.*|HostMetadata=${HOST_METADATA}|" "${AGENT_CONF}" || \ + echo "HostMetadata=${HOST_METADATA}" >> "${AGENT_CONF}" + + grep -q "^TLSConnect=" "${AGENT_CONF}" && \ + sed -i "s|^TLSConnect=.*|TLSConnect=psk|" "${AGENT_CONF}" || \ + echo "TLSConnect=psk" >> "${AGENT_CONF}" + + grep -q "^TLSAccept=" "${AGENT_CONF}" && \ + sed -i "s|^TLSAccept=.*|TLSAccept=psk|" "${AGENT_CONF}" || \ + echo "TLSAccept=psk" >> "${AGENT_CONF}" + + grep -q "^TLSPSKIdentity=" "${AGENT_CONF}" && \ + sed -i "s|^TLSPSKIdentity=.*|TLSPSKIdentity=${PSK_IDENTITY}|" "${AGENT_CONF}" || \ + echo "TLSPSKIdentity=${PSK_IDENTITY}" >> "${AGENT_CONF}" + + grep -q "^TLSPSKFile=" "${AGENT_CONF}" && \ + sed -i "s|^TLSPSKFile=.*|TLSPSKFile=${PSK_FILE}|" "${AGENT_CONF}" || \ + echo "TLSPSKFile=${PSK_FILE}" >> "${AGENT_CONF}" +} + +start_agent() { + log "Enabling and starting zabbix-agent2..." + systemctl enable zabbix-agent2 + systemctl restart zabbix-agent2 + systemctl status zabbix-agent2 --no-pager +} + +# --- Main --- + +if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run as root." >&2 + exit 1 +fi + +PSK_KEY="${1:-}" +if [ -z "${PSK_KEY}" ]; then + PSK_KEY=$(generate_psk) + log "Generated new PSK key." +fi + +# Validate PSK is valid hex and at least 32 chars +if ! echo "${PSK_KEY}" | grep -qE '^[0-9a-fA-F]{32,128}$'; then + log "ERROR: PSK must be a 32-128 character hex string." + exit 1 +fi + +log "=== Zabbix Agent 2 Deployment ===" +log "Server: ${ZABBIX_SERVER}" +log "PSK Identity: ${PSK_IDENTITY}" + +install_agent +configure_agent "${PSK_KEY}" +start_agent + +log "=== Deployment Complete ===" +log "PSK Identity: ${PSK_IDENTITY}" +log "PSK Key: ${PSK_KEY}" +log "" +log "IMPORTANT: Use this same PSK identity and key in your Zabbix server" +log "auto-registration encryption settings." diff --git a/zabbix-autoregister/deploy_zabbix_agent_linux_arm.sh b/zabbix-autoregister/deploy_zabbix_agent_linux_arm.sh new file mode 100644 index 0000000..af4144c --- /dev/null +++ b/zabbix-autoregister/deploy_zabbix_agent_linux_arm.sh @@ -0,0 +1,266 @@ +#!/bin/bash +# +# Zabbix Agent 2 Deployment Script - Linux ARM (aarch64 / armhf) +# Installs and configures Zabbix Agent 2 with PSK auto-registration +# Target server: zabbix.snarfnet.net +# +# Usage: sudo bash deploy_zabbix_agent_linux_arm.sh [psk_key] +# psk_key - (optional) 128-char hex PSK. If omitted, one is generated. +# +set -euo pipefail + +ZABBIX_SERVER="zabbix.snarfnet.net" +ZABBIX_VERSION="7.0.0" +PSK_IDENTITY="PSK_autoregister" +PSK_FILE="/etc/zabbix/zabbix_agent2.psk" +AGENT_CONF="/etc/zabbix/zabbix_agent2.conf" +HOST_METADATA="Linux" +INSTALL_DIR="/opt/zabbix-agent2" + +# --- Functions --- + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } + +detect_arch() { + ARCH=$(uname -m) + case "${ARCH}" in + aarch64|arm64) + ARCH_LABEL="aarch64" + TARBALL_ARCH="linux_arm64" + ;; + armv7l|armhf) + ARCH_LABEL="armhf" + TARBALL_ARCH="linux_arm" + ;; + armv6l) + ARCH_LABEL="armv6" + TARBALL_ARCH="linux_arm" + ;; + *) + log "ERROR: Unsupported architecture '${ARCH}'." + log " Use deploy_zabbix_agent_linux.sh for x86_64 systems." + exit 1 + ;; + esac + log "Detected architecture: ${ARCH} (${ARCH_LABEL})" +} + +detect_os() { + if [ -f /etc/os-release ]; then + . /etc/os-release + OS_ID="${ID}" + OS_VERSION="${VERSION_ID%%.*}" + else + OS_ID="unknown" + OS_VERSION="0" + fi +} + +install_agent_package_manager() { + detect_os + case "${OS_ID}" in + debian|ubuntu|raspbian) + log "Installing via apt (Debian/Ubuntu/Raspbian)..." + # Determine arch string for the repo + local dpkg_arch + dpkg_arch=$(dpkg --print-architecture) + + wget -q "https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest+ubuntu_all.deb" -O /tmp/zabbix-release.deb 2>/dev/null || \ + wget -q "https://repo.zabbix.com/zabbix/7.0/debian/pool/main/z/zabbix-release/zabbix-release_latest+debian${OS_VERSION}_all.deb" -O /tmp/zabbix-release.deb 2>/dev/null || true + + if [ -f /tmp/zabbix-release.deb ]; then + dpkg -i /tmp/zabbix-release.deb + apt-get update + apt-get install -y zabbix-agent2 && { rm -f /tmp/zabbix-release.deb; return 0; } + fi + + log "Package manager install failed, falling back to binary tarball..." + rm -f /tmp/zabbix-release.deb + install_agent_binary + ;; + *) + log "No ARM package available for '${OS_ID}', using binary tarball..." + install_agent_binary + ;; + esac +} + +install_agent_binary() { + log "Installing Zabbix Agent 2 from pre-compiled binary..." + + local tarball_url="https://cdn.zabbix.com/zabbix/binaries/stable/7.0/${ZABBIX_VERSION}/zabbix_agent2-${ZABBIX_VERSION}-${TARBALL_ARCH}-static.tar.gz" + local tarball_path="/tmp/zabbix_agent2.tar.gz" + + log "Downloading from: ${tarball_url}" + if ! wget -q "${tarball_url}" -O "${tarball_path}" 2>/dev/null && \ + ! curl -sL "${tarball_url}" -o "${tarball_path}" 2>/dev/null; then + log "ERROR: Failed to download Zabbix Agent 2 binary." + log " URL: ${tarball_url}" + log " You may need to check https://www.zabbix.com/download for the correct ARM binary." + exit 1 + fi + + # Create directories + mkdir -p "${INSTALL_DIR}/bin" + mkdir -p /etc/zabbix + mkdir -p /var/log/zabbix + mkdir -p /var/run/zabbix + + # Extract + tar -xzf "${tarball_path}" -C "${INSTALL_DIR}" --strip-components=1 2>/dev/null || \ + tar -xzf "${tarball_path}" -C "${INSTALL_DIR}" 2>/dev/null + + # Find the binary + local agent_bin + agent_bin=$(find "${INSTALL_DIR}" -name "zabbix_agent2" -type f | head -1) + if [ -z "${agent_bin}" ]; then + log "ERROR: Could not find zabbix_agent2 binary in extracted archive." + exit 1 + fi + + # Move binary to expected location + cp "${agent_bin}" "${INSTALL_DIR}/bin/zabbix_agent2" + chmod +x "${INSTALL_DIR}/bin/zabbix_agent2" + ln -sf "${INSTALL_DIR}/bin/zabbix_agent2" /usr/sbin/zabbix_agent2 + + # Create zabbix user if it doesn't exist + if ! id -u zabbix &>/dev/null; then + useradd -r -s /sbin/nologin -d /var/lib/zabbix -M zabbix + fi + + chown -R zabbix:zabbix /var/log/zabbix /var/run/zabbix + + # Set config path for binary installs + AGENT_CONF="/etc/zabbix/zabbix_agent2.conf" + + # Create systemd service + create_systemd_service + + rm -f "${tarball_path}" + log "Binary installation complete." +} + +create_systemd_service() { + log "Creating systemd service..." + cat > /etc/systemd/system/zabbix-agent2.service << 'EOF' +[Unit] +Description=Zabbix Agent 2 +After=syslog.target +After=network.target + +[Service] +Environment="CONFFILE=/etc/zabbix/zabbix_agent2.conf" +Type=simple +Restart=on-failure +PIDFile=/var/run/zabbix/zabbix_agent2.pid +KillMode=control-group +ExecStart=/usr/sbin/zabbix_agent2 -c $CONFFILE +ExecStop=/bin/kill -SIGTERM $MAINPID +RestartSec=10s +User=zabbix +Group=zabbix + +[Install] +WantedBy=multi-user.target +EOF + + systemctl daemon-reload +} + +generate_psk() { + openssl rand -hex 32 +} + +configure_agent() { + local psk_key="$1" + + log "Writing PSK to ${PSK_FILE}..." + echo "${psk_key}" > "${PSK_FILE}" + chmod 640 "${PSK_FILE}" + chown root:zabbix "${PSK_FILE}" + + log "Writing agent configuration to ${AGENT_CONF}..." + # Back up existing config if present + [ -f "${AGENT_CONF}" ] && cp "${AGENT_CONF}" "${AGENT_CONF}.bak.$(date +%s)" + + cat > "${AGENT_CONF}" << EOF +# Zabbix Agent 2 Configuration +# Auto-generated by ARM deployment script on $(date '+%Y-%m-%d %H:%M:%S') +# Architecture: ${ARCH} (${ARCH_LABEL}) + +Server=${ZABBIX_SERVER} +ServerActive=${ZABBIX_SERVER} +HostnameItem=system.hostname +HostMetadata=${HOST_METADATA} + +# PSK Encryption +TLSConnect=psk +TLSAccept=psk +TLSPSKIdentity=${PSK_IDENTITY} +TLSPSKFile=${PSK_FILE} + +# Logging +LogFile=/var/log/zabbix/zabbix_agent2.log +LogFileSize=10 + +# Performance +BufferSend=5 +BufferSize=100 +EOF + + chown root:zabbix "${AGENT_CONF}" + chmod 644 "${AGENT_CONF}" +} + +start_agent() { + log "Enabling and starting zabbix-agent2..." + systemctl enable zabbix-agent2 + systemctl restart zabbix-agent2 + + sleep 2 + if systemctl is-active --quiet zabbix-agent2; then + log "Zabbix Agent 2 is running." + systemctl status zabbix-agent2 --no-pager + else + log "WARNING: Agent may not have started. Check logs:" + log " journalctl -u zabbix-agent2 -n 20" + log " cat /var/log/zabbix/zabbix_agent2.log" + fi +} + +# --- Main --- + +if [ "$(id -u)" -ne 0 ]; then + echo "This script must be run as root." >&2 + exit 1 +fi + +PSK_KEY="${1:-}" +if [ -z "${PSK_KEY}" ]; then + PSK_KEY=$(generate_psk) + log "Generated new PSK key." +fi + +# Validate PSK is valid hex and at least 32 chars +if ! echo "${PSK_KEY}" | grep -qE '^[0-9a-fA-F]{32,128}$'; then + log "ERROR: PSK must be a 32-128 character hex string." + exit 1 +fi + +detect_arch + +log "=== Zabbix Agent 2 Deployment (ARM) ===" +log "Server: ${ZABBIX_SERVER}" +log "PSK Identity: ${PSK_IDENTITY}" +log "Architecture: ${ARCH_LABEL}" + +install_agent_package_manager +configure_agent "${PSK_KEY}" +start_agent + +log "=== Deployment Complete ===" +log "PSK Identity: ${PSK_IDENTITY}" +log "PSK Key: ${PSK_KEY}" +log "" +log "IMPORTANT: Use this same PSK identity and key in your Zabbix server" +log "auto-registration encryption settings." diff --git a/zabbix-autoregister/deploy_zabbix_agent_windows.ps1 b/zabbix-autoregister/deploy_zabbix_agent_windows.ps1 new file mode 100644 index 0000000..da15b15 --- /dev/null +++ b/zabbix-autoregister/deploy_zabbix_agent_windows.ps1 @@ -0,0 +1,199 @@ +#Requires -RunAsAdministrator +<# +.SYNOPSIS + Zabbix Agent 2 Deployment Script - Windows + Installs and configures Zabbix Agent 2 with PSK auto-registration. + +.DESCRIPTION + Target server: zabbix.snarfnet.net + Downloads Zabbix Agent 2 MSI, installs it, configures PSK encryption, + and starts the service for auto-registration. + +.PARAMETER PskKey + Optional. A 64-character hex PSK key. If omitted, one is generated. + +.PARAMETER ZabbixVersion + Optional. Zabbix version to install. Defaults to 7.0.0. + +.EXAMPLE + .\deploy_zabbix_agent_windows.ps1 + .\deploy_zabbix_agent_windows.ps1 -PskKey "aabbccdd..." +#> + +param( + [Parameter(Mandatory = $false)] + [string]$PskKey = "", + + [Parameter(Mandatory = $false)] + [string]$ZabbixVersion = "7.0.26" +) + +# --- Configuration --- +$ZabbixServer = "zabbix.snarfnet.net" +$PskIdentity = "PSK_autoregister" +$HostMetadata = "Windows" +$InstallDir = "C:\Program Files\Zabbix Agent 2" +$ConfFile = "$InstallDir\zabbix_agent2.conf" +$PskFile = "$InstallDir\zabbix_agent2.psk" +$MsiUrl = "https://cdn.zabbix.com/zabbix/binaries/stable/7.0/$ZabbixVersion/zabbix_agent2-$ZabbixVersion-windows-amd64-openssl.msi" +$MsiPath = "$env:TEMP\zabbix_agent2.msi" + +# --- Functions --- + +function Write-Log { + param([string]$Message) + Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message" +} + +function New-PskKey { + $bytes = New-Object byte[] 32 + $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create() + $rng.GetBytes($bytes) + return ($bytes | ForEach-Object { $_.ToString("x2") }) -join '' +} + +function Install-ZabbixAgent { + Write-Log "Downloading Zabbix Agent 2 v$ZabbixVersion..." + + try { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Invoke-WebRequest -Uri $MsiUrl -OutFile $MsiPath -UseBasicParsing + } + catch { + Write-Log "ERROR: Failed to download MSI from $MsiUrl" + Write-Log " $_" + exit 1 + } + + Write-Log "Installing Zabbix Agent 2..." + $msiArgs = @( + "/i", $MsiPath, + "/qn", + "/l*v", "$env:TEMP\zabbix_agent2_install.log", + "SERVER=$ZabbixServer", + "SERVERACTIVE=$ZabbixServer", + "INSTALLFOLDER=`"$InstallDir`"" + ) + $process = Start-Process msiexec.exe -ArgumentList $msiArgs -Wait -PassThru + if ($process.ExitCode -ne 0) { + Write-Log "ERROR: MSI installation failed with exit code $($process.ExitCode)" + Write-Log " Check log: $env:TEMP\zabbix_agent2_install.log" + exit 1 + } + + Remove-Item $MsiPath -Force -ErrorAction SilentlyContinue + Write-Log "Installation complete." +} + +function Set-AgentConfiguration { + param([string]$Key) + + Write-Log "Writing PSK to $PskFile..." + Set-Content -Path $PskFile -Value $Key -NoNewline + $acl = Get-Acl $PskFile + $acl.SetAccessRuleProtection($true, $false) + $adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule( + "BUILTIN\Administrators", "FullControl", "Allow") + $systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule( + "NT AUTHORITY\SYSTEM", "FullControl", "Allow") + $acl.AddAccessRule($adminRule) + $acl.AddAccessRule($systemRule) + Set-Acl -Path $PskFile -AclObject $acl + + Write-Log "Configuring $ConfFile..." + if (Test-Path $ConfFile) { + Copy-Item $ConfFile "$ConfFile.bak.$(Get-Date -Format 'yyyyMMddHHmmss')" + } + + $config = @" +# Zabbix Agent 2 Configuration +# Auto-generated by deployment script on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + +Server=$ZabbixServer +ServerActive=$ZabbixServer +HostnameItem=system.hostname +HostMetadata=$HostMetadata + +# PSK Encryption +TLSConnect=psk +TLSAccept=psk +TLSPSKIdentity=$PskIdentity +TLSPSKFile=$PskFile + +# Logging +LogFile=$InstallDir\zabbix_agent2.log +LogFileSize=10 + +# Performance +BufferSend=5 +BufferSize=100 +"@ + + Set-Content -Path $ConfFile -Value $config + Write-Log "Configuration written." +} + +function Start-ZabbixAgent { + Write-Log "Configuring Zabbix Agent 2 service..." + + $svc = Get-Service -Name "Zabbix Agent 2" -ErrorAction SilentlyContinue + if (-not $svc) { + Write-Log "ERROR: Zabbix Agent 2 service not found. Installation may have failed." + exit 1 + } + + Set-Service -Name "Zabbix Agent 2" -StartupType Automatic + Restart-Service -Name "Zabbix Agent 2" -Force + Start-Sleep -Seconds 2 + + $svc = Get-Service -Name "Zabbix Agent 2" + if ($svc.Status -eq "Running") { + Write-Log "Zabbix Agent 2 is running." + } + else { + Write-Log "WARNING: Service status is '$($svc.Status)'. Check logs at $InstallDir\zabbix_agent2.log" + } +} + +function Add-FirewallRule { + $ruleName = "Zabbix Agent 2 (TCP-In 10050)" + $existing = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue + if (-not $existing) { + Write-Log "Adding firewall rule for port 10050..." + New-NetFirewallRule -DisplayName $ruleName ` + -Direction Inbound -Protocol TCP -LocalPort 10050 ` + -Action Allow -Profile Domain, Private | Out-Null + } + else { + Write-Log "Firewall rule already exists." + } +} + +# --- Main --- + +Write-Log "=== Zabbix Agent 2 Deployment (Windows) ===" +Write-Log "Server: $ZabbixServer" +Write-Log "PSK Identity: $PskIdentity" + +# Generate or validate PSK +if ([string]::IsNullOrEmpty($PskKey)) { + $PskKey = New-PskKey + Write-Log "Generated new PSK key." +} + +if ($PskKey -notmatch '^[0-9a-fA-F]{32,128}$') { + Write-Log "ERROR: PSK must be a 32-128 character hex string." + exit 1 +} + +Install-ZabbixAgent +Set-AgentConfiguration -Key $PskKey +Add-FirewallRule +Start-ZabbixAgent + +Write-Log "=== Deployment Complete ===" +Write-Log "PSK Identity: $PskIdentity" +Write-Log "PSK Key: $PskKey" +Write-Log "" +Write-Log "IMPORTANT: Use this same PSK identity and key in your Zabbix server" +Write-Log " auto-registration encryption settings."