Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix client cert handling for delegate authn #38512

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions cmd/kubernetes-discovery/artifacts/local-cluster-up/etcd-pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
kind: ReplicationController
apiVersion: v1
metadata:
name: etcd
labels:
etcd: "true"
spec:
replicas: 1
selector:
etcd: "true"
template:
metadata:
labels:
etcd: "true"
spec:
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.0.15
command:
- "etcd"
- "--listen-client-urls=https://0.0.0.0:4001"
- "--advertise-client-urls=https://etcd.kube-public.svc:4001"
- "--trusted-ca-file=/var/run/serving-ca/ca.crt"
- "--cert-file=/var/run/serving-cert/tls.crt"
- "--key-file=/var/run/serving-cert/tls.key"
- "--client-cert-auth=true"
- "--listen-peer-urls=https://0.0.0.0:7001"
- "--initial-advertise-peer-urls=https://etcd.kube-public.svc:7001"
- "--peer-trusted-ca-file=/var/run/serving-ca/ca.crt"
- "--peer-cert-file=/var/run/serving-cert/tls.crt"
- "--peer-key-file=/var/run/serving-cert/tls.key"
- "--peer-client-cert-auth=true"
- "--initial-cluster=default=https://etcd.kube-public.svc:7001"
ports:
- containerPort: 4001
volumeMounts:
- mountPath: /var/run/serving-cert
name: volume-serving-cert
- mountPath: /var/run/serving-ca
name: volume-etcd-ca
volumes:
- secret:
defaultMode: 420
secretName: serving-etcd
name: volume-serving-cert
- configMap:
defaultMode: 420
name: etcd-ca
name: volume-etcd-ca

11 changes: 11 additions & 0 deletions cmd/kubernetes-discovery/artifacts/local-cluster-up/etcd-svc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: etcd
spec:
ports:
- port: 4001
protocol: TCP
targetPort: 4001
selector:
etcd: "true"
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
kind: ReplicationController
apiVersion: v1
metadata:
name: kubernetes-discovery
labels:
kubernetes-discovery: "true"
spec:
replicas: 1
selector:
kubernetes-discovery: "true"
template:
metadata:
labels:
kubernetes-discovery: "true"
spec:
containers:
- name: kubernetes-discovery
image: kubernetes-discovery:latest
imagePullPolicy: Never
args:
- "--tls-cert-file=/var/run/serving-cert/tls.crt"
- "--tls-private-key-file=/var/run/serving-cert/tls.key"
- "--tls-ca-file=/var/run/serving-ca/ca.crt"
- "--client-ca-file=/var/run/client-ca/ca.crt"
- "--authentication-kubeconfig=/var/run/auth-kubeconfig/kubeconfig"
- "--authorization-kubeconfig=/var/run/auth-kubeconfig/kubeconfig"
- "--requestheader-username-headers=X-Remote-User"
- "--requestheader-group-headers=X-Remote-Group"
- "--requestheader-extra-headers-prefix=X-Remote-Extra-"
- "--requestheader-client-ca-file=/var/run/request-header-ca/ca.crt"
- "--etcd-servers=https://etcd.kube-public.svc:4001"
- "--etcd-certfile=/var/run/etcd-client-cert/tls.crt"
- "--etcd-keyfile=/var/run/etcd-client-cert/tls.key"
- "--etcd-cafile=/var/run/etcd-ca/ca.crt"
ports:
- containerPort: 443
volumeMounts:
- mountPath: /var/run/request-header-ca
name: volume-request-header-ca
- mountPath: /var/run/client-ca
name: volume-client-ca
- mountPath: /var/run/auth-proxy-client
name: volume-auth-proxy-client
- mountPath: /var/run/auth-kubeconfig
name: volume-auth-kubeconfig
- mountPath: /var/run/etcd-client-cert
name: volume-etcd-client-cert
- mountPath: /var/run/serving-ca
name: volume-serving-ca
- mountPath: /var/run/serving-cert
name: volume-serving-cert
- mountPath: /var/run/etcd-ca
name: volume-etcd-ca
volumes:
- configMap:
defaultMode: 420
name: request-header-ca
name: volume-request-header-ca
- configMap:
defaultMode: 420
name: client-ca
name: volume-client-ca
- name: volume-auth-proxy-client
secret:
defaultMode: 420
secretName: auth-proxy-client
- name: volume-auth-kubeconfig
secret:
defaultMode: 420
secretName: discovery-auth-kubeconfig
- name: volume-etcd-client-cert
secret:
defaultMode: 420
secretName: discovery-etcd
- name: volume-serving-cert
secret:
defaultMode: 420
secretName: serving-discovery
- configMap:
defaultMode: 420
name: discovery-ca
name: volume-serving-ca
- configMap:
defaultMode: 420
name: etcd-ca
name: volume-etcd-ca
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
labels:
kubernetes-discovery: "true"
name: kubernetes-discovery
spec:
ports:
- port: 443
protocol: TCP
nodePort: 31090
targetPort: 443
selector:
kubernetes-discovery: "true"
type: NodePort
18 changes: 18 additions & 0 deletions cmd/kubernetes-discovery/artifacts/simple-image/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2016 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM fedora
MAINTAINER David Eads <deads@redhat.com>
ADD kubernetes-discovery /
ENTRYPOINT ["/kubernetes-discovery"]
28 changes: 28 additions & 0 deletions cmd/kubernetes-discovery/hack/build-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash

