본문 바로가기

개인공부

[AWS] 10. AWS 조직 및 계정 관리 — Organizations와 SCP

다계정 환경은 보안·비용·정책을 계정 단위로 격리하는 구조다.
Organizations로 여러 계정을 하나의 조직으로 묶고, SCP로 OU 전체에 권한 상한선을 강제한다.
이번 주차는 개념 → SCP 정책 → 콘솔 데모(조직 생성, SCP 적용, 태그 정책) 순서로 진행했다.


1. AWS 계정 개념

AWS 계정(account)은 AWS 리소스를 사용하는 고유한 논리 단위다. 12자리 숫자 ID로 식별된다.

  • 계정 생성 시 root user가 자동 생성되고, 그 아래 IAM User를 만든다
  • 결제, 보안, 리소스 격리가 계정 단위로 독립적으로 관리된다
  • 즉 한 계정에서 일어난 일은 그 계정 안에 갇힌다 — 이게 다계정 설계의 출발점이다

2. 다계정 환경 운영의 장점

강의에서는 단일 계정의 한계를 먼저 보여줬다. Engineering / Product 팀이 하나의 계정 안에서 Production VPC와 Development VPC를 Peering으로 묶어 쓰는 구조였다.

이 단일 계정 구조에서 터지는 문제:

  • 개발 코드 부하 테스트가 Production VPC를 느리게 만들고 throttling 에러 발생
  • 재무팀이 Prod와 Dev 비용을 구분하지 못함
  • 외부 계약업체가 Production VPC를 통해 고객 데이터에 접근 가능 — CEO가 우려

해결은 워크로드를 계정 단위로 쪼개는 것이다. 다계정 아키텍처의 장점:

항목 효과
보안 격리 운영 계정 접근 제한, 환경별 다른 보안 제어
비용 분리 계정별 청구서 확인, 태깅/Cost Explorer 분석
정책 유연성 OU 기반 SCP 일괄 적용
blast radius 최소화 사고를 한 계정에 국한

예시로 금융회사는 고객 데이터를 '보안 계정', 개발을 '테스트 계정'으로 분리하고, 스타트업은 비용 모니터링을 위해 '마케팅'·'개발' 계정을 따로 운용한다.

💡 실습 중 느낀 점

  • 단일 계정에서 VPC만 나눠 격리하는 방식은 네트워크 격리지 권한·비용 격리가 아니다. Peering으로 연결된 순간 IAM 권한만 있으면 옆 VPC 리소스에 접근 가능하다는 게 핵심 한계로 와닿았다.
  • "외부 계약업체가 Production에 접근 가능"이라는 시나리오가 현실적이다. IAM 정책을 아무리 촘촘히 짜도 같은 계정 안이면 휴먼 에러 한 번에 뚫린다. 계정 경계 자체가 가장 강한 격리라는 걸 다시 확인했다.
  • blast radius라는 표현이 인상적이었다. 리소스 격리를 "사고 시 피해 범위를 어디까지 가둘 것인가"의 관점으로 보면 계정 분리의 명분이 명확해진다.

3. AWS Organizations 구조

여러 AWS 계정을 조직적으로 관리하는 서비스다. 계층 구조는 Root → OU → 계정.

조직 (Organization)
└─ 관리 계정 (Management Account)
   ├─ OU-A
   │  ├─ 계정 1
   │  └─ 계정 2
   └─ OU-B
      ├─ 계정 3
      └─ 계정 4

핵심 구성요소

  • Root: 최상위 노드. 모든 OU와 계정을 포함하는 컨테이너. Root에 SCP를 적용하면 모든 OU·멤버 계정에 적용되지만 관리 계정에는 적용되지 않는다
  • OU (Organizational Unit): 계정을 그룹화하는 단위. OU 안에 하위 OU를 둬서 세분화 가능. OU별로 SCP 적용
  • 계정 (Account): 실제 리소스를 쓰는 단위. 관리 계정과 멤버 계정으로 구분
    • 관리 계정: 조직을 생성한 계정. 조직의 최종 소유자로 모든 요금 지불 책임. SCP 미적용
    • 멤버 계정: OU 정책을 적용받는 계정

