Reputation: 1653
My scenario: I have a public facing web app hosted on Amazon EC2 servers. I have a self-hosted database server behind a firewall. I have self-hosted Web Service servers with a web service for data access. I want to allow only applications I approve (my own living in the cloud) to access the services and I don't want any data passed in clear-text.
From what I can tell reading all the disjointed and maddeningly obfuscated MSDN articles, Stackoverflow threads, Code Project articles, and other blogs. The type of security I need is: Transport Security mode with Certificate clientCredentialType, using wsHttpBinding. First question, am I right in assuming that? Will that give me enough security? This isn't B2B or anything like that. It is, however, cross domain and I just want to ensure I can trust the caller. My service is running in an AppPool owned by a specific user so I can access the DB with integrated security. I need to make sure only callers to my service that I approve get in. I don't need to encrypt the message anymore than SSL already does I don't believe.
All the scenarios possible make it very very difficult to know if this is what I want. But assuming it is the next question is how do I set up the Certs? I currently have a Certificate on the server, and I can only access with Https. (security mode="Transport", clientCredentialType="None"). But for the life of me I can't figure out what I need to do to change clientCredentialType to Certificate and get it to work.
All development articles I read say that Cert setup is an Admin tool and beyond the scope of the article. Well, the WCF stuff is straightforward, it's exactly the friggin cert stuff I need help with, and there are no useful articles that I've found yet. Those that come close show how to do it with makecert.exe and say in production it will be different, but then don't say how to do it in production.
I'm sure my frustration level is showing, sorry about that. But it really makes no sense that there isn't a clear description on how to do what seems like a pretty common security scenario in WCF.
Any and all help appreciated, Ken
Upvotes: 3
Views: 2963
Reputation: 511
The type of security I need is: Transport Security mode with Certificate clientCredentialType, using wsHttpBinding. First question, am I right in assuming that?
Yes. Message security would also work assuming you do not use WCF streaming features, but with transport security you can benefit hardware acceleration.
how do I set up the Certs?
Please see the detailed answer below.
What do I give the client from the server and where does it go? If I have several clients (a web farm) do I have to have a different client cert for all of them, or can they share one cert that my server accepts?
You need 3 certificates :
The client needs:
What do I give the server from the client and where does it go?
The server needs:
In this scenario (communication between web farm and self hosted web services), you own both client and server machines. There is no need for third-party issued certificates (you trust yourself, right?). Which means you can safely use home-made certificates.
Here is a quick guide I hope will help you (or someone else), achieve this. If you already own certificates as your question suggests, feel free to skip step I. Furthermore, you may already have bought third-party issued certificates, in that case the root certificate authority (VeriSign, Microsoft, etc) certificate may already be installed on your client and server machines.
As explained in this msdn article, use makecert
to generate 3 certificates:
MyRootCA
, and its revocation list.https://mywebserver.myprivatedomain.com/service1.svc
, then your certificate CN (Common Name) will be mywebserver.myprivatedomain.com
.MyAmazonClient
.Here is a simple batch that achieves those 3 steps:
REM 1: MyRootCA
makecert -n "CN=MyRootCA" -r -sv "MyRootCA.pvk" "MyRootCA.cer"
makecert -crl -n "CN=MyRootCA" -r -sv "MyRootCA.pvk" "MyRootCA.crl"
REM 2: mywebserver.myprivatedomain.com
makecert -sk "mywebserver.myprivatedomain.com" -iv "MyRootCA.pvk" -n "CN=mywebserver.myprivatedomain.com" -ic "MyRootCA.cer" -sr LocalMachine -ss My -sky exchange -pe
REM 3: MyAmazonClient
makecert -sk "MyAmazonClient" -iv "MyRootCA.pvk" -n "CN=MyAmazonClient" -ic "MyRootCA.cer" -sr LocalMachine -ss My -sky signature -pe
This batch will create 3 files in the current folder:
The 2 other certificates (client and server) are installed in local computer certificate store.
Using the Certificates MMC Snap-in, export them into .pfx files:
On your server machine (the one exposing the web services), copy the following files:
Using the Certificates MMC Snap-in on the server machine, install the certificates in the following locations:
Local Computer > Trusted Root Certification Authorities > Certificates
Local Computer > Trusted People > Certificates
Local Computer > Personal > Certificates
Grant your IIS AppPool access to the private key of the mywebserver.myprivatedomain.com certificate. In MMC Certificates Snap-in, right click mywebserver.myprivatedomain.com > All Tasks > Manage Private Keys... Then add the identity your AppPool is running with. Note than when using ApplicationPoolIdentity (by default), identity name is IIS AppPool\YourAppPoolNameHere
.
Using IIS Manager, locate your website and add an https binding with your mywebserver.myprivatedomain.com
certificate. See Step 4: Configure Your Temporary Service Certificate in IIS to Support SSL.
<system.serviceModel>
<protocolMapping>
<add scheme="https" binding="wsHttpBinding" />
</protocolMapping>
<bindings>
<wsHttpBinding>
<!-- configure wsHttp binding with Transport security mode and clientCredentialType as Certificate -->
<binding>
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
On each client machine (web farm), copy the following files:
Using the Certificates MMC Snap-in on the client machines, install the certificates in the following locations:
Local Computer > Trusted Root Certification Authorities > Certificates
Local Computer > Personal > Certificates
Grant your IIS AppPool access to the private key of the MyAmazonClient certificate (same steps as II).
<system.serviceModel>
<client>
<!-- this endpoint has an https: address -->
<endpoint address="https://mywebserver.myprivatedomain.com/service1.svc"
behaviorConfiguration="endpointCredentialBehavior"
binding="wsHttpBinding"
bindingConfiguration="Binding1"
contract="MyWebApp.IServiceContract"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialBehavior">
<clientCredentials>
<clientCertificate findValue="MyAmazonClient"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<!-- configure wsHttpbinding with Transport security mode
and clientCredentialType as Certificate -->
<binding name="Binding1">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
And that's it.
Upvotes: 3