There are numerous advantages to deploying an internal root CA to an enterprise:
- Autonomy: Enterprises can control how their certificates are issued, structured, and revoked independently of a third party.
- Slow or fast replacement cycles are permissible if you control the infrastructure, letting you customize the CA to the business needs
- Want to set rules for what asymmetric cryptography to use? Don't like SHA1? You're in control!
- Cost: Services like Let's Encrypt break this a bit, but require a publicly auditable service. Most paid CAs charge per-certificate, which can really add up
- Better than self-signed: Training users to ignore certificate errors is extremely poor cyber hygiene, leaving your users vulnerable to all kinds of problems
- Multi-purpose: Certificates can be used for users, services, email encryption, getting rid of passwords. They're not just to authenticate web servers.
The only major obstacle to internal CAs happens to be a pretty old one - finding a scalable way to deliver the root Certificate Authority to appropriate "trust stores" (they do exactly what it sounds like they do) on all managed systems. Here are a few "hot-spots" that I've found over the years, ordered from high-value, low effort to low-value, high effort. They're all worthwhile, so please consider it an "order of operations" and not an elimination list:
- Windows Certificate Store: With Microsoft Windows' SChannel library, just about everything on the system will install a certificate in one move. I'm not a Windows expert, but this delivery is always the most valuable up-front.
- Linux Trust Store: Linux provides a trust store in different locations depending on distribution base.
- Firefox: Mozilla's NSS will store independently from Windows or Linux, and will need to be automated independently.
- Java Trust Stores are also independently held and specific to deployed version. This will require extensive deployment automation (do it on install, and do it once).
- Python also has a self-deployed trust store when using libraries like requests, but Debian/Ubuntu specific packages are tweaked to use the system. There are a ton of tweaks to just make it use the system store, but the easiest is to leverage
REQUESTS_CA_BUNDLEas an environment variable pointing to your system trust store.
Hopefully it's pretty clear that automation is about to become your new best friend when it comes to internal CA administration. Let's outline how we'd want to tackle the Linux aspects of this problem:
- Pick up the root certificate, and deliver from the Controller to the managed node
- Either Git or an Artifacts store would be adequate for publishing a root certificate for delivery. For simplicity's sake, I'll be adding it to the Git repository.
- Ansible's copy module enables us to easily complete this task, and is idempotent.
- Install any software packages necessary to import certificates into the trust store
- Ansible's apt module enables us to easily complete this task, and is idempotent.
- Install the certificate into a system's trust store
- Locations differ based on distribution. Some handling to detect operating system and act accordingly will be worthwhile in mixed environment
- Ansible's shell module can be used, but only as a fallback. It's not idempotent, and can be distribution-specific.
- Restart any necessary services
Here's where the beauty of idempotency really starts to shine. With Ansible, it's possible to just set a schedule for the playbook to execute in a CI tool like Jenkins. CI tools add some neat features here, like only executing on a source control change, which may not apply when using an artifacts store to deploy the root certificate.
In this example, I will be adding the play to my nightly update playbook to illustrate how easy this is:
After completion, this action can be tested by a wide variety of means - my favorite would be cURLing a web service that leverages the root CA: