Entra ID 자동화 #4 조건부 액세스: 정책을 코드로 관리하기

5 분 소요

계정과 그룹이 “누가 무엇에 속하는가"라면, 조건부 액세스(Conditional Access)는 그 로그인을 지금 이 상황에서 허용할 것인가를 정하는 층입니다. P1 라이선스 기능이고, 실질적으로 조직의 제로 트러스트 정책이 구현되는 곳입니다. 이번 편은 개념 정리와 함께, 정책을 포털 클릭이 아니라 코드로 관리하는 방법을 다룹니다.

구조: 정책은 if-then 문입니다 #

조건부 액세스 정책 하나는 두 부분으로 이루어집니다.

  • 할당(if): 누가(사용자·그룹), 무엇에(앱), 어떤 조건에서(위치, 디바이스 상태, 플랫폼, 로그인 위험도)
  • 제어(then): 차단하거나, 조건을 붙여 허용하거나(MFA 요구, 규격 디바이스 요구, 세션 제한)

로그인마다 해당되는 모든 정책이 평가되고, 적용 대상 정책의 요구 사항을 전부 만족해야 접근이 허용됩니다. 정책 A가 MFA를, 정책 B가 규격 디바이스를 요구하면 둘 다 충족해야 합니다. 이 “전부 AND” 특성 때문에 정책이 늘수록 상호작용이 복잡해지고, 그래서 뒤에서 다룰 테스트 절차가 중요해집니다.

전형적인 기본 정책 세트는 이렇습니다. 전 사용자 MFA 요구(레거시 인증 차단 포함), 관리자에게 피싱 저항 인증 요구, 미등록 디바이스에서의 다운로드 제한. 참고로 Microsoft가 테넌트에 관리형 정책(Microsoft-managed policies)을 report-only 상태로 자동 배포하고 일정 기간(최소 45일) 뒤 활성화하는 체계도 운영 중이므로, 우리 테넌트에 어떤 관리형 정책이 와 있는지 파악하는 것도 관리 업무의 일부입니다.

Graph API로 정책 다루기 #

정책은 Graph의 /identity/conditionalAccess/policies 리소스입니다. 조회, 생성, 수정, 삭제 전부 API로 됩니다.

정책 API 요청
GET https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies

POST https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies
Content-Type: application/json

{
  "displayName": "CA002: 전 사용자 MFA 요구",
  "state": "enabledForReportingButNotEnforced",
  "conditions": {
    "users": {
      "includeUsers": ["All"],
      "excludeUsers": ["<비상 계정 objectId>"]
    },
    "applications": { "includeApplications": ["All"] }
  },
  "grantControls": {
    "operator": "OR",
    "builtInControls": ["mfa"]
  }
}

state 값이 세 가지라는 것이 핵심입니다. enabled, disabled, 그리고 enabledForReportingButNotEnforced(report-only). 정책 운영의 안전장치가 이 세 번째 상태에 들어 있습니다.

policy-as-code: 클릭 대신 리뷰와 배포 #

정책을 API로 다룰 수 있다는 것은 곧 코드로 관리할 수 있다는 뜻입니다. 실무 구성은 이렇습니다.

  1. 정책 정의를 JSON 파일로 저장소에 둡니다. 정책 하나가 파일 하나, 명명 규칙(번호 + 목적)을 파일명과 displayName에 함께 적용합니다.
  2. 변경은 PR로 갑니다. “게스트 MFA 예외 추가” 같은 변경이 diff로 보이고, 보안 담당자의 리뷰를 거칩니다. 포털 클릭에는 없는 감사 가능성입니다.
  3. CI가 배포합니다. 병합되면 파이프라인이 Graph API로 실제 테넌트에 반영합니다. Terraform의 Entra 프로바이더로 같은 흐름을 만들 수도 있습니다.
  4. 드리프트를 감시합니다. 누군가 포털에서 직접 고친 정책과 저장소 정의의 차이를 주기적으로 비교해 알립니다. 코드가 진실이 되려면 드리프트 감지가 반드시 따라와야 합니다.

이 구성의 가치는 감사와 롤백입니다. “이 정책이 언제 왜 바뀌었나"가 git 히스토리로 남고, 잘못된 변경은 revert 한 번으로 되돌립니다.

report-only: 정책 사고를 막는 유일한 절차 #

조건부 액세스의 사고는 파급이 큽니다. 조건을 잘못 잡으면 전 직원이 로그인을 못 하는 상황이 됩니다. 그래서 새 정책과 큰 변경에는 고정된 절차가 있습니다.

  1. report-only 상태로 배포합니다. 정책이 평가는 되지만 강제되지 않고, 로그인 로그에 “이 정책이 켜져 있었다면 어떤 결과였을지"가 기록됩니다.
  2. 영향을 확인합니다. 로그인 로그의 report-only 탭과 인사이트 워크북에서, 의도한 대상에게 의도한 결과가 나오는지, 의도하지 않은 차단이 없는지 봅니다. What If 도구(및 평가 API)로 특정 사용자·시나리오의 결과를 시뮬레이션할 수도 있습니다.
  3. 기간을 두고 관찰한 뒤 enabled로 전환합니다. 트래픽 패턴이 다른 요일까지 포함해서 보는 것이 안전합니다.

policy-as-code와 결합하면, “새 정책 PR은 state가 report-only여야만 병합 가능, enabled 전환은 별도 PR"이라는 규칙을 파이프라인에서 강제할 수 있습니다.

비상 계정: 모든 정책의 예외 #

비상 접근 계정(break-glass account)은 조건부 액세스 사고 시 잠기지 않고 들어갈 수 있는 최후의 관리자 계정입니다. 원칙은 명확합니다.

  • 클라우드 전용 계정 두 개 이상, 강력한 자격 증명(가능하면 피싱 저항 방식)으로 만들어 물리적으로 안전하게 보관합니다.
  • 모든 조건부 액세스 정책의 excludeUsers에 넣습니다. policy-as-code라면 이 제외가 모든 정책 파일에 들어 있는지를 CI 테스트로 검사할 수 있습니다. 코드 관리의 또 하나의 이점입니다.
  • 이 계정의 로그인에는 즉시 알림을 겁니다. 쓰일 일이 없어야 정상인 계정이므로, 로그인 자체가 사건입니다.

하나 더, 실수 방지 장치로 삭제 복원을 알아 두면 좋습니다. 조건부 액세스 정책은 삭제 후 30일간 복원 가능한 소프트 삭제입니다. 자동화 스크립트가 정책을 잘못 지웠더라도 되돌릴 창이 있습니다.

정리 #

  • 조건부 액세스는 로그인마다 평가되는 if-then 정책의 집합이고, 적용되는 정책의 요구를 전부 만족해야 접근이 허용됩니다.
  • 정책은 /identity/conditionalAccess/policies로 완전히 CRUD 가능하므로, JSON + PR 리뷰 + CI 배포 + 드리프트 감지의 policy-as-code로 관리할 수 있습니다.
  • 새 정책은 반드시 report-only로 배포해 로그로 영향을 확인한 뒤 활성화합니다. 이 절차를 파이프라인 규칙으로 강제할 수 있습니다.
  • 비상 계정은 모든 정책에서 제외하고, 그 제외 여부를 CI로 검사하며, 로그인 시 즉시 알림을 겁니다.
  • 정책 삭제는 30일 소프트 삭제라 복원 창이 있습니다. 다음 편은 마지막으로, 상시 관리자 권한을 없애는 PIM과 감사 자동화입니다.
X