목차
6 장

보안 기본 — 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)표준 — 거의 모든 경우
하드웨어 MFAYubiKey 같은 USB 키루트 / 고특권 — 최강
U2F / WebAuthn브라우저 + 하드웨어 키운영 자격 격상
SMS문자 메시지사용 금지 (SIM swap 공격)

루트는 하드웨어 MFA가 이상적이고, 일반 사용자는 virtual MFA로 충분합니다.

루트 사용자 MFA 활성화 #

가입 직후 첫 작업으로 즉시 합니다.

루트 MFA
콘솔 (루트 로그인) → 우측 상단 사용자 메뉴 → Security credentials
→ Multi-factor authentication (MFA) → Assign MFA device
→ Virtual MFA / Hardware MFA 선택
→ QR 코드를 휴대폰 앱으로 스캔
→ 연속 두 코드 입력 (앱이 30 초마다 새 코드)

이후 루트 로그인 때마다 비밀번호 + 6 자리 코드를 요구합니다.

IAM 사용자에 MFA 강제 #

루트만 켜는 것은 부족합니다. 모든 IAM 사용자에 강제해야 합니다. 두 가지 방법이 있습니다.

방법 1: 정책으로 — “MFA가 켜진 세션이 아니면 거의 모든 액션 거부"입니다.

IAM 사용자 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: SSO5장 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-OLD

IAM Credential Report — 회전 점검 #

CSV 한 장으로 모든 사용자의 키 / MFA / 활동 상태를 봅니다.

Credential Report 받기
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d > report.csv
report.csv의 흥미로운 컬럼
user
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_used

90일 넘은 키, MFA 안 켠 사용자, 한 달 미사용 사용자가 한눈에 보입니다.

노출된 키 발견 시 #

코드에 키를 push 했다면, 봇이 발견하기까지 보통 분 단위입니다.

즉시 해야 할 일 (시간 순) #

0분 — 키 비활성화
aws iam update-access-key --user-name <user> --access-key-id <키ID> --status Inactive
5분 — 새 키 발급, 옛 키는 그대로 비활성
aws iam create-access-key --user-name <user>
10분 — 옛 키 사용 흔적 확인 (CloudTrail)
# 콘솔 → CloudTrail → Event history
# AccessKeyId로 검색 → 의도하지 않은 사용 있는지
30분 — 옛 키 삭제
aws iam delete-access-key --user-name <user> --access-key-id <키ID>
git history 청소
# 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일 미사용 권한은 좁힐 후보입니다.

CLI에서
aws iam generate-service-last-accessed-details --arn arn:aws:iam::123:role/MyRole
# (잠시 후)
aws iam get-service-last-accessed-details --job-id ...

최소 권한 — 통하는 패턴 #

“필요한 만큼만, 필요한 곳에만.” 이상은 쉬운데 운영에서 어떻게 실천하는지가 문제입니다.

패턴 1: 넓게 시작 → 좁히기 #

처음부터 완벽한 권한을 짜기는 어렵습니다. 다음 흐름이 현실적입니다.

  1. 시작은 PowerUserAccess / 서비스의 *FullAccess.
  2. 일주일 운영 후 Access Analyzer의 Action Last Accessed 확인.
  3. 안 쓰는 서비스 / 액션 제거.
  4. 와일드카드를 ARN으로 좁힘.
  5. 조건(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을 두 개로 분리합니다.

항목평소사고 시
사용ReadOnlyBreak-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 eventsAPI 호출 (RunInstances, DeleteBucket 등)무료 (한 번)
Data eventsS3 객체 접근, 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 알림을 보냅니다.

연습문제 #

  1. §“MFA — 가장 중요한 한 가지"의 표를 근거로, 루트와 일반 사용자에 각각 어떤 MFA 종류를 쓰고 왜 SMS를 금지하는지 한 단락으로 적어 보세요.
  2. §“액세스 키 회전"의 5단계 절차를 보지 않고 적어 보세요. 4단계에서 옛 키를 바로 삭제하지 않고 비활성화만 하는 이유를 4장의 자격 체인과 연결해 설명해 두세요.
  3. §“최소 권한 — 통하는 패턴"의 다섯 패턴 중 하나를 골라, 그것이 §“자주 만나는 사고 사례"의 어느 사례를 막아 주는지 짝지어 보세요.

한 줄 요약: AWS 보안 사고의 거의 전부는 MFA 부재 · 키 노출 · 과도한 권한 · 로깅 부재에서 나온다. 모든 사용자에 MFA를 강제하고, 액세스 키는 90일마다 회전하며, IAM Access Analyzer로 넓은 권한을 좁히고, 사람은 SSO · 머신은 Role로 영구 키를 줄인다. CloudTrail · GuardDuty를 켜 두면 사고를 늦지 않게 발견한다.

다음 챕터 #

여기까지가 가입 직후의 셋업입니다. 다음 7장 CloudWatch 입문에서는 모든 운영의 눈인 CloudWatch를 정리합니다. Logs / Metrics / Alarms / Dashboards의 구성, 로그 그룹과 retention, Metric Filter, Logs Insights 쿼리 기초까지 다룹니다.

X