Vuoi impedire la scadenza delle password per un insieme di utenti in Active Directory mantenendo standard di sicurezza elevati? Con una Fine‑Grained Password Policy (FGPP) puoi impostare MaxPasswordAge a zero, imporre almeno 16 caratteri e abilitare la complessità, il tutto senza alterare la Default Domain Policy.
Panoramica: cos’è una FGPP e quando serve
Le Fine‑Grained Password Policy (FGPP), introdotte da Windows Server 2008, consentono di applicare criteri password differenti all’interno dello stesso dominio, superando il limite “un solo set di regole per dominio” della Default Domain Policy (DDP). Le FGPP si applicano direttamente a utenti e/o a gruppi di sicurezza (consigliato: Global Security Group nello stesso dominio). Non si collegano a OU come i GPO: se vuoi coprire un’intera OU, crea un gruppo che contenga gli utenti (direttamente o tramite membership dinamica) e applica la FGPP a quel gruppo.
Nel nostro scenario l’obiettivo è: password che non scadono, lunghezza minima 16, complessità abilitata. Il dubbio tipico riguarda la voce Enforce maximum password age presente nell’interfaccia dell’Active Directory Administrative Center (ADAC).
Risposta rapida al dubbio
Deselezionare il checkbox Enforce maximum password age non imposta “mai scade”. Semplicemente la FGPP non definisce quel valore e quindi continuerà ad avere effetto ciò che è previsto nella Default Domain Policy (se questa impone, ad esempio, 30 o 60 giorni, la password continuerà a scadere).
Per ottenere “mai scade” in modo centralizzato con una FGPP devi impostare il valore massimo a 0 (zero). Poiché l’interfaccia ADAC non accetta “0 giorni”, occorre salvarlo via PowerShell o ADSI Edit.
Conclusione operativa: lasciare il checkbox non selezionato non basta; imposta
MaxPasswordAge = 0
nella FGPP (PowerShell/ADSI) oppure, per eccezioni puntuali, usa il flag di account Password never expires.
Prerequisiti e note di design
- Functional level: FGPP richiede dominio almeno Windows Server 2008.
- Dove vivono le FGPP: vengono create come Password Settings Object (PSO) in
CN=Password Settings Container,CN=System,DC=...
. - Ambito: applicabili a utenti e gruppi di sicurezza (stesso dominio). Non alle OU.
- Precedence: se a un utente si applicano più PSO, vince quello con msDS‑PasswordSettingsPrecedence più basso; a parità, prevale il PSO con GUID inferiore.
- Permessi: servono diritti di scrittura sul PSO e lettura sui soggetti; in genere membri di Domain Admins o delega mirata.
- Ambienti ibridi: con identità sincronizzate verso Entra ID (Azure AD), la scadenza resta governata da AD on‑prem. Le FGPP non “si vedono” nel cloud ma l’effetto per l’utente sincronizzato è quello previsto on‑prem.
Scelte operative a confronto
Approccio | Quando usarlo | Passaggi essenziali | Pro | Contro |
---|---|---|---|---|
A. FGPP con MaxPasswordAge = 0 (mai scade) | Quando serve una soluzione centrale e coerente per gruppi di utenti (anche su larga scala). | 1) Crea/modifica la FGPP in ADAC. 2) Spunta Enforce maximum password age per rendere editabile il campo, salva con un valore qualsiasi >0, poi imposta 0 via PowerShell o ADSI:– ADSI Edit → attributo msDS-MaximumPasswordAge = 0:0:0 – PowerShell: Set‑ADFineGrainedPasswordPolicy -Identity "NomePolicy" -MaxPasswordAge ([TimeSpan]::Zero) 3) Collega la FGPP a utenti o (preferibilmente) a un gruppo con Add‑ADFineGrainedPasswordPolicySubject . | Gestione centralizzata; facile audit; parametri di robustezza (min length, complessità, history) nello stesso oggetto. | Richiede conoscere bene precedenze e membership; l’interfaccia non consente direttamente “0 giorni”. |
B. Flag “Password never expires” sul singolo account | Per eccezioni puntuali (es. account di servizio legacy o pochi utenti particolari). | ADUC → scheda Account → spunta Password never expires. | Immediato; nessuna dipendenza da precedenze PSO. | Non scalabile; difficile da tracciare su larga scala; rischio di configurazioni incoerenti. |
Nota critica: lasciare il checkbox di ADAC non selezionato non azzera l’età massima. Se la Default Domain Policy prevede un valore > 0, la password continuerà a scadere.
Parametri di sicurezza complementari nella stessa FGPP
Requisito | Dove si imposta | Consiglio pratico |
---|---|---|
Lunghezza minima 16 caratteri | Minimum password length = 16 | Se introduci “mai scade”, alza anche PasswordHistoryCount (es. ≥ 24) e valuta un dizionario di password vietate. |
Complessità | Password must meet complexity requirements = Enabled | Valuta filtri password avanzati o Azure AD Password Protection per bloccare parole comuni e varianti “leet”. |
Procedura dettagliata con AD Administrative Center
- Apri Active Directory Administrative Center (ADAC).
- Vai su
Contoso (local)
→System
→Password Settings Container
. - Clic su New → Password Settings e compila:
- Name: es.
FGPP-16C-NoExpire
- Precedence: numero basso se vuoi che prevalga (es. 10).
- Password must meet complexity requirements: Enabled
- Minimum password length: 16
- Enforce minimum password age, Password history, Lockout: a tua scelta.
- Enforce maximum password age: spunta la casella (solo per rendere editabile il campo), imposta temporaneamente un valore > 0 e salva.
- Name: es.
- Chiudi ADAC.
- Apri ADSI Edit (
adsiedit.msc
), connettiti al Default naming context, apriCN=Password Settings Container,CN=System,DC=...
, trova la tua FGPP, proprietà → msDS‑MaximumPasswordAge → imposta0:0:0
→ OK. - In alternativa all’uso di ADSI, usa PowerShell (vedi sezione successiva) per impostare
MaxPasswordAge
a zero. - Applica la FGPP a un gruppo di utenti o a utenti specifici: in ADAC, apri la FGPP → Directly Applies To → Add → seleziona il gruppo/utente → OK.
Procedura completa in PowerShell
I cmdlet seguenti richiedono il modulo ActiveDirectory su una macchina con RSAT o su un Domain Controller.
Creare una nuova FGPP “16 caratteri + complessità + password mai scade”
Import-Module ActiveDirectory
1) Creazione della FGPP
New-ADFineGrainedPasswordPolicy ` -Name "FGPP-16C-NoExpire"`
-Precedence 10 ` -ComplexityEnabled $true`
-MinPasswordLength 16 ` -PasswordHistoryCount 24`
-MinPasswordAge (New-TimeSpan -Days 1) `
-MaxPasswordAge ([TimeSpan]::Zero)
2) Creazione/uso di un gruppo di sicurezza per l'ambito
New-ADGroup -Name "GG-Password-NoExpire" -GroupScope Global -GroupCategory Security -Path "OU=Gruppi,DC=contoso,DC=local"
3) Aggiungi gli utenti target al gruppo
Add-ADGroupMember -Identity "GG-Password-NoExpire" -Members user1,user2
4) Applica la FGPP al gruppo
Add-ADFineGrainedPasswordPolicySubject -Identity "FGPP-16C-NoExpire" -Subjects "GG-Password-NoExpire"
Convertire una FGPP esistente impostando “MaxPasswordAge = 0”
Set-ADFineGrainedPasswordPolicy -Identity "NomePolicyEsistente" -MaxPasswordAge ([TimeSpan]::Zero)
Verifica rapida
# Quale PSO risulta applicato a un utente?
Get-ADUserResultantPasswordPolicy -Identity user1 | Format-List Name,Precedence,MinPasswordLength,ComplexityEnabled,MaxPasswordAge
In alternativa, verifica l'attributo "msDS-ResultantPSO" e la scadenza vista dal dominio
Get-ADUser user1 -Properties msDS-ResultantPSO | Select-Object Name,msDS-ResultantPSO
net user user1 /domain
Rollback: tornare a una scadenza periodica
# Esempio: riportare la scadenza a 180 giorni
Set-ADFineGrainedPasswordPolicy -Identity "FGPP-16C-NoExpire" -MaxPasswordAge (New-TimeSpan -Days 180)
Alternativa puntuale: flag “Password never expires”
Per pochi account eccezionali, puoi usare il flag a livello di utente. Ha la precedenza sui criteri di dominio e impedisce la scadenza indipendentemente dalla DDP/FGPP.
# Abilita/Disabilita "Password never expires" su uno o più account
Set-ADUser user1 -PasswordNeverExpires $true
Get-ADUser -Filter * -Properties PasswordNeverExpires | Where-Object {$_.PasswordNeverExpires} | Select-Object SamAccountName
Usalo con parsimonia: è poco tracciabile su larga scala e può generare incoerenze.
Verifica, propagazione e timing
- Le FGPP non sono GPO: non serve
gpupdate
. Entrano in vigore al prossimo logon/kerberos TGT refresh e dopo la replica AD. - Controlli rapidi:
Get‑ADUser <utente> -Properties msDS-ResultantPSO
→ controlla il PSO risultante.Get‑ADUserResultantPasswordPolicy -Identity <utente>
→ verifica cheMaxPasswordAge
sia00:00:00
.net user <utente> /domain
→ la voce “Password expires” deve risultare Never.
- Password già scaduta: se un utente è già in stato “expired”, applicare la FGPP con MaxPasswordAge = 0 rimuove la scadenza dai successivi controlli; potrebbe essere necessario attendere la replica tra DC o ripetere l’accesso.
Linee guida di sicurezza quando disattivi la scadenza
- Rafforza il segreto: lunghezza minima alta (16+), history estesa (≥ 24), complessità abilitata.
- Blocca password deboli: filtri di password vietate (on‑prem o via Azure AD Password Protection).
- MFA per privilegiati: amministratori ed utenti sensibili dovrebbero usare MFA e postazioni sicure.
- Account di servizio: valuta gMSA (Group Managed Service Accounts) per eliminare la gestione manuale delle password dei servizi.
- Audit: abilita auditing di modifiche directory (eventi di tipo Directory Service Changes) e verifica periodicamente i PSO con
Get‑ADFineGrainedPasswordPolicy
.
Esempi di scenari reali
Team di amministrazione con password che non scadono
- Crea il gruppo
GG-Admins-NoExpire
e metti dentro gli amministratori. - Crea la FGPP
FGPP-ADM-16C-NoExpire
conMaxPasswordAge = 0
,MinPasswordLength = 16
, complessità abilitata. - Precedence bassa (es. 5) per assicurare prevalenza su altri PSO.
- Applica la FGPP al gruppo.
Copertura di un’intera OU tramite gruppo
- Crea un gruppo
GG-OU-Finance-NoExpire
. - Aggiungi automaticamente gli utenti dell’OU “Finance” (con script periodico o membership dinamica tramite strumenti terzi).
- Applica la FGPP a quel gruppo. In questo modo ottieni l’effetto “per OU” senza collegare la FGPP all’OU (che non è supportato).
Script di riferimento pronto all’uso
Import-Module ActiveDirectory
Parametri
$psoName = "FGPP-16C-NoExpire"
$precedence = 10
$groupName = "GG-Password-NoExpire"
$ouGroups = "OU=Gruppi,DC=contoso,DC=local"
Crea il gruppo se non esiste
if (-not (Get-ADGroup -Filter "SamAccountName -eq '$groupName'" -ErrorAction SilentlyContinue)) {
New-ADGroup -Name $groupName -SamAccountName $groupName -GroupScope Global -GroupCategory Security -Path $ouGroups
}
Crea o aggiorna la FGPP
if (-not (Get-ADFineGrainedPasswordPolicy -Filter "Name -eq '$psoName'" -ErrorAction SilentlyContinue)) {
New-ADFineGrainedPasswordPolicy ` -Name $psoName`
-Precedence $precedence ` -ComplexityEnabled $true`
-MinPasswordLength 16 ` -PasswordHistoryCount 24`
-MinPasswordAge (New-TimeSpan -Days 1) `
-MaxPasswordAge ([TimeSpan]::Zero)
} else {
Set-ADFineGrainedPasswordPolicy -Identity $psoName -ComplexityEnabled $true -MinPasswordLength 16 -PasswordHistoryCount 24 -MinPasswordAge (New-TimeSpan -Days 1) -MaxPasswordAge ([TimeSpan]::Zero)
}
Applica la FGPP al gruppo
$subjects = (Get-ADFineGrainedPasswordPolicy -Identity $psoName).AppliesTo
if ($subjects -notcontains (Get-ADGroup $groupName).DistinguishedName) {
Add-ADFineGrainedPasswordPolicySubject -Identity $psoName -Subjects $groupName
}
Verifica
Get-ADFineGrainedPasswordPolicy -Identity $psoName | Format-List Name,Precedence,MinPasswordLength,ComplexityEnabled,MaxPasswordAge,PasswordHistoryCount
Domande frequenti e troubleshooting
La UI non accetta “0” come massimo: è normale?
Sì. Salva un valore temporaneo e imposta successivamente MaxPasswordAge = 0
con PowerShell o ADSI Edit.
Ho deselezionato Enforce maximum password age ma le password scadono ancora.
Perché stai ereditando il valore dalla Default Domain Policy. Imposta esplicitamente 0
nella FGPP o usa il flag di account Password never expires.
Ho applicato la FGPP all’OU, ma non funziona.
Le FGPP non si applicano alle OU. Applica la PSO a utenti o a un gruppo di sicurezza che li contiene.
Due FGPP si sovrappongono sullo stesso utente: quale prevale?
Vince la PSO con Precedence (msDS‑PasswordSettingsPrecedence) più basso. A parità, prevale quella con GUID inferiore.
“net user” mostra ancora una data di scadenza.
Controlla: (1) replica tra Domain Controller, (2) che l’utente sia davvero membro del gruppo a cui è applicata la FGPP, (3) il PSO risultante con Get‑ADUserResultantPasswordPolicy
, (4) che la tua PSO abbia MaxPasswordAge = 0
.
È una buona pratica disattivare la scadenza periodica?
Molte linee guida moderne scoraggiano rotazioni arbitrarie; se togli la scadenza, compensa con lunghezza elevata, complessità, password ban list, MFA e monitoraggio.
Checklist operativa
- Definisci l’ambito (utenti/gruppi) e crea un gruppo dedicato.
- Crea la FGPP con Precedence adeguata.
- Imposta MinPasswordLength = 16 e ComplexityEnabled = True.
- Imposta MaxPasswordAge = 0 via PowerShell o ADSI Edit.
- Collega la FGPP ai soggetti corretti.
- Verifica con
Get‑ADUserResultantPasswordPolicy
enet user /domain
. - Monitora con auditing e report periodici.
Riepilogo essenziale
- Non basta deselezionare Enforce maximum password age: imposta il valore a 0 (PowerShell/ADSI) oppure, per casi isolati, usa il flag Password never expires sugli account.
- Lunghezza minima 16 e complessità abilitata restano configurabili nella stessa FGPP insieme ad altri parametri (history, lockout, ecc.).
- Verifica sempre la PSO risultante per assicurarti che la Default Domain Policy o PSO concorrenti non sovrascrivano il tuo criterio.
Esempi di comandi “copia e incolla”
# Impedire la scadenza via FGPP esistente
Set‑ADFineGrainedPasswordPolicy -Identity "FGPP-16C-NoExpire" -MaxPasswordAge ([TimeSpan]::Zero)
Imporre 16 caratteri e complessità
Set‑ADFineGrainedPasswordPolicy -Identity "FGPP-16C-NoExpire" -MinPasswordLength 16 -ComplexityEnabled $true
Collegare la FGPP a un gruppo
Add‑ADFineGrainedPasswordPolicySubject -Identity "FGPP-16C-NoExpire" -Subjects "GG-Password-NoExpire"
Verificare la PSO risultante su un utente
Get‑ADUserResultantPasswordPolicy -Identity user1
Verificare dal punto di vista del client
net user user1 /domain
Con questi passaggi ottieni password che non scadono, senza indebolire il controllo sul loro livello di robustezza e senza dipendere da interventi manuali su singoli account.