39 lines
2.2 KiB
Bash
39 lines
2.2 KiB
Bash
#!/usr/bin/env bash
|
|
# breakglass-signin-alert.sh — alert #dev-alerts on ANY sign-in by the ACG M365
|
|
# break-glass account (sysadmin@azcomputerguru.onmicrosoft.com). A break-glass login
|
|
# should be rare and always investigated. Run on a schedule (hourly/daily).
|
|
#
|
|
# State: tracks the last-checked UTC timestamp in a sidecar so it only alerts on NEW
|
|
# sign-ins. First run seeds the timestamp (no alert for history) unless --backfill <ISO>.
|
|
# DRY_RUN=1 prints what it would post instead of posting.
|
|
#
|
|
# Usage: breakglass-signin-alert.sh [--since <ISO8601>]
|
|
set -u
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)" # skill scripts -> repo root
|
|
TEN="ce61461e-81a0-4c84-bb4a-7b354a9a356d" # azcomputerguru.com
|
|
BG="8c363d17-02ed-45e1-97d0-49e5819e6ff6" # sysadmin@azcomputerguru.onmicrosoft.com
|
|
STATE="$SCRIPT_DIR/.breakglass-lastcheck"
|
|
|
|
NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
if [ "${1:-}" = "--since" ] && [ -n "${2:-}" ]; then SINCE="$2";
|
|
elif [ -f "$STATE" ]; then SINCE="$(cat "$STATE")";
|
|
else SINCE="$NOW"; echo "$NOW" > "$STATE"; echo "[seed] first run — seeded $NOW, no history alerted"; exit 0; fi
|
|
|
|
G=$("$SCRIPT_DIR/get-token.sh" "$TEN" investigator 2>/dev/null) || { echo "[err] token"; exit 1; }
|
|
RESP=$(curl -s "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=userId+eq+'$BG'+and+createdDateTime+ge+$SINCE&\$top=50" -H "Authorization: Bearer $G" | tr -d '\000-\037')
|
|
N=$(echo "$RESP" | jq -r '.value | length' 2>/dev/null)
|
|
[ -z "$N" ] && { echo "[err] query"; exit 1; }
|
|
|
|
if [ "$N" -gt 0 ]; then
|
|
while IFS= read -r line; do
|
|
[ -z "$line" ] && continue
|
|
MSG="[SECURITY] BREAK-GLASS SIGN-IN - sysadmin@azcomputerguru.onmicrosoft.com used: $line -- investigate if unplanned."
|
|
if [ "${DRY_RUN:-0}" = "1" ]; then echo "WOULD POST: $MSG";
|
|
else bash "$ROOT/.claude/scripts/post-bot-alert.sh" "$MSG" >/dev/null 2>&1; echo "[alert] posted: $line"; fi
|
|
done < <(echo "$RESP" | jq -r '.value[] | "\(.createdDateTime) result=\(.status.errorCode) app=\(.appDisplayName) ip=\(.ipAddress) loc=\(.location.countryOrRegion)/\(.location.city // "?")"')
|
|
else
|
|
echo "[ok] no break-glass sign-ins since $SINCE"
|
|
fi
|
|
echo "$NOW" > "$STATE"
|