121 lines
3.5 KiB
Shell
Executable file
121 lines
3.5 KiB
Shell
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
echo "INSTALL_REQUIRES_ROOT" >&2
|
|
exit 1
|
|
fi
|
|
|
|
FRONT_HOST="${1:-}"
|
|
KNOWN_HOSTS_SOURCE="${2:-}"
|
|
if [[ ! "$FRONT_HOST" =~ ^[0-9A-Fa-f:.]+$ ]]; then
|
|
echo "FRONT_HOST_MUST_BE_LITERAL_IP" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$KNOWN_HOSTS_SOURCE" || ! -f "$KNOWN_HOSTS_SOURCE" ]]; then
|
|
echo "KNOWN_HOSTS_SOURCE_INVALID" >&2
|
|
exit 1
|
|
fi
|
|
|
|
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-12-12-ubuntu}"
|
|
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-7a500f2d-9aed-4b93-b3b8-59c87c65d031}"
|
|
ACTUAL_HOST="$(hostname)"
|
|
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
|
|
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
|
|
echo "TARGET_IDENTITY_MISMATCH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
CONFIG_ROOT="/etc/guanghu/zhulan-front-tunnel"
|
|
KEY_FILE="$CONFIG_ROOT/id_ed25519"
|
|
KNOWN_HOSTS="$CONFIG_ROOT/known_hosts"
|
|
SSH_CONFIG="$CONFIG_ROOT/ssh_config"
|
|
SERVICE_FILE="/etc/systemd/system/zhulan-front-tunnel.service"
|
|
if [[ ! -f "$KEY_FILE" || ! -f "$KEY_FILE.pub" ]]; then
|
|
echo "TUNNEL_IDENTITY_NOT_PREPARED" >&2
|
|
exit 1
|
|
fi
|
|
if ! getent passwd zhulan-tunnel >/dev/null; then
|
|
echo "TUNNEL_USER_NOT_PREPARED" >&2
|
|
exit 1
|
|
fi
|
|
|
|
install -o root -g zhulan-tunnel -m 0640 "$KNOWN_HOSTS_SOURCE" "$KNOWN_HOSTS"
|
|
if ! ssh-keygen -F "$FRONT_HOST" -f "$KNOWN_HOSTS" >/dev/null; then
|
|
echo "PINNED_FRONT_HOST_KEY_MISSING" >&2
|
|
exit 1
|
|
fi
|
|
EXPECTED_FRONT_HOST_KEY="${ZHULAN_EXPECTED_FRONT_HOST_KEY:-SHA256:P2EtuYFg8hptha4s0auP4yzp+Wg+H27bw4mdqzk1Cvk}"
|
|
ACTUAL_FRONT_HOST_KEY="$(ssh-keygen -F "$FRONT_HOST" -f "$KNOWN_HOSTS" | awk 'NF && $1 !~ /^#/ {print $2, $3}' | ssh-keygen -lf - 2>/dev/null | awk '{print $2}' | head -1)"
|
|
if [[ "$ACTUAL_FRONT_HOST_KEY" != "$EXPECTED_FRONT_HOST_KEY" ]]; then
|
|
echo "PINNED_FRONT_HOST_KEY_MISMATCH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
cat >"$SSH_CONFIG.tmp" <<EOF
|
|
Host guanghu-zhulan-front
|
|
HostName $FRONT_HOST
|
|
User zhulan-proxy
|
|
Port 22
|
|
IdentityFile $KEY_FILE
|
|
IdentitiesOnly yes
|
|
UserKnownHostsFile $KNOWN_HOSTS
|
|
StrictHostKeyChecking yes
|
|
BatchMode yes
|
|
RequestTTY no
|
|
ExitOnForwardFailure yes
|
|
ServerAliveInterval 30
|
|
ServerAliveCountMax 3
|
|
RemoteForward 127.0.0.1:17631 127.0.0.1:17631
|
|
EOF
|
|
chown root:zhulan-tunnel "$SSH_CONFIG.tmp"
|
|
chmod 0640 "$SSH_CONFIG.tmp"
|
|
mv "$SSH_CONFIG.tmp" "$SSH_CONFIG"
|
|
|
|
cat >"$SERVICE_FILE.tmp" <<'EOF'
|
|
[Unit]
|
|
Description=Zhulan SG003 to GZ006 loopback-only reverse proxy tunnel
|
|
After=network-online.target zhulan-remote-cell.service
|
|
Wants=network-online.target
|
|
Requires=zhulan-remote-cell.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=zhulan-tunnel
|
|
Group=zhulan-tunnel
|
|
ExecStart=/usr/bin/ssh -F /etc/guanghu/zhulan-front-tunnel/ssh_config -NT guanghu-zhulan-front
|
|
Restart=always
|
|
RestartSec=5
|
|
UMask=0077
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectControlGroups=true
|
|
RestrictSUIDSGID=true
|
|
LockPersonality=true
|
|
MemoryDenyWriteExecute=true
|
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
|
ReadOnlyPaths=/etc/guanghu/zhulan-front-tunnel
|
|
StateDirectory=guanghu/zhulan-front-tunnel
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
chown root:root "$SERVICE_FILE.tmp"
|
|
chmod 0644 "$SERVICE_FILE.tmp"
|
|
mv "$SERVICE_FILE.tmp" "$SERVICE_FILE"
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable --now zhulan-front-tunnel.service
|
|
for _ in $(seq 1 20); do
|
|
if systemctl is-active --quiet zhulan-front-tunnel.service; then
|
|
systemctl show zhulan-front-tunnel.service -p ActiveState -p SubState -p MainPID
|
|
exit 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
systemctl status zhulan-front-tunnel.service --no-pager >&2 || true
|
|
exit 1
|