Updating a WCF Azure Service to SSL and Client Certificate authentication
I created a WCF Service in Azure and started to use it, it started very simple but we added new features that need to be protected, so I started the journey of taking my simple WCF Service and configure it to use SSL and client authentication, one of the requirements was minimal downtime, so I need a transition period where both endpoints were available (Secure and Non-Secure) until I was sure that all the clients were configured properly.
I used as base this article “Using Certificate Based Authentication to Consume a Windows Azure WCF Service from SharePoint 2010” from MSDN and did a set of needed adjustments to make it work in my environment.
Configure the Server
1. Add the new certificate to the Web Role
2. Add the new SSL endpoint
With this we have a new SSL secured endpoint, but any client can use it
Now lets configure the service , to do so you need to modify the web.config, in my case I was using httpBinding, I added two bindings under <system.serviceModel> the NormalBinding to make explicitly the non secure endpoint and the new SecureBinding
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="NormalBinding" />
<binding name="SecureBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
And now set the binding configuration to my service, both of them the Secure and the Normal to ensure both are available
<services>
<service name="MyWebRole.MyService">
<endpoint binding="basicHttpBinding" bindingConfiguration="NormalBinding" contract="IService" />
<endpoint binding="basicHttpBinding" bindingConfiguration="SecureBinding" contract="IService" />
</service>
</services>
Under <Configuration> configure the SSL negotiation
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert" />
</security>
</system.webServer>
You can try to debug or deploy the Service and is very likely you will hit my major issue
“The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'”
To fix that you need to unlock the web.config, to do it modify the ServiceDefinition.csdef and add a task
<WebRole name="BeaconServiceWebRole" vmsize="Small">
<Startup>
<Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple">
</Task>
</Startup>
Create a Startup,cmd file in your web role and add this
%APPCMD% unlock config /section:system.webServer/security/access
Try to debug and deploy and should work
You will notice that those instructions are already in the article that I mention at the beginning, I guess the Azure SDK has changed since then and now you need to use the environment variable %APPCMD% to call the configuration, to be able to debug that I did a couple of things
- Add this to the Startup.cmd
%APPCMD% set config -section:system.webServer/httpErrors -errorMode:Detailed
It will allow you to see the detail of the errors, which will help you to understand the underlying issue
- Debugging locally you can add logging to your startup.cmd commands so you can see if they are successful, the quick way is to send it to a file like
%APPCMD% unlock config /section:system.webServer/security/access >> C:\logging\unlock.log
With that information I was able to figure out that the unlock wasn’t being executed and found the new way to do it with the %APPCMD% variable
Configure the client
Modify the app.config or web.config of the client to add the new configuration, you will need a new behavior, binding configuration and update the endpoint to use https my config looks like this
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="CertBehavior">
<clientCredentials>
<clientCertificate findValue="REplacewihtyourownthumbprintXXXXXXXXXXXX"
storeLocation="LocalMachine" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="secureByCert">
<security mode="Transport">
<transport clientCredentialType ="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://myservice.cloudapp.net/service.svc" binding="basicHttpBinding"
bindingConfiguration="secureByCert"
behaviorConfiguration="CertBehavior"
contract="IService" name="securedEndpoint" />
</client>
</system.serviceModel>
For web sites running in IIS you need to ensure the user in the app pool have permissions , usually the IIS applications run under Network Service to grant permissions to that account:
- Open MMC.EXE
- Added the certificate snap-in for local computer
- Locate your certificate
- Right Click -> All Tasks -> Manage Private Keys
- Add the <LocalMachine>\NETWORK SERVICE account and assigned Read rights.
Remove the Non Secure Endpoint
When all the clients are updated you can remove the non secure endpoint, to do that just remove the non secure endpoint
<endpoint binding="basicHttpBinding" bindingConfiguration="NormalBinding" contract="IService" />
The new configuration will be , with only the secure endpoint available
<services>
<service name="MyWebRole.MyService">
<endpoint binding="basicHttpBinding" bindingConfiguration="SecureBinding" contract="IService" />
</service>
</services>
To avoid any downtime you can publish this new configuration to Staging in Windows Azure and swap it , the details are here Staging an application in Windows Azure
Comments
Anonymous
December 16, 2014
Hi Jaime, I've tried all the steps you mentioned above and deployed the service to Azure. I then tried to build an anonymous client by attaching a certificate to this call and I was able to successfully make a call to the service and get a response back. But, I want to allow only the clients whose certificates are already imported to the certificate store of my server. How do I block an anonymous client with an anonymous certificate from making a call? Any help is appreciated! Thanks in advance! Thanks and Regards, Hima Sindhu Kacham.Anonymous
June 26, 2015
The comment has been removed