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

image

2. Add the new SSL endpoint

image

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:

  1. Open MMC.EXE
  2. Added the certificate snap-in for local computer
  3. Locate your certificate
  4. Right Click -> All Tasks -> Manage Private Keys
  5. 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