Windows 서비스 계정 선정 ── LocalSystem·가상 계정·gMSA를 구분해서 쓰기
· 업데이트: · Go Komura · Windows, Windows 서비스, 서비스 계정, gMSA, LocalSystem, 가상 계정, 보안, Active Directory, 최소 권한
수정 이력(1건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- 한국어 전면 재작성에 맞춰 본문 표현을 바로잡았습니다. 기술적인 주장은 일본어판과 같습니다.
- 최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22176383)
아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.
Go Komura (2026). 「Windows 서비스 계정 선정 ── LocalSystem·가상 계정·gMSA를 구분해서 쓰기」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/windows-service-accounts-gmsa-guide/
- DOI(등록된 아카이브)
- 10.5281/zenodo.22176383
- DOI(마지막 등록 버전)
- 10.5281/zenodo.22176384
「일단 LocalSystem으로 돌리던 사내 서비스가 보안 감사에서 『과도한 권한』으로 지적받았다. 무엇으로 바꿔야 하는가」「서비스에서 공유 폴더에 접근하지 못해 도메인 사용자로 돌리고 있다. 비밀번호가 만료되면 서비스가 멈추므로 만료 없음으로 두고, 절차서에 평문으로 적어 두었다」── 고객의 Windows 서비스 상담에서 이 두 가지는 단골입니다.
양쪽 현장에 공통인 것은, 서비스의 실행 계정이 「설계 판단」이 아니라 「동작한 설정」인 채로 고정되어 있다는 점입니다. Windows 서비스는 반드시 어떤 계정의 보안 컨텍스트에서 움직이며, 그 계정이 로컬에서 무엇을 할 수 있는지, 네트워크 너머에서 누구로 보이는지, 비밀번호를 누가 관리하는지를 전부 결정합니다. 여기를 기본값으로 두면, 한 서비스의 취약점이 머신 전체의 장악으로 직결되고, 평문 비밀번호가 절차서와 스크립트에 흩어집니다.
flowchart TB
accTitle: 실행 계정이 결정하는 세 가지
accDescr: 서비스는 반드시 어떤 계정의 보안 컨텍스트에서 움직이며, 그 계정이 로컬에서 할 수 있는 일, 네트워크 너머에서 누구로 보이는지, 비밀번호를 누가 관리하는지를 모두 결정한다
acct["서비스의 실행 계정"] --> local["로컬에서 무엇을 할 수 있는가"]
acct --> net["네트워크 너머에서 누구로 보이는가"]
acct --> pwd["비밀번호를 누가 관리하는가"]
그림 1: 실행 계정 선정은 로컬 권한·네트워크상 신원·비밀번호 관리 셋을 동시에 결정하는 설계 판단이 된다.
실질적인 선택지는 여섯 가지입니다 ── LocalSystem, LocalService, NetworkService, 가상 계정(NT SERVICE\<서비스 이름="">), 도메인 사용자, 그리고 gMSA(그룹 관리 서비스 계정). 이 글은 중소기업 정보시스템 담당자와 Windows 앱 개발자를 대상으로, 이 여섯 가지의 권한·네트워크상 신원·비밀번호 관리를 한 장의 표로 정리하고, 판단 흐름까지를 2026년 8월 시점의 Microsoft Learn 1차 정보를 바탕으로 정리합니다.서비스>
서비스 자체를 만드는 법(작업 스케줄러와의 구분, .NET Worker Service로 구현)은 「Windows 서비스 만드는 방법과 운영」에서 다룹니다. 이 글은 그 가운데 사고가 가장 많은 「실행 계정」에 집중합니다.
1. 먼저 결론
- 고민되면, 단일 머신 안에서 끝나는 서비스는 가상 계정, 도메인 안 리소스에 서비스 고유 신원으로 접근하는 서비스는 gMSA가 제1 후보입니다. Microsoft도 가능한 한 관리되는 계정(MSA/가상 계정)을 쓰라는 지침을 제시합니다.12
- LocalSystem을 「돌아가니까」로 고르면 안 됩니다. 토큰에 SYSTEM과 BUILTIN\Administrators가 들어가고 SeDebugPrivilege 같은 강한 특권을 가지므로, 장악당하면 그 머신의 거의 전부를 잃습니다.
sc.exe create의 기본값이 LocalSystem인 점이 이 사고의 온상입니다.34 - LocalService와 NetworkService의 차이는 네트워크상 신원입니다. 로컬 권한은 둘 다 최소이지만, 원격에는 LocalService가 익명으로, NetworkService가 컴퓨터 계정으로 보입니다.5
- **가상 계정(NT SERVICE\<서비스 이름="">)은 비밀번호 관리가 필요 없으면서 서비스마다 신원을 분리할 수 있는, 지금의 기본 해법입니다.** ACL에 「NT SERVICE\\서비스 이름」을 직접 지정할 수 있고, SQL Server의 기본 서비스 계정도 이것입니다.[^understand-service-accounts][^sql-service-accounts]서비스>
- LocalSystem·NetworkService·가상 계정이 네트워크에 나갈 때는 컴퓨터 계정(DOMAIN\컴퓨터 이름$)이 됩니다. 공유 폴더나 SQL Server의 ACL에 PC$를 부여하면 도메인 사용자를 쓰지 않아도 되는 경우가 많습니다.36
- 도메인 사용자를 서비스에 쓰는 구성은 비밀번호 운영과 Kerberoasting 양쪽에서 부채가 됩니다. SCM은 저장한 비밀번호로 로그온하므로 만료는 서비스 시작 실패가 되고, 그것을 피하는 「만료 없음+평문 메모」는 공격자에게 선물이 됩니다.78
- gMSA는 Active Directory가 비밀번호를 자동 생성·자동 순환합니다. 요건은 도메인과 KDS 루트 키이며, 서비스에는 「DOMAIN\계정 이름$」을 비밀번호 칸을 비운 채로 설정합니다. 지원하지 않는 앱이 있으므로 사전 검증이 필요합니다.910
- 계정을 바꾸면 프로필·%TEMP%·DPAPI의 전제가 바뀝니다. 옛 계정의 DPAPI로 보호한 데이터는 새 계정으로 복호화할 수 없습니다.
- 현황 파악은 서비스 목록의 실행 계정과 이벤트 ID 4624(로그온 유형 5)로 확인할 수 있습니다.11
한 문장으로 정리하면, 「서비스에 사람용 비밀번호를 주지 않는」 구성(기본 제공 계정·가상 계정·gMSA)을 기본으로 두고, 도메인 사용자는 최후의 수단으로 둔다가 이 글의 결론입니다.
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 19건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 선택지의 전체 모습 ── 여섯 실행 계정을 한 장의 표로
전제를 한 단계만 복습합니다. 서비스를 시작할 때 서비스 제어 관리자(SCM)는 구성된 계정으로 로그온하고, 성공하면 액세스 토큰을 만들어 서비스 프로세스에 할당합니다. 이후 파일이나 파이프 등 모든 리소스 접근은 이 토큰과 ACL의 대조로 판정됩니다.7 즉 실행 계정 선정은 서비스 프로세스에 넘기는 토큰의 내용을 정하는 설계입니다. 여섯 선택지를 늘어놓습니다.
flowchart TB
accTitle: 서비스 시작 시 SCM이 하는 일
accDescr: SCM은 구성된 계정으로 로그온하고, 성공하면 액세스 토큰을 만들어 서비스 프로세스에 할당하며, 이후 리소스 접근은 토큰과 ACL의 대조로 판정된다
scm["SCM"] --> logon["구성된 계정으로 로그온"]
logon --> token["액세스 토큰을 만든다"]
token --> proc["서비스 프로세스에 할당한다"]
proc --> access["파일이나 파이프에 접근"]
access --> check{"ACL이 허용하는가?"}
check -->|예| ok["접근 성공"]
check -->|아니오| deny["접근 거부"]
그림 2: 서비스의 모든 리소스 접근은, 시작 시 SCM이 만든 토큰과 ACL의 대조로 판정된다.
| 계정 | 로컬 권한 | 네트워크상 신원 | 비밀번호 관리 | 주된 쓰임 |
|---|---|---|---|---|
| LocalSystem | 거의 무제한(SYSTEM+Administrators) | 컴퓨터 계정(PC$) | 불필요(비밀번호 없음) | OS와 한몸으로 도는 예외적인 서비스만 |
| LocalService | 최소(Users급) | 익명 | 불필요 | 네트워크상 신원이 필요 없는 로컬 처리 |
| NetworkService | 최소(Users급) | 컴퓨터 계정(PC$) | 불필요 | 저권한+머신 단위 신원으로 충분한 처리 |
| 가상 계정 NT SERVICE\<이름>이름> | 최소+ACL에서 개별 부여 | 컴퓨터 계정(PC$) | 불필요(자동 관리) | 단일 서버에서 도는 업무 서비스의 기본 해법 |
| 도메인 사용자 | 부여한 만큼만 | 그 사용자 자신 | 수동(만료·유출·순환을 모두 사람이) | gMSA 미지원 앱에서의 최후 수단 |
| gMSA | 부여한 만큼만 | 그 gMSA 자신 | AD가 자동 생성·자동 순환 | 도메인 환경에서 서비스 고유 신원이 필요할 때 |
LocalSystem·LocalService·NetworkService·가상 계정은 모두 비밀번호라는 개념 자체가 없습니다. SCM에 저장한 비밀번호로 로그온하는(=만료나 유출이 있을 수 있는) 것은 도메인 사용자와 로컬 사용자뿐입니다.73
아래에서 이 표를 한 행씩 파고듭니다.
3. LocalSystem의 무엇이 문제인가
3.1. 「관리자로 실행」보다 더 강하다
LocalSystem(표시 이름은 로컬 시스템, NT AUTHORITY\SYSTEM)은 SCM이 쓰는 미리 정의된 계정이며, 로컬 컴퓨터에서 광범위한 특권을 가집니다. 토큰에는 NT AUTHORITY\SYSTEM과 BUILTIN\Administrators의 SID가 들어가고, 시스템의 대부분 개체에 접근할 수 있습니다. 나아가 다른 프로세스를 디버그할 수 있는 SeDebugPrivilege, OS의 일부로 동작하는 SeTcbPrivilege가 기본으로 켜져 있습니다.3
이 강함은 장악당했을 때 피해의 크기와 동의어입니다. LocalSystem으로 도는 서비스에 임의 코드 실행 취약점이 하나 있으면, 공격자는 그 머신에서 모든 사용자 파일의 읽기·변조(NTFS에서 SYSTEM은 기본으로 모든 권한입니다5), SeDebugPrivilege로 다른 프로세스의 메모리 읽기, 그리고 자격 정보 탈취와 그로부터의 측면 이동(Pass-the-Hash 등의 출발점)까지 한꺼번에 도달합니다. 인증 정보 탈취와 측면 이동의 연쇄는 「그림으로 이해하는 NTLM과 Kerberos」와 「Windows LAPS 실무 가이드」에서 다룬 그대로입니다.
flowchart TB
accTitle: LocalSystem 서비스가 장악당했을 때의 피해
accDescr: LocalSystem으로 도는 서비스에 임의 코드 실행 취약점이 하나 있으면, 공격자는 모든 사용자 파일의 읽기·변조, 다른 프로세스의 메모리 읽기, 자격 정보 탈취에서 측면 이동까지 도달한다
vuln["임의 코드 실행 취약점 하나"] --> sys["공격자가 SYSTEM 권한을 얻는다"]
sys --> files["파일의 읽기·변조"]
sys --> mem["다른 프로세스의 메모리 읽기"]
sys --> cred["자격 정보 탈취"]
cred --> lateral["다른 머신으로의 측면 이동"]
그림 3: LocalSystem 서비스의 취약점 하나로, 공격자는 머신 전체의 장악과 측면 이동의 출발점까지 한꺼번에 도달한다.
3.2. 그런데도 계속 골라지는 이유
이유는 단순합니다. 기본값이고, 액세스 거부가 절대 나오지 않기 때문입니다. sc.exe create에서 obj=를 생략한 때의 기본값은 LocalSystem이며4, 옛 샘플 코드와 설치 프로그램 뼈대에도 LocalSystem을 전제로 한 것이 많이 남아 있습니다. 개발 중에 권한 오류와 무관할 수 있으므로, 「돌아갔으니 그대로」가 양산되는 구조입니다. Microsoft 자신의 문서도, 대부분의 서비스에 이 정도의 특권 수준은 필요하지 않으며, 필요가 없으면 LocalService나 NetworkService 사용을 검토하라고 분명히 적습니다.3
flowchart TB
accTitle: LocalSystem이 계속 골라지는 구조
accDescr: sc.exe create의 기본값이 LocalSystem이며, 옛 샘플 코드와 뼈대도 LocalSystem 전제이므로, 개발 중에 권한 오류가 나오지 않고, 돌아갔으니 그대로라는 구성이 양산된다
def["sc.exe create의 기본값"] --> lsys["LocalSystem으로 생성"]
old["옛 샘플과 뼈대"] --> lsys
lsys --> noerr["개발 중에 액세스 거부가 나오지 않음"]
noerr --> asis["돌아갔으니 그대로"]
asis --> mass["과도한 권한의 서비스가 양산"]
그림 4: 기본값과 「액세스 거부가 나오지 않는」 개발 경험이, LocalSystem인 채로 고정되는 서비스를 양산한다.
3.3. TrustedInstaller와의 차이 ── LocalSystem도 무제한은 아니다
참고로 LocalSystem을 「Windows의 최강 계정」이라고 부르는 것은 정확하지 않습니다. Windows Vista 이후의 Windows 리소스 보호(WRP)는 OS의 중요한 시스템 파일·폴더·레지스트리 키의 변경을 TrustedInstaller(Windows Modules Installer 서비스)에만 허용하며, SYSTEM이나 관리자라도 재작성은 액세스 거부가 됩니다.12 파일 탐색기의 「TrustedInstaller의 사용 권한이 필요합니다」가 이 메커니즘입니다. 반대로 말하면, WRP 보호 영역 밖의 거의 전부에 손이 닿는 것이 LocalSystem이며, 업무 서비스에 줄 이유는 보통 없습니다.
flowchart TB
accTitle: WRP 보호 영역과 TrustedInstaller의 관계
accDescr: WRP가 보호하는 중요한 시스템 파일이나 레지스트리 키의 변경은 TrustedInstaller에만 허용되며, SYSTEM이나 관리자라도 액세스 거부가 된다
ti["TrustedInstaller"] -->|변경 가능| wrp["WRP 보호의 시스템 파일 등"]
sysadm["SYSTEM·관리자"] -->|액세스 거부| wrp
sysadm -->|거의 전부 가능| other["WRP 보호 영역 밖"]
그림 5: LocalSystem도 무제한이 아니며, WRP 보호 영역의 변경은 TrustedInstaller에만 허용된다.
3.4. LocalSystem이 타당한 경우
예외적으로 타당한 것은, 장치 드라이버와 밀접하게 연계하거나, OS의 보안 기반을 조작하거나, 다른 서비스나 세션을 관리하는 등, 요구되는 특권이 애초에 관리자급을 넘는 서비스입니다. 백업 에이전트나 EDR 같은 소프트웨어가 해당합니다. 그때에도 정말로 그 특권을 쓰는 코드 경로가 있는지 확인하고, 권한이 필요한 처리만 분리할 수 없는지를 검토할 가치가 있습니다(판단하는 법은 「Windows의 관리자 특권이 필요해지는 것은 언제인가」 참조).
4. LocalService와 NetworkService ── 최소 권한의 기본 제공 계정
LocalService(NT AUTHORITY\LOCAL SERVICE, SID: S-1-5-19)와 NetworkService(NT AUTHORITY\NETWORK SERVICE, SID: S-1-5-20)는 저권한 서비스를 위해 마련된 기본 제공 계정입니다. 둘 다 로컬에서는 최소한의 권한만 가지며, 대체로 Users 그룹 구성원 수준의 접근만 할 수 있습니다.51
둘의 차이는 한 점, 네트워크 너머에서 누구로 보이는가입니다.5
- LocalService: 원격에 익명 자격 정보로 연결합니다. 인증을 요구하는 리소스에는 접근할 수 없습니다.
- NetworkService: 원격에 컴퓨터의 자격 정보(도메인 환경이라면 DOMAIN\컴퓨터 이름$)를 제시합니다.
「네트워크에 나가지 않거나, 나가도 신원이 필요 없으면」 LocalService, 「도메인 안 리소스에 머신의 신원으로 접근하고 싶으면」 NetworkService, 라는 구분입니다.
flowchart TB
accTitle: LocalService와 NetworkService의 차이
accDescr: 로컬 권한은 둘 다 최소이지만, 원격에는 LocalService가 익명 자격 정보로 연결하고, NetworkService는 컴퓨터의 자격 정보를 제시한다
ls["LocalService"] --> anon["익명 자격 정보로 연결"]
anon -.-> ng["인증을 요구하는 리소스는 불가"]
ns["NetworkService"] --> comp["컴퓨터의 자격 정보를 제시"]
comp -.-> pc["도메인 환경에서는 PC$로 보인다"]
그림 6: 로컬 권한은 같은 최소라도, 네트워크 너머에서 보이는 신원이 익명인지 컴퓨터 계정인지로 갈린다.
다만 이 둘에는 지금 관점에서 보면 약점이 있습니다. 같은 계정을 다수의 서비스가 공유한다는 점입니다. LocalService로 도는 서비스가 다섯 있으면, ACL이 계정 단위인 한 다섯은 서로의 리소스에 접근할 수 있습니다. SQL Server가 Local Service 계정을 지원하지 않는 것도, 공유 계정이라 다른 서비스와 분리할 수 없기 때문입니다.1
flowchart TB
accTitle: 공유 계정으로는 분리할 수 없다
accDescr: 여러 서비스가 같은 LocalService를 공유하면, ACL이 계정 단위인 한 서로의 리소스에 접근할 수 있다
sva["서비스 A"] --> acct["같은 LocalService"]
svb["서비스 B"] --> acct
svc["서비스 C"] --> acct
acct --> mutual["서로의 리소스에 접근 가능"]
mutual -.-> reason["ACL이 계정 단위이기 때문"]
그림 7: 같은 계정을 공유하는 서비스끼리는, ACL로는 서로의 리소스에서 분리할 수 없다.
이 「저권한인 채로, 서비스마다 분리하고 싶다」를 푸는 것이 다음의 가상 계정입니다.
5. 가상 계정(NT SERVICE\<서비스 이름="">) ── 지금의 기본 해법서비스>
5.1. 비밀번호 없이, 서비스마다 신원을 가질 수 있다
가상 계정은 Windows Server 2008 R2 / Windows 7 이후에서 쓸 수 있는 「관리되는 로컬 계정」입니다. 특징은 세 가지입니다.6
- 계정은 자동으로 관리되며, 생성도 비밀번호 설정도 필요 없습니다
- 이름은
NT SERVICE\<서비스 이름>이며, 서비스 하나마다 고유한 신원이 됩니다 - 도메인 환경에서는 네트워크에 컴퓨터 계정(DOMAIN\컴퓨터 이름$)의 자격 정보로 접근할 수 있습니다
즉 LocalService/NetworkService의 「비밀번호 관리가 필요 없다」는 장점을 유지한 채로, 「계정 공유로 분리할 수 없다」는 단점을 없앱니다. SQL Server 설치가 기본으로 NT SERVICE\MSSQLSERVER 같은 가상 계정을 쓰는 것도 이 때문입니다.1
flowchart TB
accTitle: 가상 계정이 양립시키는 것
accDescr: 가상 계정은 LocalService나 NetworkService의 비밀번호 관리 불필요라는 장점을 유지한 채로, 계정 공유로 분리할 수 없다는 단점을 없애고, 서비스 하나마다 고유한 신원을 가진다
merit["장점(비밀번호 관리 불필요)"] -->|유지| va["가상 계정"]
demerit["단점(공유로 분리 불가)"] -->|해소| va
va --> ident["서비스마다 고유한 신원"]
va --> auto["생성도 비밀번호 설정도 불필요"]
그림 8: 가상 계정은 기본 제공 계정의 장점을 유지한 채로, 공유로 인한 분리 불가라는 단점만 없앤다.
5.2. ACL에 「NT SERVICE\서비스 이름」을 직접 쓸 수 있다
실무상의 편리함은 ACL에 그 서비스만 이름을 지정해 추가할 수 있다는 점입니다. 「이 데이터 폴더는 이 서비스만 쓸 수 있다」를 그룹 생성도 비밀번호 관리도 없이 실현할 수 있습니다.
# 서비스의 로그온 계정을 가상 계정으로 변경한다
# obj= 의 값은 「NT SERVICE\서비스 이름」. 비밀번호는 지정하지 않는다
sc.exe config MyAppService obj= "NT SERVICE\MyAppService"
# 구성을 확인한다(SERVICE_START_NAME 을 확인한다)
sc.exe qc MyAppService
# 데이터 폴더에 대한 변경 권한을 이 서비스에만 부여한다
icacls "C:\ProgramData\MyApp" /grant "NT SERVICE\MyAppService:(OI)(CI)M"
GUI라면 services.msc에서 서비스 속성 →「로그온」 탭 →「계정」에 NT SERVICE\서비스 이름을 입력하고, 비밀번호 칸은 비운 채로 둡니다(가상 계정이나 MSA에서는 비밀번호를 지정하지 않는 것이 SCM의 사양입니다). 변경 후 서비스를 다시 시작하면 적용됩니다.
5.3. 제약 ── 머신 밖에서는 「그 서비스」인지 알 수 없다
가상 계정의 신원은 머신 로컬이며, 도메인에서는 인식되지 않습니다. 네트워크상에서는 뒤에서 말하듯 컴퓨터 계정으로 축소되므로, 원격 쪽에서는 「어느 서비스인지」를 구분할 수 없고, 여러 서버에서 같은 신원을 공유할 수도 없습니다.10
flowchart TB
accTitle: 가상 계정의 신원은 머신 밖에서 축소된다
accDescr: 머신 안에서는 서비스마다 고유한 가상 계정도, 네트워크상에서는 컴퓨터 계정으로 축소되어, 원격 쪽에서는 어느 서비스인지 구분할 수 없다
vaa["가상 계정 A"] --> pc["컴퓨터 계정 PC$"]
vab["가상 계정 B"] --> pc
pc --> remote["원격 쪽에서 보이는 신원"]
remote -.-> nodist["어느 서비스인지 구분할 수 없다"]
그림 9: 머신 안에서는 고유한 신원이라도, 네트워크 너머에서는 모든 서비스가 같은 PC$로 보인다.
이 제약 ── 네트워크 너머에서 서비스 고유 신원이 필요하거나, 여러 서버에서 같은 신원이 필요하거나 ── 가 문제가 되는 시점이 gMSA(8장)의 차례입니다.
6. 네트워크에 나갈 때의 신원 ── 컴퓨터 계정(PC$)의 실무
6.1. 「서비스는 공유 폴더에 접근할 수 없다」는 오해
도메인 가입 머신에서는 LocalSystem·NetworkService·가상 계정으로 도는 서비스가 원격 리소스에 접근할 때, 컴퓨터 계정(DOMAIN\컴퓨터 이름$)으로 인증됩니다.36 글머리의 「공유 폴더에 접근하지 못해 도메인 사용자로 바꿨다」는 상담의 상당수는 사실 이것으로 해결됩니다. 연결 대상 ACL이 PC$를 허용하지 않았을 뿐입니다.
flowchart TB
accTitle: 컴퓨터 계정으로의 원격 접근
accDescr: 도메인 가입 머신의 LocalSystem·NetworkService·가상 계정 서비스는 원격에 컴퓨터 계정으로 인증되며, 연결 대상 ACL이 PC$를 허용하면 접근할 수 있다
svc["서비스(LocalSystem·가상 계정 등)"] --> auth["PC$로 인증"]
auth --> acl{"연결 대상 ACL이 PC$를 허용?"}
acl -->|예| ok["공유 폴더나 DB 접근 성공"]
acl -->|아니오| ng["접근 거부"]
그림 10: 도메인 환경이라면, 연결 대상 ACL에 PC$를 부여하는 것만으로 도메인 사용자 없는 원격 접근이 성립한다.
파일 서버 쪽 부여는 평범한 ACL 조작과 같으며, 계정 이름에 컴퓨터 이름$을 지정합니다(GUI의 개체 선택 대화 상자에서는 개체 유형에 「컴퓨터」를 포함합니다).
# 파일 서버 쪽: APPSV01 위의 서비스에 공유 폴더에 대한 변경 권한을 준다
# 공유 사용 권한과 NTFS 사용 권한 양쪽에 부여가 필요하다
Grant-SmbShareAccess -Name "AppData" -AccountName "CORP\APPSV01$" -AccessRight Change -Force
icacls "D:\Shares\AppData" /grant "CORP\APPSV01$:(OI)(CI)M"
SQL Server도 마찬가지로, 컴퓨터 계정을 로그인으로 만들면 연결 문자열은 Integrated Security=true인 채로 비밀번호 없이 통과합니다.
-- DB 서버 쪽: APPSV01 위의 서비스로부터의 Windows 통합 인증을 허용한다
CREATE LOGIN [CORP\APPSV01$] FROM WINDOWS;
6.2. PC$ 방식의 한계를 알아 두기
이 방식에는 한계가 두 가지 있습니다.
- 단위가 머신 단위가 됩니다. 같은 머신에서 도는 LocalSystem·NetworkService·모든 가상 계정 서비스는 원격에서는 모두 같은 PC$로 보입니다. 연결 대상에서 「이 서비스만 허용」할 수 없고, 어느 서비스가 그 계정을 썼는지도 감사할 수 없습니다.2
- 작업 그룹 환경에서는 쓸 수 없습니다. 컴퓨터 계정은 Active Directory의 개체이므로, 도메인에 가입하지 않은 머신에는 존재하지 않습니다. 연결 대상의 계정 자격 정보를 명시적으로 다루는 설계가 필요합니다.
한계 1을 넘고 싶어지면, 다음 장의 도메인 사용자가 아니라… 그 문제점을 건너뛰고 gMSA로 가는 것이 2026년의 답입니다.
flowchart TB
accTitle: PC$ 방식의 두 한계
accDescr: PC$에 의한 인증은 단위가 머신 단위라 서비스별 허용도 감사도 할 수 없고, 작업 그룹 환경에서는 컴퓨터 계정 자체가 없어 쓸 수 없다
pcs["PC$ 방식"] --> lim1["한계 1(단위가 머신 단위)"]
pcs --> lim2["한계 2(작업 그룹 불가)"]
lim1 -.-> noaudit["서비스 단위의 허용·감사 불가"]
lim2 -.-> nocred["명시적 자격 정보의 설계로"]
lim1 --> gmsa["넘고 싶으면 gMSA로"]
그림 11: 머신 단위의 세분성과 도메인 전제라는 두 한계를 넘고 싶으면, 도메인 사용자를 건너뛰고 gMSA로 간다.
7. 도메인 사용자를 서비스에 쓰는 문제
7.1. 비밀번호의 구조적 문제
도메인 사용자(또는 로컬 사용자)를 서비스에 할당하면, SCM이 그 비밀번호를 저장하고 시작할 때마다 로그온에 씁니다. SCM은 만료를 관리해 주지 않으므로, 비밀번호가 만료되면 로그온이 실패하고 서비스는 시작되지 않습니다.7
여기서 현장에서 자주 보는 악순환이 시작됩니다.
- 만료로 서비스가 멈추는 사고가 난다
- 재발 방지로 「비밀번호 만료 없음」을 설정한다
- 변경 절차가 갖춰지지 않고, 여러 서버의 절차서·스크립트·작업 스케줄러에 같은 비밀번호가 평문으로 적힌다
- 퇴사자가 나와도 비밀번호는 바뀌지 않는다(바꾸면 어디가 멈출지 모른다)
flowchart TB
accTitle: 도메인 사용자 운영의 악순환
accDescr: 비밀번호 만료로 서비스가 정지하고, 재발 방지로 만료 없음을 설정하며, 평문 비밀번호가 절차서나 스크립트로 퍼지고, 퇴사자가 나와도 바꿀 수 없게 된다
expire["1. 만료로 서비스 정지"] --> forever["2. 재발 방지로 만료 없음을 설정"]
forever --> spread["3. 평문 비밀번호가 퍼진다"]
spread -.-> where["절차서·스크립트·작업"]
spread --> stuck["4. 퇴사자가 나와도 바꿀 수 없다"]
그림 12: 만료 사고를 기점으로, 만료 없음과 평문 비밀번호의 확산이 고정되어 간다.
Microsoft도, 도메인 계정을 서비스에 쓰는 구성에서는 비밀번호와 SPN의 수동 관리에 상당한 운영 공수가 들고, 유지보수가 서비스 정지를 부를 수 있다고 지적합니다.1
7.2. Kerberoasting ── 서비스 계정은 표적이 된다
또 하나, 도메인 사용자 서비스 계정 특유의 공격이 Kerberoasting입니다. Kerberos 인증을 받는 서비스는 실행 계정에 SPN(서비스 주체 이름)을 등록합니다. 도메인의 임의의 인증된 사용자는 SPN이 등록된 계정에 대한 서비스 티켓을 요청할 수 있으므로, 공격자는 티켓을 얻어 오프라인으로 비밀번호 무차별 대입을 시도합니다. 사람이 정한 10〜16자 정도의 비밀번호는 이 공격을 견디지 못합니다.
flowchart TB
accTitle: Kerberoasting의 흐름
accDescr: SPN이 등록된 서비스 계정에 대한 서비스 티켓은 임의의 인증된 사용자가 요청할 수 있으므로, 공격자는 티켓을 얻어 오프라인으로 비밀번호 무차별 대입을 시도한다
atk["도메인의 인증된 사용자"] --> req["SPN 대상의 티켓 요청"]
req --> tkt["서비스 티켓을 얻는다"]
tkt --> brute["오프라인 무차별 대입"]
brute --> weak["10〜16자 정도로는 해독된다"]
그림 13: 인증된 사용자라면 누구나 티켓을 요청할 수 있고, 사람이 정한 길이의 비밀번호는 오프라인 무차별 대입을 견디지 못한다.
실효성 있는 대책은 비밀번호를 사람이 추측·해독할 수 없는 강도로 만드는 것입니다. Microsoft도 긴 비밀번호의 강제와, 비밀번호가 기계 생성의 긴 난수가 되는 gMSA 사용을 듭니다.8 같은 문서는 Kerberos 아머링(FAST)에도 언급하지만, FAST가 보호하는 것은 사전 인증 데이터와 KDC 위장에 대한 내성이며, 인증된 사용자에 의한 SPN으로의 서비스 티켓 요청 자체는 막지 않으므로, 서비스 계정 비밀번호 강도의 대체재가 되지 않습니다. SPN과 Kerberos의 관계, 인증이 NTLM으로 떨어지는 조건은 「그림으로 이해하는 NTLM과 Kerberos」에서 그림으로 설명합니다.
7.3. 그래도 도메인 사용자를 쓴다면
애플리케이션이 gMSA를 지원하지 않는 등의 이유로 도메인 사용자를 쓸 수밖에 없다면, 다음을 최소한의 완화책으로 하십시오.
- 비밀번호는 25자 이상의 난수 생성으로 하고, 비밀번호 관리 도구 외(절차서·스크립트·공유 Excel)에는 적지 않습니다
- 서비스 전용 계정으로 만들고, 서비스마다 나눕니다(사람 계정과 겸용하지 않습니다2)
- 대화형 로그온과 원격 데스크톱을 거부하고, 「서비스로 로그온」만 허용합니다
- 소속 그룹을 최소화합니다(Domain Admins에 넣는 것은 논외입니다)
- 정기 순환 절차를 갖추고, 변경이 파급되는 곳을 대장으로 만듭니다
이것을 모두 하는 것보다 gMSA로 이전하는 편이 안전하고 쉽습니다 ── 그것이 다음 장입니다.
8. gMSA ── 비밀번호 관리를 Active Directory에 맡긴다
8.1. 메커니즘과 효과
gMSA(그룹 관리 서비스 계정)는 비밀번호 관리를 도메인 컨트롤러에 맡기는 도메인 계정입니다. 비밀번호는 KDS(키 배포 서비스)의 루트 키에서 도메인 컨트롤러가 계산하며, 허용된 호스트만 그것을 가져옵니다.13
flowchart TB
accTitle: gMSA의 비밀번호 관리 메커니즘
accDescr: KDS의 루트 키에서 도메인 컨트롤러가 비밀번호를 계산하고, 허용된 호스트만 그것을 가져와 서비스 실행에 쓰며, 비밀번호는 기본 30일마다 자동 순환된다
kds["KDS 루트 키"] --> dc["DC가 비밀번호를 계산"]
dc --> host["허용된 호스트가 가져온다"]
host --> svc["서비스 실행에 사용"]
dc -.-> rot["기본 30일마다 자동 순환"]
그림 14: 비밀번호의 생성·배포·갱신을 도메인 컨트롤러가 맡고, 사람은 비밀번호를 모른 채로 운영할 수 있다.
효과는 분명합니다.9
- 240바이트의 난수 생성 비밀번호: 무차별 대입이나 사전 공격이 현실적이지 않게 되고, Kerberoasting 내성이 크게 올라갑니다
- 기본 30일마다 자동 순환: 사람이 변경을 계획할 필요도, 서비스를 멈출 필요도 없습니다
- 여러 서버에서 같은 신원을 공유 가능: 부하 분산 아래의 서버 팜에서도 동일 주체로 상호 인증할 수 있습니다
- SPN 관리의 단순화: SPN의 등록·관리도 위임·단순화할 수 있습니다
사람은 비밀번호를 모른 채로 운영할 수 있습니다 ── Windows LAPS가 로컬 관리자 비밀번호에 대해 하는 일을, 서비스 계정에 대해 하는 메커니즘으로 보면 위치가 잡히기 쉬울 것입니다.
8.2. 요건
gMSA에는 전제 조건이 있습니다.10
- Active Directory 도메인 환경일 것(작업 그룹 불가)
- 도메인과 포리스트의 기능 수준이 Windows Server 2012 이상일 것
- KDS 루트 키가 이미 만들어져 있을 것
- gMSA 이름은 도메인이 아니라 포리스트 안에서 고유할 것
- 비밀번호 변경 간격은 생성 시에만 설정할 수 있을 것
KDS 루트 키 생성은 한 번만 하면 되지만, 생성부터 최대 10시간은 모든 도메인 컨트롤러로의 복제를 기다리므로 gMSA를 만들 수 없습니다. 복제가 끝나기 전에 비밀번호 가져오기가 실패하는 사고를 막기 위한 안전 장치입니다.14
flowchart TB
accTitle: KDS 루트 키 생성부터 gMSA 생성까지
accDescr: KDS 루트 키 생성 후에는 모든 도메인 컨트롤러로의 복제를 기다리므로 최대 10시간은 gMSA를 만들 수 없고, 복제 완료 후에 만들 수 있게 된다
add["KDS 루트 키를 만든다"] --> wait["최대 10시간의 복제 대기"]
wait -.-> why["가져오기 실패 사고를 막는 안전 장치"]
wait --> done["모든 DC로의 복제가 완료"]
done --> ok["gMSA를 만들 수 있다"]
그림 15: 루트 키 생성 후 최대 10시간은, 복제가 끝나지 않은 채의 가져오기 실패를 막기 위한 대기 시간이 된다.
# 도메인 관리자로, 도메인 컨트롤러(또는 AD PowerShell 모듈이
# 들어 있는 관리 컴퓨터)에서 실행한다
# KDS 루트 키의 유무를 확인하고, 없으면 만든다(포리스트에서 한 번만)
Get-KdsRootKey
Add-KdsRootKey -EffectiveImmediately # 실제로 쓸 수 있는 것은 최대 10시간 후
8.3. 생성부터 설정까지의 절차
절차는 「①가져오기를 허용할 그룹을 만든다 → ②gMSA를 만든다 → ③서버에 설치한다 → ④서비스에 설정한다」의 네 단계입니다.10
flowchart TB
accTitle: gMSA 도입의 네 단계
accDescr: 비밀번호 가져오기를 허용할 그룹 생성, gMSA 생성, 각 서버에 설치, 서비스의 실행 계정으로 설정이라는 네 단계로 도입한다
st1["①가져오기를 허용할 그룹 생성"] --> st2["②gMSA를 만든다"]
st1 -.-> add["서버의 PC$를 추가"]
st2 --> st3["③각 서버에 설치"]
st3 -.-> test["Test 명령으로 가져오기를 검증"]
st3 --> st4["④서비스에 설정"]
그림 16: 그룹 생성부터 서비스 설정까지, gMSA 도입은 네 단계로 진행한다.
# ① 비밀번호 가져오기를 허용할 보안 그룹을 만들고,
# 서비스를 돌릴 서버의 컴퓨터 계정을 추가한다
New-ADGroup -Name "GG-SvcBatchHosts" -GroupScope Global
Add-ADGroupMember -Identity "GG-SvcBatchHosts" -Members "APPSV01$", "APPSV02$"
# 그룹 멤버십은 컴퓨터 로그온 시에 평가되므로,
# 추가 후에는 대상 서버를 다시 시작해 두는 것이 확실하다
# ② gMSA 를 만든다
New-ADServiceAccount -Name "svc-batch" `
-DNSHostName "svc-batch.corp.example.com" `
-PrincipalsAllowedToRetrieveManagedPassword "GG-SvcBatchHosts"
# ③ 서비스를 돌릴 각 서버에서 gMSA 를 설치하고 검증한다
Install-ADServiceAccount -Identity "svc-batch"
Test-ADServiceAccount -Identity "svc-batch" # True 이면 가져오기가 된 것이다
# ④ 서비스의 실행 계정으로 설정한다. 이름 끝에 $ 를 붙이고, 비밀번호는 지정하지 않는다
sc.exe config MyBatchService obj= "CORP\svc-batch$"
Restart-Service MyBatchService
services.msc에서 설정할 때도 계정 이름은 CORP\svc-batch$처럼 끝에 $를 붙이고, 비밀번호 칸은 비운 채로 둡니다. MSA 계열 계정은 대화형 로그인에 쓸 수 없습니다.1 이후 공유 폴더나 SQL Server의 ACL에 PC$ 대신 CORP\svc-batch$를 부여하면, 서비스 고유 신원으로의 네트워크 접근이 비밀번호 없이 완성됩니다.
8.4. 지원하지 않는 앱이 있다
주의점으로, 모든 소프트웨어가 gMSA로 도는 것은 아닙니다. Windows 서비스, IIS 애플리케이션 풀, 작업 스케줄러의 작업처럼 표준 메커니즘으로 로그온 신원을 구성하는 것은 폭넓게 지원하지만, 장애 조치 클러스터링 자체는 gMSA를 지원하지 않는 등의 제약이 있고, 앱이 내부에서 비밀번호를 요구하는 구조이면 쓸 수 없습니다.10 Microsoft도 운영 투입 전에 테스트 환경에서 gMSA로의 동작을 확인하라고 분명히 적습니다.9
flowchart TB
accTitle: gMSA 지원 여부 판별
accDescr: 표준 메커니즘으로 로그온 신원을 구성하는 앱은 폭넓게 gMSA를 지원하지만, 장애 조치 클러스터링이나 내부에서 비밀번호를 요구하는 구조의 앱에서는 쓸 수 없고, 운영 전에 테스트 환경에서 확인한다
app["쓰고 싶은 앱"] --> how{"로그온 구성 방식은?"}
how -->|표준 메커니즘| okapp["gMSA 지원"]
okapp -.-> ex1["서비스·IIS·작업 등"]
how -->|비밀번호 요구| ngapp["gMSA 불가"]
ngapp -.-> ex2["장애 조치 클러스터 등"]
okapp --> test["운영 전에 테스트 환경에서 확인"]
그림 17: 표준 메커니즘으로 로그온을 구성하는 앱은 폭넓게 지원하지만, 미지원 구조도 있으므로 운영 전 검증이 빠질 수 없다.
참고로 단일 서버용 sMSA(독립 실행형 관리 서비스 계정)와, Windows Server 2025에서 도입된 dMSA(위임된 관리 서비스 계정. 장치 식별에 묶어 자격 정보 탈취에 대항한다)라는 형제도 있습니다. 새로 짤 때는 gMSA를 기본으로 두고, 요건에 따라 검토하십시오.6
9. 따라오는 설계 ── 로그온 권한·프로필·DPAPI·감사
계정에 묶여 바뀌는 것을 네 가지 더 잡아 두십시오.
9.1. 「서비스로 로그온」 권한(SeServiceLogonRight)
서비스로 시작하려면 계정에 「서비스로 로그온」 사용자 권한이 필요합니다. LocalSystem·LocalService·NetworkService에는 기본 제공으로 주어져 있지만, 그 밖의 계정(도메인 사용자·gMSA 등)에는 명시적 할당이 필요합니다.15
services.msc GUI의 「로그온」 탭에서 설정하면, 스냅인이 이 권한을 자동으로 부여합니다. 반면 CreateService/ChangeServiceConfig(sc.exe config가 호출하는 API)는 지정한 계정이 이 권한을 가지고 있는지를 검증하지 않습니다. 스크립트로 구성한 서비스가 시작 시 「로그온하지 못했습니다」로 멈추는 전형적 원인이 이것입니다. 도구의 부수 효과에 기대지 말고, 로컬 보안 정책(secpol.msc)의 「서비스로 로그온」에 대한 추가, 또는 GPO/Intune으로의 구성을 배포 절차에 명시적으로 넣으십시오(그룹 정책으로 이 권한을 구성하는 환경에서는, 로컬 부여가 정책 적용 시 덮어쓰인다는 점에도 주의가 필요합니다). 반대로 서비스 전용 계정에는 「대화형 로그온 거부」도 함께 설정하는 것이 정석입니다.
flowchart TB
accTitle: 「서비스로 로그온」 권한의 구성 경로에 따른 차이
accDescr: services.msc의 GUI는 권한을 자동 부여하지만, sc.exe config가 호출하는 API는 권한을 검증하지 않으므로, 권한이 없는 계정에서는 서비스가 시작 시 로그온 실패로 멈춘다
gui["services.msc에서 설정"] --> auto["권한을 자동 부여"]
auto --> okgui["서비스는 시작할 수 있다"]
cli["sc.exe config로 설정"] --> noval["권한을 검증하지 않는다"]
noval --> has{"권한을 가지고 있는가?"}
has -->|예| okcli["서비스는 시작할 수 있다"]
has -->|아니오| stop["로그온 실패로 정지"]
stop -.-> fix["secpol.msc나 GPO로 명시적으로 부여"]
그림 18: GUI는 권한을 자동 부여하지만, 스크립트 구성에서는 검증되지 않으므로, 명시적 부여를 절차에 넣을 필요가 있다.
9.2. 프로필·%TEMP%·HKEY_CURRENT_USER가 바뀐다
SCM은 서비스 시작 시 그 계정의 사용자 프로필을 로드합니다.7 즉 %TEMP%, %APPDATA%, HKEY_CURRENT_USER의 실체는 실행 계정마다 다른 것이며, 계정을 바꾸면 옛 계정 프로필에 저장해 둔 설정이나 캐시가 「사라진」 것처럼 보입니다.
설계상의 대책은 단순합니다. 서비스 데이터는 프로필 아래가 아니라 C:\ProgramData\<앱 이름> 같은 명시적 경로에 두고, 그 ACL을 실행 계정에 부여하는 것입니다. 이렇게 하면 계정 변경이 데이터 이전을 동반하지 않습니다.
flowchart TB
accTitle: 프로필 의존과 데이터 배치의 대책
accDescr: 프로필의 실체는 실행 계정마다 다르므로, 계정을 바꾸면 옛 프로필의 데이터가 사라진 것처럼 보이지만, 데이터를 명시적 경로에 두고 ACL을 부여하면 이전이 필요 없어진다
sw["실행 계정 전환"] --> newprof["다른 프로필을 로드"]
newprof --> lost["옛 데이터가 사라진 것처럼 보인다"]
lost -.->|대책| fix["ProgramData 아래에 배치"]
fix --> acl["ACL을 실행 계정에 부여"]
acl --> nomig["계정 변경에도 이전 불필요"]
그림 19: 프로필 아래를 피해 명시적 경로에 데이터를 두면, 계정 변경이 데이터 이전을 동반하지 않게 된다.
9.3. DPAPI로 보호한 데이터는 계정과 운명 공동체
더 놓치기 쉬운 것이 DPAPI입니다. 사용자 범위 DPAPI(CryptProtectData나 .NET의 ProtectedData)로 암호화한 데이터는, 원칙적으로 보호할 때와 같은 계정으로만 복호화할 수 있습니다. 계정을 바꾸는 순간 저장해 둔 연결 문자열이나 API 키를 읽을 수 없게 됩니다 ── DPAPI가 제 일을 하는 모습이지만, 이전 절차에 들어 있지 않으면 장애가 됩니다.
flowchart TB
accTitle: DPAPI 보호 데이터와 계정 변경의 관계
accDescr: 사용자 범위 DPAPI로 보호한 데이터는 보호할 때와 같은 계정으로만 복호화할 수 있으며, 실행 계정을 바꾼 뒤에는 시크릿을 다시 넣어야 한다
protect["옛 계정으로 DPAPI 보호"] --> data["보호된 연결 문자열 등"]
data --> who{"복호화하는 계정은?"}
who -->|같은 옛 계정| okdec["복호화할 수 있다"]
who -->|새 계정| ngdec["복호화할 수 없다"]
ngdec --> re["시크릿을 다시 넣는다"]
그림 20: DPAPI 보호 데이터는 보호 시의 계정과 운명 공동체이며, 계정 전환 후에는 다시 넣어야 한다.
대응은 「계정 전환 뒤에 시크릿을 다시 넣는다」는 절차를 이전 계획에 넣는 것입니다(저장 위치 설계는 「Windows 앱의 기밀 정보 저장」 참조). 참고로 gMSA나 PC$에 의한 Windows 통합 인증으로 끝나는 구성이면 시크릿 저장 자체를 없앨 수 있습니다. 「어디에 저장할지」보다 먼저 「저장하지 않고 끝낼 수 있는지」를 검토하는 것이 올바른 순서입니다.
또한 서비스가 「호출한 사용자 권한으로」 처리를 하고 싶다면, 계정을 강하게 만드는 것이 아니라 가장(impersonation)을 씁니다. 이쪽은 「Windows의 가장 토큰을 올바르게 다루기」를 참조하십시오.
9.4. 감사 ── 4624의 로그온 유형 5를 본다
서비스 시작은 보안 이벤트 로그에 이벤트 ID 4624(계정이 성공적으로 로그온했습니다)의 로그온 유형 5(Service: SCM이 서비스를 시작했다)로 기록됩니다. 이벤트 안의 「가상 계정」 필드는 MSA/가상 계정에 의한 로그온인지를 나타내므로, 관리되는 계정의 이용 현황 감시에도 쓸 수 있습니다.11
flowchart TB
accTitle: 서비스 시작 감사의 흐름
accDescr: SCM에 의한 서비스 시작은 이벤트 ID 4624의 로그온 유형 5로 기록되며, 가상 계정 필드로 관리되는 계정에 의한 로그온인지를 식별할 수 있다
start["SCM이 서비스를 시작한다"] --> ev["이벤트 ID 4624를 기록"]
ev --> type5["로그온 유형 5(Service)"]
type5 --> vafield["가상 계정 필드"]
vafield --> watch["관리되는 계정의 감시"]
그림 21: 서비스 시작은 로그온 유형 5의 4624로 기록되며, 관리되는 계정의 이용 현황까지 추적할 수 있다.
현황 파악에는 서비스 목록의 실행 계정을 집계하는 것이 빠른 방법입니다.
# 어느 서비스가 어느 계정으로 도는지 집계한다
Get-CimInstance Win32_Service |
Group-Object StartName |
Sort-Object Count -Descending |
Select-Object Count, Name
# LocalSystem 으로 도는 비표준 서비스를 가려낸다(경로로 자사/서드파티 제품을 구분한다)
Get-CimInstance Win32_Service |
Where-Object { $_.StartName -eq 'LocalSystem' -and $_.PathName -notlike '*\Windows\*' } |
Select-Object Name, DisplayName, PathName
이 출력에 「LocalSystem으로 도는 업무 서비스」「도메인 사용자로 도는 서비스」가 늘어서 있으면, 다음 장의 판단 흐름이 차례입니다.
10. 판단 흐름 ── 네 질문으로 정한다
지금까지의 내용을 선정 절차로 정리합니다. 순서대로 네 질문에 답하십시오.
flowchart TB
accTitle: 실행 계정의 판단 흐름
accDescr: 네트워크 접근 유무, 도메인 가입, 머신 단위 신원으로 충분한지, gMSA 지원의 네 질문에 순서대로 답해 실행 계정을 정한다
q1{"다른 머신에 Windows 인증으로 연결?"} -->|하지 않음| va["가상 계정"]
va -.-> sys["특권 필수면 LocalSystem"]
q1 -->|함| q2{"도메인 가입?"}
q2 -->|아니오| cred["자격 정보를 보호해 저장"]
q2 -->|예| q3{"머신 단위로 충분한가?"}
q3 -->|예| pcacl["가상 계정+PC$ 허용"]
q3 -->|아니오| q4{"앱은 gMSA를 지원?"}
q4 -->|예| gmsa["gMSA"]
q4 -->|아니오| du["전용 사용자+완화책"]
그림 22: 네 질문에 순서대로 답하면, 여섯 선택지 중 무엇을 써야 하는지가 정해진다.
질문 1: 그 서비스는 네트워크상의 다른 머신(공유 폴더·DB·API 등)에 Windows 인증으로 접근하는가?
하지 않으면 가상 계정이 기본 해법입니다. 특수한 로컬 특권이 필요한 경우에만, 그 필요성을 확인한 뒤 LocalSystem을 검토합니다.
질문 2: (접근하는 경우) 머신은 도메인에 가입해 있는가?
작업 그룹이라면 PC$도 gMSA도 쓸 수 없습니다. 연결 대상의 계정 자격 정보를 명시적으로 다루는 설계(저장은 DPAPI 등으로 보호)로 하거나, 도메인 가입을 검토합니다.
질문 3: (도메인인 경우) 머신 단위 신원(PC$)으로 충분한가?
충분하면 가상 계정(또는 NetworkService)+연결 대상 ACL에 PC$ 부여로 완성입니다. 서비스 고유 신원이나, 여러 서버에서 공통 신원이 필요하면 질문 4로.
질문 4: 애플리케이션은 gMSA를 지원하는가?
지원하면(SCM·IIS 앱 풀·작업 스케줄러 등, 표준 메커니즘으로 로그온을 구성하는 것은 대체로 지원) gMSA. 검증 환경에서의 동작 확인을 잊지 마십시오. 어떻게 해도 미지원이면, 7.3절의 완화책을 모두 적용한 뒤 전용 도메인 사용자를 씁니다.
표로 보면 다음과 같습니다.
| 상황 | 권장 | 비고 |
|---|---|---|
| 로컬 완결·보통 권한 | 가상 계정 | ACL은 NT SERVICE\<이름>에 부여 |
| 로컬 완결·관리자를 넘는 특권이 필수 | LocalSystem | 특권의 필요성을 먼저 검증한다 |
| 네트워크 신원이 필요 없는 로컬 처리 | LocalService | 기존 서비스의 현상 유지라면 가능 |
| 도메인 안 리소스에 머신 신원으로 접근 | 가상 계정(또는 NetworkService) | 연결 대상 ACL에 PC$를 부여 |
| 도메인 안 리소스에 서비스 고유 신원으로 접근 | gMSA | KDS 루트 키+지원 확인 |
| 여러 서버에서 동일 신원(부하 분산 등) | gMSA | 가상 계정으로는 불가 |
| gMSA 미지원 앱+고유 신원이 필요 | 전용 도메인 사용자 | 7.3절의 완화책을 필수로 한다 |
| 작업 그룹+원격 접근이 필요 | 명시적 자격 정보를 보호해 저장 | 설계 재검토도 검토 |
11. 정리
- 서비스의 실행 계정은 로컬 권한·네트워크상 신원·비밀번호 관리 셋을 동시에 결정하는 설계 판단입니다. 기본값(LocalSystem)인 채로 방치하지 마십시오.
- LocalSystem은 SYSTEM+Administrators의 토큰과 강한 특권을 가지며, 장악당했을 때 피해가 최대화됩니다. 대부분의 업무 서비스에 이 특권은 필요하지 않습니다.
- LocalService와 NetworkService는 둘 다 저권한이며, 차이는 네트워크상 신원(익명인지, 컴퓨터 계정인지)입니다. 다만 계정을 여러 서비스가 공유하므로 분리는 할 수 없습니다.
- 가상 계정(NT SERVICE\<서비스 이름="">)은 비밀번호 관리가 필요 없으면서 서비스 단위로 분리할 수 있는, 지금의 기본 해법입니다. ACL에 직접 지정할 수 있고, 설정은 로그온 계정 이름만 바꾸면 됩니다.서비스>
- LocalSystem·NetworkService·가상 계정은 도메인 환경에서는 DOMAIN\PC$로 네트워크에 나갑니다. 공유 폴더나 SQL Server의 ACL에 PC$를 부여하면, 도메인 사용자 없이 끝나는 구성이 많습니다.
- 도메인 사용자의 서비스 이용은 만료로 인한 정지·평문 비밀번호의 확산·Kerberoasting이라는 구조적 문제를 안습니다. 쓴다면 전용 계정+긴 난수 비밀번호+로그온 제한이 필수입니다.
- gMSA는 AD가 비밀번호를 자동 생성·자동 순환하는 메커니즘이며, 요건은 도메인·기능 수준 2012 이상·KDS 루트 키입니다. 서비스에는 「DOMAIN\이름$」을 비밀번호 칸을 비운 채로 설정합니다.
- 계정 변경 시에는 「서비스로 로그온」 권한, 프로필·%TEMP%의 이동, DPAPI 보호 데이터의 재투입을 이전 절차에 넣습니다. 감사는 이벤트 ID 4624의 로그온 유형 5로 확인할 수 있습니다.
다음에 서비스를 설치할 때, 로그온 설정 화면에서 한 번만 손을 멈추고 이렇게 다시 물으십시오. 이 서비스는 누구로서, 어디까지 접근할 수 있어야 하는가. 그 답은 이 글의 판단표 어딘가의 행이 되어 있을 것입니다.
관련 기사
- Windows 서비스 만드는 방법과 운영 ── 작업 스케줄러와의 구분부터 BackgroundService의 서비스화까지
- Windows의 관리자 특권이 필요해지는 것은 언제인가 - UAC, 보호 영역, 설계상 구분하는 법
- Windows의 가장 토큰을 올바르게 다루기 ── 스레드 단위의 권한 차용과 안전한 되돌리기
- 그림으로 이해하는 NTLM과 Kerberos ── 왜 인증은 NTLM으로 「떨어지는가」
- Windows LAPS 실무 가이드 ── 모든 PC 공통의 로컬 관리자 비밀번호를 그만두기
- Windows 앱의 기밀 정보 저장 - DPAPI로 평문 설정을 피하기
관련 상담 영역
합동회사 코무라소프트는 Windows 서비스·상주 앱의 실행 계정 설계와 최소 권한화, LocalSystem을 전제로 만들어진 기존 서비스의 가상 계정·gMSA로의 이전, 계정 변경에 따른 액세스 거부·DPAPI·프로필 기인의 장애 조사를 다룹니다. 「감사에서 지적받았지만, 무엇부터 손을 대면 좋을지 모르겠다」는 단계부터여도 괜찮습니다.
참고 링크
-
Microsoft Learn, Configure Windows service accounts and permissions. SQL Server의 기본 서비스 계정이 가상 계정(NT SERVICE\MSSQLSERVER 등)이라는 점, 가상 계정·MSA 지정 시 비밀번호 칸을 비운다는 점, MSA가 끝 $가 붙은 이름이며 대화형 로그인에는 쓸 수 없다는 점, Local Service가 공유 계정이라 분리할 수 없어 SQL Server에서 지원되지 않는다는 점, 도메인 계정 이용 시 비밀번호와 SPN의 수동 관리에 공수가 들고 유지보수가 서비스 정지를 부를 수 있다는 점, 항상 최소 권한 계정으로 서비스를 실행해야 한다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Securing on-premises service accounts. 온프레미스 서비스에는 먼저 gMSA, 쓸 수 없으면 sMSA, 이어서 컴퓨터 계정, 마지막으로 사용자 계정이라는 우선순위, 컴퓨터 계정을 쓰는 경우 어느 서비스가 그 계정을 쓰는지 판별할 수 없고 변경의 감사가 되지 않는다는 점, 서비스 계정의 역할(서비스의 식별·인증·시작)에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, LocalSystem Account. LocalSystem이 로컬 컴퓨터에서 광범위한 특권을 가지며, 토큰에 NT AUTHORITY\SYSTEM과 BUILTIN\Administrators의 SID를 포함한다는 점, 비밀번호가 없다는 점, 원격 서버에는 컴퓨터의 자격 정보를 제시한다는 점, SE_DEBUG_NAME이나 SE_TCB_NAME을 포함한 특권 목록, 대부분의 서비스에는 이 특권 수준이 필요하지 않으며 LocalService/NetworkService 사용을 검토해야 한다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, sc.exe config. 서비스의 실행 계정을 obj= 매개변수로 지정한다는 점, 그 기본값이 LocalSystem이라는 점, LocalSystem 이외의 사용자 계정을 쓸 때의 password= 매개변수에 대해. ↩ ↩2
-
Microsoft Learn, Local accounts. SYSTEM(S-1-5-18)이 NTFS 볼륨에서 기본으로 모든 권한을 가진다는 점, NETWORK SERVICE(S-1-5-20)가 원격 서버에 컴퓨터의 자격 정보를 제시한다는 점, LOCAL SERVICE(S-1-5-19)가 로컬에서 최소한의 특권을 가지고 네트워크에는 익명 자격 정보를 제시한다는 점에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Service accounts. 가상 계정이 자동 관리되는 로컬 계정으로 비밀번호 관리가 필요 없다는 점, 이름이 NT SERVICE<SERVICENAME> 형식이라는 점, 도메인 환경에서는 컴퓨터 계정(
\ ↩ ↩2 ↩3 ↩4$)의 자격 정보로 네트워크에 접근한다는 점, sMSA·gMSA·dMSA·가상 계정의 구분 기준에 대해. -
Microsoft Learn, Service User Accounts. 서비스가 사용자 계정의 보안 컨텍스트에서 실행된다는 점, SCM이 시작 시 계정에 로그온해 액세스 토큰을 서비스 프로세스에 연결한다는 점, SCM이 사용자 프로필을 로드한다는 점, SCM은 비밀번호 만료를 관리하지 않아 만료되면 로그온이 실패하고 서비스가 시작되지 않는다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Protect SMB traffic from interception. 서비스 계정 보호책으로서의 gMSA(기계 생성의 긴 난수 비밀번호로 무차별 대입·사전 공격에 의한 비밀번호 해독이 현실적이지 않게 된다는 점), 긴 비밀번호의 강제, Kerberos 아머링(FAST)에 대한 언급 등의 권고 사항에 대해. ↩ ↩2
-
Microsoft Learn, Secure group managed service accounts. gMSA의 비밀번호가 240바이트의 난수 생성이라 무차별 대입·사전 공격을 받기 어렵다는 점, Windows OS가 30일마다 비밀번호를 바꾸며 관리자에 의한 변경 계획이나 서비스 정지가 필요 없다는 점, 서버 팜으로의 배포와 SPN 관리의 단순화, 서비스가 gMSA를 지원하지 않으면 sMSA, 그것도 불가하면 강한 비밀번호 관리를 동반한 표준 사용자 계정을 쓴다는 점, 운영 전에 테스트 환경에서 gMSA로의 동작을 확인해야 한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Manage group Managed Service Accounts. gMSA의 전제 조건(도메인/포리스트 기능 수준 2012 이상, KDS 루트 키 생성), gMSA 이름이 포리스트 안에서 고유해야 한다는 점, 비밀번호 변경 간격은 생성 시에만 설정할 수 있다는 점, New-ADServiceAccount의 -PrincipalsAllowedToRetrieveManagedPassword로 비밀번호 가져오기를 허용할 그룹을 지정한다는 점, Install-ADServiceAccount/Test-ADServiceAccount의 절차, 가상 계정의 신원이 머신 로컬이며 도메인에서 인식되지 않는다는 점, 장애 조치 클러스터가 gMSA를 지원하지 않는다는 점, SCM·IIS 앱 풀·작업 스케줄러가 gMSA로의 로그온 구성을 지원한다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, 4624(S): An account was successfully logged on. 이벤트 4624가 로그온 세션 생성 시 접근 대상 컴퓨터에서 기록된다는 점, 로그온 유형 5가 서비스(SCM에 의한 서비스 시작)를 뜻한다는 점, 「Virtual Account」 필드로 MSA·가상 계정에 의한 로그온을 식별할 수 있어 관리되는 서비스 계정의 감시에 쓸 수 있다는 점에 대해. ↩ ↩2
-
Microsoft Learn, About Windows Resource Protection. Windows 리소스 보호(WRP)가 중요한 시스템 파일·폴더·레지스트리 키의 대체를 막는다는 점, WRP 보호 리소스에 대한 모든 권한이 TrustedInstaller에 제한되어 있으며 변경은 Windows Modules Installer 서비스를 통한 지원되는 대체 메커니즘으로만 할 수 있다는 점, 보호 리소스를 변경하려는 애플리케이션은 액세스 거부를 받는다는 점에 대해. ↩
-
Microsoft Learn, Group Managed Service Accounts overview. gMSA가 비밀번호 관리를 Windows에 맡기는 도메인 계정이라는 점, 키 배포 서비스(kdssvc.dll)의 공유 비밀에서 도메인 컨트롤러가 비밀번호를 계산하고, 멤버 호스트가 도메인 컨트롤러에 조회해 현재와 직전 비밀번호를 가져온다는 점, 서버 팜에서 동일 주체에 의한 상호 인증을 가능하게 한다는 점에 대해. ↩
-
Microsoft Learn, Create a Key Distribution Service (KDS) root key. 도메인 컨트롤러가 gMSA 비밀번호 생성을 시작하려면 루트 키가 필요하다는 점, Add-KdsRootKey -EffectiveImmediately에 의한 생성 절차, 생성 후 최대 10시간은 AD 복제 수렴을 기다리므로 gMSA를 만들 수 없다는 점, 복제가 불완전한 채로는 비밀번호 가져오기가 실패할 수 있다는 점에 대해. ↩
-
Microsoft Learn, Policy CSP - UserRights: LogOnAsService. 「서비스로 로그온」 권한으로 보안 주체가 서비스로 로그온할 수 있다는 점, Local System·Local Service·Network Service에는 기본 제공으로 이 권한이 있다는 점, 그 밖의 계정으로 실행하는 서비스에는 이 권한의 할당이 필요하다는 점, 그룹 정책에서의 구성 경로에 대해. ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
Windows LAPS 실무 가이드 ── 전 PC 공통 로컬 관리자 비밀번호를 그만두기
전 PC 공통 로컬 관리자 비밀번호는 한 대의 침해가 전대로 번지는 Pass-the-Hash 공격의 온상입니다. OS 표준 기능이 된 Windows LAPS의 자동 로테이션과 AD/Entra ID 저장 설정, 운영상의 함정을 설명합니다.
SMB 서명과 LDAP 채널 바인딩 ── NTLM 대책의 「남은 절반」을 실무에서 마무리하기
NTLM을 멈추기까지의 기간 동안, 릴레이 공격의 피해를 줄이는 방어가 SMB 서명과 LDAP 서명·채널 바인딩입니다. OS별 기본값, 감사 이벤트 읽는 법, 강제 적용으로 나아가는 절차, 업무 앱과 장비를 고치는 방법까지 실무 관점으로 정리합니다.
그림으로 이해하는 NTLM과 Kerberos ── 왜 인증은 NTLM으로 「떨어지는가」
NTLM과 Kerberos의 차이를 그림으로 정리합니다. 챌린지/응답, TGT와 서비스 티켓, SPN을 찾을 수 없을 때 Negotiate가 NTLM으로 떨어지는 조건, 릴레이 공격과 Pass-the-Hash가 성립하는 이유, NTLMv1 삭제까...
NTLM 사용 중단으로 업무 앱이 멈출까 ── 감사 로그를 모으는 방법과, 의존을 없애는 순서
NTLM 사용 중단에 대비해, 자사 Windows 환경과 업무 앱이 어디에서 NTLM에 의존하는지 파악하는 절차를 정리합니다. 감사 정책, NTLM/Operational 로그의 이벤트 8001~8004를 추적하는 방법, NTLM으로 fallbac...
Windows 가상화의 심층(제2회) ── 커널에서도 보이지 않는 메모리: VBS·HVCI·Credential Guard의 구조
대응 하드웨어에 클린 설치하면 기본으로 켜지는 VBS는, 하이퍼바이저와 SLAT로 커널보다 강한 격리를 만듭니다. VTL, 보안 커널, HVCI, Credential Guard의 구조를 설명합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 일단 LocalSystem으로 돌리고 있는 서비스는 지금 당장 바꿔야 합니까?
- 일률적으로 즉시 변경이 정답은 아닙니다. 먼저 그 서비스가 정말로 LocalSystem급 로컬 권한(관리자를 넘는 강한 특권)을 필요로 하는지 확인하십시오. 파일 읽기·쓰기와 네트워크 통신 정도라면, 가상 계정(NT SERVICE\서비스 이름)으로 옮기는 것이 제1 후보입니다. 이전 시에는 필요한 폴더와 레지스트리에 대한 액세스 권한 부여, 프로필이나 DPAPI에 의존하는 데이터의 취급, 「서비스로 로그온」 권한의 유무를 확인합니다. 검증 환경에서 시작과 주요 기능을 확인한 뒤 운영을 전환하십시오.
- 가상 계정과 NetworkService 중 어느 쪽을 고를까요?
- 새로 고른다면 가상 계정을 권합니다. 네트워크에서는 둘 다 컴퓨터 계정(DOMAIN\컴퓨터 이름$)으로 보이고, 로컬 권한이 작은 점도 비슷합니다. 다만 NetworkService는 여러 서비스가 같은 계정을 공유하므로, ACL로 「이 서비스만 허용」하는 분리를 할 수 없습니다. 가상 계정은 서비스마다 고유한 신원을 가지며, ACL에 NT SERVICE\서비스 이름을 직접 지정할 수 있습니다. SQL Server 등 최근 Microsoft 제품의 기본값도 가상 계정입니다.
- gMSA는 작업 그룹 환경(도메인 없음)에서도 쓸 수 있습니까?
- 쓸 수 없습니다. gMSA는 Active Directory 도메인 컨트롤러가 비밀번호를 생성·관리하는 메커니즘이며, 도메인과 KDS 루트 키 생성이 전제입니다. 작업 그룹 환경에서는 가상 계정 또는 LocalService/NetworkService로 로컬 처리를 끝내는 것이 기본입니다. 다른 머신에 접근해야 하면, 대상에 준비한 계정의 자격 정보를 명시적으로 쓰는 등 다른 설계가 됩니다. 컴퓨터 계정(PC$)으로서의 네트워크 접근도 도메인 환경에서만 성립하는 이야기입니다.
- 서비스의 실행 계정을 바꿨더니, 저장해 두었던 설정과 자격 정보를 읽을 수 없게 되었습니다. 왜입니까?
- 실행 계정마다 고유한 사용자 프로필, %TEMP%, HKEY_CURRENT_USER, DPAPI 키가 묶여 있기 때문입니다. 특히 DPAPI(CryptProtectData 등)로 사용자 범위 보호를 건 데이터는 원칙적으로 보호할 때와 같은 계정으로만 복호화할 수 있습니다. 프로필 아래(AppData 등)에 저장한 파일도 새 계정에서는 다른 경로가 됩니다. 계정을 바꾸기 전에 DPAPI 보호 데이터의 재작성 절차(API 키 재입력 등)와 프로필 아래 파일의 이전을 계획하십시오.
- 서비스에서 공유 폴더에만 접근하면 된다면, 도메인 사용자가 필요합니까?
- 많은 경우 필요하지 않습니다. 도메인 환경이라면 LocalSystem·NetworkService·가상 계정으로 도는 서비스는 원격에 컴퓨터 계정(DOMAIN\컴퓨터 이름$)으로 인증됩니다. 공유 폴더의 공유 사용 권한과 NTFS 사용 권한에 그 PC$를 추가하면 읽고 쓸 수 있습니다. 서비스 고유 신원으로 접근 제어하고 싶거나, 여러 서버에서 같은 신원이 필요하면 도메인 사용자가 아니라 gMSA를 검토하십시오.