Using Group Managed Service Account (GMSA) to connect to AD resources - artisticcheese/artisticcheesecontainer GitHub Wiki
Windows containers running on computers joined to domain has unique feature which allows them to retain some domain membership advantages without actually being part of domain.
You will be able to authenticate to Active Directory resources from Windows container which is not part of your domain. For this to work certain prerequisites needs to be met.
For once your container hosts shall be part of Active Directory and you shall be able to utilize Group Managed Service Accounts. (https://technet.microsoft.com/en-us/library/hh831782%28v=ws.11%29.aspx?f=255&MSPPError=-2147217396)
Steps below will walk you through that process. My specific environment is described as below
- Active Directory in Windows 2012 mode.
- Domain name is `artisticcheese.local`
- 3 domain members named ContainerHost1, ContainerHost2, ContainerHost3.
- ContainerHost1 and ContainerHost2 will be used to test GMSA account connectivity
- ContainerHost3 runs SQL Express edition and will be used as a target for GMSA account connectivity
- Create GMSA account in AD
Import-module ActiveDirectory
Add-KdsRootKey –EffectiveTime ((get-date).addhours(-10));
New-ADServiceAccount -Name container_host -DNSHostName servicefabric.artisticcheese.local -PrincipalsAllowedToRetrieveManagedPassword "Domain Controllers",
"domain admins", "CN=Container Hosts,CN=Builtin, DC=artisticcheese, DC=local" -KerberosEncryptionType RC4, AES128, AES256
- Add container hosts computers to identified security group and verify their membership
Get-ADGroupMember -Identity "CN=Container Hosts,CN=Builtin, DC=artisticcheese, DC=local"
distinguishedName : CN=CONTAINERHOST2,CN=Computers,DC=artisticcheese,DC=local
name : CONTAINERHOST2
objectClass : computer
objectGUID : 7e706822-fe8b-496f-9a1f-01dc8d028c87
SamAccountName : CONTAINERHOST2$
SID : S-1-5-21-2047204889-2527894210-3918991376-1112
distinguishedName : CN=CONTAINERHOST1,CN=Computers,DC=artisticcheese,DC=local
name : CONTAINERHOST1
objectClass : computer
objectGUID : 4863a778-84e9-4907-b92f-7656ca6fe840
SamAccountName : CONTAINERHOST1$
SID : S-1-5-21-2047204889-2527894210-3918991376-1111
You need to reboot computers which are part of "Container Hosts" group for settings to take effect.
- Install GMSA account on servers which will use it.
Enable-WindowsOptionalFeature -FeatureName ActiveDirectory-Powershell -online -all
Get-ADServiceAccount -Identity container_host
Install-ADServiceAccount -Identity container_host
Test-AdServiceAccount -Identity container_host
If everything is ok you need to create credential spec file which will be passed to docker during instantiation time to utilize this service account. Script below downloads module which will create this file from Microsoft github account and will create a JSON file containing required data
Invoke-WebRequest "https://raw.githubusercontent.com/Microsoft/Virtualization-Documentation/live/windows-server-container-tools/ServiceAccounts/CredentialSpec.psm1" -UseBasicParsing -OutFile $env:TEMP\cred.psm1
import-module $env:temp\cred.psm1
New-CredentialSpec -Name Gmsa -AccountName container_host
#This will return location and name of JSON file
Get-CredentialSpec
If you don't redirect docker images folder then you don't need to do anything else. If you do (if you moved docker images to different drive via "graph" property) then you need to move resulting JSON file to whatever path your redirected your images to.
Move-Item (Get-CredentialSpec).Path -Destination E:\images\credentialspecs
Import-module docker
$hostConfig = [Docker.DotNet.Models.HostConfig]::new()
($hostconfig.SecurityOpt = [System.Collections.Generic.List[string]]::new()).Add("credentialspec=file://gmsa.json")
Run-ContainerImage -ImageIdOrName "microsoft/iis:latest" -HostConfiguration $hostConfig -Name iis -Detach
Login into running docker container and check if in fact you can communicated to Active Directory. Execute nltest /parentdomain
to verify
nltest /parentdomain
artisticcheese.local. (1)
The command completed successfully
- Test GMSA account
Login into your container via
Enter-PSsession
inside ISE (important since this will allow you to edit files remotely). Once inside container perform
#This installs ASP.NET
Add-WindowsFeature Web-Asp-Net45
cd C:\inetpub\wwwroot
New-Item -ItemType File -Name sqlquery.aspx
New-Item -ItemType File -Name web.config
#This will launch new tab in your ISE editor but the file you will be editing is located inside container
psedit .\sqlquery.aspx
Onece opened paste code below in sqlquery.aspx
and web.config
and save
web.config
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
sqlquery.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
using (SqlConnection cn = new SqlConnection("server=192.168.1.188;database=master;Trusted_Connection=True;Application Name=containerTest"))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "select c.net_transport,c.protocol_type,c.auth_scheme,s.program_name from sys.dm_exec_connections c join sys.dm_exec_sessions s on c.session_id = s.session_id";
cmd.Connection=cn;
cn.Open();
SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
Response.Write("<TABLE>");
while (rdr.Read())
{
Response.Write(String.Format("<TR><TD>{0}</TD><TD>{1}</TD><TD>{2}</TD><TD>{3}</TD></TR>", rdr.GetString(0), rdr.GetString(1), rdr.GetString(2), rdr.GetString(3)));
}
}
}
</script>
Open browser on host try to navigate to your container (http://172.25.71.59/sqlquery.aspx) in my case. You shall be receiving error message regarding authentication since you did not actually create SQL logins for this GMSA account like below.
Server Error in '/' Application.
VIEW SERVER STATE permission was denied on object 'server', database 'master'.
The user does not have permission to perform this action.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: VIEW SERVER STATE permission was denied on object 'server', database 'master'.
The user does not have permission to perform this action.
CREATE LOGIN [artisticcheese\container_host$] FROM WINDOWS
sp_addsrvRolemember "artisticcheese\container_host$", "sysadmin"
Execute again the same page and you shall be seeing successfull page return with information that you do in fact connect to SQL server via GMSA and utilizing NTLM for authentication.
Shared memory TSQL NTLM SQLServerCEIP
Shared memory TSQL NTLM Microsoft SQL Server Management Studio
TCP TSQL NTLM containerTest
Shared memory TSQL NTLM Microsoft SQL Server Management Studio - Query
Shared memory TSQL NTLM Microsoft SQL Server Management Studio - Query
On ContainerHost3 server we are going to create shared folder and will provide GMSA account RW permissions to it. ```powershell new-item -Type Directory -Path e:\test New-SmbShare -Name "test" -Path "e:\test" -FullAccess "everyone" ``` We are going to restrict write via NTFS permissions instead of share permissions. Add ACL for folder to allow GSMA account to write to that folder
$rule=new-object System.Security.AccessControl.FileSystemAccessRule @("artisticcheese\container_host$","Fullcontrol","Allow")
$acl = get-acl E:\test
$acl.SetAccessRule($rule)
$acl | set-acl e:\test
Create file named write-file.aspx
inside your container with following code using the same steps as above which were used for SQL GSMA account.
<%@ Page Language="C#" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
string lines = "Hello from container";
System.IO.StreamWriter file = new System.IO.StreamWriter("\\\\192.168.1.188\\test\\test.txt");
file.WriteLine(lines);
file.Close();
}
</SCRIPT>
Execute this file via calling it in browser. It shall create file on your ContainerHost3 server. Check owner of this file which shall reading as your GSMA account. This verifies
C:\Windows\system32> get-acl E:\test\test.txt | select Owner
Owner
-----
ARTISTICCHEESE\container_host$