통합 결제 (Consolidated Billing)

여러 계정의 비용을 관리 계정 한 곳에서 통합 관리한다.

  • 볼륨 할인: 여러 계정 사용량을 합산해 더 큰 할인
  • 청구서 단일화
  • 계정별 비용 분석 (태깅 / Cost Explorer)

조직 정책(Policies) 종류

정책 유형 설명 활용 예시
SCP (Service Control Policy) 서비스/액션 허용·차단 제어 특정 계정 EC2 생성 차단
RCP (Resource Control Policy) 리소스 접근 중앙 제한 조직 외부 접근 차단
Backup Policy 계정별 백업 계획 중앙 관리 공통 백업 주기·보존 정책
Tag Policy 태그 일관성 보장 CostCenter 태그 강제
Management Policy 기능/보안 구성 중앙 통제 S3 퍼블릭 접근 제한 강제

💡 실습 중 느낀 점

  • 관리 계정에는 SCP가 적용되지 않는다는 점이 설계 핵심이다. 그래서 관리 계정에 실제 워크로드를 올리면 안 된다 — 가드레일이 안 걸리는 계정이라 사고 시 통제 불능이 된다. AWS가 "관리 계정은 비워두라"고 권하는 이유가 여기 있다.
  • Root에 SCP를 걸면 모든 멤버 계정에 내려가지만 관리 계정은 예외라는 비대칭이 처음엔 헷갈렸다. 계층도에서 관리 계정이 Root 바로 아래 별도로 그려진 이유가 이것 때문이다.
  • 통합 결제의 볼륨 할인은 실무에서 무시 못 한다. 계정을 쪼개도 사용량은 조직 전체로 합산되니 "계정 분리 = 할인 손해" 걱정은 안 해도 된다.

4. SCP (Service Control Policy)

OU 또는 개별 계정에 대해 허용 가능한 AWS 작업의 상한선을 정의하는 정책이다.

가장 중요한 성질: SCP는 권한을 부여하지 않는다. 허용 가능한 범위를 '제한'하는 가드레일일 뿐이다. 실제 권한 부여는 IAM이 한다.

동작 방식

  • OU나 계정에 부여되면 그 하위 모든 계정·사용자에게 적용
  • 기본 거부 모델: SCP에서 명시적으로 허용되지 않은 권한은 거부
  • 상위 SCP에서 허용한 것만 하위에서 허용 가능 (Deny가 우선)

SCP 평가 예시

  • 예시 1: Root / Production OU / 계정 B 모두 SCP에 Allow → 계정 B에서 액션 허용
  • 예시 2: Root·계정 B는 Allow지만 Production OU SCP에 Deny → 상위 경로 중 한 곳이라도 Deny면 최종 거부

즉 SCP는 경로상 모든 레벨에서 허용돼야 통과한다. 한 곳이라도 막으면 끝이다.

SCP 정책 예시

특정 리전만 허용 (Frankfurt 외 차단):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": "*",
    "Resource": "*",
    "Condition": {
      "StringNotLike": {
        "aws:RequestedRegion": "eu-central-1"
      }
    }
  }]
}

EC2 인스턴스 타입 제한 (t2.micro만 허용):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": "ec2:RunInstances",
    "Resource": ["arn:aws:ec2:*:*:instance/*"],
    "Condition": {
      "StringNotEquals": { "ec2:InstanceType": "t2.micro" }
    }
  }]
}

EBS 기본 암호화 비활성화 방지:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": ["ec2:DisableEbsEncryptionByDefault"],
    "Resource": "*"
  }]
}

실제 사례 1 — Frankfurt 리전만 쓰는 금융사 운영 OU

