A Public Key Infrastructure (PKI) is the basis of modern system authentication; X.509 certificates are at the core of modern cryptography. Building your own PKI is not for the faint of heart, so we usually buy our certificates from an external Certificate Authority or operate a 3rd-party off-the-shelf PKI.
But what can you do if you need to issue your own certificates while keeping your costs low? What if, for example, you're in the business of manufacturing millions of IoT devices and you need to issue a certificate to each and every one of them? And to top it off - you want to do it in a Serverless manner?
Join me in this session, as we build a Serverless PKI system with Azure Functions & Key-Vault and learn all about Key-Vault's capabilities in regards to X.509 certificates along the way.
6. Agenda
IoT Data Ingestion
PKIs, CAs & Certificates
Building a Serverless CA using .NET
Authoring Certificate Subscribers using .NET
Using the Generated Certificates
Device Provisioning Service & IoT Hub
6
7. About Eran
Eran Stiller
@eranstiller
CTO & Founder at CodeValue
Software architect, consultant and instructor
Microsoft Regional Director & Azure MVP
Founder of Azure Israel Meetup
7
9. IoT Data Ingestion
10
Data Ingestion Pipeline
Further Big Data
Processing
IoT Hub Raw Storage
(Data Lake)
Device
Device
Device
10. IoT Data Ingestion
11
Device
Device
Device
Data Ingestion Pipeline
Further Big Data
Processing
IoT Hub Raw Storage
(Data Lake)
Data Ingestion Pipeline
Further Big Data
Processing
IoT Hub Raw Storage
(Data Lake)
Device
Provisioning
Service
11. Securely Communicating with Devices
12
Confidentiality Authentication Authorization
Icons made by Freepik and Eucalyp for www.flaticon.com
14. Public Key Infrastructure (PKI)
An umbrella term for the stuff we need in order to:
Issue
Distribute
Store
Use
Verify
Revoke
and otherwise manage and interact with certificates and keys
Don’t build from scratch
Can use an off-the-shelf solution
Can build some parts and rely on others
15
15. Certificates
A driver’s license for computers and
code
Basically, a binding between an
identifier (name) and a public key
Usually encoded as X.509
16
Icon made by Becris for www.flaticon.com
16. Certificate Authority
The entity which issues certificates
Trusted by the Relying Parties
Public trusted root certificates are pre-populated
Various methods to verify identity
17
18. Certificates 101
19
Hi there, I’m Alice!
Hi Alice, I’m Bob!
How do I know you’re really Bob?
Here is my Certificate ( + certificate)
Prove it to me by decrypting this challenge ( + challenge)
There you go ( + decrypted challenge)
Continue secure conversation (Optionally – mutual authentication)
21. Azure Key Vault
Safeguard cryptographic keys and other secrets
Hardware Security Modules (HSM) as a service
Can be replaced with AWS Certificate Manager
Principles will remain unchanged
Implementation details will defer
22
24. Generating the Root Certificate on Key Vault
25
var certificateOperation = await client.CreateCertificateAsync(
_vaultBaseUrl,
_certificateName,
new CertificatePolicy(
keyProperties: new KeyProperties(false, "RSA", 2048, false),
x509CertificateProperties: new X509CertificateProperties(
"CN=" + RootSubjectName,
keyUsage: new List<string> {X509KeyUsageFlags.KeyCertSign.ToString()},
ekus: new List<string> {"1.3.6.1.5.5.7.3.2", "1.3.6.1.5.5.7.3.1"}),
issuerParameters: new IssuerParameters("Self")));
25. Generating the Root Certificate on Our Machine
26
using var certificateKey = RSA.Create();
var subjectDistinguishedName = new X500DistinguishedName("CN=" + RootSubjectName);
var request = new CertificateRequest(subjectDistinguishedName, certificateKey,
HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign, true));
request.CertificateExtensions.Add(
new X509BasicConstraintsExtension(true, true, 1, true));
// Additional X509 extensions not shown for brevity
var certificate =
request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1));
36. subject name, public key & access token
Sign a Request Using the Root Certificate
37
Device
Identity
Provider
Certificate
Authority
Key Vault
generate CSR
certificate digest (hash)
signed digest
signed certificate
Store certificate
& private key
authentication info
access token
generate
key pair
37. Getting an Access Token for Azure Functions
39
var auth = await authHelper.AcquireTokenAsync(); // AAD Token
var client = new HttpClient
{ BaseAddress = new Uri(configuration.BaseUrl) };
var request = new {access_token = auth.AccessToken};
var httpContent = ... // JSON serialization
var responseMessage = await client.PostAsync(".auth/login/aad", httpContent);
var serializedResponse = await responseMessage.Content.ReadAsStringAsync();
dynamic response = JsonConvert.DeserializeObject<dynamic>(serializedResponse);
return response.authenticationToken;
38. Issue Certificate
40
var key = RSA.Create();
var publicParameters = key.ExportParameters(false);
var request = new IssueCertificateRequest(
subjectName, publicParameters);
var httpContent = new StringContent(
JsonConvert.SerializeObject(request),
Encoding.UTF8,
MediaTypeNames.Application.Json);
39. Issue Certificate (Cont.)
41
var client = new HttpClient {BaseAddress = ...};
client.DefaultRequestHeaders.Add("X-ZUMO-AUTH", accessToken);
var responseMessage =
await client.PostAsync("api/issueCertificate", httpContent);
var serializedResponse =
await responseMessage.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<IssueCertificateResponse>(
serializedResponse);
var certificate = new X509Certificate2(
Convert.FromBase64String(response.Certificate));
return certificate;
40. Store Certificate With Private Key
42
var certificateWithPrivateKey =
certificate.CopyWithPrivateKey(key);
var rawCertificate =
certificateWithPrivateKey.Export(X509ContentType.Pfx);
var persistableCertificate =
new X509Certificate2(rawCertificate, string.Empty,
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.UserKeySet);
var store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(persistableCertificate);
43. IoT Data Ingestion (Reminder)
45
Device
Device
Device
Data Ingestion Pipeline
Further Big Data
Processing
IoT Hub Raw Storage
(Data Lake)
Device
Provisioning
Service
44. Sending Data Using the Generated Certificate
47
X509Certificate2 certificate =
LoadCertificate(configuration.DeviceName);
var security =
new SecurityProviderX509Certificate(certificate);
var transport = new ProvisioningTransportHandlerAmqp(
TransportFallbackType.TcpOnly);
var provClient = ProvisioningDeviceClient.Create(
GlobalDeviceEndpoint, configuration.DpsIdScope,
security, transport);
DeviceRegistrationResult registrationResult =
await provClient.RegisterAsync();
47. Takeaways
Certificates are hard, but crucial, to get right
Don’t author an entire PKI from scratch
Customize an existing solution where appropriate
IoT is one scenario where I encountered a need for a custom PKI
Handling certificates with .NET is surprisingly undocumented
With and without Azure Key Vault
Azure Key Vault is a great platform to base a CA on
The sample is just a sample, but is derived from a production system
Can base on it and form your own solution
51
Our story opens once upon a time, at one of my customers.
Free image URL: https://pixabay.com/photos/once-upon-a-time-writer-author-719174/
This customer was not a software company. In fact, it was a hardware company selling manufacturing equipment to various manufacturers around the world. The customer had a software development division. This division was mainly focused on writing software to operate the sold equipment and was mainly a .NET shop writing code in C#.
Free image URL: https://pixabay.com/photos/machine-plant-technology-4334729/
Until one day, the customer decided to connect the manufacturing equipment to the cloud – effectively creating an IoT system – and that’s where I came in.
Free image URL: https://pixabay.com/photos/nature-outdoor-sky-cloud-cloudy-3294543/
We had many challenges with that system, and one of the main ones was Security. How do we ensure that data is securely transported from the devices to the cloud, and that proper authentication & authorization is maintained? More specifically – how do we properly encrypt all communications and manage the infrastructure for allowing it? And how do we do it in .NET? Turns out that it is definitely possible, but documentation and knowledge is scarce, and that’s why I decided to create this session.
Free image URL: https://pixabay.com/photos/police-security-safety-protection-869216/
We want to achieve 3 main things with our secure channels: Confidentiality, Authentication & Authorization
HTTPS/TLS is the de-facto standard today for secure communication
Secure communication has some prerequisites – mainly certificates for communication and a secure PKI
There are various solutions out there for this problem out there – open source, hosted, and a combination there-of
No need to invent the wheel
However, in our project, since the customer was not a software company and there were very few developers on the project we really wanted tro keep it simple
As our solution was completely serverless and relying on Azure we decided to use Azure Key-Vault for implementing the basis for the PKI.
In addition, all developers were .NET developers so all server and client code needed to be written in C# - which caused a whole lot of trouble later on as documentation is quite scarce – but that’s why you are here for.
Free image URL: https://pixabay.com/photos/desk-table-simple-mockup-1081708/
Off-the-shelf solutions - Open source, hosted, hybrid
Show the certificate for https://github.com from the browser address bar
As we start building our CA we need to think about our root certificate and how to handle it.
Free image URL: https://pixabay.com/illustrations/safe-vault-steel-door-banking-913452/
One option is to create the certificate directly in Azure Key Vault. This is the best option and is the safest since the private key is created on Azure Key Vault and never leaves it.
But (click and show warning) – there is currently an issue where the certificate’s “Basic Constraints” extension cannot be controlled via the API, and this all created certificates are leaf certificates and cannot be properly used for signing other certificates later. As a result, we will revert to our second option.
The above RSA key is an ephemeral one.
Once we create the certificate – we upload it to Azure Key Vault, and quickly dispose of the RSA private key.
Emphasize the importance of using Managed Identities and reducing possible access to Key Vault in general and the Root Certificate in particular as much as possible
Access policies control data plane access rights
Emphasize that “Get Certificate” only allows getting the public certificate parts. Not the associated key (which cannot be obtained if you are using an HSM).
Emphasize the importance of using auditing to know who accessed the certificate and what operations were performed against it.
This slide shows usage of the built-in Key Vault logging. This can be integrated with Azure Monitor Logs to even better query and understand the resulting data.
Emphasize the importance of using auditing to know who accessed the certificate and what operations were performed against it.
This slide shows usage of the built-in Key Vault logging. This can be integrated with Azure Monitor Logs to even better query and understand the resulting data.
Now we have a root certificate, and we want to start issuing and signing certificates for our clients.
However, we want to do it in the most secure manner as possible. I.e. we don’t want the signing certificate key to ever leave its host – Azure Key Vault.
Free image: https://pixabay.com/photos/business-composition-laptop-3365360/
Emphasize that the signing key of the root certificate never leaves Key Vault
Show the code in two stages – core business logic, and then hosting.
Also show how to publish, and how authentication is handled by the App Service authentication mechanism.
Emphasize that the signing key of the root certificate never leaves Key Vault
Discuss the issue with persisting the private key, which only happens on Windows machines.
Also note the potential security flaw in this code which leaves the unencrypted certificate with private key in-memory until the GC collects it.
Mention that HSM can/should be used to store the certificate on the device.
This is the main demo of this section, where I show how do we write the client side end-to-end.
I estimate that this demo is 5-10 minutes long with mostly code.
Show how to upload the root certificate, do a proof-of-possession and setup the enrollment group.
Show how to upload the root certificate, do a proof-of-possession and setup the enrollment group.
Show device running end-to-end.