Como criar um farm do AD FS sem privilégios de administrador de domínio
Aplica-se a: Windows Server 2022, Windows Server 2019 e 2016
Visão geral
A partir do AD FS no Windows Server 2016, você pode executar o cmdlet Install-AdfsFarm como administrador local no servidor de federação, desde que o Administrador de Domínio tenha preparado o Active Directory. O script abaixo deste artigo pode ser usado para preparar o AD. As etapas são as seguintes:
- Como Administrador de Domínio, execute o script (ou crie manualmente os objetos e as permissões do Active Directory).
- O script retornará um objeto AdminConfiguration que contém o DN do objeto do AD recém-criado
- No servidor de federação, execute o cmdlet Install-AdfsFarm enquanto estiver conectado como administrador local, transmitindo o objeto da etapa 2 acima como o parâmetro AdminConfiguration
Suposições
- Contoso\localadmin é um administrador interno Administrador de não domínio no servidor de federação
- Contoso\FsSvcAcct é uma conta de domínio que será a conta de serviço do AD FS
- Contoso\FsGmsaAcct$ é uma conta gMSA que será a conta de serviço do AD FS
- $svcCred são as credenciais da conta de serviço do AD FS
- $localAdminCred são as credenciais da conta de administrador local (não DA) no servidor de federação
Como usar uma conta de domínio como a conta de serviço do AD FS
Preparar o AD
Execute o seguinte como administrador de domínio
PS:\>$adminConfig=(.\New-AdfsDkmContainer.ps1 -ServiceAccount contoso\fssvcacct -AdfsAdministratorAccount contoso\localadmin)
Saída de exemplo
$adminconfig.DkmContainerDN
CN=9530440c-bc84-4fe6-a3f9-8d60162a7bcf,CN=ADFS,CN=Microsoft,CN=Program Data,DC=contoso,DC=com
Criar o farm do AD FS
No servidor de federação como administrador local, execute o código a seguir em uma janela de comando do PowerShell com privilégios elevados.
Primeiro, se o administrador do servidor de federação não estiver usando a mesma sessão do PowerShell que o administrador de domínio acima, recrie o objeto adminConfig usando a saída acima.
PS:\>$adminConfig = @{"DKMContainerDn"="CN=9530440c-bc84-4fe6-a3f9-8d60162a7bcf,CN=ADFS,CN=Microsoft,CN=Program Data,DC=contoso,DC=com"}
Em seguida, crie o farm:
PS:\>$svcCred = (get-credential)
PS:\>$localAdminCred = (get-credential)
PS:\>Install-AdfsFarm -CertificateThumbprint 270D041785C579D75C1C981DA0F9C36ECFDB65E0 -FederationServiceName "fs.contoso.com" -ServiceAccountCredential $svcCred -Credential $localAdminCred -OverwriteConfiguration -AdminConfiguration $adminConfig -Verbose
Como usar uma gMSA como a conta de serviço do AD FS
Preparar o AD
PS:\>$adminConfig=(.\New-AdfsDkmContainer.ps1 -ServiceAccount contoso\FsGmsaAcct$ -AdfsAdministratorAccount contoso\localadmin)
Saída de exemplo
$adminconfig.DkmContainerDN
CN=8065f653-af9d-42ff-aec8-56e02be4d5f3,CN=ADFS,CN=Microsoft,CN=Program Data,DC=contoso,DC=com
Criar o farm do AD FS
No servidor de federação como administrador local, execute o código a seguir em uma janela de comando do PowerShell com privilégios elevados.
Primeiro, se o administrador do servidor de federação não estiver usando a mesma sessão do PowerShell que o administrador de domínio acima, recrie o objeto adminConfig usando a saída acima.
PS:\>$adminConfig = @{"DKMContainerDn"="CN=8065f653-af9d-42ff-aec8-56e02be4d5f3,CN=ADFS,CN=Microsoft,CN=Program Data,DC=contoso,DC=com"}
Em seguida, crie o farm: observe que a conta de computador local e a conta de administrador do AD FS precisam receber os direitos de recuperação da senha e delegação à conta na gMSA.
PS:\>$localAdminObj = Get-ADUser "localadmin"
PS:\>$adfsNodeComputerAcct = Get-ADComputer "contoso_adfs_node"
PS:\>Set-ADServiceAccount -Identity fsgmsaacct -PrincipalsAllowedToRetrieveManagedPassword @( Add=$localAdminObj.SID.Value, $adfsNodeComputerAcct.SID.Value) -PrincipalsAllowedToDelegateToAccount @( Add=$localAdminObj.SID.Value, $adfsNodeComputerAcct.SID.Value)
PS:\>$localAdminCred = (Get-Credential)
PS:\>Install-AdfsFarm -CertificateThumbprint 270D041785C579D75C1C981DA0F9C36ECFDB65E0 -FederationServiceName "fs.contoso.com" -Credential $localAdminCred -GroupServiceAccountIdentifier "contoso\fsgmsaacct$" -OverwriteConfiguration -AdminConfiguration $adminConfig
Script para preparar o AD
O script do PowerShell a seguir pode ser usado para realizar os exemplos acima
[CmdletBinding(SupportsShouldProcess=$true)]
param (
[Parameter(Mandatory=$True)]
[string]$ServiceAccount,
[Parameter(Mandatory=$True)]
[string]$AdfsAdministratorAccount
)
$ServiceAccountSplit = $ServiceAccount.Split("\");
if ($ServiceAccountSplit.Length -ne 2)
{
Write-error "Specify the ServiceAccount identifier in 'domain\username' format"
exit 1
}
$AdfsAdministratorAccountSplit = $AdfsAdministratorAccount.Split("\");
if ($AdfsAdministratorAccountSplit.Length -ne 2)
{
Write-error "Specify the AdfsAdministratorAccount identifier in 'domain\username' format"
exit 1
}
#######################################
## Verify AD module is installed
#######################################
$m = "ActiveDirectory"
if (Get-Module | Where-Object {$_.Name -eq $m})
{
write-verbose "Module $m is already imported."
}
else
{
if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $m})
{
Import-Module $m -Verbose
}
else
{
write-error "Module $m was not imported, install the Active Directory RSAT package and retry."
exit 1
}
}
push-location ad:
#######################################
## Generate random DKM container name
## The OU Name is a randomly generated Guid
#######################################
[string]$guid = [Guid]::NewGuid()
write-verbose ("OU Name" + $guid)
$ouName = $guid
$initialPath = "CN=Microsoft,CN=Program Data," + (Get-ADDomain).DistinguishedName
$ouPath = "CN=ADFS," + $initialPath
$ou = "CN=" + $ouName + "," + $ouPath
#######################################
## Create DKM container and assign default ACE which allows AD FS admin read access
#######################################
if ($pscmdlet.ShouldProcess("$ou", "Creating DKM container and assigning access"))
{
Write-Verbose ("Creating organizational unit with DN: " + $ou)
if ($AdfsAdministratorAccount.EndsWith("$"))
{
write-verbose "AD FS administrator account passed with $ suffix indicating a computer account"
$userNameSplit = $AdfsAdministratorAccount.Split("\");
$strSID = (Get-ADServiceAccount -Identity $userNameSplit[1]).SID
}
else
{
write-verbose "AD FS administrator account is a standard AD user"
$objUser = New-Object System.Security.Principal.NTAccount($AdfsAdministratorAccount)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
}
if ($null -eq (Get-ADObject -Filter {distinguishedName -eq $ouPath}))
{
Write-Verbose ("First creating initial path " + $ouPath)
New-ADObject -Name "ADFS" -Type Container -Path $initialPath
}
$acl = get-acl -Path $ouPath
[System.DirectoryServices.ActiveDirectorySecurityInheritance]$adSecInEnum = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All
$ace1 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"GenericRead","Allow",$adSecInEnum
$acl.AddAccessRule($ace1)
set-acl -Path $ouPath -AclObject $acl
New-ADObject -Name $ouName -Type Container -Path $ouPath
}
#######################################
## Grant the following permission to the service account
# Read
# Create Child
# Write Owner
# Delete Tree
# Write DACL
# Write Property
#######################################
if ($ServiceAccount.EndsWith("$"))
{
write-verbose "service account passed with $ suffix indicating a gMSA"
$userNameSplit = $ServiceAccount.Split("\");
$strSID = (Get-ADServiceAccount -Identity $userNameSplit[1]).SID
}
else
{
write-verbose "service account is a standard AD user"
$objUser = New-Object System.Security.Principal.NTAccount($ServiceAccount)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
}
if ($pscmdlet.ShouldProcess("$strSID", "Granting GenericRead, CreateChild, WriteOwner, DeleteTree, WriteDacl and WriteProperty"))
{
[System.DirectoryServices.ActiveDirectorySecurityInheritance]$adSecInEnum = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All
$ace1 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"GenericRead","Allow",$adSecInEnum
$ace2 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"CreateChild","Allow",$adSecInEnum
$ace3 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteOwner","Allow",$adSecInEnum
$ace4 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"DeleteTree","Allow",$adSecInEnum
$ace5 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteDacl","Allow",$adSecInEnum
$ace6 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteProperty","Allow",$adSecInEnum
$acl = get-acl -Path $ou
$acl.AddAccessRule($ace1)
$acl.AddAccessRule($ace2)
$acl.AddAccessRule($ace3)
$acl.AddAccessRule($ace4)
$acl.AddAccessRule($ace5)
$acl.AddAccessRule($ace6)
$acl.SetOwner($strSID)
set-acl -Path $ou -AclObject $acl
}
#######################################
## Grant the following permission to the adfs admin account
# Read
# Create Child
# Write Owner
# Delete Tree
# Write DACL
# Write Property
#######################################
if ($AdfsAdministratorAccount.EndsWith("$"))
{
write-verbose "AD FS administrator account passed with $ suffix indicating a gMSA"
$userNameSplit = $AdfsAdministratorAccount.Split("\");
$strSID = (Get-ADServiceAccount -Identity $userNameSplit[1]).SID
}
else
{
write-verbose "AD FS administrator account is a standard AD user"
$objUser = New-Object System.Security.Principal.NTAccount($AdfsAdministratorAccount)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
}
if ($pscmdlet.ShouldProcess("$strSID", "Granting GenericRead, CreateChild, WriteOwner, DeleteTree, WriteDacl and WriteProperty"))
{
[System.DirectoryServices.ActiveDirectorySecurityInheritance]$adSecInEnum = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All
$ace1 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"GenericRead","Allow",$adSecInEnum
$ace2 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"CreateChild","Allow",$adSecInEnum
$ace3 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteOwner","Allow",$adSecInEnum
$ace4 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"DeleteTree","Allow",$adSecInEnum
$ace5 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteDacl","Allow",$adSecInEnum
$ace6 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $strSID,"WriteProperty","Allow",$adSecInEnum
$acl = get-acl -Path $ou
$acl.AddAccessRule($ace1)
$acl.AddAccessRule($ace2)
$acl.AddAccessRule($ace3)
$acl.AddAccessRule($ace4)
$acl.AddAccessRule($ace5)
$acl.AddAccessRule($ace6)
$acl.SetOwner($strSID)
set-acl -Path $ou -AclObject $acl
$adminConfig = @{"DKMContainerDn"=$ou}
Write-Output $adminConfig
}
pop-location