AWS WAF로 웹 엔드포인트 보호

AWSBeginner
지금 연습하기

소개

웹 애플리케이션은 상태 확인을 사용할 수 있도록 유지하면서 내부 내보내기 경로를 차단해야 합니다. 경로 규칙을 연결하고 요청이 백엔드에 도달하는지 테스트하며 정리 전에 규칙을 업데이트합니다.

LabEx에서 AWS 시작과 보고서 읽기 신원에 최소 권한 부여하기를 먼저 완료하세요. 이 새 VM에는 애플리케이션과 독립적인 REST API 스테이지가 제공됩니다. 이전 API나 네트워킹 리소스는 필요하지 않습니다.

인증 시험 관련 주제

이 실습은 다음 시험 주제에 대한 실습 경험을 제공합니다.

리전 Web ACL 만들기

이 단계에서는 웹 액세스 제어 목록 (Web ACL) 안에 AWS WAF 요청 규칙을 정의합니다. WAF는 요청이 애플리케이션에 도달하기 전에 검사합니다. 제공된 REST API에는 리전 Web ACL과 연결할 수 있는 이름 있는 스테이지가 있습니다. 이 진입점은 API/Cognito 과정에서 사용한 HTTP API와 다릅니다.

Terminal 옆에서 AWS View를 열어 규칙, 스테이지 연결과 각 요청의 백엔드 도달 여부를 비교하세요. 관련 없는 참조 Web ACL과 스테이지를 유지하세요.

규칙은 일치 조건과 작업을 결합합니다. 기본 작업은 일치하는 규칙이 없을 때 적용됩니다. /internal/을 차단하고 다른 경로는 허용합니다.

프로젝트 디렉터리로 이동하고 준비된 운영자 신원을 확인하세요. 제공된 stage-arn.txt에는 자격 증명이 아닌 애플리케이션 스테이지 ARN이 들어 있습니다. 명령 치환은 이후 연결에 사용할 값을 저장합니다.

cd /home/labex/project
aws sts get-caller-identity --query Arn --output text
STAGE_ARN=$(cat stage-arn.txt)

labex-sec05-operator가 나와야 합니다. Web ACL을 연결하기 전에는 테스트용 내부 내보내기 요청이 백엔드에 도달합니다. curl은 실제 HTTP 요청을 보냅니다. -sS는 진행 출력을 제거하면서 연결 오류를 유지하고 -w는 응답 상태를 출력합니다.

curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/internal/export

HTTP 200과 테스트용 백엔드 응답이 나와야 합니다. 따옴표가 있는 here-document로 규칙 파일을 작성하세요. <<'EOF'와 EOF 사이의 줄은 작성한 그대로 JSON 파일이 됩니다. UriPath는 경로를 선택하고 STARTS_WITH는 접두사와 일치시키며 NONE은 변환하지 않습니다. 숫자 우선순위가 낮을수록 먼저 실행됩니다. 이 ACL에는 우선순위가 0인 규칙 하나가 있습니다. 이 실습에 집중하기 위해 가시성 설정은 선택적인 샘플과 지표를 비활성화합니다. ACL 자체와 이후 업데이트에 사용할 동일한 설정을 visibility.json에 저장하세요.

cat > rules-internal.json <<'EOF'
[{
  "Name": "block-private-export",
  "Priority": 0,
  "Action": {"Block": {}},
  "Statement": {"ByteMatchStatement": {
    "SearchString": "/internal/",
    "FieldToMatch": {"UriPath": {}},
    "PositionalConstraint": "STARTS_WITH",
    "TextTransformations": [{"Priority": 0, "Type": "NONE"}]
  }},
  "VisibilityConfig": {"SampledRequestsEnabled": false, "CloudWatchMetricsEnabled": false, "MetricName": "labex-sec05-owned-export"}
}]
EOF

기본 작업이 Allow인 리전 ACL을 만드세요. --cli-binary-format raw-in-base64-out은 AWS CLI v2가 SearchString을 base64 문자열이 아닌 리터럴 입력 바이트로 해석하도록 합니다. file://는 규칙 문서를 불러오고 --query는 생성된 ACL ID만 선택합니다.

cat > visibility.json <<'EOF'
{
  "SampledRequestsEnabled": false,
  "CloudWatchMetricsEnabled": false,
  "MetricName": "labex-sec05-owned-export"
}
EOF

ACL_ID=$(aws wafv2 create-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --default-action Allow={} \
  --visibility-config file://visibility.json \
  --rules file://rules-internal.json \
  --cli-binary-format raw-in-base64-out \
  --query Summary.Id \
  --output text)
ACL_ARN=$(aws wafv2 get-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --query WebACL.ARN \
  --output text)
aws wafv2 get-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --query 'WebACL.{Name:Name,Default:DefaultAction,Rules:Rules[].Name}'

소유한 ACL, 기본 작업 Allow와 block-private-export가 나와야 합니다. 정책을 만드는 것만으로 엔드포인트에 연결되지는 않습니다. AWS View에는 여전히 대상 연결이 없어야 합니다.

ACL 연결 및 실제 요청 테스트

이 단계에서는 정책을 제공된 REST API 스테이지에 연결하고 공개 요청과 일치하는 내보내기 요청을 비교합니다. 스테이지는 배포된 API 환경을 식별합니다. 연결은 해당 스테이지의 요청에 ACL을 적용합니다.

백엔드 앞의 WAF

연결된 Web ACL은 내부 경로가 백엔드에 도달하기 전에 거부합니다.

제공된 대상 ARN에 본인 ACL만 연결하세요. 관련 없는 참조 스테이지에는 이미 자체 참조 ACL이 있습니다. 이를 교체하지 마세요.

