|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +usage() { |
| 6 | + cat <<EOF |
| 7 | +Generate certificate suitable for use with an sidecar-injector webhook service. |
| 8 | +This script uses k8s' CertificateSigningRequest API to a generate a |
| 9 | +certificate signed by k8s CA suitable for use with sidecar-injector webhook |
| 10 | +services. This requires permissions to create and approve CSR. See |
| 11 | +https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster for |
| 12 | +detailed explantion and additional instructions. |
| 13 | +The server key/cert k8s CA cert are stored in a k8s secret. |
| 14 | +usage: ${0} [OPTIONS] |
| 15 | +The following flags are required. |
| 16 | + --service Service name of webhook. |
| 17 | + --namespace Namespace where webhook service and secret reside. |
| 18 | + --secret Secret name for CA certificate and server certificate/key pair. |
| 19 | +EOF |
| 20 | + exit 1 |
| 21 | +} |
| 22 | + |
| 23 | +while [[ $# -gt 0 ]]; do |
| 24 | + case ${1} in |
| 25 | + --service) |
| 26 | + service="$2" |
| 27 | + shift |
| 28 | + ;; |
| 29 | + --secret) |
| 30 | + secret="$2" |
| 31 | + shift |
| 32 | + ;; |
| 33 | + --namespace) |
| 34 | + namespace="$2" |
| 35 | + shift |
| 36 | + ;; |
| 37 | + *) |
| 38 | + usage |
| 39 | + ;; |
| 40 | + esac |
| 41 | + shift |
| 42 | +done |
| 43 | + |
| 44 | +[ -z ${service} ] && service=admission-webhook-example-svc |
| 45 | +[ -z ${secret} ] && secret=admission-webhook-example-certs |
| 46 | +[ -z ${namespace} ] && namespace=default |
| 47 | + |
| 48 | +if [ ! -x "$(command -v openssl)" ]; then |
| 49 | + echo "openssl not found" |
| 50 | + exit 1 |
| 51 | +fi |
| 52 | + |
| 53 | +csrName=${service}.${namespace} |
| 54 | +tmpdir=$(mktemp -d) |
| 55 | +echo "creating certs in tmpdir ${tmpdir} " |
| 56 | + |
| 57 | +cat <<EOF >> ${tmpdir}/csr.conf |
| 58 | +[req] |
| 59 | +req_extensions = v3_req |
| 60 | +distinguished_name = req_distinguished_name |
| 61 | +[req_distinguished_name] |
| 62 | +[ v3_req ] |
| 63 | +basicConstraints = CA:FALSE |
| 64 | +keyUsage = nonRepudiation, digitalSignature, keyEncipherment |
| 65 | +extendedKeyUsage = serverAuth |
| 66 | +subjectAltName = @alt_names |
| 67 | +[alt_names] |
| 68 | +DNS.1 = ${service} |
| 69 | +DNS.2 = ${service}.${namespace} |
| 70 | +DNS.3 = ${service}.${namespace}.svc |
| 71 | +EOF |
| 72 | + |
| 73 | +openssl genrsa -out ${tmpdir}/server-key.pem 2048 |
| 74 | +openssl req -new -key ${tmpdir}/server-key.pem -subj "/CN=${service}.${namespace}.svc" -out ${tmpdir}/server.csr -config ${tmpdir}/csr.conf |
| 75 | + |
| 76 | +# clean-up any previously created CSR for our service. Ignore errors if not present. |
| 77 | +kubectl delete csr ${csrName} 2>/dev/null || true |
| 78 | + |
| 79 | +# create server cert/key CSR and send to k8s API |
| 80 | +cat <<EOF | kubectl create -f - |
| 81 | +apiVersion: certificates.k8s.io/v1beta1 |
| 82 | +kind: CertificateSigningRequest |
| 83 | +metadata: |
| 84 | + name: ${csrName} |
| 85 | +spec: |
| 86 | + groups: |
| 87 | + - system:authenticated |
| 88 | + request: $(cat ${tmpdir}/server.csr | base64 | tr -d '\n') |
| 89 | + usages: |
| 90 | + - digital signature |
| 91 | + - key encipherment |
| 92 | + - server auth |
| 93 | +EOF |
| 94 | + |
| 95 | +# verify CSR has been created |
| 96 | +while true; do |
| 97 | + kubectl get csr ${csrName} |
| 98 | + if [ "$?" -eq 0 ]; then |
| 99 | + break |
| 100 | + fi |
| 101 | +done |
| 102 | + |
| 103 | +# approve and fetch the signed certificate |
| 104 | +kubectl certificate approve ${csrName} |
| 105 | +# verify certificate has been signed |
| 106 | +for x in $(seq 10); do |
| 107 | + serverCert=$(kubectl get csr ${csrName} -o jsonpath='{.status.certificate}') |
| 108 | + if [[ ${serverCert} != '' ]]; then |
| 109 | + break |
| 110 | + fi |
| 111 | + sleep 1 |
| 112 | +done |
| 113 | +if [[ ${serverCert} == '' ]]; then |
| 114 | + echo "ERROR: After approving csr ${csrName}, the signed certificate did not appear on the resource. Giving up after 10 attempts." >&2 |
| 115 | + exit 1 |
| 116 | +fi |
| 117 | +echo ${serverCert} | openssl base64 -d -A -out ${tmpdir}/server-cert.pem |
| 118 | + |
| 119 | + |
| 120 | +# create the secret with CA cert and server cert/key |
| 121 | +kubectl create secret generic ${secret} \ |
| 122 | + --from-file=key.pem=${tmpdir}/server-key.pem \ |
| 123 | + --from-file=cert.pem=${tmpdir}/server-cert.pem \ |
| 124 | + --dry-run -o yaml | |
| 125 | + kubectl -n ${namespace} apply -f - |
0 commit comments