Reputation: 67
I have a worker process running as a classic cloud service in Azure. This process needs to retrieve a value from an Azure key vault, and I need to keep the vault authentication secret outside my source tree.
Managed identities don't seem to be available for classic cloud workers, so I'm looking at certificates instead. I have gotten authentication by certificates to work locally, by creating a certificate and then uploading in Azure Active Directory for my app registration:
Certificate creation:
New-SelfSignedCertificate -Subject "CN=MyFineCertificate" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature
Code that uses it to connect to a key vault (works locally):
private static KeyVaultClient GetClient()
{
var certificate = GetCertificate();
var assertion = new ClientAssertionCertificate(clientId, certificate);
var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback((a, r, s) => GetAccessTokenUsingCert(a, r, s, assertion)));
return client;
}
private static X509Certificate2 GetCertificate()
{
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
var results = certStore.Certificates.Find(/* criteria */);
return results[0];
}
private static async Task<string> GetAccessToken(string authority, string resource, string scope, ClientAssertionCertificate cert)
{
var authContext = new AuthenticationContext(authority, TokenCache.DefaultShared);
var result = await authContext.AcquireTokenAsync(resource, cert);
return result.AccessToken;
}
So far so good. However, I want my Azure cloud worker to do this, so I need my certificate available there. My naive assumption was that I could, from the "Certificates" panel for my cloud worker in the portal, upload the certificate (pfx).
Unfortunately my cloud worker isn't able to find it. If I run this on Azure, after uploading my certificate, it doesn't show up:
foreach (StoreName name in Enum.GetValues(typeof(StoreName)))
{
foreach (StoreLocation location in Enum.GetValues(typeof(StoreLocation)))
{
var certStore = new X509Store(name, location);
certStore.Open(OpenFlags.ReadOnly);
foreach (var res in certStore.Certificates)
{
/* log certificate */
}
}
}
Why isn't it showing up? Am I even on the right track, or have I completely misunderstood how this works?
Upvotes: 4
Views: 645
Reputation: 9664
There are two parts to your question here:
Approach - As Managed Service Identity is not available with Cloud Services, how to work/authenticate with Azure Key Vault?
You are on the right track. I have described the approach for a similar problem to work with Key Vault in this SO Post - Securing sensitive information in Azure Cloud Service Configuration
Implementation - specifically how to access the self-signed certificate from cloud service role instance.
I think you might be missing to specify the certificate and it's location in the cloud service definition and configuration files. You should try adding something like this -
CSCFG
<Certificates>
<Certificate name="MyFineCertificate" thumbprint="<my_thumbprint>" thumbprintAlgorithm="<my_thumbprint_algo e.g. sha1>" />
</Certificates>
CSDEF
<Certificates>
<Certificate name="MyFineCertificate" storeLocation="LocalMachine" storeName="My" />
</Certificates>
Notice that I've mentioned store location as LocalMachine. Now, you should be able to access the certificate from your code by specifying the right location.
var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
Upvotes: 6