feat: add automatic SSH key cleanup when nodes are removed
- Create cleanup script that removes Pulse SSH keys from nodes - Add systemd path unit to watch for cleanup requests - Add systemd service to execute cleanup script - Update install-sensor-proxy.sh to install cleanup system - Handles both cluster nodes (pulse-managed-key) and standalone nodes (pulse-proxy-key) - Cleanup is triggered automatically when nodes are deleted from Pulse - All cleanup actions are logged via syslog for auditability
This commit is contained in:
parent
de3bb47930
commit
7a7158d9bd
4 changed files with 360 additions and 0 deletions
|
|
@ -305,6 +305,200 @@ fi
|
|||
|
||||
print_info "Socket ready at $SOCKET_PATH"
|
||||
|
||||
# Install cleanup system for automatic SSH key removal when nodes are deleted
|
||||
print_info "Installing cleanup system..."
|
||||
|
||||
# Install cleanup script
|
||||
CLEANUP_SCRIPT_PATH="/usr/local/bin/pulse-sensor-cleanup.sh"
|
||||
cat > "$CLEANUP_SCRIPT_PATH" << 'CLEANUP_EOF'
|
||||
#!/bin/bash
|
||||
|
||||
# pulse-sensor-cleanup.sh - Removes Pulse SSH keys from Proxmox nodes when they're removed from Pulse
|
||||
# This script is triggered by systemd path unit when cleanup-request.json is created
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
WORK_DIR="/var/lib/pulse-sensor-proxy"
|
||||
CLEANUP_REQUEST="${WORK_DIR}/cleanup-request.json"
|
||||
LOG_TAG="pulse-sensor-cleanup"
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
logger -t "$LOG_TAG" -p user.info "$1"
|
||||
echo "[INFO] $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
logger -t "$LOG_TAG" -p user.warning "$1"
|
||||
echo "[WARN] $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
logger -t "$LOG_TAG" -p user.err "$1"
|
||||
echo "[ERROR] $1" >&2
|
||||
}
|
||||
|
||||
# Check if cleanup request file exists
|
||||
if [[ ! -f "$CLEANUP_REQUEST" ]]; then
|
||||
log_info "No cleanup request found at $CLEANUP_REQUEST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info "Processing cleanup request from $CLEANUP_REQUEST"
|
||||
|
||||
# Read and parse the cleanup request
|
||||
CLEANUP_DATA=$(cat "$CLEANUP_REQUEST")
|
||||
HOST=$(echo "$CLEANUP_DATA" | grep -o '"host":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
REQUESTED_AT=$(echo "$CLEANUP_DATA" | grep -o '"requestedAt":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
|
||||
log_info "Cleanup requested at: ${REQUESTED_AT:-unknown}"
|
||||
|
||||
# Remove the cleanup request file immediately to prevent re-processing
|
||||
rm -f "$CLEANUP_REQUEST"
|
||||
|
||||
# If no specific host was provided, clean up all known nodes
|
||||
if [[ -z "$HOST" ]]; then
|
||||
log_info "No specific host provided - cleaning up all cluster nodes"
|
||||
|
||||
# Discover cluster nodes
|
||||
if command -v pvecm >/dev/null 2>&1; then
|
||||
CLUSTER_NODES=$(pvecm status 2>/dev/null | awk '/0x[0-9a-f]+.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {print $3}')
|
||||
|
||||
if [[ -n "$CLUSTER_NODES" ]]; then
|
||||
for node_ip in $CLUSTER_NODES; do
|
||||
log_info "Cleaning up SSH keys on node $node_ip"
|
||||
|
||||
# Remove both pulse-managed-key and pulse-proxy-key entries
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 root@"$node_ip" \
|
||||
"sed -i -e '/# pulse-managed-key\$/d' -e '/# pulse-proxy-key\$/d' /root/.ssh/authorized_keys" 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on $node_ip"
|
||||
done
|
||||
log_info "Cluster cleanup completed"
|
||||
else
|
||||
# Standalone node - clean up localhost
|
||||
log_info "Standalone node detected - cleaning up localhost"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
fi
|
||||
else
|
||||
log_warn "pvecm command not available - cleaning up localhost only"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
fi
|
||||
else
|
||||
log_info "Cleaning up specific host: $HOST"
|
||||
|
||||
# Extract IP from host URL
|
||||
HOST_CLEAN=$(echo "$HOST" | sed -e 's|^https\?://||' -e 's|:.*$||')
|
||||
|
||||
# Check if this is localhost
|
||||
LOCAL_IPS=$(hostname -I 2>/dev/null || echo "")
|
||||
IS_LOCAL=false
|
||||
|
||||
for local_ip in $LOCAL_IPS; do
|
||||
if [[ "$HOST_CLEAN" == "$local_ip" ]]; then
|
||||
IS_LOCAL=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$HOST_CLEAN" == "127.0.0.1" || "$HOST_CLEAN" == "localhost" ]]; then
|
||||
IS_LOCAL=true
|
||||
fi
|
||||
|
||||
if [[ "$IS_LOCAL" == true ]]; then
|
||||
log_info "Cleaning up localhost SSH keys"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
else
|
||||
log_info "Cleaning up remote host: $HOST_CLEAN"
|
||||
|
||||
# Remove both pulse-managed-key and pulse-proxy-key entries from remote host
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 root@"$HOST_CLEAN" \
|
||||
"sed -i -e '/# pulse-managed-key\$/d' -e '/# pulse-proxy-key\$/d' /root/.ssh/authorized_keys" 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
log_info "Successfully cleaned up SSH keys on $HOST_CLEAN"
|
||||
else
|
||||
log_error "Failed to clean up SSH keys on $HOST_CLEAN"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Cleanup completed successfully"
|
||||
exit 0
|
||||
CLEANUP_EOF
|
||||
|
||||
chmod +x "$CLEANUP_SCRIPT_PATH"
|
||||
print_info "Cleanup script installed"
|
||||
|
||||
# Install systemd path unit
|
||||
CLEANUP_PATH_UNIT="/etc/systemd/system/pulse-sensor-cleanup.path"
|
||||
cat > "$CLEANUP_PATH_UNIT" << 'PATH_EOF'
|
||||
[Unit]
|
||||
Description=Watch for Pulse sensor cleanup requests
|
||||
Documentation=https://github.com/rcourtman/Pulse
|
||||
|
||||
[Path]
|
||||
# Watch for the cleanup request file
|
||||
PathChanged=/var/lib/pulse-sensor-proxy/cleanup-request.json
|
||||
# Also watch for modifications
|
||||
PathModified=/var/lib/pulse-sensor-proxy/cleanup-request.json
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
PATH_EOF
|
||||
|
||||
# Install systemd service unit
|
||||
CLEANUP_SERVICE_UNIT="/etc/systemd/system/pulse-sensor-cleanup.service"
|
||||
cat > "$CLEANUP_SERVICE_UNIT" << 'SERVICE_EOF'
|
||||
[Unit]
|
||||
Description=Pulse Sensor Cleanup Service
|
||||
Documentation=https://github.com/rcourtman/Pulse
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/pulse-sensor-cleanup.sh
|
||||
User=root
|
||||
Group=root
|
||||
WorkingDirectory=/var/lib/pulse-sensor-proxy
|
||||
|
||||
# Logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=pulse-sensor-cleanup
|
||||
|
||||
# Security hardening (less restrictive than the proxy since we need SSH access)
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/pulse-sensor-proxy /root/.ssh
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
PrivateTmp=true
|
||||
RestrictSUIDSGID=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
# This service is triggered by the .path unit, no need to enable it directly
|
||||
SERVICE_EOF
|
||||
|
||||
# Enable and start the path unit
|
||||
systemctl daemon-reload
|
||||
systemctl enable pulse-sensor-cleanup.path
|
||||
systemctl start pulse-sensor-cleanup.path
|
||||
|
||||
print_info "Cleanup system installed and enabled"
|
||||
|
||||
# Configure SSH keys for cluster temperature monitoring
|
||||
print_info "Configuring proxy SSH access to cluster nodes..."
|
||||
|
||||
|
|
|
|||
123
scripts/pulse-sensor-cleanup.sh
Normal file
123
scripts/pulse-sensor-cleanup.sh
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#!/bin/bash
|
||||
|
||||
# pulse-sensor-cleanup.sh - Removes Pulse SSH keys from Proxmox nodes when they're removed from Pulse
|
||||
# This script is triggered by systemd path unit when cleanup-request.json is created
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
WORK_DIR="/var/lib/pulse-sensor-proxy"
|
||||
CLEANUP_REQUEST="${WORK_DIR}/cleanup-request.json"
|
||||
LOG_TAG="pulse-sensor-cleanup"
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
logger -t "$LOG_TAG" -p user.info "$1"
|
||||
echo "[INFO] $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
logger -t "$LOG_TAG" -p user.warning "$1"
|
||||
echo "[WARN] $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
logger -t "$LOG_TAG" -p user.err "$1"
|
||||
echo "[ERROR] $1" >&2
|
||||
}
|
||||
|
||||
# Check if cleanup request file exists
|
||||
if [[ ! -f "$CLEANUP_REQUEST" ]]; then
|
||||
log_info "No cleanup request found at $CLEANUP_REQUEST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info "Processing cleanup request from $CLEANUP_REQUEST"
|
||||
|
||||
# Read and parse the cleanup request
|
||||
CLEANUP_DATA=$(cat "$CLEANUP_REQUEST")
|
||||
HOST=$(echo "$CLEANUP_DATA" | grep -o '"host":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
REQUESTED_AT=$(echo "$CLEANUP_DATA" | grep -o '"requestedAt":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
|
||||
log_info "Cleanup requested at: ${REQUESTED_AT:-unknown}"
|
||||
|
||||
# Remove the cleanup request file immediately to prevent re-processing
|
||||
rm -f "$CLEANUP_REQUEST"
|
||||
|
||||
# If no specific host was provided, clean up all known nodes
|
||||
if [[ -z "$HOST" ]]; then
|
||||
log_info "No specific host provided - cleaning up all cluster nodes"
|
||||
|
||||
# Discover cluster nodes
|
||||
if command -v pvecm >/dev/null 2>&1; then
|
||||
CLUSTER_NODES=$(pvecm status 2>/dev/null | awk '/0x[0-9a-f]+.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {print $3}')
|
||||
|
||||
if [[ -n "$CLUSTER_NODES" ]]; then
|
||||
for node_ip in $CLUSTER_NODES; do
|
||||
log_info "Cleaning up SSH keys on node $node_ip"
|
||||
|
||||
# Remove both pulse-managed-key and pulse-proxy-key entries
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 root@"$node_ip" \
|
||||
"sed -i -e '/# pulse-managed-key\$/d' -e '/# pulse-proxy-key\$/d' /root/.ssh/authorized_keys" 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on $node_ip"
|
||||
done
|
||||
log_info "Cluster cleanup completed"
|
||||
else
|
||||
# Standalone node - clean up localhost
|
||||
log_info "Standalone node detected - cleaning up localhost"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
fi
|
||||
else
|
||||
log_warn "pvecm command not available - cleaning up localhost only"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
fi
|
||||
else
|
||||
log_info "Cleaning up specific host: $HOST"
|
||||
|
||||
# Extract IP from host URL
|
||||
HOST_CLEAN=$(echo "$HOST" | sed -e 's|^https\?://||' -e 's|:.*$||')
|
||||
|
||||
# Check if this is localhost
|
||||
LOCAL_IPS=$(hostname -I 2>/dev/null || echo "")
|
||||
IS_LOCAL=false
|
||||
|
||||
for local_ip in $LOCAL_IPS; do
|
||||
if [[ "$HOST_CLEAN" == "$local_ip" ]]; then
|
||||
IS_LOCAL=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$HOST_CLEAN" == "127.0.0.1" || "$HOST_CLEAN" == "localhost" ]]; then
|
||||
IS_LOCAL=true
|
||||
fi
|
||||
|
||||
if [[ "$IS_LOCAL" == true ]]; then
|
||||
log_info "Cleaning up localhost SSH keys"
|
||||
sed -i -e '/# pulse-managed-key$/d' -e '/# pulse-proxy-key$/d' /root/.ssh/authorized_keys 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info || \
|
||||
log_warn "Failed to clean up SSH keys on localhost"
|
||||
else
|
||||
log_info "Cleaning up remote host: $HOST_CLEAN"
|
||||
|
||||
# Remove both pulse-managed-key and pulse-proxy-key entries from remote host
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 root@"$HOST_CLEAN" \
|
||||
"sed -i -e '/# pulse-managed-key\$/d' -e '/# pulse-proxy-key\$/d' /root/.ssh/authorized_keys" 2>&1 | \
|
||||
logger -t "$LOG_TAG" -p user.info
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
log_info "Successfully cleaned up SSH keys on $HOST_CLEAN"
|
||||
else
|
||||
log_error "Failed to clean up SSH keys on $HOST_CLEAN"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Cleanup completed successfully"
|
||||
exit 0
|
||||
12
scripts/systemd/pulse-sensor-cleanup.path
Normal file
12
scripts/systemd/pulse-sensor-cleanup.path
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[Unit]
|
||||
Description=Watch for Pulse sensor cleanup requests
|
||||
Documentation=https://github.com/rcourtman/Pulse
|
||||
|
||||
[Path]
|
||||
# Watch for the cleanup request file
|
||||
PathChanged=/var/lib/pulse-sensor-proxy/cleanup-request.json
|
||||
# Also watch for modifications
|
||||
PathModified=/var/lib/pulse-sensor-proxy/cleanup-request.json
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
31
scripts/systemd/pulse-sensor-cleanup.service
Normal file
31
scripts/systemd/pulse-sensor-cleanup.service
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[Unit]
|
||||
Description=Pulse Sensor Cleanup Service
|
||||
Documentation=https://github.com/rcourtman/Pulse
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/pulse-sensor-cleanup.sh
|
||||
User=root
|
||||
Group=root
|
||||
WorkingDirectory=/var/lib/pulse-sensor-proxy
|
||||
|
||||
# Logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=pulse-sensor-cleanup
|
||||
|
||||
# Security hardening (less restrictive than the proxy since we need SSH access)
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/pulse-sensor-proxy /root/.ssh
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
PrivateTmp=true
|
||||
RestrictSUIDSGID=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
LimitNOFILE=1024
|
||||
|
||||
[Install]
|
||||
# This service is triggered by the .path unit, no need to enable it directly
|
||||
Loading…
Reference in a new issue