Active Directory FGPP: impedire la scadenza password con MaxPasswordAge=0 e lunghezza minima 16

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.

Indice

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

ApproccioQuando usarloPassaggi essenzialiProContro
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 accountPer 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

RequisitoDove si impostaConsiglio pratico
Lunghezza minima 16 caratteriMinimum password length = 16Se introduci “mai scade”, alza anche PasswordHistoryCount (es. ≥ 24) e valuta un dizionario di password vietate.
ComplessitàPassword must meet complexity requirements = EnabledValuta filtri password avanzati o Azure AD Password Protection per bloccare parole comuni e varianti “leet”.

Procedura dettagliata con AD Administrative Center

  1. Apri Active Directory Administrative Center (ADAC).
  2. Vai su Contoso (local)SystemPassword Settings Container.
  3. Clic su NewPassword 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.
  4. Chiudi ADAC.
  5. Apri ADSI Edit (adsiedit.msc), connettiti al Default naming context, apri CN=Password Settings Container,CN=System,DC=..., trova la tua FGPP, proprietà → msDS‑MaximumPasswordAge → imposta 0:0:0 → OK.
  6. In alternativa all’uso di ADSI, usa PowerShell (vedi sezione successiva) per impostare MaxPasswordAge a zero.
  7. Applica la FGPP a un gruppo di utenti o a utenti specifici: in ADAC, apri la FGPP → Directly Applies ToAdd → 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 che MaxPasswordAge sia 00: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

  1. Crea il gruppo GG-Admins-NoExpire e metti dentro gli amministratori.
  2. Crea la FGPP FGPP-ADM-16C-NoExpire con MaxPasswordAge = 0, MinPasswordLength = 16, complessità abilitata.
  3. Precedence bassa (es. 5) per assicurare prevalenza su altri PSO.
  4. Applica la FGPP al gruppo.

Copertura di un’intera OU tramite gruppo

  1. Crea un gruppo GG-OU-Finance-NoExpire.
  2. Aggiungi automaticamente gli utenti dell’OU “Finance” (con script periodico o membership dinamica tramite strumenti terzi).
  3. 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 e net user /domain.
  • Monitora con auditing e report periodici.

Riepilogo essenziale

  1. 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.
  2. Lunghezza minima 16 e complessità abilitata restano configurabili nella stessa FGPP insieme ad altri parametri (history, lockout, ecc.).
  3. 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.

Indice