Installing Certificates in Windows Azure VMs

A little while ago I posted How To: Add an HTTPS Endpoint to a Windows Azure Cloud Service which talked about the whole process around adding an HTTPS endpoint and configuring & uploading the SSL certificate for that endpoint.

This post is a follow up to that post to talk about installing any certificate to a Windows Azure VM.  You may want to do this to install various client certificates or even to install the intermediate certificates to complete the certificate chain for your SSL certificate.

In order to peak into the cloud, I’ve written a very simple app that will enumerate the certificates of the Current User\Personal (or My) store.

Create a new Windows Azure Cloud Service and add an ASP.NET Web Role to it. 

Open up default.aspx and add the following between the empty <div></div> to setup a table that will be used to list the certificates.

 <asp:Table ID="certificateTable" runat="server">
    <asp:TableRow runat="server">
        <asp:TableCell runat="server">Friendly Name:</asp:TableCell>
        <asp:TableCell runat="server">Issued By:</asp:TableCell>
        <asp:TableCell runat="server">Issued To:</asp:TableCell>
        <asp:TableCell runat="server">Expiration Date:</asp:TableCell>
    </asp:TableRow>
</asp:Table>

Now, I have some simple code that opens up a certificate store and adds a row to the table for each certificate found with the Friendly Name, Issuer, Subject and Expiration date.

 protected void Page_Load(object sender, EventArgs e)
{
    X509Certificate2Collection selectedCerts = new X509Certificate2Collection();

    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    try
    {
        store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
        foreach (X509Certificate2 cert in store.Certificates)
        {
            TableRow certificateRow = new TableRow();

            // Friendly Name
            TableCell friendlyNameCell = new TableCell();
            TextBox friendlyNameText = new TextBox();
            friendlyNameText.Text = cert.FriendlyName;
            friendlyNameCell.Controls.Add(friendlyNameText);
            certificateRow.Cells.Add(friendlyNameCell);

            // Issuer
            TableCell issuerCell = new TableCell();
            TextBox issuerText = new TextBox();
            issuerText.Text = cert.Issuer;
            issuerCell.Controls.Add(issuerText);
            certificateRow.Cells.Add(issuerCell);
            
            // Subject
            TableCell subjectCell = new TableCell();
            TextBox subjectText = new TextBox();
            subjectText.Text = cert.Subject;
            subjectCell.Controls.Add(subjectText);
            certificateRow.Cells.Add(subjectCell);

            // Expiration
            TableCell expirationCell = new TableCell();
            TextBox expirationText = new TextBox();
            expirationText.Text = cert.NotAfter.ToString("d");
            expirationCell.Controls.Add(expirationText);
            certificateRow.Cells.Add(expirationCell);
            
            // Add the TableRow to the Table
            certificateTable.Rows.Add(certificateRow);
        }
    }
    finally
    {
        store.Close();
    }
}

Build, publish and deploy this to the cloud and you’ll see that the CurrentUser\MY store is empty. 

image 

Now that I have a way to show you the certificates that I install to the cloud, let’s follow the process to install 2 certificates.  One is a self signed certificate with a private key I created myself and the other is an intermediate certificate I got from the verisign web site. 

Installing a certificate to Windows Azure is a three step process. 

  1. Configure the certificates to install per role
  2. Upload the certificates via the Windows Azure Developer Portal per hosted service
  3. Deploy your app and when VMs are setup to host each of your role instances, those VMs will contain your certificates.

Note: The configuration of the certificates are per role but the upload of the certificates are for a hosted service and will be used for all of the roles in that hosted service.

Configure the certificates.  Bring up the configuration UI for the Web Role in your solution, click on “Certificates” and click on “Add Certificate”.

image

Now click on the “. . .” to bring up the certificate selection dialog.  This currently enumerates the certificates in the CurrentUser\My store, however in future versions this will enumerate the certificates in LocalMachine\My.  The dialog specifies which store it is listing the certificates from.

image

