Running one’s own root Certificate Authority in 2023
wejn.org
wejn.org
Then stick it in step-ca and issue all your certificates with internal ACME.
This would solve a lot of problems, such as leaking private hostnames in the certificate transparency log, or hitting issuance rate limits on LE servers.
Unfortunately, name constraints don't work in all clients. Name constraints are an 'extension' to the standard and supporting them is optional.
According to [1]
> Before relying on this solution to protect our users, we wanted to make sure browsers were really implementing Name Constraints verification and doing so correctly. The initial results were promising: each of the browsers we tested (Chrome, Firefox, Edge, and Safari) all gave verification exceptions when browsing to a site where a CA signed a certificate in violation of the constraints.
> However, as we extended our test suite beyond basic tests we rapidly began to lose confidence. [...] The result was that every browser (except for Firefox, which showed a 100% pass rate) and every HTTPS client (such as Java, Node.JS, and Python) allowed some sort of Name Constraint bypass.
And even if someone went around and fixed every TLS library in the world, there'd still be millions of devices out there that never get security updates, like smart fridges and ancient android tablets.
There's a major chicken-and-egg problem: Because nobody will issue name-constrained certificates, clients don't have much reason to prioritise it as a feature. And because name constraints don't work perfectly everywhere, nobody will issue name-constrained certificates.
I doubt we'll ever see a trusted CA issuing name constrained intermediate CA certificates.
Of course, they could offer an API where if you've passed auth for *.example.com you can issue a cert for any subdomain below that without any further validation...
On a practical level, the latter is more logistically complex (and needs to be reconciled with other hard-fought battles, like CT). Given that it’s roughly the same as a wildcard certificate in terms of end-user use, it’s IMO understandable that this isn’t a priority for the CA ecosystem to support.
(The use case of circumventing CT is probably a non-starter as well. The Web PKI doesn’t want CT loopholes!)
In short, allowing user-controlled name-constrained intermediate CAs opens up multiple cans of worms that the ecosystem is not currently prepared to handle. Presenting a compelling argument for these user-controlled CAs means explaining (and getting buy-in) for solutions to the above.
> name constraints with multiple prospective paths
Can you expand on this for me? Is this really a problem?
> longer-live[d] certificates than the CA/B guidelines permit
The iCA cert would only be valid for 90 days (or less, they could make it 30 or 15 days). Would a cert be valid if the iCA cert that issued it is expired?
> known insecure algorithm choices
Disallow bad algorithms by policy. Evidence of issuance using a bad algorithm gets the iCA revoked and the ACME account locked out. Many clients don't allow insecure algorithms by their own policy.
If you're securing your internal network with bad algos but it never touches the wider internet, does it make a sound? Would this be better or worse than installing self-signed root CAs everywhere?
Sure, happy to: the issue here is that the user’s root might present multiple prospective validation paths, none of which have to agree on the total constructed set of permitted/denied name constraint subtrees. Path validation also doesn’t impose an order, meaning that two clients can (correctly!) disagree on the set of names that a validation path can issue.
Is it really a problem? Maybe: the various Web/Internet PKI standards aren’t clear about how to handle situations like this, and things that change the Web PKI to rely more heavily on correct extension handling have historically revealed lots of fragile/noncomplying clients.
> Would a cert be valid if the iCA cert that issued it is expired?
Nope, I made a mistake here: this wouldn’t be an issue, for the reason you’ve said.
(Having an ICA that expires every 90 days would impose other logistical challenges, however: you’d either need to include it in the server response along with the leaf, or lean heavily on an extension like AIA to retrieve the current ICA certificate.)
> If you're securing your internal network with bad algos but it never touches the wider internet, does it make a sound? Would this be better or worse than installing self-signed root CAs everywhere?
Probably no worse for the private network scenario, although I think the proposed solution here ends up confounding the public and private cases: the certs issued under a NC’d ICA would also be valid on the public Internet, and may end up intentionally or unintentionally depending on this behavior.
If I had to TL;DR my opinion here, I think it would be: “all of these things are solvable or addressable at the policy level, but the Web PKI has historically been brittle to assumptions that currently standardized things are correctly respected by the client ecosystem” :-)
Intermediate certificate is more secure because you can use different certificates for different subdomains, insead of sharing private key for wildcard certificate with every subdomain server.
Whether it hits CT or not - is not relevant at all. What matters is if intermediate certificate hits CT.
So when a CA gets compromised in some part of the the world (or gets manipulated by a state actor that effectively runs the CA) somebody could just emit a valid certificate for a domain you control.
In case of private intermediate name restricted CAs, that can be addressed by logging the issuance of the intermedia CAs.
Yep, that's a "main" thing that CT is intended to address. But it has other useful applications as well: because anybody (including website operators) can monitor the transparency log, they can additionally assert that their own trusted CA is not issuing more than one certificate for the domains they control.
Logging only the name-constrained intermediate CA would make third-party monitoring less useful. It would also have a perverse effect on attacker incentives: the attacker now only needs to compromise a user-controlled CA with a likely to be weaker security posture.
(That being said, maybe these tradeoffs are worth it! I don't have a strong opinion about that, other than my impression that the status quo with Let's Encrypt + intentionally leaking a few private subdomains isn't really that bad.)
1. https://shop.nitrokey.com/shop/product/nkhs2-nitrokey-hsm-2-...
If your org doesn't know how PKI works shouldn't you be paying a vendor that does?
Using nitrokey and some glue scripts you can get the cost below $500. If anyone is interested, let me know.
Why - for the love of God why - can’t I just obtain a cert like this directly out of a secret store such as an Azure Key Vault!?
These things are already full hardware security modules (HSMs) with all of the capabilities required to run just about anything short of a public Root CA and maybe even that too.
But no.
NO!
Script it yourself. Make a root cert, “upload” it, make a cert, sign it, upload it, link it, renew it, re-configure it, and on and on. Oh… you wanted a CRL too? A 1kb file? Ha-ha! No. Make it and host it yourself!!
It’s absurd.
So many services depend on a simple CA->cert setup: VPNs, API auth, load balancer back-ends, clusters, etc…
But my mark my words: no cloud will have a trivial turnkey solution this decade.
This is because running a CA is culturally accepted to be a hard problem. It is! If you’re DigiCert. It isn’t if you’re building a three-server internal use cluster. But the problem is hard, you see? That accepted fact! Everyone knows it! Ceremony is required. We can’t just hand your sever a 1kb credential file! That would be… unconventional!
It’s just not the way things are done, so stop asking.
Should the CAs issue intermediate certs that are only secure if a client implements an optional feature?
And even if most web browsers support name constraints properly - who knows if that cheap network webcam does, or that old mail client, or that 20 year old retro PC game?
If you want to uphold the name constraints in your CA cert, mark the field as critical. At that point clients that don’t understand them should fail validation of the CA cert.
Just like you presumably already wouldn't issue LE certs when you need to support clients with ancient CA bundles.
How do you think TLSv1.3 ever got rolled out?
Edit: has been fixed in osx 10.13.3. Idk about iOS.
Security-wise it shouldn't be any worse than wildcard certificates which are already a thing. It would actually improve things, because the user can now issue downstream certificates much more granularly without having to interact with the root CA (so you can issue fully offline for an intranet, or issue extremely-short-lived certificates that would otherwise run afoul of root CA's rate-limits).
They're selling something with a marginal cost of zero for $50 each. A wildcard certificate costs more not because it is materially different or "harder" to issue, but because it replaces many $50 certificates. Thus, it "must" cost more, or everybody would just use wildcard certificates everywhere and reduce profits at the large public CAs.
It is actually possible to get a domain-specific CA like the one you're thinking of. I saw one at a large department of education. It allowed unlimited issuance of certificates such as HTTPS, mail-signing, document-signing, and some other types that could be locked to a DNS domain. However, there was still a cost per certificate and the up-front cost was huge, something like $100K.
I get the negativity towards public CAs, but much of what you said isn't quite right, either.
But At least GCP and AWS have certificate authority products which essentially do work the way you want them to:
https://cloud.google.com/certificate-authority-service https://aws.amazon.com/private-ca/
Azure may well have one too, I just don't use their service.
Imagine with a straight face trying to sell someone a “password generator service” when in reality that’s just a one line script snippet.
The disconnect between the physical reality on the ground and how it is treated by industry is just absurd.
Ref: https://aws.amazon.com/private-ca/pricing/
Getting a signed cert issued should be a one-liner script referencing an AWS KMS or an Azure KeyVault!
Ceremony, as in “a well established, rigorously implemented, meticulously documented, and diligently audited process” is required to establish and maintain trust. A CA promises that folks showing up bearing their certificate _are who they say they are_ - this doesn’t mean it is perfect (there are plenty of cases where public CAs went wrong) and some random person can place their trust in that assertion.
The whole _point_ of a PKI is trust, and why would this be any different for internal systems?
The difficulty in running a CA at a very large scale (public or private) is that the root certificate revocation becomes prohibitively difficult. For this reason, its security is critical and much ceremony is warranted.
A CA doesn’t have to be a giant basket with millions of eggs in it. I have scenarios where I need a CA cert just so it can sign two (2) leaf certificates to make some load balancer happy, or to establish a site to site VPN or whatever. This is just "marking" the issued certs with a common attribute so that a load balancer can trust 'n' servers without having to have 'n' distinct certificates in its trust list.
That scenario does not need the same ceremony as DigiCert or the Microsoft kernel driver signing root certificate. It’s just a “shared secret” in a Cloudformation/Terraform/Bicep template.
If that CA gets compromised, I can just re-run the template to generate and deploy a new one! No ceremony. Just press play.
Not every gets married like Beyonce at an exotic island destination with 500 rich & famous guests. Some people just go down to the local marriage registrar office, get the paperwork done, and go home.
Unless the end-to-end, from the CA to the final certs, are managed by yourself or your immediate team, the scale would be irrelevant, and some ceremony would be required, as would be some processes that are internal to the team. My personal approach to avoid much of this is to use really short-lived certs to avoid the revocation theatre, but that doesn’t avoid the need to ensure that the CA is fundamentally secure.
> If that CA gets compromised, I can just re-run the template to generate and deploy a new one! No ceremony. Just press play.
Indeed! That, and re-distribute and implement trust for your CA Chain to all machines that need it. Your examples work fine (and I agree with) for small-scale use-cases, but if you run PKI for anything except yourself, you have to take care of the P for the KI.
Look, I am no fan of the rent-seeking bullshit the big public PKI vendors make us go through, and the incredibly high cost per certificate model. Charge me a reasonable fee for verification, and charge me a reasonable fee to set up my certificate vending endpoint, and be done. The same goes for internal use-cases. But the fact remains that verification and process are required. Fortunately, ACME for internal use and sane APIs and workflows such as Vault or smallstep provide make things very easy and cost effective. As for $400 per month for Azure certificates? Run your own instance, with your own (supposed) management processes, and see how it tallies up…
The third party in this case is just a file: the internal CA key.
Try to think of this in the following terms: the issued certs are just signed tokens, nothing more. They’re also conveniently a public-private key pair, but that’s not the point.
The point is that if you used a 1kb random password for service to service auth and someone tried to sell you a $400/mo service to generate them, you’d laugh in their face and then have security escort them from the building.
Sprinkle a tiny bit of cryptography on top and suddenly people think $4,800 annually is a bargain for 1kb passwords.
I can buy a decent used car for that kind of money.
Very few people still use TLS client authentication, but it does work. You can definitely get it up and running for less than 400 dollars per month. The magical keyword for Google here is "mutual TLS"
If you're using a Windows based system, you can do this stuff automatically through Active Directory: https://learn.microsoft.com/en-us/windows/security/operating...
The thing is, credential management is very difficult, and people are willing to pay up to solve very difficult tasks. If you build a (non-Kubernetes} certificate management solution, you'll probably want to sell it for big bucks as well. Generating certificates is just an openssl command line on a timer, the difficulty is getting those certificates deployed in the right places automatically. It's all possible through some basic scripting, but to do it right you need to solve more than just the certificate part.
Go ahead, run an internal secret store that issues properly trustworthy internal certificates. It isn’t hard, but neither is it cheap not. You oversimplify and gloss over a few _really_ important aspects of why and how certificates work. A certificate _acting like a password_ in some cases doesn’t mean it actually _is_ a password, and if you don’t really need the additional functionality to the point where the cost outweighs the delivered value, you are using the wrong tool for the job.
Running a CA is not at a technical challenge. Running a _trustworthy_ (there is that word again) CA is process heavy and it involves quite a few people doing work on a regular basis, and without those processes you may as well just something else - like an untrusted CA, or some kind of token issuing service (which, shockingly, also costs money to run properly).
A few really good options around DIY CAs were mentioned in this discussion, smallstep is pretty good for example. Nothing (except possibly your $org’s security policies) prevents you from throwing that up somewhere and start vending certs.
The fact that it is an internal CA to be used for internal purposes makes no difference, unless you believe that “everything internal is trusted because it is internal” in which case many other discussions on a very wide variety of subjects is due.
Having built many Enterprise PKI systems — including Smart Card auth — I do know the complexity involved. I can prattle on for hours about how the Key Recovery Agents should be distributed and stored, and how “offline” means no network cables at all you dimwit.
I also know that there is virtually no difference between a root CA certificate and a signed leaf certificate.
They’re both just files.
The difference is the amount of ceremony.
DigiCert’s Root CA certificate files had a lot of ceremony — with good reason.
But the CA for “I need five devs in India to get VPN certs with a common root” is practically zero.
No, it does not take a “a lot of infrastructure” to host a 1kb file. It really doesn’t, and your persistent confusion is my point: you are simply unable to let go of your preconceptions.
Just last week I needed a pair of certs with a common root for a load balancer’s back end. Not for transmitting NSA secrets over intercontinental backhaul.
I already have access to a bone-fide HSM! For pennies!
Why can’t I be allowed to use that pre-engineered secure certificate storage system for its intended purpose!?
A public-private key pair is clever cryptography, yes, but INTERNALLY within a network they're not Magic(tm) that requires a multi-billion dollar market cap company to issue with some Indian call centre verifying my identity papers.
The same cryptographic algorithm has two wildly different uses: one that is $0.0000001 in value, and one that requires a third party organisation that needs to pay their employees and can maybe justify asking for tens of dollars. (Narrator: Let's Encrypt showed that they can't justify this either.)
People conflate the two and then try to charge $50 for the $0.0000001 use-case, which is a markup of five million percent. That's what's upsetting. It's just so absurd, and people blink slowly and then start suggesting $40 options as-if that discount somehow makes it okay. Or they start talking about "all the things you get" for that $50, when it just doesn't apply.
There should be a trivial set of commands along the lines of:
New-AzKeyVaultRootCertificate -VaultName 'xyzinternal' -Name 'ContosoAPIServiceRoot'
New-AzKeyVaultSignedCertificate -VaultName 'xyzinternal' -RootCertificateName 'ContosoAPIServiceRoot' -DnsName 'apisvc1352.internal.cloud'
You can emulate the above with a 20-line script now, but it's fiddly, and doesn't cooperate with Bicep deployment templates. Similarly, there ought to be a built-in renewal mechanism (which is JUST 'cron' for the love of God!), but instead requires Azure Functions, layers of complex authorisations, and who knows what else...Then… don’t buy certificates? Use letsencrypt or run your own CA? There are tons of options out there.
"Running your own CA" like it's a big ceremony is precisely what I'm saying ought not to be necessary.
Do you "run" your own random password generation service PaaS with custom Kubernetes controllers and everything? That's what someone else suggested, and not in jest!
You can think of the private key as equivalent to a password, in the context the parent is talking about.
If you need a self-signed cert instead, maybe try https://johannes.truschnigg.info/code/tls_cert_gen
I have things set up so that the RPi connects to a WiFi, and then a cable from the RPi goes to another WiFi router.
I connect my MacBook Pro to that other router.
This way the MacBook Pro cannot reach the internet.
Then I set the http and https proxy configs in Firefox so that it goes via the squid on the RPi. And I have the root CA from the RPi trusted in Firefox.
Additionally I have set some env variables and added my root CA cert to some cert storages on the computer, so that git can clone via squid, and I can install and update things with brew etc.
It works great :D
But then I tried to set up my iPhone to also connect to that WiFi. I think I managed to trust my root CA on the phone. But I couldn’t manage to set up the http/https proxy on the iPhone and so for now only the MacBook Pro can use it, and not the iPhone
> An obvious downside of this is having to guard a bunch of secrets and the need to rotate the host certificates yearly – because Apple says so.
The guarding secrets thing makes me too uncomfortable with managing my own CA. I'm sure it'd be fine, but since there are other equivalent and safer ways to do it.. Name constraints are a thing in the spec for restricting your CA to specific domains (which is amazing,) but browser/etc support was crappy when I looked at it and maybe getting better? I don't understand why name constraints aren't implemented everywhere. Unless an enterprise environment is doing TLS inspection, name constraints are a way saner implementation.
They have weird semantics, especially in scenarios with multiple prospective validation paths: path `EE -> ICA' -> ICA'' -> TA` might result in different name constraints than `EE -> ICA' -> ICA''' -> TA`, resulting in hard-to-debug validation errors (or successes) depending on the user's trust store state.
(I don't believe that's why Chrome doesn't support them, however. Chrome's stated reason[1] is that they don't support them on user roots because RFC 5280 doesn't require them to, which is IMO a correct reading of the spec.)
[1]: https://bugs.chromium.org/p/chromium/issues/detail?id=107208...
Dockerfile:
``` FROM certbot/certbot RUN pip3 install certbot-dns-cloudflare cloudflare ```
docker-compose.yml:
``` volumes: - ${CREDENTIALS_DIRECTORY:-.}/cloudflare.ini:/cloudflare.ini - ${STATE_DIRECTORY:-./certbot}/:/etc/letsencrypt/ - ${LOGS_DIRECTORY:-/var/log/certbot}/:/var/log/letsencrypt/ command: " \ certonly \ --non-interactive \ --agree-tos \ --email postmaster@foo.bar \ --preferred-challenges dns-01 \ --dns-cloudflare \ --dns-cloudflare-credentials /cloudflare.ini \ --dns-cloudflare-propagation-seconds 30 \ -d foo.bar,*.foo.bar" ```
If you have the web server's private key, you can decrypt the traffic, but only if PFS ciphers are not used.
It is a common misconception that knowledge of CA keys allows you to decrypt traffic. It does not. It allows you to issue valid certificates. It's only used for signing.
It's the webserver's key that protects the traffic. The webserver's operator has that key regardless of who the CA is. In the case of PFS cipher suites (eg EDH) an ephemeral key is used for confidentiality and the endpoint keys are just used for integrity and key authentication. Even with the webserver key you aren't decrypting those streams.
In no case does the CA private key help you decrypt traffic.
Of course it does. You just generate certificates for every TLS handshake you see and MitM them.
And yes, it works for PFS too. There is no difference for MitM.
> In the case of PFS cipher suites (eg EDH) an ephemeral key is used for confidentiality and the endpoint keys are just used for integrity and key authentication. Even with the webserver key you aren't decrypting those streams.
You never encrypt data with a key from certificate, even without PFS. That would be too slow. You generate a pre-master key and then use it to generate keys for symmetric algorithms, like AES or Chacha20, that are actually used for data stream encryption. The only difference between PFS and non-PFS is that in the former case pre-master is generated using some form of DH, with promise of keys being destroyed after some time, and in the later case, client just generates a random key, encrypts it with the public key and sends it to the server.
Is it? I thought browsers treat localhost/127.0.0.* specifically as if it were served over https, even if it isn't - otherwise, you could basically forget developing anything locally.
Is there any feature which doesn't treat localhost as a secure origin?
I figure you can always buy a hostname, get a cert using the DNS-01 challenge, then resolve the domain to 127.0.0.1 though - or getting back to the OP and running a custom CA.
If you develop locally and it’s only HTTP with no HTTPS, then I think it works.
To my knowledge, https on loopback doesn't give you any kind of added security: Everything with enough privileges to capture the encrypted packets on loopback also has enough privileges to just capture the unencrypted memory directly. And "localhost" is also a single "domain", so a cert wouldn't even give you the ability to distinguish between different origins (as other ports or hostnames that resolve to 127.0.0.1 would do)
So it's just some buerocratic hoops to jump through to satisfy browsers.
Edit: I remember reading about some objection that the "localhost" domain could be resolved to something other than 127.0.0.1, either through the hosts file or through a faulty DNS resolver.
I think those objections were addressed in the "let localhost be localhost" proposal which mandated that the hostname "localhost" must be hardwired to 127.0.0.1 in the OS/browsers/resolvers etc and must never be permitted to point to anything else.
But maybe this proposal didn't gain traction and so browsers are defending against such rebound localhost domains.
In that case, I'd try and check if "http://127.0.0.1" works, as the IP address can't be rebound in the same way as the hostname.
Edit2: And of course there is the issue with everything that is defined on top of TLS itself, e.g. ALPN and HTTP2. If you want to test anything involving that, you'll of course need to run TLS on localhost and are gonna need a cert too.
Some browsers (notably Firefox) used to support multiple wildcards, but then again it also trusted domain certificates signed by other domain certificates for years, so that's not much to go by. These days, I don't think a single browser will accept ..foo.bar.
It's well supported now. I use it and it works for OpenSSL, Firefox, and Safari.
Personally, I don't think there's much to gain from using public PKI for internal infrastructure. I already manage secrets on my personal devices and this is no different. Also, being able to issue certs for .home.arpa domains is nice too.
Lets Encrypt offers wildcard certificates, there is no reason to have internal DNS records exposed.
Link: https://github.com/OpenVPN/easy-rsa
Summary from that page:
easy-rsa is a CLI utility to build and manage a PKI CA. In laymen's terms, this means to create a root certificate authority, and request and sign certificates, including intermediate CAs and certificate revocation lists (CRL).
> This change will affect only TLS server certificates issued from the Root CAs preinstalled with iOS, iPadOS, macOS, watchOS, and tvOS.
> This change will not affect certificates issued from user-added or administrator-added Root CAs.
The second link about the other restrictions (including <=825 days validity) does appear to apply to all CAs.
[edited: but since I also want to have host certs that are on various internal servers, the short validity applies to them]
> This will only apply to TLS server certificates from CAs that are trusted in a default installation of Google Chrome, commonly known as “publicly trusted CAs”, and will not apply to locally-operated CAs that have been manually configured.
What I haven't figured out yet is how the browser-GUI could talk to its local backend-server over https. Can an exe contain its own root-certificate-authority somehow in a way that the app-exe can work without having to update that certificate part ever?
Just create a native app. Use something like C# MAUI or whatever language you’re familiar with. Your users will thank you for a smooth experience.
You'd have to install a shady custom CA system-wide on your users, for a green lock that's 100% placebo. Just run firefox/chrome in app mode and hide the URL bar.
Basically it is a content-creation app. You use it to develop content you want to later publish and which you can develop and QA on your PC. But when used in an team-setting there might be a use-case for the QA-group to easily see the latest version of the content, even though they would not be allowed to edit it.
I'm also thinking maybe some organizations might have a rule that only https: can be used.
(Maybe the performance degradation of generating a certificate on the fly is less than using a certificate that includes 100s of SANs.)
1,000 works in Firefox and Chromium, but 10,000 gives `SSL_ERROR_RX_MALFORMED_HANDSHAKE` in Firefox, and `ERR_SSL_PROTOCOL_ERROR` in Chromium. OpenSSL won't connect to it either - it gives `read_state_machine:excessive message size:ssl/statem/statem.c:610`
So in practical terms, the answer seems to be somewhere between the 1,000 and 10,000.
[1] https://smallstep.com/docs/step-ca/
I've been using it at work for the last year for our certs and it's been quite nice. It can do pre/post hooks as well, so it directly commits the updated CA serial files to our git repo.
PKI's use case begins with shipping a trust store into the wild, where it will run unchanged for months or years.
This doesn't cover deployment of the CAs to clients, but it's easy free desktop software.
I expected the article to be about actually being a certificate authority that every browser will trust by default.
Or do I need to know all the gory details myself?
links in this comment: https://news.ycombinator.com/item?id=37542794
Let me re-phrase my question slightly:
Is there any npm-modules I can install (with npm) which would allow Node.js to automatically serve https?
Not a lot of fun.
Meanwhile, I'm guessing, there are new useful utilities out.
One I remember was easyCA or was it easyPKI?
But I agree, it's a great feature and worked as advertised after following their guide. Doesn't sound like a ringing endorsement but in my experience it's rare for custom CA tooling to Just Work and until now none of them resulted in a fully functional ACME provider to serve up your certs.
1. ACME is a dumpster fire prone to mitm attacks.
2. without HSM (an additional investment) it's super bad idea to host your root CA signing key somewhere.
We stood up the root CA, created the certificate, imported it, then destroyed the root CA. It’s a common security practice. Root CA can then never be compromised
The root CA certificate is used to establish trust in the chain of trust, but it is not directly involved in the certificate issuance process once the trust has been established.
But based on the comments here, I guess you could use the smallstep CA with Nitrokey HSM if that's your jam...
"Running a CA" is pretty much dominated by managing certificates? Including distribution and revocation - not just issuing?
ECDSA 384 or longer depending on the expected CA lifetime and security margins (see https://www.keylength.com/) is a saner choice.
I might do a writeup soon on this, it's not even that complicated.