Share via


Create a Container with Active Directory Support

Windows Containers do not ship with Active Directory support and due to their nature can’t (yet) act as a full-fledged ___domain joined objects, but a certain level of Active Directory functionality can be supported through the use of Globally Manages Service Accounts (gMSA).

An introduction to gMSA can be found here : https://blogs.technet.microsoft.com/askpfeplat/2012/12/16/windows-server-2012-group-managed-service-accounts/

The gMSA is used to create a ‘CredentialSpec’ which is passed into the container at run time. Any process running on the container under the context of ‘Local Service’ will then present the ___domain creds of the gMSA to any ___domain joined service to which it connects. For example: you could run a Windows Service on a Container using a ___domain account to access a secure SQL server.

An introduction to gMSA use on Windows Containers can be found here:  /en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts

Step by Step

Obtain a gMSA Note: In this example we assume the name of the gMSA is adoncontt1. In the likely event that your gMSA has a different name, be sure to place each instance of adoncontt1 in this example with the name of your gMSA.

On the container host console

- Open Admin PowerShell
- Install AD features

Add-WindowsFeature RSAT-AD-PowerShell Import-Module ActiveDirectory

- Create the c:\data directory

mkdir c:\data Cd c:\data

- Fetch CredentialSpec.psm1 script (see below) and place a copy in c:\data

- Create the credential spec

Import-Module ./CredentialSpec.psm1 New-CredentialSpec -Name adoncontt1 -AccountName adoncontt1

- Verify the credential spec

Get-CredentialSpec

Start the Container

Active Directory support is enabled in containers by providing the name of the credentialspec (created above) in the --security-opt option in the docker run command as shown below. In this case the name of the credentialspec is adoncontt1

- Run the container interactively

docker run -it --security-opt "credentialspec=file://adoncontt1.json" microsoft/windowsservercore

Wait for container console shell to start

On the container console

Test AD access <if using AD>

nltest /parentdomain

At his point, if no errors occurred, the LocalSystem account on the container will be a proxy for the configured gMSA account. Any process run as the LocalSystem principal on the container will appear to be the gMSA principal to all assets on the Active Directory ___domain.

CredentialSpec Source

You may locate the latest version of CredentialSpec.psm1 at Virtualization-Documentation. After cloning a local Git repo the file will be located at <local repo>\Virtualization-Documentation\windows-server-container-tools\ServiceAccounts\CredentialSpec.psm1

The latest version as of 1/30/2017 is provided here for reference:

# This requires the ActiveDirectory module. Run Add-WindowsFeature rsat-ad-powershell to install it Import-Module ActiveDirectory $Script:CredentialSpecPath="$($env:ProgramData)\Docker\CredentialSpecs"

function New-CredentialSpec
{
param(
[Parameter(Mandatory=$true)] [String] $Name,
[Parameter(Mandatory=$true)] [String] $AccountName,
[Parameter(Mandatory=$false)] [Microsoft.ActiveDirectory.Management.ADDomain] $Domain = (Get-ADDomain),
[Parameter(Mandatory=$false)] $AdditionalAccounts
)

# TODO: verify $Script:CredentialSpecPath exists

# Start hash table for output
$output = @{}

# Create ActiveDirectoryConfig Object
$output.ActiveDirectoryConfig = @{}
$output.ActiveDirectoryConfig.GroupManagedServiceAccounts = @( @{"Name" = $AccountName; "Scope" = $Domain.DNSRoot } )
$output.ActiveDirectoryConfig.GroupManagedServiceAccounts += @{"Name" = $AccountName; "Scope" = $Domain.NetBIOSName }
if ($AdditionalAccounts) {
$AdditionalAccounts | ForEach-Object {
$output.ActiveDirectoryConfig.GroupManagedServiceAccounts += @{"Name" = $_.AccountName; "Scope" = $_.DomainName }
}
}

# Create CmsPlugins Object
$output.CmsPlugins = @("ActiveDirectory")

# Create DomainJoinConfig Object
$output.DomainJoinConfig = @{}
$output.DomainJoinConfig.DnsName = $Domain.Forest
$output.DomainJoinConfig.Guid = $Domain.ObjectGUID
$output.DomainJoinConfig.DnsTreeName = $Domain.DNSRoot
$output.DomainJoinConfig.NetBiosName = $Domain.NetBIOSName
$output.DomainJoinConfig.Sid = $Domain.DomainSID.Value
$output.DomainJoinConfig.MachineAccountName = $AccountName

$output | ConvertTo-Json -Depth 5 | Out-File -FilePath "$($Script:CredentialSpecPath)\\$($Name).json" -encoding ascii
}

function Get-CredentialSpec
{
Get-ChildItem $Script:CredentialSpecPath | Select-Object @{
Name='Name'
Expression = { $_.BaseName }
},
@{
Name='Path'
Expression = { $_.FullName }
}
}

Comments

  • Anonymous
    June 23, 2017
    Hello Mark , thanks for this blog this has been very useful. Does this also apply to IIS web applications running inside a container? if not how do we get as IIS web application to run under a ___domain identity to access network resources and also provide support for windows authentication.
  • Anonymous
    July 10, 2017
    Hello Mark, the current implementation requires the app to run under local system or network account. Looks like the supported scenario is only IIS.Is there a way to run an asp.net CORE application as system account, so it can benefit GMSA? Pls see my question here: https://stackoverflow.com/questions/44591253/run-aspnet-core-app-in-docker-using-gmsa
  • Anonymous
    September 08, 2017
    Mark, would you know how to setup AD authentication for a Docker container running on CentOS Linux?