규제 때문에 운영(Prod)은 무조건 Frankfurt(eu-central-1)만 써야 하는데, 콘솔 실수로 서울/버지니아에 생성하는 사고가 반복됐다. 운영 OU에 "허용 리전 화이트리스트" SCP를 걸되, 글로벌 서비스는 NotAction으로 예외 처리했다.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyActionsOutsideFrankfurt",
    "Effect": "Deny",
    "NotAction": [
      "iam:*", "organizations:*", "route53:*", "cloudfront:*",
      "globalaccelerator:*", "support:*", "budgets:*", "waf:*", "wafv2:*"
    ],
    "Resource": "*",
    "Condition": {
      "StringNotEquals": { "aws:RequestedRegion": "eu-central-1" }
    }
  }]
}

교훈: 콘솔/CLI 어디서 실수해도 리전 차단이 걸린다. 글로벌 서비스(IAM, Route53 등)는 특정 리전에 묶이지 않으므로 NotAction에 넣어 막힘을 방지. 예외 목록은 팀별로 꼭 커스터마이징해야 한다.

실제 사례 2 — Sandbox OU "비용 폭주" 방지

교육/실험용 계정에서 누가 r5.24xlarge를 띄워 하루 새 비용이 폭증한 적이 있었다. Sandbox OU에 EC2 인스턴스 타입을 allow-list로 제한.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyRunInstancesIfNotAllowedTypes",
    "Effect": "Deny",
    "Action": "ec2:RunInstances",
    "Resource": "*",
    "Condition": {
      "StringNotEquals": {
        "ec2:InstanceType": ["t3.micro", "t3.small"]
      }
    }
  }]
}

실제 사례 3 — MFA 없으면 위험 작업 금지

운영 계정에서 MFA 없이 콘솔 접속해 보안그룹을 잘못 오픈하는 사고가 반복됐다. "MFA 미사용 시 민감 작업 Deny"를 적용.

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": "*", "Resource": "*" },
    {
      "Sid": "DenySensitiveWithoutMFA",
      "Effect": "Deny",
      "Action": [
        "iam:Create*", "iam:Update*", "iam:Delete*",
        "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress",
        "kms:DisableKey", "kms:ScheduleKeyDeletion",
        "rds:DeleteDBInstance", "s3:PutBucketAcl", "s3:PutBucketPolicy"
      ],
      "Resource": "*",
      "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "false" } }
    }
  ]
}

교훈: "MFA 없으면 안 되는 일"을 명확히 정해두면 보안사고 대부분이 전초 단계에서 차단된다. root는 비상용 하드웨어 MFA + 금고 보관 + 접근 절차 문서화.

SCP 설계 시 유의점

  • 테스트 환경에서 먼저 실험 — 잘못된 SCP는 중요 작업을 중단시킬 수 있다
  • OU/계정/정책 이름을 일관되게 관리
  • 관리 계정은 SCP 적용 제외 대상임을 항상 인지

💡 실습 중 느낀 점

  • SCP가 권한을 주는 게 아니라 빼앗기만 한다는 게 IAM과 가장 헷갈리는 지점이었다. SCP에 Allow를 써도 그건 "이만큼까지는 허용해도 된다"는 천장이지, 실제 부여가 아니다. 부여는 IAM 몫이라 둘이 교집합으로 동작한다.
  • NotAction을 Deny와 조합한 화이트리스트 패턴이 강력하다. "나열한 것 빼고 전부 막아라"가 한 줄로 표현된다. 다만 글로벌 서비스를 빼먹으면 IAM·Route53까지 막혀서 콘솔이 먹통 되는 사고로 이어질 수 있어 예외 목록 관리가 진짜 중요하다.
  • 리전 제한 SCP에서 StringNotLike vs StringNotEquals 차이가 미묘하다. 와일드카드를 쓸 거면 Like 계열, 정확히 일치만 볼 거면 Equals 계열. 강의 예시는 단일 리전이라 둘 다 동작하지만 다중 리전 패턴 매칭이 필요하면 구분해야 한다.
  • "Deny가 우선, 경로상 한 곳이라도 막으면 끝"이라는 평가 모델은 IAM의 explicit deny와 같은 직관이다. 다만 SCP는 OU 계층을 타고 내려오므로, 상위 OU에서 무심코 건 Deny가 하위 전체를 막을 수 있다는 게 더 무섭다.

