Add bind-ssh-tailscale.sh as standalone manual-run script
Places the script in standalone/ so it is excluded from setup.sh automation. Documents manual curl-and-run usage in README.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
29
README.md
29
README.md
@@ -38,6 +38,35 @@ npm config set prefix ~/.npm-global
|
|||||||
export PATH="$HOME/.npm-global/bin:$PATH"
|
export PATH="$HOME/.npm-global/bin:$PATH"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Standalone Scripts
|
||||||
|
|
||||||
|
These scripts live in `standalone/` and are **not run by `setup.sh`**. They are
|
||||||
|
single-use tools intended to be copied to a target machine and run manually.
|
||||||
|
|
||||||
|
### standalone/bind-ssh-tailscale.sh
|
||||||
|
|
||||||
|
Binds SSH to the Tailscale interface only and disables password authentication.
|
||||||
|
|
||||||
|
- Requires root (`sudo bash bind-ssh-tailscale.sh`)
|
||||||
|
- Tailscale must be installed and connected before running
|
||||||
|
- Uses a drop-in config at `/etc/ssh/sshd_config.d/99-tailscale-only.conf` if
|
||||||
|
that directory exists; otherwise edits `/etc/ssh/sshd_config` directly with
|
||||||
|
an automatic backup
|
||||||
|
- Validates the config with `sshd -t` before restarting the SSH service
|
||||||
|
- Prints revert instructions on completion
|
||||||
|
|
||||||
|
**To use on a target machine:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -O https://gitea.pdmarf.co.uk/pdm/security-tools/raw/branch/master/standalone/bind-ssh-tailscale.sh
|
||||||
|
# or via Tailscale:
|
||||||
|
curl -O http://100.120.125.113:3000/pdm/security-tools/raw/branch/master/standalone/bind-ssh-tailscale.sh
|
||||||
|
|
||||||
|
sudo bash bind-ssh-tailscale.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Claude Code Context
|
## Claude Code Context
|
||||||
|
|
||||||
This project is maintained with Claude Code. The working directory on macOS is:
|
This project is maintained with Claude Code. The working directory on macOS is:
|
||||||
|
|||||||
75
standalone/bind-ssh-tailscale.sh
Executable file
75
standalone/bind-ssh-tailscale.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"; }
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
log "ERROR: Please run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Tailscale is installed and connected
|
||||||
|
if ! command -v tailscale &>/dev/null; then
|
||||||
|
log "ERROR: Tailscale is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAILSCALE_IP=$(tailscale ip -4 2>/dev/null)
|
||||||
|
if [ -z "$TAILSCALE_IP" ]; then
|
||||||
|
log "ERROR: Could not get Tailscale IP — is Tailscale connected?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "Tailscale IP: ${TAILSCALE_IP}"
|
||||||
|
|
||||||
|
# Detect SSH service name
|
||||||
|
if systemctl is-active --quiet ssh 2>/dev/null; then
|
||||||
|
SSH_SERVICE="ssh"
|
||||||
|
elif systemctl is-active --quiet sshd 2>/dev/null; then
|
||||||
|
SSH_SERVICE="sshd"
|
||||||
|
else
|
||||||
|
log "ERROR: No running SSH service found (tried ssh, sshd)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use a drop-in file if sshd_config.d exists, otherwise edit sshd_config directly
|
||||||
|
if [ -d /etc/ssh/sshd_config.d ]; then
|
||||||
|
DROPIN="/etc/ssh/sshd_config.d/99-tailscale-only.conf"
|
||||||
|
[ -f "$DROPIN" ] && log "WARNING: ${DROPIN} already exists — overwriting"
|
||||||
|
cat > "$DROPIN" << EOF
|
||||||
|
# Bind SSH to Tailscale interface only
|
||||||
|
# To revert: rm ${DROPIN} && systemctl restart ${SSH_SERVICE}
|
||||||
|
ListenAddress ${TAILSCALE_IP}
|
||||||
|
PasswordAuthentication no
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
EOF
|
||||||
|
log "Written: ${DROPIN}"
|
||||||
|
else
|
||||||
|
BACKUP="/etc/ssh/sshd_config.bak.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
cp /etc/ssh/sshd_config "$BACKUP"
|
||||||
|
log "Backed up sshd_config to ${BACKUP}"
|
||||||
|
|
||||||
|
# Remove any existing ListenAddress lines and add ours
|
||||||
|
sed -i '/^[#]*ListenAddress/d' /etc/ssh/sshd_config
|
||||||
|
echo "ListenAddress ${TAILSCALE_IP}" >> /etc/ssh/sshd_config
|
||||||
|
log "Updated /etc/ssh/sshd_config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate config before restarting
|
||||||
|
if ! sshd -t; then
|
||||||
|
log "ERROR: SSH config validation failed — aborting without restart"
|
||||||
|
[ -n "${DROPIN:-}" ] && rm -f "$DROPIN"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log "SSH config validated OK"
|
||||||
|
|
||||||
|
systemctl restart "$SSH_SERVICE"
|
||||||
|
log "SSH service restarted"
|
||||||
|
|
||||||
|
log ""
|
||||||
|
log "Done. SSH is now bound to Tailscale only (${TAILSCALE_IP})"
|
||||||
|
log "Connect with: ssh root@${TAILSCALE_IP}"
|
||||||
|
if [ -d /etc/ssh/sshd_config.d ]; then
|
||||||
|
log "To revert: rm ${DROPIN} && systemctl restart ${SSH_SERVICE}"
|
||||||
|
else
|
||||||
|
log "To revert: cp ${BACKUP} /etc/ssh/sshd_config && systemctl restart ${SSH_SERVICE}"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user