deployment/dockerfiles/kubeflow/kfp/backend/src/cache/deployer/webhook-create-signed-cert.sh
#!/bin/bash
#
# Copyright 2020 The Kubeflow 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.

set -ex

usage() {
    cat <<EOF
Generate certificate suitable for use with an sidecar-injector webhook service.
This script uses k8s' CertificateSigningRequest API to a generate a
certificate signed by k8s CA suitable for use with sidecar-injector webhook
services. This requires permissions to create and approve CSR. See
https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster for
detailed explantion and additional instructions.
The server key/cert k8s CA cert are stored in a k8s secret.
usage: ${0} [OPTIONS]
The following flags are required.
       --service          Service name of webhook.
       --namespace        Namespace where webhook service and secret reside.
       --secret           Secret name for CA certificate and server certificate/key pair.
EOF
    exit 1
}

while [[ $# -gt 0 ]]; do
    case ${1} in
        --service)
            service="$2"
            shift
            ;;
        --secret)
            secret="$2"
            shift
            ;;
        --namespace)
            namespace="$2"
            shift
            ;;
        --cert_output_path)
            cert_output_path="$2"
            shift
            ;;
        *)
            usage
            ;;
    esac
    shift
done

[ -z ${service} ] && service=cache-server
[ -z ${secret} ] && secret=webhook-server-tls
[ -z ${namespace} ] && namespace=kubeflow
[ -z ${cert_output_path} ] && cert_output_path=${CA_FILE}

if [ ! -x "$(command -v openssl)" ]; then
    echo "openssl not found"
    exit 1
fi

csrName=${service}.${namespace}
tmpdir=$(mktemp -d)
echo "creating certs in tmpdir ${tmpdir} "

# create csr config file for csr generation. 
# [req] is for csr with distinguished_name setting.
# [v3_req] is extensions to add to a certificate request in this case is for setting key constraints and usages.
# [alt_names] specifies additional subject identities. So the keys can be matched by different DNS names. 
# Adjusted to work with the openssl certificate
cat <<EOF >> ${tmpdir}/csr.conf
[req]
x509_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${service}
DNS.2 = ${service}.${namespace}
DNS.3 = ${service}.${namespace}.svc
EOF

# Due to security constraints we cannot use the Kuberentes CSR, therefore we create an openssl certificate
openssl req -x509 -nodes -newkey rsa:4096 -keyout $tmpdir/server-key.pem -out $tmpdir/server-cert.pem -sha256 -days 3650 -config ${tmpdir}/csr.conf -subj "/CN=${service}.${namespace}.svc"

openssl base64 -in ${tmpdir}/server-cert.pem -A -out ${cert_output_path}

# create the secret with CA cert and server cert/key
kubectl create secret generic ${secret} \
        --from-file=key.pem=${tmpdir}/server-key.pem \
        --from-file=cert.pem=${tmpdir}/server-cert.pem \
        --dry-run -o yaml |
    kubectl -n ${namespace} apply -f -