*cloudNet@ 팀의 가시다 님이 진행하는 AWS Hacking & Security Study 스터디 입니다.
[실습] AWS Account Setup and Root User : 자격증명 보고서 , 암호 설정 정책
- Generate and Review the AWS Account Credential Report : 자격증명 보고서(csv) 다운로드 및 정기적으로 점검
각각의 어떤 행위를 하였는지 분석 가능합니다. (언제 액세스 키를 사용하였는지 등)
#내용
user,arn,user_creation_time,password_enabled,password_last_used,password_last_changed,password_next_rotation,mfa_active,access_key_1_active,access_key_1_last_rotated,access_key_1_last_used_date,access_key_1_last_used_region,access_key_1_last_used_service,access_key_2_active,access_key_2_last_rotated,access_key_2_last_used_date,access_key_2_last_used_region,access_key_2_last_used_service,cert_1_active,cert_1_last_rotated,cert_2_active,cert_2_last_rotated
admin,arn:aws:iam::12343:user/admin,2021-02-01T14:54:46+00:00,true,2023-09-16T06:05:41+00:00,2022-03-20T19:43:08+00:00,N/A,true,true,2023-03-23T03:32:07+00:00,2023-09-16T03:02:00+00:00,ap-northeast-2,sts,false,N/A,N/A,N/A,N/A,false,N/A,false,N/A
...
- Configure a Strong Password Policy for Your Users : 암호 설정 정책 사용
[실습] CloudFront with S3 Bucket Origin : 접근 제한된 버킷을 CloudFront를 통해서 접속
- 현재 OAI는 권장하지 않습니다 → OAC로 구성을 적극 권장합니다 –링크
- 실습에서는 OAI 사용
- 버킷 만들었으며 정책은 차단 상태입니다.
버킷에 있는 객체 접근하였지만 차단 설정으로 인하여 안되는 모습니다.
CF 생성 모습입니다.
CF 설정 완료 후 S3의 정책 확인 시 아래와 같은 모습을 확인할 수 있습니다. (해당 CF만 S3에 접근 가능합니다.)
CF 도메인으로 접근 시 S3 접근과 다르게 접근이 되는 모습을 볼 수가 있다.
[실습] Level 200: Automated IAM User Cleanup : 미사용 IAM User 와 IAM Role, 액세스 키 중지 혹은 삭제
- 동작 : AWS Lambda 함수는 Amazon CloudWatch Events의 정기적으로 예약된 이벤트에 의해 트리거됩니다. AWS IAM 사용자 및 관련 IAM 액세스 키의 상태를 확인하기 위해 Lambda 함수가 실행되면 결과는 Amazon SNS를 통해 지정된 이메일 연락처로 전송됩니다. IAM Access Analyser에서 식별된 사용되지 않은 역할 및 사용되지 않은 권한에 대해서도 검사가 수행됩니다.
- 주의 : 실 서비스 사용 환경에 적용하지 말것, 테스트 동작 확인으로 사용 할 것
- [CloudShell 권장 or 자신의 PC(aws sam 설치 필요)] DEPLOYING IAM LAMBDA CLEANUP WITH AWS SAM
# 파일 다운로드
wget https://wellarchitectedlabs.com/Security/200_Automated_IAM_User_Cleanup/Code/cloudformation-iam-user-cleanup.yaml
wget https://wellarchitectedlabs.com/Security/200_Automated_IAM_User_Cleanup/Code/lambda-iam-user-cleanup.py
# S3 버킷 생성
#aws s3 mb s3://버킷(유일한 이름) --region ap-northeast-2
NICKNAME=<각자 자신의 유일한 닉네임>
NICKNAME=gasida
aws s3 mb s3://$NICKNAME-ahss-4w --region ap-northeast-2
aws s3 ls
# Run the following command to prepare your deployment package
# AWS CloudFormation 'package' 명령을 사용하여 'cloudformation-iam-user-cleanup.yaml' 템플릿 파일의 로컬 경로를 S3 오브젝트 URL로 변환합니다.
# 변환된 템플릿은 'output-template.yaml' 파일로 저장되며, 필요한 모든 로컬 파일은 '$NICKNAME-ahss-4w'라는 이름의 S3 버킷에 업로드됩니다.
aws cloudformation package --template-file cloudformation-iam-user-cleanup.yaml --output-template-file output-template.yaml --s3-bucket $NICKNAME-ahss-4w
# AWS S3 'ls' 명령을 사용하여 '$NICKNAME-ahss-4w'라는 이름의 S3 버킷 내에 있는 모든 객체를 나열합니다.
# '--human-readable' 옵션은 파일 크기를 사람이 읽기 쉽게 표시하도록 지시합니다 (예: KB, MB 등).
aws s3 ls s3://$NICKNAME-ahss-4w --human-readable
# Once you have finished preparing the package you can deploy the CloudFormation with AWS SAM:
MYEMAIL='<각자 자신의 이메일>'
MYEMAIL='gasida.seo@gmail.com'
aws cloudformation deploy --template-file output-template.yaml --stack-name IAM-User-Cleanup --capabilities CAPABILITY_IAM --parameter-overrides NotificationEmail=$MYEMAIL
- 아래 자신의 이메일로 SNS 구독 승인 클릭
- AWS CloudFormation 스택 배포 확인 → 생성된 Lambda 클릭해서 이동
- Lambda : EventBridge(CW Events) 확인, 코드 내용 확인 → 테스트 : 더미 이벤트 실행
- 이메일 확인
- 분석1 : cloudformation-iam-user-cleanup.yaml – 파라미터 확인
Parameters: # 매개변수 섹션 시작
NotificationEmail: # 알림 이메일 주소를 입력받는 문자열 타입의 매개변수
Type: String
AllowedPattern: (...) # 이메일 패턴을 확인하는 정규식
ConstraintDescription: Please enter a valid email. # 유효하지 않은 이메일 입력 시 출력되는 메시지
Description: The email address to send the list of affected users. # 매개변수 설명
MinAgeKeysToReport:
Type: Number
Default: 30 # 기본값 설정
MinValue: 0 # 최소값 설정
Description: The minimum age in days of access keys to include in the report.
MinAgeKeysToDisable:
Type: Number
Default: 0
MinValue: 0
# 액세스 키를 얼마나 사용하지 않으면 disable하는 기간(일). 기본값은 '0'으로 함수 비활성화 상태임.
Description:The minimum age in days of access keys to disable. Set to '0' to disable this function.
MinAgeKeysToDelete:
Type:Number
Default :0
MinValue :0
# 액세스 키를 삭제할 최소 나이(일). 기본 값은 '0'으로 함수 비활성화 상태임.
Description:The minimum age in days of access keys to delete.Set to '0'to disable this function.
MinAgeUnusedUsersToReport:
Type:Number
Default :30
MinValue :0
# 보고서에 포함할 사용하지 않는 사용자의 최소 나이(일)
Description:The minimum age in days of unused users to include in the report.
MinAgeUnusedUsersToDisable:
Type:Number
Default :0
# 사용하지 않는 사용자를 비활성화 할 최소 나이(일). '0'으로 설정하면 이 기능을 비활성화함.
Description:The minimum age in days of unused users to disable.Setto '0'to disable this function.
MinAgeUnusedUsersToDelete:
Type:Number
Default :0
MinValue :00
# 삭제할 사용하지 않는 사용자의 최소 나이(일). '00'으로 설정하면 이 기능을 비활성화함.
Description:The minimum agein daysof unusedusers to delete.Setto '00'to disablethisfunction.
MinAgeRolesToDisable:
Type: Number
Default: 0
# 사용하지 않는 역할을 비활성화 할 최소 나이(일). '0'으로 설정하면 이 기능을 비활성화함.
Description: The minimum age in days of unused roles to disable. Set to '0' to disable this function.
MinAgeRolesToDelete:
Type: Number
Default: 0
MinValue: 0
# 삭제할 사용하지 않는 역할의 최소 나이(일). '00'으로 설정하면 이 기능을 비활성화함.
Description: The minimum age in days of unused roles to delete. Set to '0' to disable this function.
AnalyzerType :
Type:String
#타입선택
AllowedValues:['NONE','ACCOUNT','ORGANIZATION']
#타입 옵션들 (NONE, ACCOUNT, ORGANIZATION 중 하나를 선택)
Default:'ACCOUNT' # 기본값은 'ACCOUNT'
# IAM Access Analyzer는 AWS 계정 내 리소스의 외부 가용성에 대한 결과를 생성합니다.
# 이 계정이 조직의 루트 계정이거나 위임된 관리자인 경우 ORGANIZATION을 선택하고, 그렇지 않으면 ACCOUNT 또는 NONE을 선택하여 이 검사를 건너뜁니다.
Description:IAM Access Analyzer produces findings on the external availabilityof resources within your AWS account.If this account is theroot accountof an organization orthe delegated administrator select ORGANIZATION, otherwise select ACCOUNTor NONEtoskipthischeck.
- 해당 코드를 보았을때 통제하는것은 3가지 엑세스 키 , IAM user , IAM Rol
- 분석2 : 수동 실행 이외 트리거 확인 → EventBridge 클릭 후 규칙 편집 확인
⇒ 요일 ? 라서 아래와 같은 요일중 실행 된다
- 분석3 : Lambda 가 실행을 할 수 있는 권한은 어디? → IAM Role 확인
- 실습 완료 후 삭제
aws cloudformation delete-stack --stack-name IAM-User-Cleanup
aws s3 rm s3://$NICKNAME-ahss-4w --recursive
aws s3 rb s3://$NICKNAME-ahss-4w
[실습] Level 200: Remote Configuration, Installation, and Viewing of CloudWatch logs
- 목적 : AWS Systems Manager, Amazon CloudWatch, Amazon Simple Storage Service(S3), Amazon Athena 및 Amazon QuickSight와 같은 AWS 서비스를 활용하면 인스턴스에 직접 액세스하거나 데이터에 직접 액세스하지 않고도 로그를 수집하고 저장할 수 있습니다. 인스턴스에서 SSH 액세스를 제거하여 위협 노출 영역을 최소화하고 귀중한 로그 데이터를 수집하여 위협 탐지를 개선합니다.
- 보안 모범 사례
- “서비스 및 애플리케이션 로깅 구성” : EC2 인스턴스에서 CloudWatch 에이전트를 구성합니다. 이를 통해 Apache 웹 서버 로그, SSH 로그, 부팅 로그 등과 같이 애플리케이션을 호스팅하는 데 사용되는 인스턴스에서 로그를 수집할 수 있습니다.
- “중앙에서 서비스 및 리소스 구성” : Systems Manager Parameter Store에 구성 파일을 저장하여 CloudWatch 로그 에이전트를 중앙에서 구성합니다. Parameter Store를 사용하면 일관되고 재사용 가능한 구성 데이터를 유지할 수 있습니다.
- “로그를 중앙에서 분석” : 이 실습에서는 두 가지 방법으로 로그를 중앙에서 분석합니다. CloudWatch 콘솔을 사용하면 모든 원시 로그 데이터를 한 위치에서 볼 수 있습니다. QuickSight를 통해 주요 데이터를 중앙에서 볼 수 있도록 다른 사람과 공유할 수 있는 로그 시각화를 생성할 수 있습니다.
- “원거리에서 작업을 수행할 수 있도록 지원” : Systems Manager Run Command를 사용하여 EC2 인스턴스에 CloudWatch 에이전트를 설치하고 시작합니다. 이러한 작업을 수행하기 위해 인스턴스에 직접 SSH를 사용할 필요가 없으므로 Run Command를 통해 “원거리에서” 이러한 작업을 수행합니다.
- “공격 표면 감소” : Run Command를 사용하면 SSH를 통해 EC2 인스턴스에 직접 연결할 필요가 없습니다. 이로 인해 인스턴스에서 SSH 액세스 포트를 닫아 워크로드의 공격 표면을 줄일 수 있습니다.
- 동작
- 실습에서는 Apache 및 PHP가 설치된 EC2 인스턴스를 배포합니다. 웹 서버는 매우 간단한 웹사이트를 호스팅합니다.
- Amazon Systems Manager(SSM)를 통해 인스턴스에 CloudWatch 에이전트를 구성합니다. 이 에이전트는 Apache 액세스 및 오류 로그, yum 로그, SSH 로그, CloudWatch 에이전트 로그 등 EC2 인스턴스에서 실행되는 서비스로부터 로그 파일을 수집합니다.
- 이러한 로그는 중앙 집중식 스토리지를 위해 EC2 인스턴스에서 CloudWatch 로그 서비스로 내보내집니다. 장기 저장 및 보관을 위해 이러한 로그를 S3 버킷으로 내보냅니다.
- 그런 다음 이러한 로그는 Athena를 통해 쿼리되므로 사람들이 로그 파일에 직접 액세스할 수 없습니다.
- 이 데이터는 QuickSight 대시보드에 시각적으로 표시됩니다.
- DEPLOY THE CLOUDFORMATION STACK – 링크
- CloudFormation 템플릿 파일 다운로드 : security-lab-stack.yaml
wget https://wellarchitectedlabs.com/Security/200_Remote_Configuration_Installation_and_Viewing_CloudWatch_Logs/code/security-lab-stack.yaml
- CloudFormation 스택 배포 : IAM 생성(체크)
- 스택 이름 : remotelogs
- BucketName : ‘각자 자신의 신규 버킷명’ ← 기존에 없던 이름, 배포 시 해당 버킷이 신규로 생성됨
- DisplayName : ‘각자 자신의 닉네임’ ← 웹 페이지에 출력되는 내용
- 배포 완료 확인 : EC2 웹사이트 접속 확인
- 배포된 EC2 접속 확인 : ‘시작 시 할당된 키 페어’ , 보안 그룹(인바운드, 아웃바운드)
보안그룹 (SSH 없음 확인)
→ SSH 접속이 될까요? , 어떤 방법으로 접속 할 수 있나요? ‘연결 → ‘Session Manager’ : 어떤 원리로 가능한지?
(옵션) CloudShell 에서 CLI 에서 접속, 자신의 PC에서 사용 시 SessionManagerPlugin 설치 필요
# aws ssm start-session --target <각자 자신의 인스턴스 ID>
# cloudshell 접속장점: 빠르다
[cloudshell-user@ip-10-4-56-85 ~]$ aws ssm start-session --target i-0f7c75cd22321
[인스턴스ID]
Starting session with SessionId: admin-096a7df573bf3f166
sh-4.2$ whoami
sh-4.2$ sudo systemctl stop sshd
sh-4.2$ sudo systemctl start sshd
sh-4.2$ exit
- 통신 확인 시 443포트 이용하여 아웃 바운드 통신, IP 조회시 아마존 IP 확인
SSM Agent 기술 참조 – AWS Systems Manager <- IMDS 비활성시 안됨
- INSTALL THE CLOUDWATCH AGENT – 링크
- CW Agent는 EC2 인스턴스의 활동을 모니터링하여 로그와 지표를 수집
- 목표 : AWS Systems Manager Run Command를 사용하여 원격에서 CW Agent를 설치 → 다수의 EC2 운영 관리에 유용
- System Manager → Run Command 메뉴 이동 – 링크 ⇒ 명령 실행 Run command 클릭
- 문서 이름 접두사 (같음) 선택 후 ‘AWS-ConfigureAWSPackage’ 입력 후 나오는 명령 선택 : 원격에서 EC2에 패키지 설치
- 대상 : 수동으로 인스턴스 선택(배포된 EC2) → S3 버킷에 쓰기 활성화(Uncheck) ⇒ 맨 하단 실행
- 대상 및 출력에서 인스턴스 선택(배포된 EC2) 후 ‘출력 보기’ 선택 → 성공 확인
2번에서 클라우드워치 에이전트를 패키지 설치만 하였지 어떤 구성 정보 파일을 입력해서 서비스를 실행할지를 하지 않았기 때문에
3번에서 설정을 해줍니다. (중앙에서 해야 하기 때문에 Parameter Store 서비스 이용)
- STORE THE CLOUDWATCH CONFIG FILE IN PARAMETER STORE – 링크
- Parameter Store를 사용하면 재사용을 위해 구성 데이터와 암호를 안전하게 저장 및 재사용 가능
- 목표 : Systems Manager의 도구인 Parameter Store를 사용하여 CloudWatch 에이전트 구성을 저장
- CloudWatch 에이전트 구성 데이터는 CloudWatch로 전송될 로그 및 지표와 이 데이터의 소스를 지정
- System Manager → Parameter Store 메뉴 이동 – 링크 → 파라미터 생성 클릭 ⇒ 아래 입력 후 하단 파라미터 생성 클릭
- Name(이름) : AmazonCloudWatch-securitylab-cw-config
- AmazonCloudWatch“ 로 되어 있어야만, CW에서 유효한 구성 파일로 인식
- 계층(표준), 유형(문자열), 데이터 형식(text)
- 값 : config.json 파일 내용 : 이 구성 파일은 수집할 측정항목과 로그를 지정합니다. https://wellarchitectedlabs.com/Security/200_Remote_Configuration_Installation_and_Viewing_CloudWatch_Logs/code/config.json
- 위 URL 접근 후 코드 복사
{
"agent": { // 에이전트 설정
"metrics_collection_interval": 60, // 메트릭 수집 간격 (초)
"run_as_user": "root" // 에이전트 실행 사용자
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
/* 수집할 로그 파일 목록.
각 항목은 파일 경로, 해당 로그가 속할 CloudWatch Logs 그룹 이름,
그리고 스트림 이름을 지정합니다. */
{
"file_path": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log",
"log_group_name": "securitylablogs",
"log_stream_name": "cw-agent-logs"
},
{
"file_path": "/var/log/httpd/access_log",
"log_group_name": "securitylablogs",
"log_stream_name":"apache-access-logs"
},
{
"file_path":"/var/log/httpd/error_log",
"log_group_name":"securitylablogs",
"log_stream_name":"apache-error-logs"
},
{
"file_path":"/var/log/boot.log",
"log_group_name":"securitylablogs",
log_stream_name:"instance-boot-logs"
},
{
file_path:"/var/log/secure",
log_group_name:"securitylablogs",
log_stream_name:"ssh-logs"
},
{
file_path:"/var/log/yum.log",
log_group_name:"securitylablogs",
log_stream_name:"yum-logs"
}
]
}
}
},
/* metrics 섹션에서는 어떤 시스템 메트릭을 수집할지 정의합니다. */
/* 여기서는 디스크 사용률 및 메모리 사용률을 수집하며,
이들은 각각 'disk'와 'mem' 섹션에서 정의됩니다.*/
/* 추가적으로 AutoScalingGroupName, ImageId, InstanceId, InstanceType와 같은 차원 정보를 추가합니다.*/
/* 이 차원 정보는 CloudWatch에서 메트릭 데이터를 필터링하거나 집계하는 데 사용됩니다. */
metrics: {
namespace : SecurityCWLab-Metrics,
append_dimensions: {
AutoScalingGroupName: "${aws:AutoScalingGroupName}",
ImageId: "${aws:ImageId}",
InstanceId: "${aws:InstanceId}",
InstanceType: "${aws:InstanceType}"
},
metrics_collected:{
disk:{
measurement:[
used_percent
],
metrics_collection_interval:60,
resources:[
"*"
]
},
mem:{
measurement:[
mem_used_percent
],
metrics_collection_interval:60
}
}
}
}
- 이
agent
섹션에서는 로그 에이전트를 실행할 사용자와 로그 수집 빈도를 지정합니다. - 이
logs
섹션에서는 모니터링할 로그 파일과 해당 로그를 저장할 로그 그룹 및 스트림을 지정합니다. 이 정보는 다음에서 확인할 수 있습니다.collect_list
- 이 실습에서는 SSH 로그, Apache 웹 서버 로그 및 CloudWatch 에이전트 자체에 대한 로그를 수집합니다. 이후 단계에서 이러한 로그를 더 자세히 검토하겠습니다.
- 그만큼
metrics
섹션에서는 수집되는 측정항목을 지정합니다(metrics_collected
), 수집 빈도, 측정 및 기타 세부 사항. - 구성 파일 생성에 대한 자세한 내용은 다음을 참조하세요.이 링크
- 파라미터 스토어에 추가된 파라미터 확인
- START THE CLOUDWATCH AGENT – 링크
- 목표 : 로그 수집을 시작하기 위해, 구성 파일을 로드하고 CloudWatch 에이전트를 다시 시작하자 ← Run Command
- System Manager → Run Command 메뉴 이동 – 링크 ⇒ 명령 실행 Run command 클릭
- 문서 이름 접두사 (같음) 선택 후 ‘AmazonCloudWatch-ManageAgent’ 입력 후 나오는 명령 선택 : 원격에서 EC2에 CW Agent에 명령 보냄
- 대상 : 수동으로 인스턴스 선택(배포된 EC2) → S3 버킷에 쓰기 활성화(Uncheck) ⇒ 맨 하단 실행
- 대상 및 출력에서 인스턴스 선택(배포된 EC2) 후 ‘출력 보기’ 선택 → 성공 확인
- 해당 EC2에서 확인
sh-4.2$ sudo systemctl status amazon-cloudwatch-agent
● amazon-cloudwatch-agent.service - Amazon CloudWatch Agent
Loaded: loaded (/etc/systemd/system/amazon-cloudwatch-agent.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2023-09-16 15:16:42 UTC; 1min 47s ago
Main PID: 4060 (amazon-cloudwat)
CGroup: /system.slice/amazon-cloudwatch-agent.service
└─4060 /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml -envconfig /opt/aws/amazon-cloudwatch-agent/etc/env-config.json -otelconfig /opt/aws/amazon-clo...
Sep 16 15:16:42 ip-10-0-0-237.ap-northeast-2.compute.internal systemd[1]: Started Amazon CloudWatch Agent.
Sep 16 15:16:42 ip-10-0-0-237.ap-northeast-2.compute.internal start-amazon-cloudwatch-agent[4060]: /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json does not exist or cannot read. Skipping it.
Sep 16 15:16:42 ip-10-0-0-237.ap-northeast-2.compute.internal start-amazon-cloudwatch-agent[4060]: I! Detecting run_as_user...
5. GENERATE LOGS – 링크
- 자신의 웹 사이트에 방문하여 웹 액세스 로그 생성 : 자신의 PC, CloudShell
- 반복 접속 및 /example 등 없는 URL도 접속 시도 해보기
while true; do curl -s <EC2 IP> ; sleep 5; date; done
6. VIEW YOUR CLOUDWATCH LOGS – 링크
- CW → 로그 그룹 : securitylablogs 클릭 – 링크 → 로그 스트림 이름 확인 ⇒ apache-access-logs 확인
- CW Live Tail 확인
- 자신의 PC 또는 CloudShell에서 EC2 웹 반복 접속 실행
- EXPORT LOGS TO S3 – 링크
- 목표 : 로그를 수집한 후 CloudWatch에서 S3 버킷으로 로그를 내보낼 수 있습니다. (버킷없으면 만들어주시고 접두어는 구분을 위하여 적어줍니다.)
- S3에 데이터를 저장하는 것이 CloudWatch에 저장하는 것보다 비용 효율적이고 안정적 ← 장기 저장 및 보관에 적합함
- CW 로그 그룹 : 작업 → Amazon S3로 데이터 내보내기
- 목표 : 로그를 수집한 후 CloudWatch에서 S3 버킷으로 로그를 내보낼 수 있습니다. (버킷없으면 만들어주시고 접두어는 구분을 위하여 적어줍니다.)
- 내보내기 상단 작업 목록 클릭 → 내보내기 태스트 정보 확인 ⇒ View in Amazon S3 클릭 후 확인
- QUERY LOGS FROM S3 USING ATHENA – 링크
- 이제 로그 데이터가 S3에 저장되면 서버리스 대화형 쿼리 서비스인 Amazon Athena를 활용하게 됩니다. 로그 파일에 대해 SQL 쿼리를 실행하여 로그 파일에서 정보를 추출합니다. 이 섹션에서는 Apache 액세스 로그에 중점을 두지만 Athena를 사용하여 모든 로그 파일을 쿼리할 수 있습니다.
- CloudWatch Insights에서 로그 데이터를 쿼리할 수 있지만 Athena 쿼리를 사용하면 S3에 저장된 파일뿐만 아니라 Insights가 CloudWatch의 데이터 쿼리만 허용하는 다른 소스에서도 데이터를 가져올 수 있습니다. Athena는 업계 표준 언어인 SQL 쿼리를 지원합니다.
- Athena → (쿼리 결과 위치 설정) 설정 편집 : s3://REPLACE_ME_BUCKETNAME/athenaqueries/
- 편집기
- 먼저 데이터베이스 생성 → 생성 후 오른쪽에 생성된 데이터베이스 선택
CREATE database security_lab_logs
- 클릭 후 퀴리2에서 아래 쿼리 실행 : 테이블 생성
CREATE EXTERNAL TABLE IF NOT EXISTS `security_lab_apache_access_logs` (
request_date string,
request_timestamp string,
request_ip string,
request_method string,
request string,
response_code int,
response_size int,
user_client_data string,
garbage string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "([^ ]*)T([^ ]*)Z ([^ ]*) (?:[^ ]* [^ ]*) (?:[^\"]*) \"([^ ]*) ([^\"]*)\" ([^ ]*) ([^ ]*) (?:\"[^\"]*\") (\"[^\"]*\")([^\n]*)"
)
LOCATION 's3://REPLACE_ME_BUCKET/lablogs/REPLACE_ME_STRING/apache-access-logs/'
TBLPROPERTIES (
'compressionType' = 'gzip'
);
- New Query → 아래 입력 후 쿼리 실행 후 결과 확인
SELECT * FROM security_lab_logs.security_lab_apache_access_logs limit 15
- New Query → 아래 입력 후 쿼리 실행 후 결과 확인 : 응답 코드와 카운트만 필터
SELECT response_code,
count(response_code) AS count
FROM security_lab_logs.security_lab_apache_access_logs
WHERE response_code IS NOT NULL
GROUP BY response_code
ORDER BY count desc
10. LAB TEARDOWN – 링크
- Deleting Athena database/table
- 테이블 삭제
- New 쿼리 창에서 아래 입력 후 실행 → 데이터베이스 삭제 확인
DROP database security_lab_logs
2. Deleting the Systems Manager stored parameter
- SSM → 파라미터 스토어 : 생성된 파라미터 선택 후 삭제
3. Deleting the S3 Bucket
aws s3 rm s3://$NICKNAME-ahss-4w-logs --recursive
aws s3 rb s3://$NICKNAME-ahss-4w-logs
4. Tearing down the CloudFormation stack : 스택 삭제
[실습] Level 300: Multilayered API Security with Cognito and WAF
- 배경 : API 보안은 이제 향상된 인식과 제품 기능 적용 범위로 인해 이점을 누리고 있지만 애플리케이션 리더는 비즈니스 요구 사항에 맞는 효과적인 API 보안 전략을 만들고 구현해야 합니다.
- API를 보호하는 효과적인 접근 방식의 예는 다음과 같습니다 → 제로 트러스트 : 승인된 요청만 애플리케이션의 비즈니스 계층에 액세스하도록 허용하는 전략입니다. 또한 아키텍처의 여러 계층에서 신뢰도를 평가하면 API 데이터가 워크로드를 통해 전송될 때 여러 검사를 수행할 수 있습니다.
- 보안 : Through the use of AWS Cognito, it is possible to create user pools which work with your API to obtain an identity access token for the user, which can then be used to enforce authorization controls in your API layer. However, not only can legitimate users potentially expose your organization to high risk, but also attacks can come with valid credential or token. To mitigate this risk, AWS Cognito enables you to configure how long your access token will be valid and the integration of Amazon WAF in conjunction with CloudFront will allow you to add another layer of API security to achieve a strong level of protection.
- Amazon API Gateway – Used for securing REST API.
- AWS Secrets Manager – Used to securely store secrets.
- Amazon CloudFront – Used to prevent direct access to API as well as to enforce encrypted end-to-end connections to origin.
- AWS WAF – Used to protect our API by filtering, monitoring, and blocking malicious traffic.
- Amazon Cognito – Used to enable access control for API
*실습은 North Virginia ‘us-east-1’ 버지니아 북부리전 에서 진행합니다
- 요청 흐름 : 외부 사용자 → API GW → Lambda(Secrets Manager – KMS) → RDS
- 유의 사항
- API 게이트웨이는 개인 서브넷(애플리케이션 계층)에 있는 람다 함수를 호출할 수 있도록 접근 허용 역할을 부여받았습니다.
- 람다 함수는 API 게이트웨이가 람다 함수를 호출할 수 있도록 허용하는 역할을 부여받았습니다.
- 시크릿 매니저가 마스터 비밀번호 저장소로 설정되어, 람다 함수가 RDS에 접근하려면 시크릿 매니저에서 비밀번호를 가져와야 합니다. 이렇게 하면 시크릿 매니저를 사용하여 비밀번호를 암호화하고 저장한 후 필요할 때 투명하게 복호화 할 수 있습니다.
- Amazon RDS for MySQL와 연결된 보안 그룹은 3306 포트에서 오는 인바운드 트래픽만 람다와 연결된 특정 보안 그룹으로부터 허용합니다. 이렇게 하면 람다가 Amazon RDS for MySQL에 충분히 접속하는데 필요한 접근 권한을 얻을 수 있습니다.
- S3 버킷 생성 및 Lambda deployment packages 업로드 해두기
# S3 버킷 생성
NICKNAME=gasida
aws s3 mb s3://$NICKNAME-walab --region us-east-1
# Lambda deployment packages 다운로드
wget https://d3h9zoi3eqyz7s.cloudfront.net/Security/300_multilayer_api_security_with_congnito_and_waf/rds-create-table.zip
wget https://d3h9zoi3eqyz7s.cloudfront.net/Security/300_multilayer_api_security_with_congnito_and_waf/rds-query.zip
wget https://d3h9zoi3eqyz7s.cloudfront.net/Security/300_multilayer_api_security_with_congnito_and_waf/python-requests-lambda-layer.zip
# S3 버킷에 업로드
aws s3 cp rds-create-table.zip s3://$NICKNAME-walab
aws s3 cp rds-query.zip s3://$NICKNAME-walab
aws s3 cp python-requests-lambda-layer.zip s3://$NICKNAME-walab
# 확인
aws s3 ls s3://$NICKNAME-walab --human-readable --summarize
==
2023-09-22 00:40:56 1.8 MiB python-requests-lambda-layer.zip
2023-09-22 00:40:48 1.1 MiB rds-create-table.zip
2023-09-22 00:40:53 105.6 KiB rds-query.zip
==
- AWS CloudFormation 템플릿 파일 다운로드 : section1-base.yaml
wget https://wellarchitectedlabs.com/Security/300_Multilayered_API_Security_with_Cognito_and_WAF/Code/templates/section1/section1-base.yaml
- AWS CloudFormation Stack 배포 : Name(walab-api)
- 배포 후 output 에 Cloud9URL 클릭 후 테스트 환경 진입
- cd walab-scripts 후 bash install_package.sh 실행(boto3, requests 설치)
#
aws sts get-caller-identity
aws s3 ls
# 버전 확인
python3 -V
pip3 --version
#
cd walab-scripts
cat install_package.sh
bash install_package.sh
pip3 list
- Confirm Successful Application Deployment 확인 : CF Output에 APIGatewayURL 복사(메모, 자주 사용 예정)
# In Cloud9, execute the script called sendRequest.py with the argument of your APIGatewayURL.
APIGatewayURL=https://9kbjn8il2l.execute-api.us-east-1.amazonaws.com/Dev/?id=1
python sendRequest.py $APIGatewayURL
==
Sending your request WITHOUT id token generated by Cognito.....
Response code: 200 , Response Data: ["My favorite player is Lionel Messi"]
==
- 혹은 웹 브라우저에서 위 주소 접속 확인 , 뒤에 id=2 , id=3 변경해서 확인해보자
- API GW → walab-api(Edge) 선택 ⇒ 리소스 선택 : GET 통합 요청 확인 (Lambda) , 그외 접속 URL도 확인
- API GW → wa-lab-rds-api(Regional) 선택 ⇒ 정보 확인, 접속 URL 확인 ← 위, APIGatewayURL 주소
- Lambda 확인 : 2개 – RDSCreateTable , RDSTest(Test Lambda function to access a RDS Database and read sample data)
ㄴ주황색: 프로비저닝(RDS 테이블 생성)
ㄴ파란색: 람다가 RDS 연결 (주로동작)
- RDSTest : 트리거 API GW 2개 확인, 권한 확인, RDS 접속을 위한 환경 변수, VPC내 배치
USE SECRETS SECURELY – 링크 ← 자동 교체를 위한 Lambda 배포에 5분 소요 : 제대로 동작하지 않아서 Skip 하였습니다. (여기선 설명만)
- 배경 : 비밀을 안전한 방법으로 저장하더라도 비밀번호는 무차별 대입 공격에 취약합니다. 따라서 배포된 아키텍처를 강화하여 자동 순환을 사용하여 비밀번호의 수명을 제한할 수 있습니다. 이 작업에 접근하는 이상적인 방법은 AWS Secrets Manager를 사용하는 것입니다. 이를 통해 다른 데이터베이스 또는 타사 서비스에 대한 암호를 자동으로 교체할 수 있습니다.
- Secret Manager → KMS 키를 통해 암/복호화 , 생성된 값 선택 : 보안 암호값 확인(메모)해보기 → 실습으로 아래 암호값이 변경됨
- Configure Password Rotation 실행
- AWS Secrets Manager can be configured to automatically rotate a password for an Amazon RDS database. When you enable rotation for Amazon RDS, Secrets Manager provides a complete, ready-to-run Lambda rotation function.
- 교체 편집 클릭 : 시간단위(최소 4h)
- CloudFormation 스택 생성 확인 : 자동 교체를 수행할 Lambda(Role) 생성됨 ⇒ 배포 완료 후 아래 진행
3. PREVENT REQUESTS FROM ACCESSING API DIRECTLY – 링크
- 설명 : CloudFront를 지역 API 엔드포인트와 통합하면 서비스가 여러 엣지 위치에 트래픽을 분산하여 성능을 향상시킬 뿐만 아니라 특정 지리적 위치의 요청이 처리되지 않도록 차단하는 데 사용할 수 있는 지역 차단도 지원합니다. Amazon CloudFront를 사용하면 HTTPS를 사용하여 오리진 API에 대한 암호화된 종단 간 연결을 적용할 수도 있습니다. 또한 CloudFront는 읽기 속도가 느리거나 쓰기 속도가 느린 공격자로부터 연결을 자동으로 닫을 수 있습니다. 그런 다음 API 게이트웨이는 다음 과 같이 구성할 수 있습니다.CloudFront의 요청만 수락합니다. 이렇게 하면 누구도 API Gateway 배포에 직접 액세스하지 못하도록 방지할 수 있습니다. 이 실습 섹션에서는 AWS Secrets Manager에서 생성된 CloudFront 사용자 지정 헤더 값을 다음과 함께 사용합니다
- 다운로드 : section3-enhance_security.yaml
wget https://wellarchitectedlabs.com/Security/300_Multilayered_API_Security_with_Cognito_and_WAF/Code/templates/section3/section3-enhance_security.yaml
- AWS CloudFormation Stack 배포 : Name(walab-cdn-waf-cognito), APIGatewayURL과 S3버킷명 기입
- 배포 확인(CF output): CloudFront(WAF, Origin-API_GW), WAF(2개, 1개는 API GW에 연동), Secret Manager(OriginVerifyHeader + 자동 교체 Lambda)
⇒ 이제부터 APIGatewayURL로 접속 불가!, 아래 설정 필요
- Add custom HTTP headers to the requests : 요청에 사용자 HTTP 헤더를 추가
- 스택 배포가 완료되면 이제 CloudFront의 요청에 사용자 지정 헤더를 추가할 수 있습니다. 앞서 설명한 대로 이렇게 하면 사용자가 CloudFront를 우회하여 API에 직접 액세스하는 것을 방지할 수 있습니다
- CF Output : OriginVerifyHeaderName 이 X-Origin-Verify 로 설정되어 있는지 확인하세요
- 이제 OriginVerifyHeader 값을 클릭하면 다음과 같이 AWS Secrets Manager로 진입
- AWS Secrets Manager에서 OriginVerifyHeader 비밀을 클릭하여 X-Origin-Verify 헤더 값을 가져오기
- 비밀 값 대화 상자에서 비밀 값 검색을 클릭합니다 . HEADERVALUE의 비밀 값을 기록합니다.
- 이 값을 CloudFront의 오리진 헤더 값 으로 사용하겠습니다
- 이제 Secrets Manager는 이 헤더 값을 자동으로 교체하여 이전 실습에서 암호 정보를 교체한 것과 동일한 방식으로 향후 손상 가능성을 방지.
- CloudFront → 원본 (편집) : 사용자 정의 헤더 추가 : X-Origin-Verify , 값은 위 Secret Manager값 붙여넣기 ⇒ 변경 사항 저장(3~5분 반영 시간 소요)
- WAF(API-GW) → 정책 확인 : 헤더와 값 매칭 확인
- 이제 최종 확인 : CF Output에 CloudFrontEndpoint 클릭해서 접속 확인, APIGatewayURL도 다시 접속 확인
⇒ WebACL에서 Sample Request 확인
XFF에 IP 2개의 의미는 무엇인가? 왼쪽은 클라이언트 오른쪽은 CF
→ X-Origin-Verify는 어느 구간에서 생성되고 체크하는 걸까? ⇒ 클라우드프런트가 부착(헤더) 해서 api 게이트웨이에 전송 → api 게이트웨이는 waf의 룰에 해당 헤더가 있어야 허용
- Cloud9 에서도 확인
# APIGatewayURL 시도
APIGatewayURL='https://p9pxds4mke.execute-api.us-east-1.amazonaws.com/Dev/?id=1'
python sendRequest.py $APIGatewayURL
# CloudFrontEndpoint 시도
CloudFrontEndpoint='https://d3ua9kogvj5qwi.cloudfront.net/?id=2'
python sendRequest.py $CloudFrontEndpoint
4. APPLICATION LAYER DEFENCE – 링크
- 목표 : SQL 주입, 분산 서비스 거부(DDoS) 및 기타 일반적인 공격과 같은 취약성의 위험을 완화하기 위해 AWS WAF를 사용하여 보안을 더욱 강화
- SQL Injection 공격 시도 : (TMI) Lab Authors – Jang Whan Han, Well-Architected Geo Solutions Architect.
# SQL Injection 공격 시도 : 모든 값이 다 출력
python sendRequest.py 'https://d3ua9kogvj5qwi.cloudfront.net/?id=1 or 1=1'
Sending your request WITHOUT id token generated by Cognito.....
Response code: 200 , Response Data: ["My favorite player is Lionel Messi","My favorite player is Cristiano Ronaldo","My favorite player is Son Heung-min"]
- CF Output WAFWebACLG 클릭(CF WAF) : resource(CF 확인), Rules → 관리형 그룹 추가(AWS 관리형) : SQL database
# SQL Injection 공격 시도 >> 어떻게 될까요?
python sendRequest.py 'https://d3ua9kogvj5qwi.cloudfront.net/?id=1 or 1=1'
...
확인
5. CONTROL ACCESS TO API – 링크
- 목표 : 식별된 사용자만 API에 액세스 허용 ← Amazon Cognito
- 사용자는 우리가 생성한 사용자 풀에 로그인하고 자격 증명 또는 액세스 토큰을 얻은 다음 토큰 중 하나로 API 메서드를 호출할 수 있습니다.
- 이러한 토큰은 일반적으로 요청의 Authorization 헤더로 설정됩니다.
- Sign up with Amazon Cognito user pools
- 이미 배포한 두 번째 CloudFormation 템플릿에는 Amazon Cognito 사용자 풀이 이미 포함되어 있습니다.
- Cognito의 앱 클라이언트 암호를 얻는 것부터 시작하겠습니다 . 이 암호는 랩의 후반부에서 ID 토큰을 생성하는 데 사용할 것입니다.
- Take note of App client secret. Other required values such as user pool ID and App client ID are available in the Output section of the current cloudformation stack.
- Create Cognito user pools as Authorizer in API Gateway Console
- API GW → wa-lab-rds-api 선택 : 리소스 → 메서드 요청 정보 확인 : 권한 부여 NONE
- 왼쪽 메뉴 ‘권한 부여자’ → ‘권한 부여자 생성’ : 이름(walab-authorizer), 유형(cognito), Cognito 사용자 풀, 토큰 소스(Authorization)
- 리소스 → GET → 메서드 요청 편집 : (새창) 권한 부여(walab-authorizer) → 저장
- 상단 API 배포 → 스테이지(Dev), 설명(WA Lab) ⇒ 배포
- 배포 완료 후 리소스에서 GET 하단에 권한 부여 부분 확인
- Add Authorization header in CloudFront
- 설명 : 기본적으로 CloudFront는 엣지 로케이션에서 객체를 캐싱할 때 헤더를 고려하지 않습니다. 이제 API에 액세스하려면 요청에 유효한 ID 토큰이 있는 Authorization 헤더가 있어야 합니다. 따라서 헤더를 API 게이트웨이로 전달하도록 CloudFront를 구성합니다
- CloudFront → 동작(편집) : 헤더 추가 → 변경 사항 저장
- CloudFront → 무효화 : /*
- Cognito 사용자 Sign up : CF output에 CognitoSignupURL 클릭 → 아래 Sign up 클릭 ⇒ 기입한 이메일로 확인
- Cognito 에 사용자 추가 확인
- Generate an ID Token and send a request with ID Token
- Cloud9 에서 먼저 그냥 요청 시도
# CloudFrontEndpoint 시도
CloudFrontEndpoint='https://d3ua9kogvj5qwi.cloudfront.net/?id=1'
python sendRequest.py $CloudFrontEndpoint
- 사용자 이름과 비밀번호, Cognito 사용자 풀 ID, 앱 클라이언트 ID 및 앱 비밀번호를 사용하여 ID 토큰을 생성해 보겠습니다.
- Cognito에 가입할 때 앱 클라이언트 비밀번호를 기록해 두었습니다 . 사용자 풀 ID, 앱 클라이언트 ID 등 기타 필수 값은 현재 cloudformation 스택의 출력 섹션 에서 확인할 수 있습니다.
- 위에서 생성한 ID 토큰으로 요청 보내서 확인 → CloudFront를 통해서 API에 액세스하려면 ID 토큰을 Authorization 헤더로 제공해야 합니다.
python sendRequest.py $CloudFrontEndpoint $IDT
6.TEAR DOWN – 링크
- walab-cdn-waf-cognito 스택 삭제
- aws-cloud9-walab-api-Cloud9-IDE… 스택 삭제 → 위 2개 스택 삭제 완료 시 walab-api 스택 삭제⇒ 30분이 지나도 삭제가 안될 경우 아래 잔여 리소스 수동 삭제
- RDS 인스턴스 삭제 → RDS 서브넷 그룹 삭제
- VPC에 NATGW 삭제 → VPC 람다 보안 그룹 삭제
- CloudWatch 로그 그룹 삭제
- S3 버킷 삭제
- 실습용 IAM User 삭제