From e06795533f53aabd66b06ff179c7b57102970859 Mon Sep 17 00:00:00 2001 From: Walter Fender Date: Wed, 14 Jun 2017 13:04:16 -0700 Subject: [PATCH] Working on fixing #43716. This will create the necessary certificates. On GCE is will upload those certificates to Metadata. They are then pulled down on to the kube-apiserver. They are written to the /etc/src/kubernetes/pki directory. Finally they are loaded vi the appropriate command line flags. The requestheader-client-ca-file can be seen by running the following:- kubectl get ConfigMap extension-apiserver-authentication --namespace=kube-system -o yaml Minor bug fixes. Made sure AGGR_MASTER_NAME is set up in all configs. Clean up variable names. Added additional requestheader configuration parameters. Added check so that if there is no Aggregator CA contents we won't start the aggregator with the relevant flags. --- cluster/common.sh | 91 ++++++++++++++++++++++++-- cluster/gce/config-default.sh | 1 + cluster/gce/config-test.sh | 1 + cluster/gce/gci/configure-helper.sh | 21 ++++++ cluster/kubemark/gce/config-default.sh | 1 + 5 files changed, 108 insertions(+), 7 deletions(-) diff --git a/cluster/common.sh b/cluster/common.sh index 60ff964eb9..9b7cb72142 100755 --- a/cluster/common.sh +++ b/cluster/common.sh @@ -575,6 +575,10 @@ function build-kube-master-certs { KUBEAPISERVER_CERT: $(yaml-quote ${KUBEAPISERVER_CERT_BASE64:-}) KUBEAPISERVER_KEY: $(yaml-quote ${KUBEAPISERVER_KEY_BASE64:-}) CA_KEY: $(yaml-quote ${CA_KEY_BASE64:-}) +AGGREGATOR_CA_KEY: $(yaml-quote ${AGGREGATOR_CA_KEY_BASE64:-}) +REQUESTHEADER_CA_CERT: $(yaml-quote ${REQUESTHEADER_CA_CERT_BASE64:-}) +PROXY_CLIENT_CERT: $(yaml-quote ${PROXY_CLIENT_CERT_BASE64:-}) +PROXY_CLIENT_KEY: $(yaml-quote ${PROXY_CLIENT_KEY_BASE64:-}) EOF } @@ -949,7 +953,9 @@ function create-certs { echo "Generating certs for alternate-names: ${sans}" + setup-easyrsa PRIMARY_CN="${primary_cn}" SANS="${sans}" generate-certs + AGGREGATOR_PRIMARY_CN="${primary_cn}" AGGREGATOR_SANS="${sans}" generate-aggregator-certs CERT_DIR="${KUBE_TEMP}/easy-rsa-master/easyrsa3" # By default, linux wraps base64 output every 76 cols, so we use 'tr -d' to remove whitespaces. @@ -964,6 +970,34 @@ function create-certs { KUBECFG_KEY_BASE64=$(cat "${CERT_DIR}/pki/private/kubecfg.key" | base64 | tr -d '\r\n') KUBEAPISERVER_CERT_BASE64=$(cat "${CERT_DIR}/pki/issued/kube-apiserver.crt" | base64 | tr -d '\r\n') KUBEAPISERVER_KEY_BASE64=$(cat "${CERT_DIR}/pki/private/kube-apiserver.key" | base64 | tr -d '\r\n') + + # Setting up an addition directory (beyond pki) as it is the simplest way to + # ensure we get a different CA pair to sign the proxy-client certs and which + # we can send CA public key to the user-apiserver to validate communication. + AGGREGATOR_CERT_DIR="${KUBE_TEMP}/easy-rsa-master/aggregator" + AGGREGATOR_CA_KEY_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/private/ca.key" | base64 | tr -d '\r\n') + REQUESTHEADER_CA_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/ca.crt" | base64 | tr -d '\r\n') + PROXY_CLIENT_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/issued/proxy-client.crt" | base64 | tr -d '\r\n') + PROXY_CLIENT_KEY_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/private/proxy-client.key" | base64 | tr -d '\r\n') +} + +function setup-easyrsa { + local -r cert_create_debug_output=$(mktemp "${KUBE_TEMP}/cert_create_debug_output.XXX") + # Note: This was heavily cribbed from make-ca-cert.sh + (set -x + cd "${KUBE_TEMP}" + curl -L -O --connect-timeout 20 --retry 6 --retry-delay 2 https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz + tar xzf easy-rsa.tar.gz + mkdir easy-rsa-master/kubelet + cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/kubelet + mkdir easy-rsa-master/aggregator + cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/aggregator) &>${cert_create_debug_output} || { + # If there was an error in the subshell, just die. + # TODO(roberthbailey): add better error handling here + cat "${cert_create_debug_output}" >&2 + echo "=== Failed to setup easy-rsa: Aborting ===" >&2 + exit 2 + } } # Runs the easy RSA commands to generate certificate files. @@ -980,12 +1014,7 @@ function generate-certs { local -r cert_create_debug_output=$(mktemp "${KUBE_TEMP}/cert_create_debug_output.XXX") # Note: This was heavily cribbed from make-ca-cert.sh (set -x - cd "${KUBE_TEMP}" - curl -L -O --connect-timeout 20 --retry 6 --retry-delay 2 https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz - tar xzf easy-rsa.tar.gz - mkdir easy-rsa-master/kubelet - cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/kubelet - cd easy-rsa-master/easyrsa3 + cd "${KUBE_TEMP}/easy-rsa-master/easyrsa3" ./easyrsa init-pki # this puts the cert into pki/ca.crt and the key into pki/private/ca.key ./easyrsa --batch "--req-cn=${PRIMARY_CN}@$(date +%s)" build-ca nopass @@ -1010,7 +1039,51 @@ function generate-certs { # If there was an error in the subshell, just die. # TODO(roberthbailey): add better error handling here cat "${cert_create_debug_output}" >&2 - echo "=== Failed to generate certificates: Aborting ===" >&2 + echo "=== Failed to generate master certificates: Aborting ===" >&2 + exit 2 + } +} + +# Runs the easy RSA commands to generate aggregator certificate files. +# The generated files are at ${KUBE_TEMP}/easy-rsa-master/aggregator +# +# Assumed vars +# KUBE_TEMP +# AGGREGATOR_MASTER_NAME +# AGGREGATOR_PRIMARY_CN: Primary canonical name +# AGGREGATOR_SANS: Subject alternate names +# +# +function generate-aggregator-certs { + local -r cert_create_debug_output=$(mktemp "${KUBE_TEMP}/cert_create_debug_output.XXX") + # Note: This was heavily cribbed from make-ca-cert.sh + (set -x + cd "${KUBE_TEMP}/easy-rsa-master/aggregator" + ./easyrsa init-pki + # this puts the cert into pki/ca.crt and the key into pki/private/ca.key + ./easyrsa --batch "--req-cn=${AGGREGATOR_PRIMARY_CN}@$(date +%s)" build-ca nopass + ./easyrsa --subject-alt-name="${AGGREGATOR_SANS}" build-server-full "${AGGREGATOR_MASTER_NAME}" nopass + ./easyrsa build-client-full aggregator-apiserver nopass + + kube::util::ensure-cfssl "${KUBE_TEMP}/cfssl" + + # make the config for the signer + echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","client auth"]}}}' > "ca-config.json" + # create the aggregator client cert with the correct groups + echo '{"CN":"aggregator","hosts":[""],"key":{"algo":"rsa","size":2048}}' | "${CFSSL_BIN}" gencert -ca=pki/ca.crt -ca-key=pki/private/ca.key -config=ca-config.json - | "${CFSSLJSON_BIN}" -bare proxy-client + mv "proxy-client-key.pem" "pki/private/proxy-client.key" + mv "proxy-client.pem" "pki/issued/proxy-client.crt" + rm -f "proxy-client.csr" + + # Make a superuser client cert with subject "O=system:masters, CN=kubecfg" + ./easyrsa --dn-mode=org \ + --req-cn=proxy-clientcfg --req-org=system:aggregator \ + --req-c= --req-st= --req-city= --req-email= --req-ou= \ + build-client-full proxy-clientcfg nopass) &>${cert_create_debug_output} || { + # If there was an error in the subshell, just die. + # TODO(roberthbailey): add better error handling here + cat "${cert_create_debug_output}" >&2 + echo "=== Failed to generate aggregator certificates: Aborting ===" >&2 exit 2 } } @@ -1168,6 +1241,10 @@ function parse-master-env() { KUBELET_KEY_BASE64=$(get-env-val "${master_env}" "KUBELET_KEY") MASTER_CERT_BASE64=$(get-env-val "${master_env}" "MASTER_CERT") MASTER_KEY_BASE64=$(get-env-val "${master_env}" "MASTER_KEY") + AGGREGATOR_CA_KEY_BASE64=$(get-env-val "${master_env}" "AGGREGATOR_CA_KEY") + REQUESTHEADER_CA_CERT_BASE64=$(get-env-val "${master_env}" "REQUESTHEADER_CA_CERT") + PROXY_CLIENT_CERT_BASE64=$(get-env-val "${master_env}" "PROXY_CLIENT_CERT") + PROXY_CLIENT_KEY_BASE64=$(get-env-val "${master_env}" "PROXY_CLIENT_KEY") } # Update or verify required gcloud components are installed diff --git a/cluster/gce/config-default.sh b/cluster/gce/config-default.sh index 49eefb0e52..7e0d078028 100755 --- a/cluster/gce/config-default.sh +++ b/cluster/gce/config-default.sh @@ -83,6 +83,7 @@ NETWORK=${KUBE_GCE_NETWORK:-default} INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX:-kubernetes}" CLUSTER_NAME="${CLUSTER_NAME:-${INSTANCE_PREFIX}}" MASTER_NAME="${INSTANCE_PREFIX}-master" +AGGREGATOR_MASTER_NAME="${INSTANCE_PREFIX}-aggregator" INITIAL_ETCD_CLUSTER="${MASTER_NAME}" ETCD_QUORUM_READ="${ENABLE_ETCD_QUORUM_READ:-false}" MASTER_TAG="${INSTANCE_PREFIX}-master" diff --git a/cluster/gce/config-test.sh b/cluster/gce/config-test.sh index 1d8df0e055..bf442df0b2 100755 --- a/cluster/gce/config-test.sh +++ b/cluster/gce/config-test.sh @@ -81,6 +81,7 @@ NETWORK=${KUBE_GCE_NETWORK:-e2e} INSTANCE_PREFIX="${KUBE_GCE_INSTANCE_PREFIX:-e2e-test-${USER}}" CLUSTER_NAME="${CLUSTER_NAME:-${INSTANCE_PREFIX}}" MASTER_NAME="${INSTANCE_PREFIX}-master" +AGGREGATOR_MASTER_NAME="${INSTANCE_PREFIX}-aggregator" INITIAL_ETCD_CLUSTER="${MASTER_NAME}" ETCD_QUORUM_READ="${ENABLE_ETCD_QUORUM_READ:-false}" MASTER_TAG="${INSTANCE_PREFIX}-master" diff --git a/cluster/gce/gci/configure-helper.sh b/cluster/gce/gci/configure-helper.sh index 91fe619b57..14234126b8 100644 --- a/cluster/gce/gci/configure-helper.sh +++ b/cluster/gce/gci/configure-helper.sh @@ -323,6 +323,18 @@ function create-master-pki { # < 1.6. ln -sf "${APISERVER_SERVER_KEY_PATH}" /etc/srv/kubernetes/server.key ln -sf "${APISERVER_SERVER_CERT_PATH}" /etc/srv/kubernetes/server.cert + + AGGREGATOR_CA_KEY_PATH="${pki_dir}/aggr_ca.key" + echo "${AGGREGATOR_CA_KEY:-}" | base64 --decode > "${AGGREGATOR_CA_KEY_PATH}" + + REQUESTHEADER_CA_CERT_PATH="${pki_dir}/aggr_ca.crt" + echo "${REQUESTHEADER_CA_CERT:-}" | base64 --decode > "${REQUESTHEADER_CA_CERT_PATH}" + + PROXY_CLIENT_KEY_PATH="${pki_dir}/proxy_client.key" + echo "${PROXY_CLIENT_KEY:-}" | base64 --decode > "${PROXY_CLIENT_KEY_PATH}" + + PROXY_CLIENT_CERT_PATH="${pki_dir}/proxy_client.crt" + echo "${PROXY_CLIENT_CERT:-}" | base64 --decode > "${PROXY_CLIENT_CERT_PATH}" } # After the first boot and on upgrade, these files exist on the master-pd @@ -1202,6 +1214,15 @@ function start-kube-apiserver { params+=" --secure-port=443" params+=" --tls-cert-file=${APISERVER_SERVER_CERT_PATH}" params+=" --tls-private-key-file=${APISERVER_SERVER_KEY_PATH}" + if [[ ! -z "${REQUESTHEADER_CA_CERT:-}" ]]; then + params+=" --requestheader-client-ca-file=${REQUESTHEADER_CA_CERT_PATH}" + params+=" --requestheader-allowed-names=aggregator" + params+=" --requestheader-extra-headers-prefix=X-Remote-Extra-" + params+=" --requestheader-group-headers=X-Remote-Group" + params+=" --requestheader-username-headers=X-Remote-User" + params+=" --proxy-client-cert-file=${PROXY_CLIENT_CERT_PATH}" + params+=" --proxy-client-key-file=${PROXY_CLIENT_KEY_PATH}" + fi params+=" --enable-aggregator-routing=true" if [[ -e "${APISERVER_CLIENT_CERT_PATH}" ]] && [[ -e "${APISERVER_CLIENT_KEY_PATH}" ]]; then params+=" --kubelet-client-certificate=${APISERVER_CLIENT_CERT_PATH}" diff --git a/cluster/kubemark/gce/config-default.sh b/cluster/kubemark/gce/config-default.sh index 8314484f82..3acd3f3881 100644 --- a/cluster/kubemark/gce/config-default.sh +++ b/cluster/kubemark/gce/config-default.sh @@ -42,6 +42,7 @@ MASTER_IMAGE_PROJECT=${KUBE_GCE_MASTER_PROJECT:-cos-cloud} NETWORK=${KUBE_GCE_NETWORK:-default} INSTANCE_PREFIX="${INSTANCE_PREFIX:-"default"}" MASTER_NAME="${INSTANCE_PREFIX}-kubemark-master" +AGGREGATOR_MASTER_NAME="${INSTANCE_PREFIX}-kubemark-aggregator" MASTER_TAG="kubemark-master" EVENT_STORE_NAME="${INSTANCE_PREFIX}-event-store" MASTER_IP_RANGE="${MASTER_IP_RANGE:-10.246.0.0/24}"