| 
									
										
										
										
											2017-05-03 01:20:32 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   pkgs ? import <nixpkgs> {}, | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  |   internalDomain ? "cloud.yourdomain.net", | 
					
						
							|  |  |  |   externalDomain ? "myawesomecluster.cluster.yourdomain.net", | 
					
						
							| 
									
										
										
										
											2018-02-04 21:23:36 +01:00
										 |  |  |   serviceClusterIp ? "10.0.0.1", | 
					
						
							|  |  |  |   kubelets | 
					
						
							| 
									
										
										
										
											2017-05-03 01:20:32 +02:00
										 |  |  | }: | 
					
						
							|  |  |  | let | 
					
						
							| 
									
										
										
										
											2018-03-17 01:35:35 -04:00
										 |  |  |    runWithCFSSL = name: cmd: | 
					
						
							|  |  |  |      let secrets = pkgs.runCommand "${name}-cfss.json" { | 
					
						
							|  |  |  |          buildInputs = [ pkgs.cfssl pkgs.jq ]; | 
					
						
							|  |  |  |          outputs = [ "out" "cert" "key" "csr" ]; | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |        ''
 | 
					
						
							|  |  |  |          ( | 
					
						
							|  |  |  |            echo "${cmd}" | 
					
						
							|  |  |  |            cfssl ${cmd} > tmp | 
					
						
							|  |  |  |            cat tmp | jq -r .key > $key | 
					
						
							|  |  |  |            cat tmp | jq -r .cert > $cert | 
					
						
							|  |  |  |            cat tmp | jq -r .csr > $csr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |            touch $out | 
					
						
							|  |  |  |          ) 2>&1 | fold -w 80 -s | 
					
						
							|  |  |  |        '';
 | 
					
						
							|  |  |  |      in { | 
					
						
							|  |  |  |        key = secrets.key; | 
					
						
							|  |  |  |        cert = secrets.cert; | 
					
						
							|  |  |  |        csr = secrets.csr; | 
					
						
							|  |  |  |      }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    writeCFSSL = content: | 
					
						
							|  |  |  |      pkgs.runCommand content.name { | 
					
						
							|  |  |  |       buildInputs = [ pkgs.cfssl pkgs.jq ]; | 
					
						
							|  |  |  |      } ''
 | 
					
						
							|  |  |  |        mkdir -p $out | 
					
						
							|  |  |  |        cd $out | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        json=${pkgs.lib.escapeShellArg (builtins.toJSON content)} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        # for a given $field in the $json, treat the associated value as a | 
					
						
							|  |  |  |        # file path and substitute the contents thereof into the $json | 
					
						
							|  |  |  |        # object. | 
					
						
							|  |  |  |        expandFileField() { | 
					
						
							|  |  |  |          local field=$1 | 
					
						
							|  |  |  |          if jq -e --arg field "$field" 'has($field)'; then | 
					
						
							|  |  |  |            local path="$(echo "$json" | jq -r ".$field")" | 
					
						
							|  |  |  |            json="$(echo "$json" | jq --arg val "$(cat "$path")" ".$field = \$val")" | 
					
						
							|  |  |  |          fi | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        expandFileField key | 
					
						
							|  |  |  |        expandFileField ca | 
					
						
							|  |  |  |        expandFileField cert | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        echo "$json" | cfssljson -bare ${content.name} | 
					
						
							|  |  |  |      '';
 | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   noCSR = content: pkgs.lib.filterAttrs (n: v: n != "csr") content; | 
					
						
							|  |  |  |   noKey = content: pkgs.lib.filterAttrs (n: v: n != "key") content; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 01:35:35 -04:00
										 |  |  |   writeFile = content: | 
					
						
							|  |  |  |     if pkgs.lib.isDerivation content | 
					
						
							|  |  |  |     then content | 
					
						
							|  |  |  |     else pkgs.writeText "content" (builtins.toJSON content); | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   createServingCertKey = { ca, cn, hosts? [], size ? 2048, name ? cn }: | 
					
						
							|  |  |  |     noCSR ( | 
					
						
							|  |  |  |       (runWithCFSSL name "gencert -ca=${writeFile ca.cert} -ca-key=${writeFile ca.key} -profile=server -config=${writeFile ca.config} ${writeFile { | 
					
						
							|  |  |  |         CN = cn; | 
					
						
							|  |  |  |         hosts = hosts; | 
					
						
							|  |  |  |         key = { algo = "rsa"; inherit size; }; | 
					
						
							|  |  |  |       }}") // { inherit name; }
 | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createClientCertKey = { ca, cn, groups ? [], size ? 2048, name ? cn }: | 
					
						
							|  |  |  |     noCSR ( | 
					
						
							|  |  |  |       (runWithCFSSL name "gencert -ca=${writeFile ca.cert} -ca-key=${writeFile ca.key} -profile=client -config=${writeFile ca.config} ${writeFile { | 
					
						
							|  |  |  |         CN = cn; | 
					
						
							|  |  |  |         names = map (group: {O = group;}) groups; | 
					
						
							|  |  |  |         hosts = [""]; | 
					
						
							|  |  |  |         key = { algo = "rsa"; inherit size; }; | 
					
						
							|  |  |  |       }}") // { inherit name; }
 | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   createSigningCertKey = { C ? "xx", ST ? "x", L ? "x", O ? "x", OU ? "x", CN ? "ca", emailAddress ? "x", expiry ? "43800h", size ? 2048, name ? CN }: | 
					
						
							|  |  |  |     (noCSR (runWithCFSSL CN "genkey -initca ${writeFile { | 
					
						
							|  |  |  |       key = { algo = "rsa"; inherit size; }; | 
					
						
							|  |  |  |       names = [{ inherit C ST L O OU CN emailAddress; }]; | 
					
						
							|  |  |  |     }}")) // {
 | 
					
						
							|  |  |  |       inherit name; | 
					
						
							|  |  |  |       config.signing = { | 
					
						
							|  |  |  |         default.expiry = expiry; | 
					
						
							|  |  |  |         profiles = { | 
					
						
							|  |  |  |           server = { | 
					
						
							|  |  |  |             inherit expiry; | 
					
						
							|  |  |  |             usages = [ | 
					
						
							|  |  |  |               "signing" | 
					
						
							|  |  |  |               "key encipherment" | 
					
						
							|  |  |  |               "server auth" | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |           client = { | 
					
						
							|  |  |  |             inherit expiry; | 
					
						
							|  |  |  |             usages = [ | 
					
						
							|  |  |  |               "signing" | 
					
						
							|  |  |  |               "key encipherment" | 
					
						
							|  |  |  |               "client auth" | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |           peer = { | 
					
						
							|  |  |  |             inherit expiry; | 
					
						
							|  |  |  |             usages = [ | 
					
						
							|  |  |  |               "signing" | 
					
						
							|  |  |  |               "key encipherment" | 
					
						
							|  |  |  |               "server auth" | 
					
						
							|  |  |  |               "client auth" | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ca = createSigningCertKey {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   kube-apiserver = createServingCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "kube-apiserver"; | 
					
						
							|  |  |  |     hosts = ["kubernetes.default" "kubernetes.default.svc" "localhost" "api.${externalDomain}" serviceClusterIp]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   kubelet = createServingCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "kubelet"; | 
					
						
							|  |  |  |     hosts = ["*.${externalDomain}"]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   service-accounts = createServingCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "kube-service-accounts"; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   etcd = createServingCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "etcd"; | 
					
						
							|  |  |  |     hosts = ["etcd.${externalDomain}"]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   etcd-client = createClientCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "etcd-client"; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   kubelet-client = createClientCertKey { | 
					
						
							|  |  |  |     inherit ca; | 
					
						
							|  |  |  |     cn = "kubelet-client"; | 
					
						
							|  |  |  |     groups = ["system:masters"]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   apiserver-client = { | 
					
						
							| 
									
										
										
										
											2018-02-04 21:23:36 +01:00
										 |  |  |     kubelet = hostname: createClientCertKey { | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  |       inherit ca; | 
					
						
							| 
									
										
										
										
											2018-02-04 21:23:36 +01:00
										 |  |  |       name = "apiserver-client-kubelet-${hostname}"; | 
					
						
							|  |  |  |       cn = "system:node:${hostname}.${externalDomain}"; | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  |       groups = ["system:nodes"]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kube-proxy = createClientCertKey { | 
					
						
							|  |  |  |       inherit ca; | 
					
						
							|  |  |  |       name = "apiserver-client-kube-proxy"; | 
					
						
							|  |  |  |       cn = "system:kube-proxy"; | 
					
						
							|  |  |  |       groups = ["system:kube-proxy" "system:nodes"]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kube-controller-manager = createClientCertKey { | 
					
						
							|  |  |  |       inherit ca; | 
					
						
							|  |  |  |       name = "apiserver-client-kube-controller-manager"; | 
					
						
							|  |  |  |       cn = "system:kube-controller-manager"; | 
					
						
							|  |  |  |       groups = ["system:masters"]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kube-scheduler = createClientCertKey { | 
					
						
							|  |  |  |       inherit ca; | 
					
						
							|  |  |  |       name = "apiserver-client-kube-scheduler"; | 
					
						
							|  |  |  |       cn = "system:kube-scheduler"; | 
					
						
							|  |  |  |       groups = ["system:kube-scheduler"]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     admin = createClientCertKey { | 
					
						
							|  |  |  |       inherit ca; | 
					
						
							|  |  |  |       cn = "admin"; | 
					
						
							|  |  |  |       groups = ["system:masters"]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | in { | 
					
						
							|  |  |  |   master = pkgs.buildEnv { | 
					
						
							|  |  |  |     name = "master-keys"; | 
					
						
							|  |  |  |     paths = [ | 
					
						
							|  |  |  |       (writeCFSSL (noKey ca)) | 
					
						
							|  |  |  |       (writeCFSSL kube-apiserver) | 
					
						
							|  |  |  |       (writeCFSSL kubelet-client) | 
					
						
							|  |  |  |       (writeCFSSL apiserver-client.kube-controller-manager) | 
					
						
							|  |  |  |       (writeCFSSL apiserver-client.kube-scheduler) | 
					
						
							|  |  |  |       (writeCFSSL service-accounts) | 
					
						
							|  |  |  |       (writeCFSSL etcd) | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   worker = pkgs.buildEnv { | 
					
						
							|  |  |  |     name = "worker-keys"; | 
					
						
							|  |  |  |     paths = [ | 
					
						
							|  |  |  |       (writeCFSSL (noKey ca)) | 
					
						
							|  |  |  |       (writeCFSSL kubelet) | 
					
						
							|  |  |  |       (writeCFSSL apiserver-client.kube-proxy) | 
					
						
							|  |  |  |       (writeCFSSL etcd-client) | 
					
						
							| 
									
										
										
										
											2018-02-04 21:23:36 +01:00
										 |  |  |     ] ++ map (hostname: writeCFSSL (apiserver-client.kubelet hostname)) kubelets; | 
					
						
							| 
									
										
										
										
											2017-09-09 02:00:35 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   admin = writeCFSSL apiserver-client.admin; | 
					
						
							|  |  |  | } |