W większości środowisk, które przechodzą pierwszy porządny audyt, liczba kont technicznych okazuje się wyższa niż liczba kont pracowników. Nie o kilka procent — wielokrotnie. I w odróżnieniu od kont ludzkich nikt ich nie odbiera przy odejściu z firmy, nie obejmuje MFA i nie przegląda co kwartał.
Ten tekst jest instrukcją wykonawczą. Pięć kroków, konkretne zapytania, konkretne kryteria decyzyjne i — co ważniejsze — opis pułapek, które sprawiają, że audyt kont serwisowych robiony „z listy" daje fałszywe poczucie kontroli.
Konta serwisowe w AD to najstarszy i najbardziej niedoceniany wycinek szerszej kategorii: non-human identities (NHI) — tożsamości przypisanych aplikacjom, workloadom, automatyzacji i, coraz częściej, agentom AI. Że to nie jest problem teoretyczny, najlepiej widać po portfelach zakupowych dostawców: w ciągu dwóch tygodni czerwca 2026 roku Quest przejął Anetac, a SailPoint kupił Entro Security — obie transakcje dotyczyły dokładnie tej warstwy. Wcześniej tę samą drogą poszedł CyberArk (Venafi, Zilla Security), a całość domyka zapowiedziane przejęcie CyberArk przez Palo Alto Networks.
Rynek wycenia ten problem w miliardach dolarów. Twój audyt zaczyna się od jednego pliku CSV.
Najczęstszy błąd: przyjęcie, że „konto serwisowe" to konto z prefiksem svc_. Konwencja nazewnicza jest wynikiem audytu, nigdy jego punktem wyjścia — konta sprzed wdrożenia standardu nazywają się backup2, jkowalski_adm albo integracja.
W Active Directory NHI występuje w sześciu formach i każdą trzeba zebrać osobno:
Konta użytkownika z SPN — klasyczne konta serwisowe Kerberos.
gMSA / sMSA — konta zarządzane, z automatyczną rotacją hasła.
Konta komputerów — pełnoprawne tożsamości, często z delegacją.
Konta użytkownika bez SPN, używane przez usługi, zadania harmonogramu, pule aplikacji IIS lub połączenia do baz danych.
Konta aplikacyjne w Entra ID — service principals i managed identities, jeśli katalog jest hybrydowy.
Konta „zerowe" — utworzone pod wdrożenie, które nigdy nie ruszyło, i pozostawione z ważnym hasłem.
Zebranie punktów 1–3 to kwestia jednego skryptu. Punkty 4–6 wymagają korelacji z rzeczywistym użyciem i to one decydują o jakości audytu.
powershell
# Konta użytkownika z SPN
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName,PasswordLastSet,PasswordNeverExpires,LastLogonDate,MemberOf,'msDS-SupportedEncryptionTypes',adminCount |
Select-Object SamAccountName,DistinguishedName,PasswordLastSet,PasswordNeverExpires,LastLogonDate,adminCount,
@{n='SPN';e={$_.ServicePrincipalName -join ';'}},
@{n='EncTypes';e={$_.'msDS-SupportedEncryptionTypes'}} |
Export-Csv .\nhi_spn.csv -NoTypeInformation -Encoding UTF8
# Konta zarządzane
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword,LastLogonDate |
Export-Csv .\nhi_gmsa.csv -NoTypeInformation -Encoding UTF8
# Kandydaci spoza SPN: hasło bez wygasania
Get-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} -Properties PasswordLastSet,LastLogonDate,Description |
Export-Csv .\nhi_never_expires.csv -NoTypeInformation -Encoding UTF8
Czego nie widać na tej liście: pole LastLogonDate pochodzi z atrybutu lastLogonTimestamp, który replikuje się z opóźnieniem 9–14 dni. Jeśli na jego podstawie uznasz konto za nieużywane i je wyłączysz, masz od kilku dni do dwóch tygodni marginesu błędu. Do decyzji o wyłączeniu używaj atrybutu lastLogon — niereplikowanego, odczytywanego z każdego kontrolera domeny osobno i agregowanego po maksimum.
powershell
$dcs = (Get-ADDomainController -Filter *).HostName
$wyniki = foreach ($dc in $dcs) {
Get-ADUser -Server $dc -Filter {ServicePrincipalName -like "*"} -Properties lastLogon |
Select-Object SamAccountName,@{n='LastLogon';e={
if ($_.lastLogon) { [datetime]::FromFileTime($_.lastLogon) } else { $null }}}
}
$wyniki | Group-Object SamAccountName | ForEach-Object {
[pscustomobject]@{
Konto = $_.Name
LastLogon = ($_.Group.LastLogon | Measure-Object -Maximum).Maximum
}
} | Sort-Object LastLogon
To jest krok, który decyduje o powodzeniu całego przedsięwzięcia, i to jego pominięcie sprawia, że projekty „porządkowania kont serwisowych" utykają na etapie prezentacji.
Powód jest prosty: nikt nie zrotuje hasła konta, o którym nie wie, ile systemów się rozsypie. Blokerem rotacji nie jest technologia — jest nim nieznany blast radius. Mapowanie użycia trzeba więc zrobić przed rotacją, nie po pierwszej awarii.
Trzy źródła danych, w kolejności użyteczności:
a) Konfiguracja lokalna na serwerach członkowskich — źródło prawdy o tym, co uruchamia się jako dane konto:
powershell
# Usługi Windows działające na koncie domenowym
Get-CimInstance Win32_Service |
Where-Object { $_.StartName -and $_.StartName -notmatch '^(LocalSystem|NT AUTHORITY\\|NT SERVICE\\)' } |
Select-Object SystemName,Name,StartName,State,StartMode
# Zadania harmonogramu
Get-ScheduledTask | Where-Object {
$_.Principal.UserId -and
$_.Principal.UserId -notmatch '^(SYSTEM|LOCAL SERVICE|NETWORK SERVICE)$'
} | Select-Object TaskPath,TaskName,@{n='RunAs';e={$_.Principal.UserId}}
# Pule aplikacji IIS
& "$env:SystemRoot\System32\inetsrv\appcmd.exe" list apppool /text:name,processModel.identityType,processModel.userName
Uruchom to przez Invoke-Command na całej puli serwerów i zrzuć do jednego zbioru. To jedyny sposób, żeby zobaczyć zależność „konto → host → usługa".
b) Logi kontrolerów domeny — zdarzenie 4769 (żądanie biletu usługowego Kerberos) pokazuje, które konta klienckie sięgają po które SPN. To najlepsza dostępna mapa ruchu do kont serwisowych. Z tego samego zdarzenia odczytasz Ticket Encryption Type: wartość 0x17 (RC4) przy współczesnym kliencie to klasyczny sygnał próby kerberoastingu.
c) Logi serwerów członkowskich — zdarzenie 4624 typ 5 (logon usługi) oraz 4648 (użycie jawnych poświadczeń). To drugie jest szczególnie wartościowe: pokazuje przypadki, w których człowiek ręcznie użył poświadczeń konta technicznego.
Przy skali powyżej kilkudziesięciu serwerów te zapytania kieruj do SIEM-u, nie do Get-WinEvent.
Konto bez właściciela jest niezarządzalne z definicji: nie ma kto zaakceptować rotacji, ograniczenia uprawnień ani wyłączenia.
Dla każdego konta z listy przypisz cztery pola:
Pole
Wymóg
Właściciel biznesowy
Imiennie. Nie zespół, nie „IT"
Właściciel techniczny
Osoba, która wie, co się zepsuje po rotacji
Usługa biznesowa
Nazwa systemu, który to konto obsługuje
Okno serwisowe
Kiedy można bezpiecznie zrotować hasło
Test sieroty: wyślij właścicielowi zapytanie „czy konto X może zostać wyłączone w przyszły czwartek o 22:00?". Brak odpowiedzi w ciągu 5 dni roboczych = konto formalnie nie ma właściciela i trafia do ścieżki wygaszania (patrz krok 5).
To nie jest sztuczka administracyjna, tylko mechanizm przenoszący ciężar dowodu. W standardowym układzie to bezpieczeństwo musi udowodnić, że konto jest zbędne. Test sieroty odwraca to: właściciel musi potwierdzić, że jest potrzebne. Przy kilkuset kontach ta zmiana kierunku jest jedyną rzeczą, która pozwala zamknąć projekt w skończonym czasie.
Lista 400 kont bez priorytetyzacji nie doprowadzi do żadnej zmiany. Potrzebny jest prosty, powtarzalny scoring. Poniższy model jest addytywny i celowo topornie prosty — jego zaletą jest to, że da się go policzyć z danych z kroku 1 i obronić przed zarządem.
Czynnik
Warunek
Punkty
Uprawnienia
Członek grupy uprzywilejowanej (Domain Admins, Account Operators, Backup Operators, Server Operators)
40
adminCount = 1 przy braku aktualnego członkostwa (pozostałość po AdminSDHolder)
15
Wiek hasła
PasswordLastSet starsze niż 2 lata
25
starsze niż 5 lat
40
Szyfrowanie
Brak wymuszonego AES (msDS-SupportedEncryptionTypes bez bitów 0x8/0x10)
20
Delegacja
Unconstrained delegation
40
Constrained / resource-based constrained delegation
15
Ekspozycja
Konto interaktywnie logowalne (brak blokady logowania lokalnego/RDP przez GPO)
15
SPN wystawiony na usługę dostępną z sieci użytkowników
10
Progi: ≥ 70 pkt — remediacja w bieżącym sprincie. 40–69 — plan kwartalny. < 40 — cykliczna recertyfikacja.
Zapytania do trzech najcięższych czynników:
powershell
# Unconstrained delegation (UAC bit 524288)
Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)" -Properties samAccountName,objectClass
# Constrained + RBCD
Get-ADObject -LDAPFilter "(msDS-AllowedToDelegateTo=*)" -Properties samAccountName,msDS-AllowedToDelegateTo
Get-ADObject -LDAPFilter "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)" -Properties samAccountName
# Konta z SPN bez wymuszonego AES — bezpośredni cel kerberoastingu
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties 'msDS-SupportedEncryptionTypes' |
Where-Object { -not $_.'msDS-SupportedEncryptionTypes' -or (($_.'msDS-SupportedEncryptionTypes' -band 0x18) -eq 0) } |
Select-Object SamAccountName
Kerberos działa tak, że dowolny uwierzytelniony użytkownik domeny może poprosić o bilet usługowy dla dowolnego SPN. Bilet jest zaszyfrowany kluczem pochodzącym z hasła konta serwisowego, więc atakujący zabiera go offline i łamie bez żadnego ruchu w kierunku ofiary — zero nieudanych logowań, zero blokad konta, zero alertów. To jest kerberoasting.
Wynikają z tego dwie konsekwencje, które umykają w standardowych audytach:
Hasło konta z SPN jest realną granicą bezpieczeństwa domeny, a nie ustawieniem higienicznym. 12-znakowe hasło słownikowe ustawione w 2019 roku jest dziś, przy współczesnym sprzęcie, materiałem na kilka godzin łamania.
Konto z SPN w grupie Domain Admins to jednokrokowa ścieżka do przejęcia domeny. Ta kombinacja powinna być traktowana jako incydent, nie jako ustalenie audytowe. Sprawdź ją w pierwszej kolejności:
powershell
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties MemberOf |
Where-Object { $_.MemberOf -match 'Domain Admins|Enterprise Admins|Administrators' } |
Select-Object SamAccountName,PasswordLastSet
Hasła w preferencjach zasad grupy. Stary mechanizm GPP pozwalał ustawiać hasła lokalnych kont w plikach XML na SYSVOL. Klucz odszyfrowujący Microsoft opublikował publicznie w 2014 roku, a pliki bardzo często zostają po migracjach:
powershell
Get-ChildItem "\\$env:USERDNSDOMAIN\SYSVOL\$env:USERDNSDOMAIN\Policies" -Recurse -Include *.xml -ErrorAction SilentlyContinue |
Select-String -Pattern "cpassword"
Pole opisu konta. W dużych środowiskach niemal zawsze znajdzie się kilka kont, których hasło ktoś wpisał w atrybut description albo info „na chwilę".
powershell
Get-ADUser -Filter * -Properties Description,info |
Where-Object { $_.Description -match 'haslo|hasło|pass|pwd|:' -or $_.info -match 'haslo|hasło|pass|pwd' } |
Select-Object SamAccountName,Description
Sprawdź też datę hasła konta krbtgt — jeśli jest starsza niż rok, każdy wcześniej wykradziony hash pozostaje zdatny do wystawienia Golden Ticket:
powershell
Get-ADUser krbtgt -Properties PasswordLastSet | Select-Object PasswordLastSet
Jednorazowy audyt ma okres przydatności około 18 miesięcy. Żeby wynik był trwały, potrzebne są cztery mechanizmy.
Migracja do gMSA wszędzie, gdzie to możliwe. Group Managed Service Account ma hasło o długości 240 znaków, rotowane automatycznie co 30 dni, nieznane żadnemu człowiekowi i niemożliwe do użycia interaktywnie. To jednocześnie rozwiązuje problem rotacji, kerberoastingu i współdzielenia poświadczeń. Ograniczenie: usługa musi wspierać gMSA (SQL Server, IIS, usługi .NET — tak; część starszego oprogramowania firm trzecich — nie).
powershell
New-ADServiceAccount -Name gmsa_app01 -DNSHostName app01.domena.local `
-PrincipalsAllowedToRetrieveManagedPassword "GRP_APP01_Servers" `
-ServicePrincipalNames "HTTP/app01.domena.local"
Rotacja etapowa dla reszty. Wzorzec, który działa: konto dubluje się (svc_app → svc_app_v2), nowe konto dostaje uprawnienia, systemy przechodzą na nie pojedynczo według mapy z kroku 2, stare konto zostaje wyłączone (nie usunięte) na 30 dni i dopiero potem skasowane. Rollback polega na odwróceniu jednego przełączenia, a nie na odtwarzaniu hasła.
Wygaszanie zamiast kasowania. Konta bez właściciela: wyłącz → przenieś do dedykowanej OU OU=NHI_Kwarantanna → odczekaj 60 dni → usuń. Kwarantanna zamienia nieodwracalną decyzję w odwracalną, co jest jedynym sposobem, żeby zespoły utrzymania w ogóle zgodziły się na czyszczenie.
Bramka na wejściu. Nowe konto techniczne powstaje wyłącznie z wypełnionym właścicielem, uzasadnieniem uprawnień i datą przeglądu. Bez tego następny audyt znajdzie dokładnie te same 400 kont, tylko z nowymi nazwami.
Warto nazwać rzecz po imieniu: w typowej organizacji koszt rotacji ponosi utrzymanie, a korzyść odnosi bezpieczeństwo. Administrator, który zrotuje hasło i położy produkcję, dostanie incydent na swoje nazwisko. Administrator, który nie zrobi nic, nie dostanie nic. Przy takim rozkładzie bodźców żadna polityka nie zadziała.
Drugi, równie systemowy mechanizm: instrukcje instalacyjne dostawców. Znaczna część dokumentacji wdrożeniowej od lat zaleca uruchomienie usługi na koncie z uprawnieniami administratora domeny „dla uproszczenia instalacji". Nadmiarowe uprawnienia nie powstają więc wskutek zaniedbania — są instalowane w dniu pierwszym i nikt nigdy do nich nie wraca, bo system działa.
Praktyczne wnioski dla prowadzącego audyt:
Zaplanuj rotację w oknie serwisowym z gotowym rollbackiem i weź odpowiedzialność za incydent na siebie. To zmienia rachunek bodźców skuteczniej niż każda polityka.
Nie pytaj dostawcy „czy da się na mniejszych uprawnieniach". Pytaj o listę konkretnych uprawnień potrzebnych do działania — inne pytanie, inna odpowiedź.
Zacznij od 10 kont z najwyższym scoringiem, nie od wszystkich naraz. Skuteczny audyt kont serwisowych mierzy się liczbą zamkniętych ścieżek ataku, nie długością arkusza.
Jak odróżnić konto serwisowe od zwykłego konta użytkownika w AD? Nie ma atrybutu, który to jednoznacznie oznacza. Pewnymi sygnałami są: obecność SPN, ustawiona flaga PasswordNeverExpires, brak logowań interaktywnych przy regularnych logowaniach typu 5 oraz występowanie konta w konfiguracji usług Windows, zadań harmonogramu lub pul aplikacji IIS.
Czy konta serwisowe można objąć MFA? Nie w klasycznym rozumieniu — konto nieinteraktywne nie ma jak potwierdzić drugiego składnika. Zamiast tego stosuje się ograniczenie źródła logowania (LogonWorkstations), blokadę logowania interaktywnego przez GPO, gMSA oraz warunkową kontrolę dostępu opartą o tożsamość workloadu.
Jak często rotować hasła kont serwisowych? Dla kont zarządzanych ręcznie: maksymalnie 12 miesięcy, a dla kont uprzywilejowanych 6 miesięcy. Dla gMSA rotacja jest automatyczna i domyślnie odbywa się co 30 dni. Kluczowe jest jednak nie samo interwał, lecz posiadanie mapy użycia, która czyni rotację bezpieczną.
Czy usunięcie nieużywanego konta serwisowego jest bezpieczne? Bezpieczniejsze jest wyłączenie i przeniesienie do OU kwarantanny na 30–60 dni. Konta wykorzystywane w procesach kwartalnych lub rocznych nie pojawią się w logach z ostatnich 30 dni i łatwo uznać je omyłkowo za martwe.
Audyt kont serwisowych w Active Directory nie jest ćwiczeniem z generowania list. Jego produktem jest pięć rzeczy: kompletna inwentaryzacja obejmująca konta bez SPN, mapa realnego użycia, imienny właściciel dla każdego konta, scoring ryzyka z progami działania i proces, który nie pozwala problemowi odrosnąć.
To samo, co robisz skryptem w AD, wielcy dostawcy kupują dziś za miliardy dolarów w postaci gotowych platform. Warstwa, na którą patrzysz — konta techniczne, tokeny, sekrety i agenci AI — przestała być detalem konfiguracyjnym i stała się jednym z głównych wektorów ataku. Dobra wiadomość jest taka, że w Active Directory pierwsze 80% wartości tego audytu zdobywa się narzędziami, które już masz.