119 lines
4.4 KiB
Bash
Executable file
119 lines
4.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
|
tmp="$(mktemp -d)"
|
|
trap 'rm -rf -- "$tmp"' EXIT
|
|
mkdir -p "$tmp/bin"
|
|
|
|
# Extract and run the exact hook template without writing to PAM or contacting
|
|
# Telegram. The stubs record invocation and deliberately make curl slow.
|
|
awk '/^cat > "\$NOTIFY_SCRIPT" <<.HOOK/ { copying=1; next }
|
|
copying && /^HOOK$/ { exit }
|
|
copying { print }' ochenstarik-server-tg-4.sh > "$tmp/notify-hook"
|
|
[[ -s "$tmp/notify-hook" ]]
|
|
# Relocate only the extracted fixture; production PAM paths are fixed and do
|
|
# not trust session-provided test overrides.
|
|
sed -i "s|/etc/ochenstarik-server/telegram.conf|$tmp/config|g; s|/var/log/ochenstarik-ssh-login-telegram.log|$tmp/notify.log|g; s|/usr/bin/setsid|$tmp/bin/setsid|g" "$tmp/notify-hook"
|
|
bash -n "$tmp/notify-hook"
|
|
chmod 700 "$tmp/notify-hook"
|
|
cat > "$tmp/config" <<'CONFIG'
|
|
TG_BOT_TOKEN=123456:secret-token-marker
|
|
TG_CHAT_ID=12345
|
|
SERVER_IP=192.0.2.1
|
|
CONFIG
|
|
chmod 600 "$tmp/config"
|
|
|
|
cat > "$tmp/bin/setsid" <<'SETSID_STUB'
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
printf 'called\n' >> "$SETSID_LOG"
|
|
exec /usr/bin/setsid "$@"
|
|
SETSID_STUB
|
|
cat > "$tmp/bin/curl" <<'CURL_STUB'
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
printf '%s\n' "$*" >> "$CURL_ARGS_LOG"
|
|
cat > "$CURL_CONFIG_LOG"
|
|
touch "$CURL_STARTED"
|
|
sleep 1
|
|
touch "$CURL_DONE"
|
|
printf '200\n' >&2
|
|
exit 0
|
|
CURL_STUB
|
|
chmod +x "$tmp/bin/setsid" "$tmp/bin/curl"
|
|
|
|
export PATH="$tmp/bin:$PATH"
|
|
export SETSID_LOG="$tmp/setsid.log" CURL_ARGS_LOG="$tmp/curl-args"
|
|
export CURL_CONFIG_LOG="$tmp/curl-config" CURL_STARTED="$tmp/curl-started"
|
|
export CURL_DONE="$tmp/curl-done"
|
|
export PAM_USER=test-user PAM_RHOST=192.0.2.7 PAM_SERVICE=sshd PAM_TTY=pts/1
|
|
|
|
PAM_TYPE=close_session "$tmp/notify-hook"
|
|
[[ ! -e "$SETSID_LOG" && ! -e "$CURL_STARTED" ]]
|
|
|
|
started_ns="$(date +%s%N)"
|
|
PAM_TYPE=open_session "$tmp/notify-hook"
|
|
elapsed_ms=$(( ($(date +%s%N) - started_ns) / 1000000 ))
|
|
((elapsed_ms < 500)) || { printf 'PAM hook waited %s ms for background work.\n' "$elapsed_ms" >&2; exit 1; }
|
|
|
|
for _ in {1..60}; do
|
|
[[ -e "$CURL_STARTED" ]] && break
|
|
sleep 0.05
|
|
done
|
|
[[ -e "$CURL_STARTED" ]]
|
|
[[ "$(wc -l < "$SETSID_LOG")" == 1 ]]
|
|
! grep -Fq 'secret-token-marker' "$CURL_ARGS_LOG"
|
|
grep -Fq 'url = "https://api.telegram.org/bot123456:secret-token-marker/sendMessage"' "$CURL_CONFIG_LOG"
|
|
|
|
# Verify the generated backup runner's opt-in encryption and strict offsite
|
|
# transport contract without invoking it against the host filesystem.
|
|
awk '/^ cat > "\$BACKUP_RUNNER" <<.BACKUP_RUNNER_EOF/ { copying=1; next }
|
|
copying && /^BACKUP_RUNNER_EOF$/ { exit }
|
|
copying { print }' ochenstarik-server-backup-7.sh > "$tmp/backup-runner"
|
|
bash -n "$tmp/backup-runner"
|
|
grep -Fq 'BACKUP_ENCRYPTION=none' "$tmp/backup-runner"
|
|
grep -Fq 'age --encrypt --recipient "$AGE_RECIPIENT" --output "$temporary"' "$tmp/backup-runner"
|
|
grep -Fq 'StrictHostKeyChecking=yes' "$tmp/backup-runner"
|
|
grep -Fq 'BatchMode=yes' "$tmp/backup-runner"
|
|
grep -Fq 'UserKnownHostsFile=$OFFSITE_KNOWN_HOSTS' "$tmp/backup-runner"
|
|
grep -Fq 'Выгрузка на заданный SSH-хост не удалась' "$tmp/backup-runner"
|
|
if grep -Fq 'ssh-keyscan' ochenstarik-server-backup-7.sh; then
|
|
printf 'Backup setup must not trust an unverified ssh-keyscan result.\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
awk '/^upload_offsite\(\)/ { copying=1 }
|
|
copying { print }
|
|
copying && /^}/ { exit }' "$tmp/backup-runner" > "$tmp/upload-function"
|
|
source "$tmp/upload-function"
|
|
log() { :; }
|
|
die() { printf '%s\n' "$*" >&2; exit 1; }
|
|
cat > "$tmp/bin/scp" <<'SCP_STUB'
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
printf '%s\n' "$*" >> "$SCP_ARGS_LOG"
|
|
exit "${SCP_EXIT_CODE:-0}"
|
|
SCP_STUB
|
|
chmod +x "$tmp/bin/scp"
|
|
export SCP_ARGS_LOG="$tmp/scp-args"
|
|
OFFSITE_TARGET='backup@example.test'
|
|
OFFSITE_PATH='/srv/backups'
|
|
OFFSITE_KNOWN_HOSTS="$tmp/known_hosts"
|
|
touch "$OFFSITE_KNOWN_HOSTS" "$tmp/archive.tar.zst.age" "$tmp/archive.sha256"
|
|
SCP_EXIT_CODE=0 upload_offsite "$tmp/archive.tar.zst.age" "$tmp/archive.sha256"
|
|
grep -Fq -- '-o BatchMode=yes' "$SCP_ARGS_LOG"
|
|
grep -Fq -- '-o StrictHostKeyChecking=yes' "$SCP_ARGS_LOG"
|
|
grep -Fq -- "-o UserKnownHostsFile=$OFFSITE_KNOWN_HOSTS" "$SCP_ARGS_LOG"
|
|
if (SCP_EXIT_CODE=42 upload_offsite "$tmp/archive.tar.zst.age" "$tmp/archive.sha256") \
|
|
>/dev/null 2>&1; then
|
|
printf 'Offsite upload failure was accepted as success.\n' >&2
|
|
exit 1
|
|
fi
|
|
for _ in {1..60}; do
|
|
[[ -e "$CURL_DONE" ]] && break
|
|
sleep 0.05
|
|
done
|
|
[[ -e "$CURL_DONE" ]]
|
|
|
|
printf 'Notification and backup security tests passed.\n'
|