trust corporate MITM root CA on lookingglass for TLS-intercepting proxy

This commit is contained in:
Noah Masur
2026-08-03 15:58:12 -04:00
parent df38163999
commit f3a8d45722
3 changed files with 91 additions and 0 deletions
+37
View File
@@ -2,6 +2,43 @@
## 2026-08-03
- Added `presets/security/corporate-ca.nix` (nix-darwin) and enabled it on the
`lookingglass` host to trust a corporate TLS-intercepting proxy's root CA.
Behind the corp network, Nix fetches failed with `SSL peer certificate ...
self-signed certificate in certificate chain (19)` because Nix's stock Mozilla
CA bundle doesn't contain the interception root. The module appends the cert
to `security.pki.certificateFiles`, which rebuilds
`/etc/ssl/certs/ca-certificates.crt` (read by both the Nix daemon and, via
`NIX_SSL_CERT_FILE`, client-side flake fetches).
The cert is kept **out of this public repo** and referenced by absolute path.
It is passed as a string (not a Nix path literal) so pure flake evaluation
doesn't read it at eval time, and it lives at a root-owned, world-readable
path because the unprivileged `nixbld` build user cannot traverse `$HOME`
(mode `0750`) to read it at build time.
One-time setup on a machine behind the proxy:
```sh
# 1. Extract the self-signed corporate root from any TLS connection it MITMs
# (the last cert in the chain, subject == issuer). Any HTTPS host works:
echo | openssl s_client -connect example.com:443 -servername example.com \
-showcerts 2>/dev/null \
| awk '/BEGIN CERT/{c++} c==2' > /tmp/CorpCA.pem
openssl x509 -in /tmp/CorpCA.pem -noout -subject -issuer # sanity check
# 2. Install to the root-owned path the config points at:
sudo install -d -m 0755 -o root -g wheel /etc/ssl/corp-ca
sudo install -m 0644 -o root -g wheel /tmp/CorpCA.pem \
/etc/ssl/corp-ca/CorpCA.pem
# 3. Bootstrap the first rebuild (which must fetch inputs over the proxy)
# with a combined bundle, then it's permanent:
cat /etc/ssl/certs/ca-certificates.crt /etc/ssl/corp-ca/CorpCA.pem \
> /tmp/combined-ca.crt
NIX_SSL_CERT_FILE=/tmp/combined-ca.crt nh darwin switch . --configuration lookingglass
```
- Fixed the `zellij-session` fish function in `presets/programs/zellij.nix`
truncating the session name (derived from the target directory basename)
to 20 characters. Zellij names each session's Unix-domain IPC socket
@@ -17,6 +17,16 @@ rec {
# gaming.enable = true;
};
# Corporate network runs a TLS-intercepting proxy. Trust its root CA so Nix
# fetches don't fail with "self-signed certificate in certificate chain". The
# cert lives outside this public repo at a root-owned, world-readable path so
# the unprivileged Nix build user can read it (a copy under $HOME is not
# traversable by nixbld). See docs/CHANGELOG.md to extract and install it.
nmasur.presets.security.corporateCa = {
enable = true;
certFile = "/etc/ssl/corp-ca/CorpCA.pem";
};
home-manager.users."Noah.Masur" = {
nmasur.settings = {
username = nmasur.settings.username;
@@ -0,0 +1,44 @@
{
config,
lib,
...
}:
let
cfg = config.nmasur.presets.security.corporateCa;
in
{
options.nmasur.presets.security.corporateCa = {
enable = lib.mkEnableOption "trusting a corporate MITM root CA for TLS interception";
certFile = lib.mkOption {
type = lib.types.str;
example = "/etc/ssl/corp-ca/CorpCA.pem";
description = ''
Absolute path to a PEM-encoded corporate root CA certificate to add to
the system trust store.
Kept out of this (public) repo on purpose, so it points at a file you
drop on the machine by hand. Passed as a string rather than a Nix path
literal so pure flake evaluation does not try to read the out-of-repo
file at eval time; it is read at build time instead (Darwin builds run
without a sandbox).
'';
};
};
config = lib.mkIf cfg.enable {
# Append the corporate root to /etc/ssl/certs/ca-certificates.crt, which
# both the Nix daemon and (via NIX_SSL_CERT_FILE) client-side flake fetches
# read. Without this, fetches behind the corporate TLS-intercepting proxy
# fail with "self-signed certificate in certificate chain".
security.pki.certificateFiles = [ cfg.certFile ];
};
}