5. SCP vs IAM 정책

구분 SCP IAM 정책
적용 범위 OU, 계정 전체 사용자, 그룹, 역할
역할 허용 권한의 상한선 정의 세부 작업 권한 부여
기본값 FullAWSAccess 없음 (명시 필요)
실행 시점 API 요청이 서비스로 전달되기 API 요청이 서비스에 도달했을 때
평가 방식 Deny 우선, 범위 제한 Allow/Deny로 구체적 제어

최종 허용 = SCP 허용 ∩ IAM 허용. 두 조건이 모두 충족돼야 실행된다.

정책 적용 순서:

  1. SCP에서 허용되는지 먼저 확인
  2. IAM 정책에서 허용 여부 확인
  3. 둘 다 허용일 때만 실행

핵심: SCP가 차단한 권한은 IAM 정책으로도 복구 불가. 천장을 IAM으로 뚫을 수는 없다.

💡 실습 중 느낀 점

  • "SCP는 요청 전, IAM은 요청 도달 시 평가"라는 실행 시점 차이가 머릿속 모델을 정리해줬다. SCP는 게이트(문), IAM은 그 안의 자물쇠다. 문이 닫혀 있으면 자물쇠 열쇠가 있어도 못 들어간다.
  • 기본값 차이가 실무적으로 중요하다. SCP는 기본 FullAWSAccess(전부 허용)라서 SCP를 안 걸면 IAM만으로 통제된다. 반면 IAM은 기본 거부라 명시 안 하면 아무것도 안 된다. 두 레이어의 default가 반대라는 걸 알아야 디버깅이 된다.
  • 권한 문제로 Access Denied가 떴을 때, IAM만 보면 답이 안 나오는 경우가 SCP 때문일 수 있다는 걸 배웠다. 다계정 환경 트러블슈팅은 두 레이어를 같이 봐야 한다.

6. 콘솔 데모 — SCP 적용

데모 절차

1) 관리 계정 — SCP·OU 생성

  • Organizations 콘솔 > 정책 > SCP
    • SCP 생성: Frankfurt(eu-central-1) 리전만 허용 (이름: Allow-Only-Frankfurt)
    • SCP 생성: t3.micro만 허용 (이름: Allow-Only-t3.micro)
  • Organizations 콘솔 > AWS 계정
    • OU 생성: Sandbox-OU
    • OU 생성: Dev-OU
    • 멤버 계정을 Sandbox-OU에 추가

📸 [스크린샷: SCP 정책 목록 — Allow-Only-Frankfurt, Allow-Only-t3.micro 생성됨]

📸 [스크린샷: Sandbox-OU / Dev-OU 생성 후 계층 구조]

2) 관리 계정 — SCP를 OU에 연결

  • Allow-Only-t3.microSandbox-OU에 적용
  • Allow-Only-FrankfurtDev-OU에 적용

📸 [스크린샷: Sandbox-OU에 SCP 연결된 상태]

3) 멤버 계정 — Sandbox-OU 상태에서 검증

  • t3.micro EC2 생성 → 정상 작동
  • t3.micro 외 타입 EC2 생성 → Access Denied

📸 [스크린샷: t3.micro 인스턴스 생성 성공]

📸 [스크린샷: t3.large 등 생성 시도 시 Access Denied 에러 메시지]

4) 관리 계정 — 계정을 Dev-OU로 이동

5) 멤버 계정 — Dev-OU 상태에서 검증

  • 서울 리전에 EC2 생성 → Access Denied
  • Frankfurt(eu-central-1)에 EC2 생성 → 정상 작동

📸 [스크린샷: 서울 리전 생성 시 Access Denied]

📸 [스크린샷: Frankfurt 리전 생성 성공]

