ac0ff8e2af
ci / build-test (push) Has been cancelled
- untrack CLAUDE.md (tailnet leak) + stale HANDOFF.md; keep local via .gitignore - add source-available LICENSE (attribution on fork, royalty on commercial use) - add lab/ reproduction kit (fake-cred LIVE-VM/mock rotation POCs) + lab/README - rewrite README to current status (22 drivers, 8 LIVE-VM/14 MOCK-ONLY/0 LIVE-REAL, 247 tests) and carry the credential-handling safety rules Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58 lines
2.0 KiB
Bash
Executable File
58 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Assert the AWS cutover after `incredigo rotate --execute`.
|
|
set -euo pipefail
|
|
export GNUPGHOME="$HOME/.lab-gnupg"
|
|
export GOPASS_HOMEDIR="$HOME/.lab-gopass"
|
|
VENV="$HOME/moto-venv"
|
|
EP="http://127.0.0.1:5000"
|
|
OLD=$(cat "$HOME/.lab-aws-oldkey")
|
|
ENTRY="imported/aws/labkey"
|
|
|
|
# New key id from the rotated gopass blob (strip userinfo: between :// and first @,
|
|
# the id is before the first ':').
|
|
NEWBLOB=$(gopass show -o "$ENTRY")
|
|
NEW=$(printf '%s' "$NEWBLOB" | sed -E 's#^aws://([^:]+):.*#\1#')
|
|
|
|
echo "OLD AccessKeyId: $OLD"
|
|
echo "NEW AccessKeyId: $NEW"
|
|
|
|
"$VENV/bin/python" - "$EP" "$OLD" "$NEW" <<'PY'
|
|
import sys, boto3
|
|
ep, old, new = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
a = boto3.client("iam", endpoint_url=ep, region_name="us-east-1",
|
|
aws_access_key_id="admin", aws_secret_access_key="admin")
|
|
keys = [k["AccessKeyId"] for k in a.list_access_keys(UserName="labapp")["AccessKeyMetadata"]]
|
|
print("labapp keys after rotate:", keys)
|
|
ok = True
|
|
if old in keys:
|
|
print("FAIL: old key still present"); ok = False
|
|
else:
|
|
print("PASS: old key deleted at provider")
|
|
if new not in keys:
|
|
print("FAIL: new key absent"); ok = False
|
|
else:
|
|
print("PASS: new key present at provider")
|
|
if old == new:
|
|
print("FAIL: old == new"); ok = False
|
|
else:
|
|
print("PASS: old != new")
|
|
sys.exit(0 if ok else 1)
|
|
PY
|
|
|
|
echo "-- audit-log leak check (no key material) --"
|
|
AUD="$HOME/rotate-audit.jsonl"
|
|
if [ -f "$AUD" ]; then
|
|
if grep -qF "$OLD" "$AUD" || grep -qF "$NEW" "$AUD"; then
|
|
echo "FAIL: AccessKeyId found in audit log"; exit 1
|
|
fi
|
|
# secret material check: pull the new secret from the blob and grep
|
|
NSEC=$(printf '%s' "$NEWBLOB" | sed -E 's#^aws://[^:]+:([^@]+)@.*#\1#' | python3 -c 'import sys,urllib.parse;print(urllib.parse.unquote(sys.stdin.read()))')
|
|
if [ -n "$NSEC" ] && grep -qF "$NSEC" "$AUD"; then
|
|
echo "FAIL: SecretAccessKey found in audit log"; exit 1
|
|
fi
|
|
echo "PASS: audit log carries no key id or secret"
|
|
else
|
|
echo "note: no audit log at $AUD"
|
|
fi
|
|
echo "ALL CUTOVER ASSERTIONS PASSED"
|