보안 기본 — MFA, 키 회전, 최소 권한
루트와 IAM 사용자 MFA 강제, 액세스 키 회전 자동화, IAM Access Analyzer로 권한 점검, 최소 권한 패턴, 그리고 자주 만나는 사고 사례까지 — 운영에서 통하는 보안 가드레일을 정리합니다.
2장 IAM에서 권한 모델을, 5장 CloudShell과 SSO에서 SSO 로그인까지 봤습니다. 본 챕터는 그 위에 운영에서 통하는 보안 가드레일을 한 번에 정리합니다. 가입 직후 반드시 거쳐야 할 첫 셋업의 마지막 축입니다.
AWS 보안 사고의 90%는 다음 중 하나입니다. 루트나 사용자 비밀번호가 피싱으로 탈취되는 경우(MFA가 없어서), 액세스 키가 git / 슬랙 / 로그에 노출되는 경우, 너무 넓은 권한이 침해 시 피해를 키우는 경우, 그리고 CloudTrail / GuardDuty가 꺼져 있어 사건을 못 발견하는 경우입니다.
이 네 가지에 가드레일을 깔면 사고 확률이 한 자릿수로 떨어집니다. 본 챕터는 그 가드레일을 차례로 세웁니다.
MFA — 가장 중요한 한 가지 #
비밀번호 한 줄로 끝나는 인증은 2026년의 운영 수준이 아닙니다. 피싱 한 번이면 비밀번호는 흘러갑니다. **MFA (Multi-Factor Authentication)**는 두 번째 요소(보통 휴대폰 앱)의 6 자리 코드를 추가로 요구합니다.
MFA 종류 #
| 종류 | 무엇 | 추천 |
|---|---|---|
| Virtual MFA (TOTP) | 휴대폰 앱 (Google Authenticator, 1Password, Authy) | 표준 — 거의 모든 경우 |
| 하드웨어 MFA | YubiKey 같은 USB 키 | 루트 / 고특권 — 최강 |
| U2F / WebAuthn | 브라우저 + 하드웨어 키 | 운영 자격 격상 |
| SMS | 문자 메시지 | 사용 금지 (SIM swap 공격) |
루트는 하드웨어 MFA가 이상적이고, 일반 사용자는 virtual MFA로 충분합니다.
루트 사용자 MFA 활성화 #
가입 직후 첫 작업으로 즉시 합니다.
콘솔 (루트 로그인) → 우측 상단 사용자 메뉴 → Security credentials
→ Multi-factor authentication (MFA) → Assign MFA device
→ Virtual MFA / Hardware MFA 선택
→ QR 코드를 휴대폰 앱으로 스캔
→ 연속 두 코드 입력 (앱이 30 초마다 새 코드)이후 루트 로그인 때마다 비밀번호 + 6 자리 코드를 요구합니다.
IAM 사용자에 MFA 강제 #
루트만 켜는 것은 부족합니다. 모든 IAM 사용자에 강제해야 합니다. 두 가지 방법이 있습니다.
방법 1: 정책으로 — “MFA가 켜진 세션이 아니면 거의 모든 액션 거부"입니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSelfManageCredentials",
"Effect": "Allow",
"Action": [
"iam:ChangePassword",
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ResyncMFADevice"
],
"Resource": [
"arn:aws:iam::*:user/${aws:username}",
"arn:aws:iam::*:mfa/${aws:username}"
]
},
{
"Sid": "DenyAllExceptListedIfNoMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ResyncMFADevice",
"iam:ChangePassword",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
}
}
]
}이 정책을 모든 사용자가 속한 그룹에 붙이면 MFA 없이는 사실상 아무것도 못 합니다. MFA 등록만 예외입니다.
방법 2: SSO — 5장 CloudShell과 SSO의 IAM Identity Center 사용자에는 콘솔 / CLI 로그인 시 MFA가 자동 강제됩니다. 정책을 따로 짜지 않아도 됩니다.
첫 로그인 시 MFA 등록 강제 흐름 #
신규 IAM 사용자가 처음 로그인하면, 위 정책으로 MFA 등록 외엔 아무것도 못 합니다. 자기 MFA를 등록하면 그 다음부터 정상 사용합니다. 이 흐름이 표준입니다.
액세스 키 회전 — 90일이 표준 #
4장 CLI와 SDK에서 본 액세스 키는 시간이 지나면 노출 위험이 누적됩니다.
회전 정책 #
| 항목 | 권장 회전 주기 |
|---|---|
| 사용자 액세스 키 | 90일 |
| CI / CD 키 | 60일 (또는 OIDC로 전환) |
| 서비스 계정 키 | 30~60일 |
| 임시 자격 (SSO / Role) | 회전 불필요 (자동으로 단기 발급) |
회전 절차 #
키를 한 번에 두 개까지 가질 수 있는 IAM의 특성을 활용합니다.
# 1) 새 키 발급 (이제 활성 키 2 개)
aws iam create-access-key --user-name curtis
# 2) 모든 환경에서 새 키로 교체 (CI 환경 변수, ~/.aws/credentials, etc.)
# 3) 며칠 모니터링 — 옛 키 사용이 있는지
# CloudTrail 또는 IAM credential report로 확인
# 4) 옛 키 비활성화 (삭제는 아직 X — 롤백용)
aws iam update-access-key --user-name curtis --access-key-id AKIA-OLD --status Inactive
# 5) 일주일 더 모니터링 → 정말 안 쓰면 삭제
aws iam delete-access-key --user-name curtis --access-key-id AKIA-OLDIAM Credential Report — 회전 점검 #
CSV 한 장으로 모든 사용자의 키 / MFA / 활동 상태를 봅니다.
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d > report.csvuser
mfa_active
access_key_1_active
access_key_1_last_rotated
access_key_1_last_used_date
access_key_2_active
access_key_2_last_rotated
password_last_used90일 넘은 키, MFA 안 켠 사용자, 한 달 미사용 사용자가 한눈에 보입니다.
노출된 키 발견 시 #
코드에 키를 push 했다면, 봇이 발견하기까지 보통 분 단위입니다.
즉시 해야 할 일 (시간 순) #
aws iam update-access-key --user-name <user> --access-key-id <키ID> --status Inactiveaws iam create-access-key --user-name <user># 콘솔 → CloudTrail → Event history
# AccessKeyId로 검색 → 의도하지 않은 사용 있는지aws iam delete-access-key --user-name <user> --access-key-id <키ID># BFG Repo-Cleaner 또는 git filter-repo로 history에서 키 제거
# (이미 push 됐다면 history 청소만으론 안전 X — 키 삭제가 더 중요)AWS가 자동으로 도와주는 도구 #
AWS는 GitHub 등 공개 저장소를 스캔해 노출 키를 발견하면 사용자에게 즉시 이메일을 보내고, 일부 경우 자동으로 키를 비활성화하고 정책을 첨부합니다. 다만 이건 보조 안전망입니다. 직접 발견이 더 빠릅니다.
IAM Access Analyzer — 너무 넓은 권한 찾기 #
내 계정의 정책과 자원 정책(S3 버킷 정책, KMS 키 정책 등)을 분석해 외부 접근이 가능한 부분을 찾는 도구입니다. 무료입니다.
활성화 #
콘솔 → IAM → Access Analyzer → Create analyzer
- Type: Account / Organization
- Name: my-account-analyzer활성화 후 24시간 안에 외부 접근 가능 자원의 목록이 나옵니다.
무엇을 잡아 주는가 #
| 자원 | 위험 |
|---|---|
| S3 버킷 — public read | 누구나 객체 읽기 |
| S3 버킷 — 다른 계정에 권한 | 의도한 설정인지 확인 필요 |
| KMS 키 — 외부 사용 | 암호화 키 노출 |
| IAM Role — 외부 trust | 다른 계정이 빌릴 수 있음 |
| Lambda — 외부 호출 권한 | 누구나 호출 가능 |
| RDS 스냅샷 / SQS / SNS / Secrets Manager / EBS / ECR — public | 데이터 / 메시지 노출 |
정책 검증 #
새 정책을 만들 때 Access Analyzer가 권장 사항도 보여줍니다. 사용 안 하는 권한, 너무 넓은 와일드카드, 조건 없는 경우의 추가 권장 등입니다.
Action Last Accessed — 미사용 권한 찾기 #
각 IAM 사용자 / 역할에 대해 마지막으로 사용한 액션을 보여 줍니다. 90일 미사용 권한은 좁힐 후보입니다.
aws iam generate-service-last-accessed-details --arn arn:aws:iam::123:role/MyRole
# (잠시 후)
aws iam get-service-last-accessed-details --job-id ...최소 권한 — 통하는 패턴 #
“필요한 만큼만, 필요한 곳에만.” 이상은 쉬운데 운영에서 어떻게 실천하는지가 문제입니다.
패턴 1: 넓게 시작 → 좁히기 #
처음부터 완벽한 권한을 짜기는 어렵습니다. 다음 흐름이 현실적입니다.
- 시작은
PowerUserAccess/ 서비스의*FullAccess. - 일주일 운영 후 Access Analyzer의 Action Last Accessed 확인.
- 안 쓰는 서비스 / 액션 제거.
- 와일드카드를 ARN으로 좁힘.
- 조건(Condition) 추가.
이 사이클을 분기마다 반복합니다.
패턴 2: 사용자 ↔ 역할 분리 #
2장 IAM의 패턴을 재확인합니다.
- 사람은 SSO 로(5장 CloudShell과 SSO).
- 머신은 Role 로(인스턴스 프로파일, 실행 역할, OIDC).
- CI/CD는 OIDC + Role 로(GitHub Actions, GitLab).
영구 액세스 키가 거의 사라지는 구조입니다.
패턴 3: 권한 경계 (Permission Boundary) #
“이 사용자는 무엇을 하든 이 한도 안에서만.” 신입 개발자에게 IAM 권한을 주되, 그가 새 정책이나 사용자를 만들어 자기 권한을 늘리는 사고를 차단합니다.
{
"Effect": "Allow",
"Action": [
"ec2:*",
"s3:*",
"rds:*",
"logs:*"
],
"Resource": "*",
"Condition": {
"StringEquals": { "aws:RequestTag/env": "dev" }
}
}이 경계가 붙은 사용자는 자기 정책으로도 dev 환경 자원 외엔 만들 수 없습니다.
패턴 4: 환경 분리 #
- 계정 분리(Organizations) — 가장 강한 방어선이며 29장 보안 거버넌스에서 다룹니다.
- VPC 분리 — 같은 계정이라도 prod VPC와 dev VPC를 분리합니다(8장 EC2와 VPC).
- 태그 분리 —
env=prod태그로 권한과 비용을 분리합니다(3장 비용 관리의 태그 전략).
패턴 5: Break-glass 역할 #
평소엔 ReadOnly만, 사고 시에 잠시 Admin으로 격상합니다. SSO Permission Set을 두 개로 분리합니다.
| 항목 | 평소 | 사고 시 |
|---|---|---|
| 사용 | ReadOnly | Break-glass-Admin (1시간) |
| 알림 | — | Slack 채널에 자동 알림 |
| 감사 | — | CloudTrail로 모든 액션 기록 |
CloudTrail — 누가 무엇을 했는가 #
CloudTrail은 계정 안의 모든 API 호출을 기록합니다. 가입 직후 자동으로 활성화되어 지난 90일 이벤트를 무료로 조회할 수 있습니다. 운영용은 Trail을 만들어 S3에 영구 저장합니다.
가입 직후 점검 #
콘솔 → CloudTrail → Trails
→ Multi-region Trail 한 개 만들기 (운영 표준)
- 이름: my-trail
- Storage: 새 S3 버킷
- Log file SSE-KMS encryption: 켜기
- Log file validation: 켜기 (변조 감지)CloudTrail의 두 종류 이벤트 #
| 종류 | 무엇 | 비용 |
|---|---|---|
| Management events | API 호출 (RunInstances, DeleteBucket 등) | 무료 (한 번) |
| Data events | S3 객체 접근, Lambda 호출 등 | 유료 (양 많음) |
대부분의 Trail은 management만 켭니다. data events는 특정 버킷 / 함수에만 켭니다.
자주 쓰는 쿼리 #
콘솔 Event history에서 검색합니다.
- AccessKeyId — 노출 키 사용 흔적
- UserName — 한 사용자가 한 일
- EventName —
ConsoleLogin,DeleteBucket,RunInstances - 시간 범위
CloudTrail Lake 또는 Athena로 SQL 분석도 가능합니다(큰 조직).
GuardDuty — 위협 탐지 자동화 #
GuardDuty는 CloudTrail / VPC Flow Logs / DNS 로그를 머신러닝으로 분석해 의심스러운 활동을 잡아 줍니다.
잡아 주는 예 #
| 패턴 | 설명 |
|---|---|
| EC2가 비정상 지역에서 통신 | 침입 / C&C |
| 액세스 키가 비정상 지역에서 사용 | 키 노출 후 사용 |
| Cryptocurrency 채굴 트래픽 | 침입 후 채굴 |
| EC2의 비정상 포트 스캔 | 측면 이동 |
| Tor exit node와의 통신 | 의심 트래픽 |
| IAM 사용자의 비정상 행동 | 자격 도용 |
활성화 #
콘솔 → GuardDuty → Get started → Enable
- 30 일 무료 평가
- 무료 평가 후 데이터 양 기반 과금 (보통 \$10~50 / 월 / 작은 운영)운영 단계에서는 반드시 켭니다. 가격 대비 잡아 주는 사고가 큽니다.
Security Hub — 보안 상태 통합 #
여러 보안 도구의 결과를 한곳에 모읍니다. CIS Benchmark, AWS Foundational Security Best Practices 등 표준 점검을 자동 실행합니다.
콘솔 → Security Hub → Enable
- 권장 표준 모두 켜기
- GuardDuty / Access Analyzer / Inspector 결과가 통합됨가입 직후엔 살짝 과합니다. 한 분기 후 자원이 일정 수준 이상이 되면 켭니다.
자주 만나는 사고 사례 #
사례 1: GitHub에 액세스 키 push → 가상화폐 채굴 #
가장 흔한 시나리오입니다. 분 단위로 봇이 발견하고, 시간 단위로 비용이 누적됩니다.
대응 — 즉시 키 비활성화 → 새 키 → CloudTrail로 사용 흔적 → 가능하면 계정 자체 격리. 청구 분쟁 시 AWS 지원에 연락하면 대부분 무료 티어 사고는 소급 면제됩니다(반복은 안 됨).
예방 — pre-commit hook(gitleaks, truffleHog), GitHub secret scanning, 로컬에 키 자체를 안 두기(SSO).
사례 2: 너무 넓은 S3 버킷 정책 #
“우리 회사 사람들이 다 볼 수 있게” 하려고 Principal: "*"를 추가하면 public read가 되어 검색 엔진에 인덱싱됩니다.
대응 — Access Analyzer가 잡아 줍니다. S3 Block Public Access가 계정 / 버킷 단위로 강제합니다.
예방 — S3 Block Public Access 항상 켜기, 정말 public이 필요한 경우는 CloudFront + Origin Access Control 패턴.
사례 3: MFA 없는 루트 비밀번호 피싱 #
“AWS 결제 알림” 가짜 메일 → 가짜 로그인 페이지 → 비밀번호 입력. 루트 MFA가 없으면 그대로 침해됩니다.
대응 — 비밀번호 즉시 변경, 모든 자원 점검, AWS 지원 연락.
예방 — 루트 MFA 필수(이상적으로 하드웨어), 일상 작업은 IAM / SSO로.
사례 4: 퇴사자의 액세스 키가 살아 있음 #
퇴사 처리 후에도 IAM 사용자 / 키가 그대로 남아 몇 달 뒤 사고가 납니다.
대응 — 즉시 사용자 비활성화 / 삭제 + Trail 점검.
예방 — 퇴사 체크리스트에 IAM 정리 포함. SSO 면 IdP에서 비활성화하면 끝입니다.
사례 5: CloudTrail이 꺼짐 #
침해 조사를 시작하려는데 사건 시점의 로그가 없습니다. 누군가 의도적으로 Trail을 껐거나 처음부터 안 켰던 경우입니다.
대응 — 이미 늦었습니다. 가능한 다른 로그(CloudWatch, GuardDuty findings)로 부분 복원합니다.
예방 — Trail 활성화 + Log file validation + S3 객체 잠금. SCP(Service Control Policy)로 CloudTrail 비활성화 자체를 거부합니다.
자주 만나는 함정 #
- MFA만 켜고 끝 — MFA가 켜져 있어도 액세스 키가 노출되면 키는 그대로 작동합니다(CLI 호출은 MFA와 무관, 4장의 자격 체인). 키도 같이 신경 쓰거나 SSO로 키 자체를 줄입니다.
- 회전을 약속만 하고 안 함 — Credential Report로 정기 점검을 자동화합니다. 90일 넘은 키는 Slack 알림으로 보냅니다.
iam:PassRole의 광범위 허용 —iam:PassRole = *은 사실상 권한 상승이 가능합니다. 역할 ARN으로 좁힙니다.- 조건을 너무 강하게 → 본인이 잠김 —
aws:SourceIp로 회사 IP만 허용했는데 본인이 외출 중인 경우입니다. 콘솔 IP 가드는 마지막에 두고, 우회 통로(VPN / 비상 사용자)를 둡니다. - GuardDuty 끄기 — “비용 아까워서” 끄는 경우, 한 사건이 GuardDuty 1년 비용보다 큽니다. 운영에서는 항상 켭니다.
- Security Hub 발견을 안 봄 — 켜고 알림을 안 보면 의미가 없습니다. 주간 리뷰 또는 EventBridge로 Slack 알림을 보냅니다.
연습문제 #
- §“MFA — 가장 중요한 한 가지"의 표를 근거로, 루트와 일반 사용자에 각각 어떤 MFA 종류를 쓰고 왜 SMS를 금지하는지 한 단락으로 적어 보세요.
- §“액세스 키 회전"의 5단계 절차를 보지 않고 적어 보세요. 4단계에서 옛 키를 바로 삭제하지 않고 비활성화만 하는 이유를 4장의 자격 체인과 연결해 설명해 두세요.
- §“최소 권한 — 통하는 패턴"의 다섯 패턴 중 하나를 골라, 그것이 §“자주 만나는 사고 사례"의 어느 사례를 막아 주는지 짝지어 보세요.
한 줄 요약: AWS 보안 사고의 거의 전부는 MFA 부재 · 키 노출 · 과도한 권한 · 로깅 부재에서 나온다. 모든 사용자에 MFA를 강제하고, 액세스 키는 90일마다 회전하며, IAM Access Analyzer로 넓은 권한을 좁히고, 사람은 SSO · 머신은 Role로 영구 키를 줄인다. CloudTrail · GuardDuty를 켜 두면 사고를 늦지 않게 발견한다.
다음 챕터 #
여기까지가 가입 직후의 셋업입니다. 다음 7장 CloudWatch 입문에서는 모든 운영의 눈인 CloudWatch를 정리합니다. Logs / Metrics / Alarms / Dashboards의 구성, 로그 그룹과 retention, Metric Filter, Logs Insights 쿼리 기초까지 다룹니다.