# Copyright 2014 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../..
source "${KUBE_ROOT}/hack/lib/util.sh"

# Register function to be called on EXIT to remove generated binary.
function cleanup {
rm "${KUBE_ROOT}/cmd/kubernetes-discovery/artifacts/simple-image/kubernetes-discovery"
}
trap cleanup EXIT

cp -v ${KUBE_ROOT}/_output/local/bin/linux/amd64/kubernetes-discovery "${KUBE_ROOT}/cmd/kubernetes-discovery/artifacts/simple-image/kubernetes-discovery"
docker build -t kubernetes-discovery:latest ${KUBE_ROOT}/cmd/kubernetes-discovery/artifacts/simple-image
3 changes: 2 additions & 1 deletion cmd/kubernetes-discovery/pkg/cmd/server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ func NewCommandStartDiscoveryServer(out, err io.Writer) *cobra.Command {
StdOut: out,
StdErr: err,
}
o.Etcd.StorageConfig.Type = storagebackend.StorageTypeETCD3
o.Etcd.StorageConfig.Prefix = defaultEtcdPathPrefix
o.Etcd.StorageConfig.Codec = api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)
o.SecureServing.ServingOptions.BindPort = 9090
o.SecureServing.ServingOptions.BindPort = 443

cmd := &cobra.Command{
Short: "Launch a discovery summarizer and proxy server",
Expand Down
135 changes: 134 additions & 1 deletion hack/lib/util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ kube::util::wait_for_url() {
local i
for i in $(seq 1 $times); do
local out
if out=$(curl -gkfs $url 2>/dev/null); then
if out=$(curl --max-time 1 -gkfs $url 2>/dev/null); then
kube::log::status "On try ${i}, ${prefix}: ${out}"
return 0
fi
Expand Down Expand Up @@ -443,4 +443,137 @@ kube::util::download_file() {
return 1
}

# Test whether cfssl and cfssljson are installed.
# Sets:
# CFSSL_BIN: The path of the installed cfssl binary
# CFSSLJSON_BIN: The path of the installed cfssljson binary
function kube::util::test_cfssl_installed {
if ! command -v cfssl &>/dev/null || ! command -v cfssljson &>/dev/null; then
echo "Failed to successfully run 'cfssl', please verify that cfssl and cfssljson are in \$PATH."
echo "Hint: export PATH=\$PATH:\$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/..."
exit 1
fi
CFSSL_BIN=$(command -v cfssl)
CFSSLJSON_BIN=$(command -v cfssljson)
}

# Test whether openssl is installed.
# Sets:
# OPENSSL_BIN: The path to the openssl binary to use
function kube::util::test_openssl_installed {
openssl version >& /dev/null
if [ "$?" != "0" ]; then
echo "Failed to run openssl. Please ensure openssl is installed"
exit 1
fi
OPENSSL_BIN=$(command -v openssl)
}

# creates a client CA, args are sudo, dest-dir, ca-id, purpose
# purpose is dropped in after "key encipherment", you usually want
# '"client auth"'
# '"server auth"'
# '"client auth","server auth"'
function kube::util::create_signing_certkey {
local sudo=$1
local dest_dir=$2
local id=$3
local purpose=$4
# Create client ca
${sudo} /bin/bash -e <<EOF
rm -f "${dest_dir}/${id}-ca.crt" "${dest_dir}/${id}-ca.key"
${OPENSSL_BIN} req -x509 -sha256 -new -nodes -days 365 -newkey rsa:2048 -keyout "${dest_dir}/${id}-ca.key" -out "${dest_dir}/${id}-ca.crt" -subj "/C=xx/ST=x/L=x/O=x/OU=x/CN=ca/emailAddress=x/"
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment",${purpose}]}}}' > "${dest_dir}/${id}-ca-config.json"
EOF
}

# signs a client certificate: args are sudo, dest-dir, CA, filename (roughly), username, groups...
function kube::util::create_client_certkey {
local sudo=$1
local dest_dir=$2
local ca=$3
local id=$4
local cn=${5:-$4}
local groups=""
local SEP=""
shift 5
while [ -n "${1:-}" ]; do
groups+="${SEP}{\"O\":\"$1\"}"
SEP=","
shift 1
done
${sudo} /bin/bash -e <<EOF
cd ${dest_dir}
echo '{"CN":"${cn}","names":[${groups}],"hosts":[""],"key":{"algo":"rsa","size":2048}}' | ${CFSSL_BIN} gencert -ca=${ca}.crt -ca-key=${ca}.key -config=${ca}-config.json - | ${CFSSLJSON_BIN} -bare client-${id}
mv "client-${id}-key.pem" "client-${id}.key"
mv "client-${id}.pem" "client-${id}.crt"
rm -f "client-${id}.csr"
EOF
}

# signs a serving certificate: args are sudo, dest-dir, ca, filename (roughly), subject, hosts...
function kube::util::create_serving_certkey {
local sudo=$1
local dest_dir=$2
local ca=$3
local id=$4
local cn=${5:-$4}
local hosts=""
local SEP=""
shift 5
while [ -n "${1:-}" ]; do
hosts+="${SEP}\"$1\""
SEP=","
shift 1
done
${sudo} /bin/bash -e <<EOF
cd ${dest_dir}
echo '{"CN":"${cn}","hosts":[${hosts}],"key":{"algo":"rsa","size":2048}}' | ${CFSSL_BIN} gencert -ca=${ca}.crt -ca-key=${ca}.key -config=${ca}-config.json - | ${CFSSLJSON_BIN} -bare serving-${id}
mv "serving-${id}-key.pem" "serving-${id}.key"
mv "serving-${id}.pem" "serving-${id}.crt"
rm -f "serving-${id}.csr"
EOF
}

# creates a self-contained kubeconfig: args are sudo, dest-dir, ca file, host, port, client id, token(optional)
function kube::util::write_client_kubeconfig {
local sudo=$1
local dest_dir=$2
local ca_file=$3
local api_host=$4
local api_port=$5
local client_id=$6
local token=${7:-}
cat <<EOF | ${sudo} tee "${dest_dir}"/${client_id}.kubeconfig > /dev/null
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: ${ca_file}
server: https://${api_host}:${api_port}/
name: local-up-cluster
users:
- user:
token: ${token}
client-certificate: ${dest_dir}/client-${client_id}.crt
client-key: ${dest_dir}/client-${client_id}.key
name: local-up-cluster
contexts:
- context:
cluster: local-up-cluster
user: local-up-cluster
name: local-up-cluster
current-context: local-up-cluster
EOF

# flatten the kubeconfig files to make them self contained
username=$(whoami)
${sudo} /bin/bash -e <<EOF
$(kube::util::find-binary kubectl) --kubeconfig="${dest_dir}/${client_id}.kubeconfig" config view --minify --flatten > "/tmp/${client_id}.kubeconfig"
mv -f "/tmp/${client_id}.kubeconfig" "${dest_dir}/${client_id}.kubeconfig"
chown ${username} "${dest_dir}/${client_id}.kubeconfig"
EOF
}


# ex: ts=2 sw=2 et filetype=sh