【问题标题】:How to access CA certificates when building derivation构建派生时如何访问 CA 证书
【发布时间】:2020-05-12 14:42:49
【问题描述】:

我想在运行nix-shell 时自动将 CA 证书添加到 Java 密钥库。在以下脚本生效之前:

with import <nixpkgs> {
  config.allowUnfree = true;
  config.oraclejdk.accept_license = true;
};

let dependencies = rec {
  _oraclejdk8 = stdenv.lib.overrideDerivation pkgs.oraclejdk8 (attrs : {
    installPhase = ''
      ${attrs.installPhase}

      pems_dir=pems
      mkdir "$pems_dir"

      echo "split bundled ca-certificates into separate files 'cert.N.pem'\
                and add them to default keystore"

      keytool=$out/bin/keytool
      keystore=$jrePath/lib/security/cacerts

      pushd "$pems_dir"
      awk 'BEGIN {c=0;doPrint=0;} /END CERT/ {print > "cert." c ".pem";doPrint=0;} /BEGIN CERT/{c++;doPrint=1;} { if(doPrint == 1) {print > "cert." c ".pem"} }' < /etc/ssl/certs/ca-bundle.crt

      # import certificates
      for f in `ls cert.*.pem`; do
        alias=`basename $f`
        $keytool -import -trustcacerts -noprompt -keystore "$keystore" -alias "$alias" -file "$f" -storepass changeit;
      done
      popd

    '';
  });

};
in with dependencies;
stdenv.mkDerivation rec {
  name = "env";
  buildInputs = [ _oraclejdk8 ];
}

但现在它失败并出现以下错误:

/nix/store/9fx2jfmks2zhvv2kmqgl6rg0fbkc3da0-stdenv-linux/setup: line 1391: /etc/ssl/certs/ca-bundle.crt: No such file or directory

现在似乎无法访问任何现有文件。但实际上这个文件只是一个存储链接:

$ readlink -f /etc/ssl/certs/ca-bundle.crt
/nix/store/w3vw4q9z7s0wig6ng4nv62af1917ynrm-ca-certificates.crt

如何在我的脚本中访问此文件?

【问题讨论】:

    标签: nix


    【解决方案1】:

    Nix 是一个封闭的构建系统,这意味着必须声明所有输入,以便可以跟踪它们。 您可以提取 Nixpkgs 的一组证书颁发机构证书,即 pkgs.cacert

      # CAREFUL, read on!
      awk 'BEGIN {c=0;doPrint=0;} /END CERT/ {print > "cert." c ".pem";doPrint=0;} /BEGIN CERT/{c++;doPrint=1;} { if(doPrint == 1) {print > "cert." c ".pem"} }' < ${cacert}/etc/ssl/certs/ca-bundle.crt
    

    但是,在固定加密配置时要小心,因为当它发生更改时,您需要在任何地方对其进行更新。假设您要运行 2 年前的软件版本,您想使用 2 年前的证书还是环境中的证书来运行它?

    另一个问题是这些证书应该写入哪里? Keytool 默认写入主目录,在构建沙箱中是不存在的。

    在您的情况下,正确的解决方案似乎不是在沙箱中添加证书,而是返回一个脚本,该脚本将在有意义的上下文中执行此操作。何时何地取决于您,但请确保您从良好来源获得这些证书。如果您可以假设您的部署始终使用足够最新的 Nixpkgs 完成,那么您可以这样做。否则,您可能最好使用系统中已有的 /etc

    【讨论】:

    • 感谢您的回答!目标实际上是从当前配置 (/etc) 中获取证书,因为它包含一些用于中间人代理的额外证书。这意味着pkgs.cacert 无能为力。我想知道是否可以从我的脚本访问当前的 NixOS 配置?
    • 如果您想在派生中不可变地执行此操作,您可以将您的 mitm 证书连接到 pkgs.cacert 中的文件。如果您想从评估主机获取它,请使用${/etc/ssl/certs/ca-bundle.crt}。如果您想在运行时执行此操作,请使用pkgs.writeScriptshellHook
    • 我已经尝试过这个${/etc/ssl/certs/ca-bundle.crt} - 它被扩展为存储中的路径,但问题是这个路径实际上是另一个指向/etc/ssl/certs/ca-bundle.crt 的符号链接,它又指向一个正确的店内推导。但是由于在执行脚本时无法访问/etc,因此这种方法不起作用。看起来我需要手动添加对正确派生的依赖,但我不知道如何。你能建议吗?
    • 你可以试试builtins.toFile "ca-bundle.crt" (builtins.readFile /etc/ssl/certs/ca-bundle.crt)。我真的怀疑这是一种可维护的方法。这应该是您自己的快速破解还是要部署?
    • 我同意,这看起来不太好。但总的来说,为什么在构建派生时不能从主机配置中获取一些东西。我花了一些时间将 ca-certs 添加到 NixOS 配置中,我不想花更多时间将它添加到我使用的每个 java 应用程序中。从我的角度来看,应该有一些自然的方式来通过基于它的派生来继承主机配置。但我可能不明白 Nix 背后的一些基本思想:)
    猜你喜欢
    • 2019-03-26
    • 2015-03-15
    • 2019-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 2019-11-02
    相关资源
    最近更新 更多