diff --git a/bootstraps/optional/idle-shutdown/install-idle.sh b/bootstraps/optional/idle-shutdown/install-idle.sh index bd99f9b..8d87d2e 100755 --- a/bootstraps/optional/idle-shutdown/install-idle.sh +++ b/bootstraps/optional/idle-shutdown/install-idle.sh @@ -233,8 +233,9 @@ JSON WAKE_INLINE=$(cat <&2 + exit 1 +fi + +RED='\033[0;31m'; GREEN='\033[0;32m'; BOLD='\033[1m'; NC='\033[0m' +PASS=0; FAIL=0 + +pass() { printf "${GREEN} \xE2\x9C\x93${NC} %s\n" "$1"; PASS=$((PASS + 1)); } +fail() { printf "${RED} \xE2\x9C\x97${NC} %s\n" "$1"; FAIL=$((FAIL + 1)); } + +printf "${BOLD}idle-shutdown wake Lambda IAM policy${NC}\n" + +# Get the heredoc body between 'WAKE_INLINE=$(cat <" or "FAIL ". +RESULTS="$(POLICY="$POLICY" python3 - <<'PY' +import json, os + +region, acct, inst = "us-east-1", "123456789012", "i-0123456789abcdef0" +text = (os.environ["POLICY"] + .replace("${REGION}", region) + .replace("${ACCT_ID}", acct) + .replace("${INSTANCE_ID}", inst)) +instance_arn = f"arn:aws:ec2:{region}:{acct}:instance/{inst}" + +def out(ok, msg): + print(("PASS " if ok else "FAIL ") + msg) + +try: + doc = json.loads(text) +except ValueError as e: + out(False, f"policy is valid JSON ({e})") + raise SystemExit(0) +out(True, "policy is valid JSON") + +def as_list(v): + return v if isinstance(v, list) else [v] + +stmts = as_list(doc.get("Statement", [])) +describe_seen = False +start_seen = False +for s in stmts: + actions = as_list(s.get("Action", [])) + resources = as_list(s.get("Resource", [])) + describes = [a for a in actions if a.startswith("ec2:Describe")] + if describes: + describe_seen = True + out(resources == ["*"], + f"{', '.join(describes)} uses Resource \"*\" (got {resources})") + if "ec2:StartInstances" in actions: + start_seen = True + out(resources == [instance_arn], + f"ec2:StartInstances is limited to the instance ARN (got {resources})") + +out(describe_seen, "policy allows ec2:DescribeInstanceStatus") +out(start_seen, "policy allows ec2:StartInstances") +PY +)" + +while IFS= read -r line; do + [[ -z "$line" ]] && continue + case "$line" in + PASS\ *) pass "${line#PASS }" ;; + *) fail "${line#FAIL }" ;; + esac +done <<< "$RESULTS" + +printf "\n%d passed, %d failed\n" "$PASS" "$FAIL" +[[ "$FAIL" -eq 0 ]]