I'm currently trying to make some improvements to some old (and soon to be phased out) infrastructure in preperation for a move to .NET core. We have a small feedback form which writes into a SQL table using SQLOLEDB connection strings. These strings works fine with a username/password defined in cleartext though I am looking to move away from this method in favour of integrated authentication.
I have done a lot of work to get to where I am:
- Built a docker container based on IIS with ASP features installed.
- Running the container in a swarm on a Windows host - joined to our AD domain.
- Setup gMSAs in order to provide domain account access to the database.
At present, I've ran through all the steps in MS' gMSA on Windows Containers guide (https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts). The tests check out, I'm able to run all the tests in https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/gmsa-troubleshooting#check-the-container with no issues, however when I try to connect using my connection string, I receive an error in my logs showing:
2020-09-28 19:36:43 172.17.173.120 POST /Default.asp |42|80040e4d|Login_failed_for_user_'NT_AUTHORITY\ANONYMOUS_LOGON'.
This, to me, doesn't make much sense since the application pool identity is set to network and the tests check out on the container.
Now I've tried a few things like editing the web.config to have impersonate set to true/false, authentication via Windows but I'm still kind of stumped. I've set the host to be allowed to delegate any service over Kerberos.
I also tried logging in using:
docker exec -it --user "NT AUTHORITY\NETWORK SERVICE" cb4 powershell
then running:
$connectionString = 'Data Source=serverhostname.domain.local;database=databasename;Integrated Security = True;'
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $connectionString
$sqlConnection.Open()
$sqlConnection | select *
which results in a database connection with an open state.
The application pool is setup with the NetworkService identity
Get-ItemProperty IIS:\AppPools\domain.co.uk\ -Name processModel
identityType : NetworkService
userName :
password :
loadUserProfile : False
setProfileEnvironment : True
logonType : LogonBatch
manualGroupMembership : False
idleTimeout : 00:20:00
idleTimeoutAction : Terminate
maxProcesses : 1
shutdownTimeLimit : 00:01:30
startupTimeLimit : 00:01:30
pingingEnabled : True
pingInterval : 00:00:30
pingResponseTime : 00:01:30
logEventOnProcessModel : IdleTimeout
PSPath : WebAdministration::\\413E8843BBEF\AppPools\domain.co.uk\
PSParentPath : WebAdministration::\\413E8843BBEF\AppPools
PSChildName : domain.co.uk\
PSDrive : IIS
PSProvider : WebAdministration
Attributes : {identityType, userName, password, loadUserProfile...}
ChildElements : {}
ElementTagName : processModel
Methods :
Schema : Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema
Any suggestions would be appreciated!
Ok, so I figured this out and posted my findings in a public Gist:
https://gist.github.com/jimbo8098/48fa8d1cd05a61b35534aa107decb3e3
Basically, the problem was that while the application pool identity was set to Network, the site was not, it was using what appears to have been IUSR. Given this, I was not relaying the gMSA account to ASP's scripts and therefore I was unable to use integrated auth. The solution was to run:
What this did was set the username and password to blank and the logon method to network. This was perfect since it meant the application pool and site both used the expected account, the gMSA one.
A very useful way I found to get to the bottom of this was to make a test script:
Prior to the solution, this showed IUSR and was my big clue to the problem. After the solution, the UserName read
app$
(where app was the name of the gMSA) with the expected Domain.