#!/bin/bash # 生产环境:api-server 二进制替换 + 单元降权(User=root → User=pms) # 备份 → 原子替换 → 失败立即回滚(单元 + 二进制) set -e TS=$(date +%Y%m%d-%H%M%S) BK=/root/sec-hardening-backup-20260920-014533 DIR=/data/pms/api-server BIN=$DIR/pms-api mkdir -p "$BK/units-prod" cp -a "$BIN" "$DIR/pms-api.bak-sec-$TS" echo "binary backup: $DIR/pms-api.bak-sec-$TS" for u in pms-api pms-device; do f=/etc/systemd/system/$u.service cp -a "$f" "$BK/units-prod/$u.service.bak" sed -i 's/^User=root$/User=pms/' "$f" grep -q '^Group=' "$f" || sed -i 's/^User=pms$/User=pms\nGroup=pms/' "$f" done systemctl daemon-reload echo "=== 生产单元 ===" grep -H 'User=\|Group=' /etc/systemd/system/pms-api.service /etc/systemd/system/pms-device.service chmod +x "$DIR/pms-api.new" systemctl stop pms-api mv -f "$DIR/pms-api.new" "$BIN" chmod +x "$BIN" systemctl start pms-api systemctl restart pms-device sleep 5 fail=0 for u in pms-api pms-device; do st=$(systemctl is-active "$u") pid=$(systemctl show -p MainPID --value "$u") usr=$(ps -o user= -p "$pid" 2>/dev/null | tr -d ' ') echo "$u active=$st pid=$pid user=$usr" [ "$st" = "active" ] || fail=1 done curl -s -o /dev/null -w 'health http=%{http_code}\n' http://127.0.0.1:9000/api/health curl -s http://127.0.0.1:9000/api/health; echo echo "md5: $(md5sum "$BIN" | awk '{print $1}')" ss -ltnp | grep -E ':(9000|9001)\b' if [ $fail -ne 0 ]; then echo "!!! 生产启动失败,立即回滚(单元 + 二进制)!!!" systemctl stop pms-api pms-device cp -a "$DIR/pms-api.bak-sec-$TS" "$BIN" for u in pms-api pms-device; do cp -a "$BK/units-prod/$u.service.bak" /etc/systemd/system/$u.service done systemctl daemon-reload systemctl start pms-api pms-device sleep 3 echo "回滚后: pms-api=$(systemctl is-active pms-api) pms-device=$(systemctl is-active pms-device)" journalctl -u pms-api -n 30 --no-pager exit 1 fi echo "生产部署完成"