aws wafv2 associate-web-acl --web-acl-arn "$ACL_ARN" --resource-arn "$STAGE_ARN"
aws wafv2 get-web-acl-for-resource \
  --resource-arn "$STAGE_ARN" \
  --query WebACL.Name \
  --output text

labex-sec05-owned-export가 나와야 합니다. /internal/과 일치하지 않는 공개 상태 확인 경로를 테스트한 다음 내부 내보내기 경로를 테스트하세요.

curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/health
curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/internal/export

상태 확인은 HTTP 200, 내보내기는 block-private-export를 포함한 HTTP 403이어야 합니다. Block 결정은 백엔드 실행 전에 응답을 반환합니다. AWS View에는 상태 확인 요청이 Executed, 차단된 요청이 Not reached로 표시되어야 합니다. 네이티브 연결만으로는 충분하지 않습니다. 이 실제 HTTP 결과가 적용 여부를 증명합니다.

상태 확인은 백엔드에 도달하고 내부 내보내기는 실행 전에 차단되는 AWS View 예시

규칙 업데이트 및 실제 동작 관찰

이 단계에서는 애플리케이션을 다시 시작하지 않고 보호 대상을 admin 접두사로 옮기고 변경된 동작을 확인합니다. Web ACL 업데이트는 규칙 목록을 교체합니다. 잠금 토큰은 동시에 발생한 변경을 덮어쓰지 않도록 보호합니다. 업데이트 직전에 현재 네이티브 설정에서 가져와 변수에 보관하세요.

이전 파일의 URI 접두사를 바꾸어 새 규칙 문서를 만드세요. sed는 텍스트를 변환하고 >는 원래 규칙 문서를 유지하면서 새 파일을 씁니다.

sed 's|/internal/|/admin/|' rules-internal.json > rules-admin.json
LOCK_TOKEN=$(aws wafv2 get-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --query LockToken \
  --output text)
aws wafv2 update-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --lock-token "$LOCK_TOKEN" \
  --default-action Allow={} \
  --visibility-config file://visibility.json \
  --rules file://rules-admin.json \
  --cli-binary-format raw-in-base64-out \
  --query NextLockToken \
  --output text

반환된 잠금 토큰은 새 ACL 개정판을 식별하며 인증 자격 증명이 아닙니다. 이제 이전 internal 접두사는 기본 Allow 작업으로 통과하고 admin 내보내기는 차단되어야 합니다.

curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/internal/export
curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/admin/export

HTTP 200 다음에 HTTP 403이 나와야 합니다. AWS View에는 새 /admin/ 접두사, 앞서 차단된 internal 요청과 현재 허용된 internal/차단된 admin 요청 쌍이 표시되어야 합니다. 요청은 현재 네이티브 규칙을 사용합니다. VM이나 애플리케이션을 다시 시작할 필요는 없습니다. 이 실습 환경에서는 지원하지 않는 정책 유형이 안전하게 거부되므로 여기서 배운 명령문 유형만 사용하세요.

실시간 접두사 업데이트 후 internal 내보내기는 허용되고 admin 내보내기는 차단되는 AWS View 예시

소유한 ACL만 연결 해제 및 삭제

이 단계에서는 정책을 제거하고 일반적인 애플리케이션 라우팅이 복구되는지 확인합니다. 앞선 기능 검사를 먼저 마치세요. 연결 해제는 이 스테이지의 규칙 적용을 제거하고 이후 ACL 삭제는 소유한 정책 리소스를 제거합니다.

대상 스테이지에서 본인 Web ACL을 연결 해제하고 성공한 네이티브 쿼리로 연결을 확인하세요. 인증 오류를 삭제 증거로 취급하지 말고 빈 연결이 나오는지 확인하세요.

aws wafv2 disassociate-web-acl --resource-arn "$STAGE_ARN"
aws wafv2 get-web-acl-for-resource --resource-arn "$STAGE_ARN" --query WebACL

앞서 차단된 admin 내보내기가 이제 제공된 백엔드에 다시 도달해야 합니다.

curl -sS -w '\nHTTP %{http_code}\n' http://127.0.0.1:8090/admin/export

HTTP 200이 나와야 합니다. 현재 잠금 토큰을 구하고 소유한 ACL만 삭제한 다음 남은 ACL 목록을 성공적으로 조회하세요. 소유한 이름은 없어야 하며 labex-sec05-reference는 남아야 합니다.

LOCK_TOKEN=$(aws wafv2 get-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --query LockToken \
  --output text)
aws wafv2 delete-web-acl \
  --name labex-sec05-owned-export \
  --scope REGIONAL \
  --id "$ACL_ID" \
  --lock-token "$LOCK_TOKEN"
aws wafv2 list-web-acls --scope REGIONAL --query 'WebACLs[].Name'

제공된 두 API 스테이지와 참조 ACL을 그대로 유지하세요. 로컬 규칙 및 가시성 문서를 제거한 다음 일회용 CLI 프로필을 제거하기 전에 이 단계의 검증을 실행하세요.

rm -f rules-internal.json rules-admin.json visibility.json
rm -f /home/labex/.aws/credentials /home/labex/.aws/config
unset STAGE_ARN ACL_ID ACL_ARN LOCK_TOKEN

요약

리전 Web ACL을 만들고 REST API 스테이지에 연결하여 실제 HTTP 허용/차단 동작을 테스트했습니다. 일치하는 요청은 백엔드 전에 차단되었고 상태 확인 요청은 계속 통과했습니다. URI 접두사를 업데이트하면 실제 라우팅이 바뀌었으며 연결 해제로 엔드포인트가 복구되었습니다. 제공된 스테이지와 참조 정책을 유지하면서 소유한 ACL만 삭제했습니다.