Note: Development and Testing purposes only. Not supported in production environments.
Link to other containerization articles
In this blog post about security and containers, we will be discussing about implementing a Kerberos Double Hop from the client machine to the PI Web API container and finally to the PI Data Archive container. Previously, when we are using the PI Web API container located here Spin up PI Web API container (AF Server included), we are using local accounts for authentication to the backend server such as the AF Server or the PI Data Archive. The limitation is that without Kerberos Delegation, we will not be able to have per user security which means that all users of PI Web API will have the same permissions. i.e. an operator can read the sensitive tags that were meant for the upper management and vice versa. Obviously, this is not ideal. What we want is to have more granularity in assigning permissions to the right people so that they can only access the tags that they are supposed to read.
You will need to have 2 GMSA accounts. You can request such accounts from your IT department. They can refer to this blog post if they do not know how to create GMSA Spin up AF Server container (Kerberos enabled). Also be sure that one of them has the TrustedforDelegation property set to True. This can be done with the Set-ADServiceAccount cmdlet.
You will also need to build the PI Data Archive container by following the instructions in the Build the image section here.
For the PI Web API container, you will need to pull it from the repository by using this command.
docker pull elee3/afserver:webapi18
Demo without GMSA
First let us demonstrate how authentication will look like when we run containers without GMSA.
Let's have a look at the various authentication modes that PI Web API offers.
For more detailed explanation aboout each mode, please refer to this page.
We will only be going through the first 3 modes as Bearer requires an external identity provider which is out of the scope of this blog.
Create the PI Data Archive container and the PI Web API container. We will also create a local user called 'enduser' in the two containers.
docker run -h pi --name pi -e trust=%computername% pidax:18 docker run -h wa --name wa elee3/afserver:webapi18 docker exec wa net user enduser qwert123! /add docker exec pi net user enduser qwert123! /add
Now let's open up PSE and connect to the hostname "wa". If prompted for the credentials, use
Change the authentication to Anonymous and check in the changes. Restart the PI Web API service.
Verify that the setting has taken effect by using internet explorer to browse to /system/configuration. There will be no need for any credentials.
We can now try to connect to the PI Data Archive container with this URL.
Check the PI Data Archive logs to see how PI Web API is authenticating.
Result: With Anonymous authentication, PI Web API authenticates with its service account using NTLM.
Now use PSE to change the authentication to Basic and check in. Restart the PI Web API service.
Close internet explorer and reopen it to point to /system/configuration to check the authentication method. This time, there will be a prompt for credentials. Enter
Try to connect to the same PI Data Archive earlier. You will get an error as the default PI Data Archive container doesn't have any mappings for enduser
Let's see what is happening on the PI Data Archive side.
Result: With Basic authentication, the end user credential has been transferred to the PI Data Archive with NTLM.
Finally use PSE to change the authentication to Keberos and check in. Restart the PI Web API service.
Close internet explorer and reopen it to point to /system/configuration to check the authentication method. The prompt for credentials will look different from the Basic authentication one. Use the same credentials as you did for the Basic authentication scenario.
Try to connect to the same PI Data Archive again. You should not be able to connect. When you check on the PI Data Archive logs, you will see
Result: With Kerberos authentication, the delegation failed and the credential became NT AUTHORITY\ANONYMOUS LOGON even though we logged on to PI Web API with the local account 'enduser'.
Demo with GMSA
Now we shall use the GMSA accounts that we have to make the last scenario with Kerberos delegation work.
Download the scripts for Kerberos enabled PI Data Archive and PI Web API here.
I will use the name 'untrusted' as the name of the GMSA account that is not trusted for delegation and 'trusted' as the name of the GMSA account that is trusted for delegation. Set the SPN for 'trusted' like such
setspn -s HTTP/trusted trusted
Once you have the scripts, run them like this
.\New-KerberosPIDA.ps1 -AccountName untrusted -ContainerName pik .\New-KerberosPWA.ps1 -AccountName trusted -ContainerName wak
The scripts will help you to create a credential spec for the container based on the GMSA that you provide to it. A credential spec will let the container know how it can access Active Directory resources. Then, it will use this credential spec to create the container using docker run command. It will also set the hostname of the container to be the same as the name of the GMSA. This is required because it is a current limitation with the implementation that might be resolved in the future so that you can choose your own hostnames.
Open internet explorer now with your domain account and access PI Web API /system/userinfo. The hostname is 'trusted'.
Make sure that ImpersonationLevel is 'Delegation'.
Now try to access the PI Data Archive. The hostname is 'untrusted'. You will be unable to access. Why? Because you haven't created a mapping yet! So let's use SMT to create a mapping to your domain account. After creating a mapping. Try again and you should be able to connect. The PI Data Archive logs will show that you have connected with Kerberos. You do not need any mapping to your PI Web API service account at all if Kerberos delegation is working properly.
Result: With Kerberos authentication method in PI Web API and the use of GMSAs, Kerberos delegation works. The end domain user is delegated from the client to the PI Web API container to the PI Data Archive container. We have successfully completed the double hop.
If this doesn't seem to work for you, one thing you can try is to check the setting for internet explorer according to this KB article.
Your browser settings might differ from mine but the container settings should be the same since the containers are newly created.
Alternative: Resource Based Constrained Delegation
A more secure way to do Kerberos delegation instead of trusting the PI Web API container GMSA for delegation is to set the property "PrincipalsAllowedToDelegateToAccount" on the PI Data Archive container GMSA. This is what we call Resource Based Constrained Delegation (RBCD). You do not have to trust any GMSAs for delegation in this scenario. You will still need two GMSAs.
Assuming that you have already created the two containers with the scripts found above. I will use 'pida' as the name of the PI Data Archive container GMSA and 'piwebapi' as the name of the PI Web API container GMSA.
.\New-KerberosPIDA.ps1 -AccountName pida -ContainerName pik .\New-KerberosPWA.ps1 -AccountName piwebapi -ContainerName wak
Execute these two additional commands to enable RBCD.
docker exec pik powershell -command "Add-WindowsFeature RSAT-AD-PowerShell" docker exec pik powershell -command "Set-ADServiceAccount $env:computername -PrincipalsAllowedToDelegateToAccount (Get-ADServiceAccount piwebapi)"
You will still be able to connect with Kerberos delegation from the client machine to the PI Web API container to the PI Data Archive container. In this case, the PI Data Archive container only strictly allows delegation from the PI Web API container with 'piwebapi' as its GMSA.
We have seen that containers are able to utilize Kerberos delegation with the usage of GMSAs. This is important for middleware server containers such as PI Web API. Here is a quick summary of the various results that we have seen.
|Authentication Mode||No GMSA||With GMSA|
|Anonymous||NTLM with service account||No reason to do this|
|Basic||NTLM with local end user account||No reason to do this|
|Kerberos||NTLM with anonymous logon||Kerberos delegation with domain end user account|
The interesting thing is that Basic authentication can also have per user security with local end user accounts. But you will need to maintain the list of local users in the PI Web API container and the PI Data Archive container separately which is not recommended. The ideal case is to go with Kerberos delegation.