💡 실습 중 느낀 점

  • 계정을 OU 사이에서 이동시키니 적용되는 SCP가 즉시 바뀌었다. Sandbox-OU에선 인스턴스 타입이 막히다가 Dev-OU로 옮기니 리전이 막힌다. SCP가 계정에 직접 붙는 게 아니라 OU 소속으로 결정된다는 걸 몸으로 확인했다. 계정 이동 한 번이 권한 전체를 갈아끼우는 셈이라 운영 중 이동은 신중해야 한다.
  • Access Denied 메시지만으로는 IAM 때문인지 SCP 때문인지 구분이 안 된다. 같은 작업이 OU 이동 후 풀리거나 막히는 걸 보고 나서야 "아 이건 SCP구나"를 역추적했다. 실무라면 CloudTrail로 explicit deny 출처를 봐야 할 듯하다.
  • 리전 제한 SCP는 콘솔 우측 상단 리전을 바꾸는 것만으로 결과가 갈린다. CLI라면 --region 플래그 하나 차이다. 가드레일이 "사용자가 어디서 요청했는가(aws:RequestedRegion)"를 보기 때문에, 콘솔이든 CLI든 SDK든 동일하게 막힌다는 게 SCP의 강점이다.

7. 콘솔 데모 — 태그 정책 적용

데모 절차

1) 관리 계정

  • Organizations 콘솔 > 정책 > 태그 정책 > 활성화
  • 태그 정책 생성 (이름: RequireProjectTag, 태그 키: Project)
  • 태그 정책을 Dev-OU에 추가

📸 [스크린샷: 태그 정책 RequireProjectTag 생성 — 태그 키 Project]

2) 멤버 계정

  • Frankfurt 리전에 EC2 인스턴스 생성 (태그 없이)
  • → 생성은 되지만 Tag Policy 리포트에서 누락(non-compliant)으로 표시

3) 관리 계정

  • Resource Explorer > 태그 정책 > 규정 준수 보고서 (최소 24시간 후 생성)

📸 [스크린샷: 아직 보고서가 생성되지 않음...]

💡 실습 중 느낀 점

  • 태그 정책은 SCP와 동작 방식이 근본적으로 다르다. SCP는 위반 작업을 차단(Deny)하지만, 태그 정책은 막지 않고 리포트에만 표시한다. 태그 없이도 인스턴스가 멀쩡히 생성됐다. "강제"가 아니라 "감사(audit)" 도구에 가깝다.
  • 진짜 태그를 강제하려면 태그 정책만으론 부족하고 SCP의 aws:RequestTag 조건을 같이 써야 한다는 걸 알게 됐다. 태그 정책 = 표준 정의 + 컴플라이언스 리포팅, SCP = 실제 차단. 역할 분담이 명확하다.
  • 규정 준수 보고서가 최소 24시간 후 생성된다는 점이 실습 흐름에선 답답했다. 즉시 확인이 안 되니 데모 당일엔 "non-compliant로 잡힐 것이다"까지만 확인하고 넘어갔다. 실시간 검증이 필요하면 AWS Config rule을 쓰는 게 맞는 방향으로 보인다.

학습 정리

  • AWS Organizations는 여러 계정을 하나의 조직으로 묶어 Root → OU → 계정 계층으로 중앙 관리한다
  • 다계정 분리는 보안·비용·blast radius를 계정 경계로 격리하는 가장 강력한 수단이다
  • 관리 계정에는 SCP가 적용되지 않으므로 실제 워크로드를 올리면 안 된다
  • SCP는 권한을 부여하지 않고 상한선만 제한한다. 실제 권한은 IAM이 부여하고, 최종 허용은 둘의 교집합이다
  • SCP는 OU 소속으로 결정되므로 계정을 OU 간 이동하면 적용 정책이 즉시 바뀐다
  • SCP가 차단한 권한은 IAM으로 복구 불가 — 천장은 못 뚫는다
  • 태그 정책은 차단이 아니라 컴플라이언스 리포팅 도구다. 강제하려면 SCP를 병행해야 한다
  • 잘못된 SCP는 운영을 마비시킬 수 있으니 테스트 환경에서 먼저 검증한다

다음 시간에는 AWS의 네트워크/컴퓨팅 서비스를 더 깊게 다뤄보겠다.