buildkite-agent: secrecy improvements: non-store, non-Nix provisioning of secrets

authored by Kosyrev Serge and committed by Domen Kožar 3fa4e1e3 3385c85f

+40 -22
+40 -22
nixos/modules/services/continuous-integration/buildkite-agent.nix
··· 4 4 5 5 let 6 6 cfg = config.services.buildkite-agent; 7 - configFile = pkgs.writeText "buildkite-agent.cfg" 8 - '' 9 - token="${cfg.token}" 10 - name="${cfg.name}" 11 - meta-data="${cfg.meta-data}" 12 - hooks-path="${cfg.package}/share/hooks" 13 - build-path="${cfg.dataDir}" 14 - ''; 15 7 in 16 8 17 9 { ··· 39 31 type = types.listOf types.package; 40 32 }; 41 33 42 - token = mkOption { 43 - type = types.str; 34 + tokenPath = mkOption { 35 + type = types.path; 44 36 description = '' 45 37 The token from your Buildkite "Agents" page. 38 + 39 + A run-time path to the token file, which is supposed to be provisioned 40 + outside of Nix store. 46 41 ''; 47 42 }; 48 43 ··· 62 57 }; 63 58 64 59 openssh = 65 - { privateKey = mkOption { 66 - type = types.str; 60 + { privateKeyPath = mkOption { 61 + type = types.path; 67 62 description = '' 68 63 Private agent key. 64 + 65 + A run-time path to the key file, which is supposed to be provisioned 66 + outside of Nix store. 69 67 ''; 70 68 }; 71 - publicKey = mkOption { 72 - type = types.str; 69 + publicKeyPath = mkOption { 70 + type = types.path; 73 71 description = '' 74 72 Public agent key. 73 + 74 + A run-time path to the key file, which is supposed to be provisioned 75 + outside of Nix store. 75 76 ''; 76 77 }; 77 78 }; ··· 84 85 home = cfg.dataDir; 85 86 createHome = true; 86 87 description = "Buildkite agent user"; 88 + extraGroups = [ "keys" ]; 87 89 }; 88 90 89 91 environment.systemPackages = [ cfg.package ]; 90 92 91 93 systemd.services.buildkite-agent = 94 + let copy = x: target: perms: 95 + "cp -f ${x} ${target}; ${pkgs.coreutils}/bin/chmod ${toString perms} ${target}; "; 96 + in 92 97 { description = "Buildkite Agent"; 93 98 wantedBy = [ "multi-user.target" ]; 94 99 after = [ "network.target" ]; ··· 97 102 HOME = cfg.dataDir; 98 103 NIX_REMOTE = "daemon"; 99 104 }; 105 + 106 + ## NB: maximum care is taken so that secrets (ssh keys and the CI token) 107 + ## don't end up in the Nix store. 100 108 preStart = '' 101 - ${pkgs.coreutils}/bin/mkdir -m 0700 -p ${cfg.dataDir}/.ssh 109 + ${pkgs.coreutils}/bin/mkdir -m 0700 -p ${cfg.dataDir}/.ssh 110 + ${copy (toString cfg.openssh.privateKeyPath) "${cfg.dataDir}/.ssh/id_rsa" 600} 111 + ${copy (toString cfg.openssh.publicKeyPath) "${cfg.dataDir}/.ssh/id_rsa.pub" 600} 102 112 103 - echo "${cfg.openssh.privateKey}" > ${cfg.dataDir}/.ssh/id_rsa 104 - ${pkgs.coreutils}/bin/chmod 600 ${cfg.dataDir}/.ssh/id_rsa 105 - 106 - echo "${cfg.openssh.publicKey}" > ${cfg.dataDir}/.ssh/id_rsa.pub 107 - ${pkgs.coreutils}/bin/chmod 600 ${cfg.dataDir}/.ssh/id_rsa.pub 108 - ''; 113 + cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF 114 + token="$(cat ${toString cfg.tokenPath})" 115 + name="${cfg.name}" 116 + meta-data="${cfg.meta-data}" 117 + hooks-path="${pkgs.buildkite-agent}/share/hooks" 118 + build-path="${cfg.dataDir}/builds" 119 + bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh" 120 + EOF 121 + ''; 109 122 110 123 serviceConfig = 111 - { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config ${configFile}"; 124 + { ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg"; 112 125 User = "buildkite-agent"; 113 126 RestartSec = 5; 114 127 Restart = "on-failure"; ··· 116 129 }; 117 130 }; 118 131 }; 132 + imports = [ 133 + (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) 134 + (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "openssh" "privateKeyPath" ]) 135 + (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] [ "services" "buildkite-agent" "openssh" "publicKeyPath" ]) 136 + ]; 119 137 }