In my example, I’m selecting a self-signed certs with an exportable private key that I’ve setup ahead of time.

This sets the thumbprint field for that certificate.

image

Now I have a CER file from verisign which is an intermediate cert.  The steps to create it was to copy a big long chunk of text from their web site and save it as a .CER file which I did.

I have a couple of choices on how to handle this, I could install this certificate to the CurrentUser\My store and select it from the VS UI to get the thumbprint.

Instead, I’m going to open the certificate, switch to Details and copy the Thumbprint from the certificate itself (the point of doing the 2 certificates is to show alternate ways of handling the certificates):

image

Now I click “Add Certificate” on the Certificates tab of the VS UI and paste in the thumbprint for my second certificate.  I also changed the names of the certificate entries to “SelfSigned” and “Intermediate” for clarity but certainly is not necessary.

image

Note: I changed the store location and store name to CurrentUser and My – typically you will install intermediate certs to the CA store but to keep this sample simple I only want to enumerate one store, CurrentUser\My which as we saw above is empty by default in Windows Azure so I’m installing the two example certificates to the CurrentUser\My store.

The dropdown for store name currently contains My, Root, CA and Trust.  We do support you opening the service definition file and setting any string for the Store Name that you would like in the event that the 4 in the drop down are not sufficient.

 <Certificate name="SelfSigned" storeLocation="CurrentUser" storeName="<enter a value>" />

I now need to upload these certificates through the Developer Portal which means I need them as files.  I have the .CER file already but need to export my self-signed cert from the certificate store.

To do so I run certmgr.msc, browse to the certificate, right click | All Tasks | Export…

image

This takes me through Windows Certificate Export Wizard.  One of the key things for SSL certificates and any other certificates where you need the private key in the Cloud, is to ensure that you select “Yes, export the private key” and provide a password during the export

image

After finishing the wizard, I now have 2 certificate files, the .CER file and the .PFX file that was just created.

image

Now I go to the Developer portal, and select my Hosted Service.  Down at the bottom I select “Manage” under the “Certificates” heading.

image 

This allows me to browse to PFX files, type the same password you entered when exporting the certificate and uploading that certificate to the cloud.

image 

You’ll notice here that the Portal only allows uploading of PFX files but we need to upload a .CER file.  This will change in the future but for now, there is some simple code you can run to convert your .CER file to PFX.  I put the following code in a console application and ran it.

 static void Main(string[] args)
{
    // The path to the certificate.
    string certificate = @"C:\Users\jnak.REDMOND\Desktop\verisignintermediate.cer";

    // Load the certificate into an X509Certificate object.
    X509Certificate cert = new X509Certificate(certificate);
    byte[] certData = cert.Export(X509ContentType.Pkcs12);

    System.IO.File.WriteAllBytes(@"C:\Users\jnak.REDMOND\Desktop\verisignintermediate.pfx", certData);
}

Now that I have a PFX file for my CER file, I upload that leaving the password field blank because the password is only used to protect private keys which CER files do not have and therefore this PFX file also does not have.

You can see here that both certificates are now installed to my Hosted Service.

image

Now I deploy my Cloud Service which will enumerate the two certificates I installed to the CurrentUser\My store.  If you deployed the app already as I did above, just suspend and delete that deployment and deploy the app again with the new configuration.  (both the service definition and service configuration files have changed so the package (cspkg) and service configuration (cscfg) need to be deployed again to Windows Azure.

After you complete the deploy process and your app is running on Windows Azure, you’ll now see the following:

image

This shows that the VMs in the cloud for your role have the certificates you configured and uploaded installed.

Finally I’ll reiterate that certificate configuration is on a per role basis.  As an example, if I added a worker role to this same Cloud Service, the VMs for the worker role instances would not contain the certificates we configured above unless you opened up the configuration UI for the Worker role and added the same entries to the Certificates tab.

That said, because the certificates are upload per hosted service – you do not need to upload the certificates to the cloud more than once for a given Cloud Service.