Open JohnGalt1717 opened 6 months ago
A primary main concern for certificate setup is how you acquire the cert and keep it fresh, issuing a new cert on service startup is a massive no-no if using a public CA and instead you should probably pull from a secrets vault (otherwise you will quickly achieve your own denial-of-service via rate limits for issuance). Likewise if a service is long lived then it needs to refresh it's certificate(s) periodically. E.g. some CAs might issue a 24hr cert that would reasonably expire before the next service restart.
If issuance is outside the scope, then generically it's a secrets fetch/refresh problem. If issuance is in scope then you would need generic cert lifetime management hooks. Certs are typically for dns identifiers but they can cover many other things too, issuance can take seconds, minutes or hours (depending on the CA issuance process), so you can't block on issuance/renewal anywhere.
Background: I make a dotnet based ACME cert manager (for windows) and we have prototype k8s stuff, but it's clearly not a k8s specific problem.
So @webprofusion-chrisc did i miss anything that I should update in my proposal above? My concept is that it's declaritive, and at dev time it's really spinning docker containers that do the CA and everything else, and then it just dumps the config, and then Aspirate etc. would then go and orchastrate cert-manager on k8s as an example, and Azure could do the same with Azure KeyVault. (and there could be permutations with k8s and Azure Keyvault which can map those certs to file shares if you want)
This would abstract out what's actually happening, while doing the right work.
On spin up, it just loads the cer/key from the mapped directory into the containers with the mappings on the resources, the CA is responsible for (and should block until) it has refreshed all tokens on spin up in dev, and in k8s etc, that's a service that's running automatically doing it.
cc @DamianEdwards @blowdart
@JohnGalt1717 my main reticence about the idea is having CA as specific language as I feel they are step removed from aspire-land concerns. Secrets vaults (or perhaps well-known secrets like 'sql-server-connection-cert') seem like all that would be necessary.
@webprofusion-chrisc the purpose of Aspire is to make working in development like it's a production environment as easy as possible and being able to translate that design to production quickly and simply. Be that with Azure bicep or Aspir8, doesn't matter.
In all of those environments you will need to define certificates for many things (i.e. in k8s the docs clearly state that you should still be using TLS for all services internal coms because of security issues inside of k8s if someone gets inside the firewall). DataProtection requires a certificate, OpenIddict and all OpenIDConnect implementations require certificates, most databases will require a client certificate to be configured correctly and securely.
Even using YARP you need to issue a locally trusted certificate for development (i.e. you can use .net dev cert but...) and you need to be able to request your publicly trusted certificate from your cert store. Aspire being able to have a language that can be used to express both of these is invaluable.
There could be multiple certificate providers supported, like AzureKeyVault can be the CA and issue certs. This could be one. Cert-Manager on K8s is an obvious one too. I'm sure AWS and Google Cloud also have the same.
Being able to spin up something that can be messaged for production of "use your production way to create a certificate that does X,Y and Z" is a baseline, otherwise it's outside of your configuration. Being able to use something that is off the shelf and local for development and Testing instead of production/cloud issued is highly desirable just like local devs don't want to be using cloud Postgres for debugging.
So Building a CA and then issuing Certs and being able to share those certs between services is super valuable because it happens everywhere all the time in the real world. And it makes testing sooo much better in your CI/CD pipeline too if done right.
(secrets are the same, but separate request)
It could be that you're just using the term CA differently to how I interpret it. In my vocabulary a CA is a very high level part of the issuance food chain and is not an interchangeable terms for a secrets store or other cert cache etc because a CA is literally a trusted authority, not a cert store.
The artifacts that really matter from a CA are it's issuing root, intermediates (possibly no need for those in dev) and your end-entity/leaf, which amounts to maybe 100 lines of code to simulate.
One thing that's making nervous about CA specific language for dependencies is that people often do (incorrectly) design container based solutions to issue new certs on startups (instead of just pulling the latest), so if you have CI/CD which need trusted certs you can hit the public CA rate limit very quickly and I guess I'm trying to encourage architectures that can be started up 100s of times per day. My own (aspire enabled) k8s development spins up 100-200 instances multiple times per day, on a single machine.
One of the hardest things to do in K8s and other orchestrators (amongst others) is certificate management. And this isn't just at the ingress. Best practices say that all coms within your k8s cluster should be encrypted and you should be using certificate validation because of the hacks against containers that can compromise your entire cluster.
There is a solution to this in the k8s world: cert-manager. And in Azure it's KeyVault certificates.
In an ideal world, we would be able to define in Aspire Host something like the following:
var ca = .AddCA({some params});
Then, on each Micro Service/Resource add .AddSigningCert(ca) .AddCommsCert(ca)
And then
.AddYarp() .AddSigningCert(ca) .AddPublicCert(domains, or whatever)
For developers, what this would do is use step-ca or something similar in a docker container, and then spin the certs from there for the whole thing, and on the Yarp ingress those certs would be added to trust on every platform (I know, hard on Linux, but do it anyhow please)
And this would then generate the manifest information that would be necessary for Azure/AWS/Aspirate etc. to create the ingress, and setup all of the tooling internally and map it.
I.e. in K8s this would spin cert-manager, define the CA resource, define certificates for each of the micro services spun from the cert-manager CA, setup Yarp for ingress, define all of the micro-services endpoints on that Yarp instance, and use cert-manager to acquire the cert from Azure KeyVault/let's encrypt/AWS's version etc.
You would be a hero if this worked, and you'd be providing people with a HUGE reason to use C# in the world of micro-services and orchestration.
While I understand this is probably not doable for V1, it would be the next major win for V2 to have this because it squares the circle of everything other than just plain secrets and configmaps and is THE hardest thing to get right in this space.