How to create a "CertificateSigningRequest" with apiVersion "certificates.k8s.io/v1" for a webhook

3/1/2021

I have a wehook running in my cluster.

I created a certificate and signed it successfully.

certificate configuration:

cat > csr.conf <<EOF
[req]
req_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 = s-controller.ns-controller
DNS.2 = s-controller.ns-controller.svc
EOF

I them create the certificate as following:

openssl genrsa -out server-key.pem 2048
openssl req -new -key server-key.pem -subj "/CN=s-controller.ns-controller.svc" -out server.csr -config csr.conf

certificate signing request (v1beta1)

cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
    name: csr-controller
spec:
    groups:
    - system:authenticated
    request: $(cat server.csr | base64 | tr -d '\n')
    usages:
    - digital signature
    - key encipherment
    - server auth
EOF

This worked just fine!

Since I updated my kubernetes version, I get the following warning: Warning: certificates.k8s.io/v1beta1 CertificateSigningRequest is deprecated in v1.19+, unavailable in v1.22+; use certificates.k8s.io/v1, I updated the CertificateSigningRequest so now it is as following:

cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
    name: csr-controller
spec:
    groups:
    - system:authenticated
    request: $(cat server.csr | base64 | tr -d '\n')
    signerName: kubernetes.io/kube-apiserver-client
    usages:
    - digital signature
    - key encipherment
    - client auth
EOF

And now the api server fails to connect to my webhook: Post "https://s-controller.ns-controller.svc:443/mutate?timeout=30s": x509: certificate specifies an incompatible key usage

I tried updateding the certificate configuration to extendedKeyUsage = clientAuth but it didnt help.

Any idea what is the correct signerName and configuration to the certificates.k8s.io/v1 apiVersion

-- David Wer
kubernetes
kubernetes-apiserver

3 Answers

3/22/2021

How to create a CertificateSigningRequest with apiVersion certificates.k8s.io/v1 for a webhook?

I have successfully created certificates.k8s.io/v1 with the following issuers and openssl csr config. It was tested with this webhook example.

Please check out the configs below:

#csr.conf
 
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${service}
DNS.2 = ${service}.${namespace}
DNS.3 = ${service}.${namespace}.svc

and:

#csr-for-webhook.yaml
 
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: ${csrName}
spec:
  groups:
  - system:authenticated
  request: $(cat ${tmpdir}/server.csr | base64 | tr -d '\n')
  usages:
  - digital signature
  - key encipherment
  - client auth
  signerName: kubernetes.io/kube-apiserver-client
-- WytrzymaƂy Wiktor
Source: StackOverflow

8/5/2021

In your old CertificateSigningRequest yaml you were using server auth as one of the key usages but, in latest one you changed it to client auth . the cert needed by webhook need to be signed with server auth key and signerName should be kubernetes.io/kubelet-serving . So update your files as follows to avoid the issue :

csr.conf

 cat > csr.conf <<EOF
 [req]
 req_extensions = v3_req
 distinguished_name = req_distinguished_name
 prompt = no
 [req_distinguished_name]
 CN = s-controller.ns-controller.svc
 [ v3_req ]
 basicConstraints = CA:FALSE
 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 extendedKeyUsage = clientAuth, serverAuth
 subjectAltName = @alt_names
 [alt_names]
 DNS.1 = s-controller.ns-controller
 DNS.2 = s-controller.ns-controller.svc
 EOF 

Generate csr with subject.organization as "system:nodes"

openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=system:node:s-contoller.ns-controller.svc /OU="system:nodes" /O=system:nodes" -out $server.csr -config csr.conf

csr-for-webhook.yaml

cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: csr-controller
spec:
    groups:
    - system:authenticated
    request: $(cat server.csr | base64 | tr -d '\n')
    signerName: kubernetes.io/kubelet-serving
    usages:
    - digital signature
    - key encipherment
    - server auth
EOF

source : https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/

PS: I have tested it with Kubernetes version 1.21.3

-- Vamsi Krishna DS
Source: StackOverflow

3/11/2021

I haven't managed to create a CertificateSigningRequest as I wished, HOWEVER I bypassed the issue by create my own CA as following:

First, I edited my certificate configurations file so it will include a commonName and currect extendedKeyUsage:

cat > csr.conf <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
CN = s-controller.ns-controller.svc
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = s-controller.ns-controller
DNS.2 = s-controller.ns-controller.svc
EOF

Generate CA certificate (notice the -days 365)

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt -subj "/CN=admission_ca"

Generate tls key and certificdate

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -config csr.conf
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -extensions v3_req -extfile csr.conf

Create a kubernetes tls secret for the webhook

kubectl create secret tls webhook-tls --cert=server.crt --key=server.key

Set the CA_BUNDLE

export CA_BUNDLE=$(cat ca.crt | base64 | tr -d '\n')

Remove all generated files

rm ca.crt 
rm ca.key 
rm server.key
rm server.csr
rm server.crt

In my webhhok, I have a volume volumeMount:

volume:

volumes:
- name: tls-vol
    secret:
      secretName: webhook-tls

volumeMount:

volumeMounts:
- name: tls-vol
  mountPath: /etc/webhook/certs
  readOnly: true

And the comantainer args

args:
- -tlsCertFile=/etc/webhook/certs/tls.crt
- -tlsKeyFile=/etc/webhook/certs/tls.key
-- David Wer
Source: StackOverflow