NHI Top 10을 IAM Role 타입별로 다시 읽기 — ADFS/IAM 엔지니어의 실무 가이드
OWASP가 2024년 말 공개한 Non-Human Identities Top 10 (2025)은 비인간 식별자 보안의 좋은 출발점이다. 그런데 막상 실무에서 들고 펴보면 한 가지 불편함이 있다 — 위협 타입 순(NHI1 Improper Offboarding → NHI10 Human Use of NHI)으로 나열되어 있어서, “지금 내가 관리하는 이 Role에 어떤 위험이 우선인가” 로 바로 매핑이 안 된다.
엔터프라이즈 IAM 실무는 Role 단위로 굴러간다. 같은 NHI 위험이라도 AD 표준 서비스 계정에서 다루는 방식과 클라우드 IAM Role에서 다루는 방식은 완전히 다르고, 어떤 위험은 Role 타입을 바꾸기만 해도 자동으로 사라진다. 이 글은 5년간 ADFS와 AD 서비스 계정을 운영하면서 보아온 관점에서, NHI Top 10을 8개의 Role 타입별로 재배치한다.
글의 전제: Microsoft는 ADFS의 신규 기능 개발을 사실상 멈추고 Microsoft Entra ID로의 마이그레이션을 공식 권장하고 있다. AWS·Azure·GCP의 클라우드 IAM이 신규 워크로드의 표준 경로라는 것도 분명한 사실이다. 그럼에도 이 글이 ADFS와 AD 서비스 계정을 비중 있게 다루는 이유는 — 국내 대기업·금융권·공공 부문의 상당수가 여전히 온프레미스 IdP를 현역으로 운영 중이고, 그 환경에서 NHI 위험은 지금 당장 다뤄야 할 문제이기 때문이다. 글 후반의 Cloud IAM Role · OIDC Federation · SPIFFE 섹션이 사실상의 마이그레이션 경로 역할을 한다. 사장되는 흐름을 알면서도 현역 운영 책임이 있는 엔지니어를 1차 독자로 상정한다.
왜 Role-based로 봐야 하는가
세 가지 이유다.
첫째, 자동 완화 효과 때문이다. 예를 들어 NHI10(Human Use of NHI) — 관리자가 서비스 계정으로 콘솔 로그인 — 은 표준 AD 서비스 계정에서는 거의 막을 수 없는 위험이지만, gMSA로 바꾸면 AD가 비밀번호를 사람에게 절대 알려주지 않기 때문에 위험 자체가 사라진다. Role 타입을 알면 어떤 위험은 통제로 막을 게 아니라 마이그레이션으로 없앨 수 있다는 판단이 선다.
둘째, 위험의 우선순위가 Role마다 다르다. ADFS Application Group의 client_secret과 클라우드 IAM Role은 둘 다 NHI지만, 전자는 시크릿 유출(NHI2) 이 가장 큰 위협이고 후자는 과대권한(NHI5) 이 가장 큰 위협이다. 10개 위험을 동일 우선순위로 보면 자원 배분이 산만해진다.
셋째, 마이그레이션 사다리가 보인다. Legacy SA → gMSA → Managed Identity → Federation으로 한 칸씩 옮길 때마다 어떤 NHI 위험이 자동 완화되고 어떤 위험이 새로 부각되는지 — 이게 보이면 NHI Top 10이 “외울 체크리스트”가 아니라 “내 환경의 성숙도 진단표”가 된다.
Role 타입별 NHI 위험 매핑
1. AD 표준 서비스 계정 (Legacy Service Account)
비밀번호 기반으로 사람이 만들고 사람이 관리하는 전통적인 서비스 계정. SQL Server, IIS App Pool, 스케줄러 등 온프레미스 워크로드에서 여전히 가장 흔하다.
가장 큰 위험은 NHI10, NHI7, NHI1. 비밀번호를 사람이 알고 있으므로 관리자가 콘솔 로그인에 그대로 사용한다(NHI10). 비밀번호 회전이 운영 부담 때문에 사실상 멈춰 있다(NHI7). 운영 인계 과정에서 자격증명이 흘러 다니다가 퇴직자에게 남는다(NHI1). 게다가 도메인에 따라 NTLM 인증이 여전히 활성화되어 있다면 NHI4(Insecure Authentication)까지 추가된다.
통제 핵심: 가능하면 gMSA 또는 Managed Identity로 마이그레이션이 최우선이다. 불가피한 경우에는 비밀번호 회전을 PowerShell로 자동화하고, 관리자 사용은 PAM(예: LAPS, CyberArk) 너머에서만 가능하도록 격리한다. ADFS 자체를 표준 SA로 운영하면 token-signing 인증서까지 같은 계정에 묶이는 구조라 분리가 필수다.
2. gMSA (Group Managed Service Account)
AD가 비밀번호를 자동으로 회전(기본 30일)하고, 사람은 비밀번호 자체를 모르게 만든 계정.1 Windows Server 2016 이후 ADFS에서 권장되는 서비스 계정 유형이기도 하다.
자동 완화되는 위험: NHI10, NHI7. 비밀번호를 사람이 모르므로 수동 로그인 자체가 불가능하다 — NHI10이 구조적으로 차단된다. 회전이 자동이므로 NHI7도 함께 해결된다.
잔여 위험: NHI5, NHI9, NHI1. 그룹 권한이 누적되면 과대권한 문제(NHI5)는 여전하고, 한 gMSA를 여러 서비스에 묶으면 NHI9(Reuse)가 발생한다. 퇴직 직원의 머신이 PrincipalsAllowedToRetrieveManagedPassword에 남아 있으면 NHI1도 잔존한다.
통제 핵심: PrincipalsAllowedToRetrieveManagedPassword 화이트리스트를 가능한 좁게 유지하고, 서비스 1개당 gMSA 1개 원칙을 지킨다. 도입 요건은 Windows Server 2012 이상 DC 1대 + KDS Root Key 사전 생성(기본 10시간 전파 대기) + 서비스의 gMSA 지원 여부.2 도메인·포레스트 기능 수준은 명시적 요구는 아니지만 모든 기기에서 일관되게 지원하려면 권장된다.
3. ADFS Application Group / Server Application (OAuth client_credentials)
ADFS에 등록된 OAuth 2.0 / OIDC 클라이언트 애플리케이션. 온프레미스 IdP 운영자라면 가장 자주 다루는 NHI 형태다.
가장 큰 위험은 NHI2, NHI4, NHI6. client_secret이 설정 파일·환경변수에 평문으로 남기 쉽다(NHI2). 레거시 WS-Trust / WS-Fed가 혼용되면 NHI4가 추가된다. Redirect URI 검증이 느슨하거나 sub/aud 클레임 검증을 안 하면 NHI6 영역으로 들어간다.
통제 핵심: client_secret을 인증서 기반 클라이언트 인증(Set-AdfsServerApplication -JWTSigningCertificate)으로 대체, Redirect URI 정확 매칭, JWT의 aud 및 iss 클레임을 RP 쪽에서 반드시 검증한다. Secret 회전은 Set-AdfsServerApplication -ChangeClientSecret(또는 -ResetClientSecret)로 가능하므로 PowerShell 자동화로 분기별 회전 파이프라인을 구성해두면 NHI7까지 같이 잡힌다.3
4. Cloud IAM Role / Managed Identity
클라우드 플랫폼이 워크로드에 임시 자격증명(STS 스타일 단기 토큰)을 자동 발급하는 방식. 정적 시크릿이 구조적으로 없다.
자동 완화: NHI2, NHI7. 저장할 시크릿이 없으므로 유출될 게 없고, 토큰은 짧은 TTL로 자동 만료된다.
잔여 위험: NHI5, NHI8, NHI3. 와일드카드 Resource나 AllAccess급 광범위 정책은 여전히 흔하고(NHI5), dev/prod에 같은 Role을 재사용하면 NHI8이 발생하며, 3rd party 벤더(SaaS·옵저버빌리티 도구)에 부여한 Role의 Trust Policy가 느슨하면 NHI3 공급망 위험이 들어온다.
통제 핵심: 클라우드 IAM에 내장된 사용 분석 도구로 unused permission을 정기적으로 식별해 권한을 깎고, Trust Policy에 ExternalId·Source IP·VPC endpoint 같은 Condition을 걸어 신뢰 범위를 좁힌다. 3rd party AssumeRole에는 ExternalId 강제가 사실상 필수다.
5. Kubernetes ServiceAccount
파드가 K8s API 서버에 인증할 때 사용하는 네이티브 ID.
가장 큰 위험은 NHI9, NHI5. 네임스페이스의 default ServiceAccount를 여러 파드가 공유하는 패턴이 너무 흔하다(NHI9). 운영 편의를 위해 cluster-admin RoleBinding을 SA에 직접 묶어버리는 경우(NHI5)도 적지 않다.
잔여 위험: NHI7, NHI3. 클러스터 외부 사용을 위해 SA 토큰을 Secret으로 추출하면 무한 유효 토큰이 만들어진다(NHI7). RBAC가 느슨하면 서드파티 컨트롤러가 광범위 권한을 갖는다(NHI3).
통제 핵심: 파드별 dedicated SA, automountServiceAccountToken: false를 기본값으로 두고 필요한 파드만 명시적으로 활성화, BoundServiceAccountTokenVolume(projected token, TTL 1시간)을 강제.4 default SA에는 어떤 RoleBinding도 붙이지 않는다.
6. OIDC Workload Identity Federation (GitHub Actions → Cloud)
외부 워크로드(GitHub Actions, GitLab CI, Argo CD 등)가 자신의 OIDC 토큰을 발급하고, 클라우드 측이 Trust Policy로 그 토큰을 검증해 임시 자격증명을 발급하는 방식.
자동 완화: NHI7, NHI2. 저장할 정적 시크릿이 완전히 없다. CI/CD에서 가장 큰 시크릿 유출 경로가 사라진다.
잔여 위험: NHI6, NHI4. Trust Policy의 sub 클레임 조건이 느슨하면 다른 레포·다른 브랜치에서도 같은 Role을 가져갈 수 있다(NHI6). 마이그레이션 중에 기존 PAT(Personal Access Token)와 병행하면 그쪽이 약한 고리가 된다(NHI4).
통제 핵심: 클라우드 IAM 신뢰 정책의 sub 컨디션을 repo:myorg/myrepo:ref:refs/heads/main처럼 정확 매칭으로 묶고, aud는 클라우드 공급자가 요구하는 고정 값으로 매칭, 와일드카드는 절대 금지.5 환경(dev/prod)별로 별도 Role을 분리해 NHI8까지 함께 해결한다.
2026년 4월 변경 사항: GitHub는 신규 레포지토리의 기본
sub클레임에 변경 불가능한(immutable) owner/repo ID를 추가하는 방식으로 포맷을 바꿨다(예:repo:octocat-123456/my-repo-456789:ref:refs/heads/main). 레포·조직 이름 재활용으로 인한 신뢰 탈취를 막기 위한 조치다. 기존 레포는 영향이 없으나, 신규 인프라 구축 시에는 immutable 포맷을 전제로 신뢰 정책을 작성해야 한다.6
7. SPIFFE / SPIRE
워크로드 attestation(노드·프로세스·K8s 메타데이터 등으로 워크로드 신원 자동 확인)을 거쳐 단기 X.509 SVID 또는 JWT-SVID를 자동 발급하는 표준.7 멀티 클라우드·하이브리드 환경에서 워크로드 ID 통합 레이어로 떠오르고 있다.
자동 완화: NHI2, NHI7, NHI4. SVID는 분 단위 TTL로 자동 갱신되므로 저장·회전 문제 자체가 없다. mTLS가 기본이라 약한 인증 방식이 끼어들 여지가 없다.
잔여 위험: NHI5, NHI3. SPIFFE ID에 부여된 인가 정책(OPA·Authzed·Cerbos 등 외부 정책 엔진과 연동)이 와일드카드면 과대권한이 그대로 재현된다(NHI5). SPIRE 서버 자체가 워크로드 PKI의 root of trust이므로, SPIRE 서버가 침해되면 전체 신원이 무너진다(NHI3 관점).
통제 핵심: ADFS PKI 운영 경험이 거의 그대로 적용된다 — SPIRE는 결국 워크로드용 미니 CA다. SPIRE 서버 격리·HSM 기반 키 보호·attestation 정책 엄격 정의가 핵심이고, 발급 정책에서 SPIFFE ID 네이밍 규약을 환경·서비스 단위로 구분해 NHI8/NHI9까지 함께 해결한다.
8. HashiCorp Vault Dynamic Secrets
요청 시점에 단기 자격증명을 동적으로 발급하는 방식. DB credentials, AWS STS, PKI 인증서, SSH 키 모두 같은 패턴으로 다룬다.
자동 완화: NHI2, NHI7. 발급된 자격증명은 TTL 기반으로 Vault가 자동 회수(revoke)한다. 시크릿이 “어딘가 저장된 상태”로 존재하는 시간 자체가 짧다.
잔여 위험: NHI4, NHI5. Vault 자체에 워크로드가 인증하는 방식이 약하면(예: 평문 token) 도미노로 무너진다(NHI4). Vault policy의 path 매칭이 와일드카드면 동적 발급되는 자격증명도 광범위해진다(NHI5).
통제 핵심: Vault 인증은 AppRole + Response Wrapping을 권장, secret_id TTL을 짧게(분 단위), policy는 path를 정확 매칭으로 작성.8 한 가지 흥미로운 연결점은 — Vault의 JWT/OIDC Auth는 ADFS를 ID Provider로 받을 수 있다. 기존 ADFS 인프라가 Vault의 사용자 인증 레이어로 그대로 재사용 가능하다는 뜻이다.
마이그레이션 사다리
8개 Role 타입을 추상화하면 다음과 같은 4단계 사다리로 정리된다.
Stage 1: Legacy SA Stage 2: gMSA Stage 3: Managed ID Stage 4: Federation / SPIFFE
│ │ │ │
├ NHI1, 4, 7, 10 ├ NHI5, 9, 1 ├ NHI5, 8, 3 ├ NHI6, 4 (잔여만)
│ 모두 활성 ├ NHI10, 7 완화 ├ NHI2, 7 완화 ├ NHI2, 7, 4 완화
│ │ (자동 회전) │ (정적 시크릿 없음) │ (정적 시크릿 자체 부재)
│ │ │ │
비밀번호 기반 AD가 비밀번호 관리 클라우드가 토큰 발급 외부 IdP가 attestation
핵심 통찰은 단순하다 — 한 단계 위로 올라가면 통제로 막던 위험 1~2개가 구조적으로 사라진다. Legacy SA에서 gMSA로 올리면 NHI10·NHI7이 통제 항목에서 빠지고, Managed Identity로 더 올리면 NHI2·NHI7이 추가로 빠진다. Federation/SPIFFE까지 가면 NHI4까지 정리된다.
물론 모든 워크로드를 4단계까지 끌어올릴 필요는 없고 — 비용·복잡도·기존 호환성 트레이드오프가 있다. 다만 “이 워크로드가 지금 Stage 몇에 있는가” 를 명시적으로 진단하면, 어떤 NHI 위험에 인력을 투입할지 판단이 훨씬 명확해진다. NHI Top 10을 Role 타입 사다리에 얹어 읽으면, 그게 보인다.
마무리
OWASP NHI Top 10을 위협 타입 순으로 외우는 건 자격증 시험을 위해서라면 충분하다. 하지만 실제 IAM 운영자에게는 Role 타입별 진단표가 더 쓸모 있다 — 같은 NHI5라도 AD 표준 SA에 붙은 NHI5와 Kubernetes SA에 붙은 NHI5는 통제 방법이 완전히 다르고, gMSA로 올리는 순간 NHI10은 더 이상 통제 대상이 아니라 해결된 문제가 된다.
다음 편에서는 이 사다리 위에 AI 에이전트라는 새 워크로드 유형을 얹는다 — OWASP가 2025년 말 발표한 Top 10 for Agentic Applications (2026)이 NHI Top 10과 어떻게 맞물리는지, 그리고 그 매핑이 권한 인식 RAG 같은 아키텍처로 어떻게 풀리는지 다룰 예정이다.
라이선스 및 출처
본 글의 NHI1~10 정의, 시나리오, 통계는 OWASP Non-Human Identities Top 10 (2025) 프로젝트를 참고했으며, 해당 프로젝트는 Creative Commons Attribution-ShareAlike 4.0 라이선스를 따른다. 본 글의 OWASP 인용 부분 역시 동일 라이선스(CC BY-SA 4.0)로 재배포된다. Role 타입별 매핑·통제 패턴·마이그레이션 사다리는 필자의 ADFS/IAM 실무 경험에 기반한 해석으로, OWASP 원문에 포함된 내용이 아니다.
본문의 기술적 사실(cmdlet 시그니처, 속성명, 기본값, 토큰 TTL, 표준 명칭 등)은 아래 1차 공식 문서로 교차 검증했다(최종 확인: 2026-05-28). 다만 각 PowerShell 명령은 환경·버전에 따라 동작이 다를 수 있으므로, 운영 적용 전 본인 환경에서 실행 검증할 것을 권한다.
References
OWASP
- OWASP Non-Human Identities Top 10 (2025): https://owasp.org/www-project-non-human-identities-top-10/2025/
- OWASP Top 10 for Agentic Applications (2026), OWASP GenAI Security Project: https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/
- OWASP Top 10 for LLM Applications (2025): https://genai.owasp.org/llm-top-10/
Microsoft (ADFS / gMSA)
- Upgrading to AD FS in Windows Server — Microsoft Learn: https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/upgrading-to-ad-fs-in-windows-server
- Set-AdfsServerApplication (ADFS) — Microsoft Learn: https://learn.microsoft.com/en-us/powershell/module/adfs/set-adfsserverapplication
- Manage Group Managed Service Accounts — Microsoft Learn: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-managed-service-accounts/group-managed-service-accounts/manage-group-managed-service-accounts
- Create the KDS Root Key — Microsoft Learn: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-managed-service-accounts/group-managed-service-accounts/create-the-key-distribution-services-kds-root-key
Kubernetes
- Service Accounts — Kubernetes Docs: https://kubernetes.io/docs/concepts/security/service-accounts/
- Managing Service Accounts — Kubernetes Docs: https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/
- KEP-1205: Bound Service Account Tokens: https://github.com/kubernetes/enhancements/blob/master/keps/sig-auth/1205-bound-service-account-tokens/README.md
OIDC / GitHub Actions
- OpenID Connect reference — GitHub Docs: https://docs.github.com/actions/reference/openid-connect-reference
- Immutable subject claims for GitHub Actions OIDC tokens — GitHub Changelog (2026-04-23): https://github.blog/changelog/2026-04-23-immutable-subject-claims-for-github-actions-oidc-tokens/
SPIFFE / SPIRE
- SPIFFE Concepts: https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/
- X.509-SVID Specification: https://spiffe.io/docs/latest/spiffe-specs/x509-svid/
- JWT-SVID Specification: https://spiffe.io/docs/latest/spiffe-specs/jwt-svid/
HashiCorp Vault
- AppRole auth method — HashiCorp Developer: https://developer.hashicorp.com/vault/docs/auth/approle
- Response Wrapping — HashiCorp Developer: https://developer.hashicorp.com/vault/docs/concepts/response-wrapping
-
gMSA 비밀번호는 AD가 기본 30일 주기로 자동 회전하며, 회전 주기는 생성 시
ManagedPasswordIntervalInDays로만 설정 가능하다(생성 후 변경 불가). Microsoft Learn, “Manage Group Managed Service Accounts.” ↩ -
gMSA는 포레스트·도메인 기능 수준에 대한 명시적 하드 요구사항이 없으나, 비밀번호 배포에는 Windows Server 2012 이상 DC와 KDS Root Key가 필요하다. KDS Root Key 생성 후 모든 DC 복제 수렴까지 기본 10시간 대기한다. Microsoft Learn, “Create the KDS Root Key” 및 “Create gMSAs for Windows containers.” ↩
-
Set-AdfsServerApplication의 시크릿 회전 파라미터는-ChangeClientSecret및-ResetClientSecret(둘 다 SwitchParameter)이며,-JWTSigningCertificate로 인증서 기반 클라이언트 인증을 설정한다. 신규 등록 시 시크릿 생성용-GenerateClientSecret은Add-AdfsServerApplication에만 존재한다. Microsoft Learn, “Set-AdfsServerApplication (ADFS).” ↩ -
Kubernetes 1.22+ 기본 동작은 TokenRequest API를 통한 단기·자동 회전 토큰을 projected volume으로 마운트하며, 기본 TTL은 1시간이다.
automountServiceAccountToken: false로 자동 주입을 차단할 수 있다. Kubernetes Docs, “Service Accounts” / KEP-1205. ↩ -
GitHub Actions OIDC 토큰의 기본
sub클레임 포맷은repo:ORG/REPO:ref:refs/heads/BRANCH이며, 클라우드 측 신뢰 정책에서 이 값을 정확 매칭 조건으로 검증해야 한다. GitHub Docs, “OpenID Connect reference.” ↩ -
GitHub Changelog, “Immutable subject claims for GitHub Actions OIDC tokens” (2026-04-23). ↩
-
SVID(SPIFFE Verifiable Identity Document)는 X.509 인증서 또는 JWT 형식으로 발급되며, 토큰은 리플레이 공격에 취약하므로 가능한 경우 X.509-SVID 사용이 권장된다. SPIFFE Docs, “SPIFFE Concepts” / “X.509-SVID” / “JWT-SVID.” ↩
-
Vault AppRole은 RoleID·SecretID로 머신 인증을 수행하며, SecretID는 Response Wrapping(
-wrap-ttl)으로 전달해 노출을 최소화하는 것이 공식 권장 패턴이다. HashiCorp Developer, “AppRole auth method” / “Response Wrapping.” ↩
Comments