Using AD Accounts in containerized NAV and what I learned on the way

Using AD Accounts in containerized NAV and what I learned on the way

29. März 2017

Using AD Accounts in containerized NAV and what I learned on the way

Since the first tries to get NAV in a Windows Container up and running I had the problem that compiling table structure changes didn’t work. The dev environment tried to connect to the NAV Server instance to start the sync but always returned with an error message that the Management Service wasn’t available1. Here is how we solved this, again with a lot of help by Jakub Vaňák:

Find the reason: maybe networking or the Service not starting?

From the very beginning, Jakub suspected that we needed to use AD accounts (as we are in Windows Containers, actually we needed to use gMSAs, read a quick intro here). To be honest, I personally was completely wrong by thinking that maybe the Management Service was blocked on some network issue, didn’t come up or at least not fully, although the event log looked fine. To verify or falsify my suspicion I built a small script along the lines of this. It clearly showed that the Service was up and available.

Find the reason: ask the application!

For that I enabled tracing on the WCF services that are part of the NAV Server. How to do that is documented quite well here and it basically comes down to adding something like the following in the Microsoft.Dynamics.Nav.Server.exe.config in the system.diagnostics section:

    <source name="System.ServiceModel" switchValue="All">  
            <add name="xml" />  
    <source name="System.IdentityModel" switchValue="All">  
            <add name="xml" />  
    <add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\log\Traces.svclog" />  

After that I copied the resulting trace to the host2 and opened it with the Service Trace Viewer Tool.

This nice tool allowed me to easily identify the problem: System.ServiceModel.Security.SecurityNegotiationException: The server has rejected the client credentials. —> System.Security.Authentication.InvalidCredentialException: The server has rejected the client credentials. —> System.ComponentModel.Win32Exception: The logon attempt failed

Ok, I wouldn’t have thought so, but obviously there seemed to be some kind of authentication even if only the dev environment asked the NAV Server instance to sync table changes. Which actually makes sense… I then wasted some time by trying to override the WCF Service configuration to not request authentication which also was doomed because I was able to kind of get there but then the dev env still tried to send the authentication info and the Service didn’t know how to respond3. Therefore, I did what I should have done in the very beginning, I followed Jakub’s idea to use gMSAs.

Solve the problem

It turned out to be not that difficult: With the documentation here and Jakub pointing me to this gist it went quite well. You can currently find the result in the gMSA branch of Jakub’s GitHub repo but I think we’ll merge it to master soon. I just don’t like to have to use hostnames identical with the gMSAs which also means you need one gMSA for every container instance per host. As you can see in the gist the author Patrick Lang seems to think that setting correct SPNs could do the trick and I’ll try to work in that direction. Therefore again, this is to be continued…

  1. The actual error message is: Unable to process table changes because the Microsoft Dynamics NAV Development Environment cannot connect to the specified Microsoft Dynamics NAV Server instance:

    Server Name: 362d57b02604
    Server Instance: navservice
    Management Port: 7045

    Microsoft Dynamics NAV Development Environment will detect a running server automatically.

    Check that:

    The Microsoft Dynamics NAV Server is running
    The management service is configured
    The firewall is open for the management port if remote
    The server is running with only one tenant
    Microsoft Dynamics NAV Development Environment is running as Administrator, or
    UAC is turned off.

  2. docker cp <containername>:<path-in-container> <local-path> which means docker cp navsql_nav_1:c:\log\Traces.svclog c:\temp
  3. It didn’t solve the problem, but also was quite interesting: It turned out that you can’t – or at least I wasn’t able to – override the Service config through the config file if the Service is generated and configured through code. I ended up trying to bind the Service to an additional endpoint on a different port which seemed to work as I didn’t get the error that the Server couldn’t authenticate. It just turned out that the error that the client tried to negotiate and the endpoint wasn’t able to was not really actual progress regarding the root problem…