After some googling I found that JDKs > 8 have this global system property javax.net.ssl.trustStore
to specify the location of an alternative trust store. Can it be used somehow to point to the location where security.pki.certificates
&co collect the certificates? Where would global java properties go to in NixOS?
It seems openjdk is already patched to read the default path from JAVAX_NET_SSL_TRUSTSTORE
. The format of this newer keystore is PKCS12: I’m not sure we have tools to convert the bundle to this, I’ll look into this.
I had the same issue and the way I solved it is via passing the path via CLI argument
Yes, a quick workaround is to generate the keystore with
nix-shell -p p11-kit --run 'trust extract --format=java-cacerts --purpose=server-auth cacerts'
and pass it from the command line.
Nice, I found the existing keystore cacerts
from the output of my jdk (e.g. by running sbt 'eval System.getProperty("java.home")'
, copied it to the new location, added additional certificates, then set JAVAX_NET_SSL_TRUSTSTORE
to point to this new cacerts
keystore and all worked well.
Based on the previous answers, I’ve added the following snippet to my /etc/nixos/configuration.nix
:
environment.variables.JAVAX_NET_SSL_TRUSTSTORE =
let
caBundle = config.environment.etc."ssl/certs/ca-bundle.crt".source;
p11kit = pkgs.p11-kit.overrideAttrs (oldAttrs: {
configureFlags = [
"--with-trust-paths=${caBundle}"
];
});
in derivation {
name = "java-cacerts";
builder = pkgs.writeShellScript "java-cacerts-builder" ''
${p11kit.bin}/bin/trust \
extract \
--format=java-cacerts \
--purpose=server-auth \
$out
'';
system = builtins.currentSystem;
};
Thank you, this worked like a charm! Why this is not a NixOS default?
Why this is not a NixOS default?
There’s simply not enough people that care about this. I had to do most of the work myself to get security.pki
working for the majority of web browsers.
Anyway, I wasn’t aware of JAVAX_NET_SSL_TRUSTSTORE. An environment isn’t ideal in this case because you usually want that as a last resort to override a default.
Nonetheless, It means openjdk can be patched to look for our trust store by default.
It shouldn’t be too hard to do, but I don’t have much time to look into this now.
Thank you for your work, it is greatly appreciated.
I’d like to help with this by patching openjdk
. What would be the first step? Open an issue in nixpkgs
?
I’ve contributed some new packages, but never something like this.
I would do something like this:
-
Start looking for references to
JAVAX_NET_SSL_TRUSTSTORE
in the sources.
I suppose the implementation of this variable would be a good place to inject a/etc/ssl/certs/java-cacerts
for NixOS. -
Change the
cacert
package to also generate such a file, using thetrust extract
command. -
Link the
cacert
output to /etc, in thesecurity.pki
module (nixos/modules/security/ca.nix).
If you get it working, open a PR and ping me. I’ll be glad to review it.
Thanks for sharing, this whole thread was a treasure trove. You snippet ends up containing exactly zero certificates. Any idea why that could be?
$ keytool -list -keystore $JAVAX_NET_SSL_TRUSTSTORE -storepass changeit
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 0 entries
vs.
$ keytool -cacerts -storepass changeit -list | head -n 8
Keystore type: PKCS12
Keystore provider: SUN
Your keystore contains 89 entries
actalisauthenticationrootca [jdk], Jan 19, 2024, trustedCertEntry,
Certificate fingerprint (SHA-256): 55:92:60:84:EC:96:3A:64:B9:6E:2A:BE:01:CE:0B:A8:6A:64:FB:FE:BC:C7:AA:B5:AF:C1:55:B3:7F:D7:60:66
addtrustexternalca [jdk], Jan 19, 2024, trustedCertEntry,
I think the way p11-kit is build has changed and it no longer uses configureFlags
. Don’t know how to do it with meson.
this is my current cacerts.nix for reference, maybe this works for you as well.
I was thinking it didn’t work and only realized today that i need to use the openjdk, as other jdk’s don’t contain the patch to read the truststore path from the env var.
# add custom ca certs
{ config, pkgs, system, lib, ... }:
let
caBundle = config.environment.etc."ssl/certs/ca-certificates.crt".source;
p11kit = pkgs.p11-kit.overrideAttrs (oldAttrs: {
mesonFlags = [
"--sysconfdir=/etc"
(lib.mesonEnable "systemd" false)
(lib.mesonOption "bashcompdir" "${placeholder "bin"}/share/bash-completion/completions")
(lib.mesonOption "trust_paths" (lib.concatStringsSep ":" [
"${caBundle}"
]))
];
});
javaCaCerts = derivation {
name = "java-cacerts";
builder = pkgs.writeShellScript "java-cacerts-builder" ''
${p11kit.bin}/bin/trust \
extract \
--format=java-cacerts \
--purpose=server-auth \
$out
'';
inherit system;
outputs = [ "out" ];
};
in {
security = {
pki = {
installCACerts = true;
# append trusted certificate authorities
certificates = [
#''
# NixOS.org
# =========
# -----BEGIN CERTIFICATE-----
# MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
# TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
# ...
# -----END CERTIFICATE-----
#''
];
};
};
environment.variables = {
JAVAX_NET_SSL_TRUSTSTORE = javaCaCerts.outPath; # requires a patched version of openjdk (openjdk is already patched, see https://github.com/NixOS/nixpkgs/blob/1b64fc1287991a9cce717a01c1973ef86cb1af0b/pkgs/development/compilers/openjdk/read-truststore-from-env-jdk10.patch)
};
}
Thanks a bunch. Just fyi security.pki.installCACerts
is not an option that exists in nixpkgs (officially).
I am entering a new project for work and I need to install some custom certificates in the JDK (11), which of course spells trouble in NixOS and led me here.
Now, I’m a beginner in NixOS and only have a rough idea what these certificates may be required for. This thread seems to contain all the necessary information to do what I need, but, as it is so often for newcomers, it lacks context that explains what to do with those snippets.
It would be tremendously helpful if somebody who truly understands what’s going on could take the time to compile this into a full tutorial that explains how do this start to end, start being “I got theses three certificates I need to install in a JDK (11) and a system that doesn’t yet have a JDK (except one bundled with Android Studio, which I think I can’t/won’t use)” and end being “sudo nixos-rebuild switch”. Ideally, some comments in the nix files would explain what’s happening and why.
In particular, I see all this nix code, but I have no idea where to place my certificates so they’ll be picked up by it. I’m sure I can figure it out. It would just be so helpful if this information was packaged in a way that wouldn’t have me guessing at first. I know, it’s extra work, but it would make entry into this world so much easier. If somebody actually takes this time, I suppose it would also be great to place this info on the Java page, which currently doesn’t have any useful info for JDK 11.
I’ve had ChatGPT compile a full tutorial from some of the provided posts and have it explain it. I did not get the chance to test it, yet. Maybe somebody could use this as a blueprint for a more detailed answer, but check that it’s actually correct and if perhaps there are better solutions that those suggested by the AI? My Chat with ChatGPT
Since your use case seems to be installing custom certificates that are project-specific rather than system-wide, setting JAVAX_NET_SSL_TRUSTSTORE
or passing -Djavax.net.ssl.trustStore=...
to the JVM command-line might actually be a suitable solution in your case? Or is that somehow not possible?
(as an aside, though I know it doesn’t help you much in the short term: my impression is that setting custom key/truststores at the JVM level is nowadays generally seen as dealing with this at the wrong granularity level: your application may want to use one set of key/truststores for one type of connection and another set for another type of connection. For that reason I think most client and server APIs/libraries now support passing in the key/truststores to be used for the connections managed by that API, in which case you could solve this at the application (configuration) level)
@raboof thanks for your answer. Unfortunately I can’t give you much of a response, as I’m really new to this ecosystem (Android, actually) and really don’t know what’s what, yet. I’m really just trying to follow the onboarding steps and adapt them to NixOS. I don’t know what these certificates will be used for.
I’ll keep your answer in mind though. Maybe it’ll become clearer in the coming weeks
Anyway, I seem to have found a solution using a very different approach, which seems to also work for the oracle jdks (not sure any of the other advice here would). Please feel free to have a look and comment on that: Altering package (oraclejdk11) installation fails - #2 by mvb
I have just discovered this today, sorry for necro-thread! I also need to add a custom root certificate to my JDK so that Keycloak can communicate with LDAP over SSL.
Sadly, it doesn’t work if I have stuff in a flake. I end up with a failure:
building the system configuration...
error:
… while calling the 'head' builtin
at /nix/store/lzhqf5y9dcgfkg5f7f96jjc814pgrsqy-source/lib/attrsets.nix:1575:11:
1574| || pred here (elemAt values 1) (head values) then
1575| head values
| ^
1576| else
… while evaluating the attribute 'value'
at /nix/store/lzhqf5y9dcgfkg5f7f96jjc814pgrsqy-source/lib/modules.nix:809:9:
808| in warnDeprecation opt //
809| { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
| ^
810| inherit (res.defsFinal') highestPrio;
(stack trace truncated; use '--show-trace' to show the full trace)
error: attribute 'system' missing
at /nix/store/lzhqf5y9dcgfkg5f7f96jjc814pgrsqy-source/lib/modules.nix:508:28:
507| builtins.addErrorContext (context name)
508| (args.${name} or config._module.args.${name})
| ^
509| ) (lib.functionArgs f);
my flake code is here, and commented out at the moment, because the flake cannot build: nixos-configuration/hosts/common/default.nix at main - kowis-projects/nixos-configuration - Kowis Software Forge
Thanks in advance for any advice. I don’t yet know enough about nix to figure this one out on my own.