<p>During Kubernetes upgrade from 1.14 to 1.15 with kubespray, my team had a blocking issue with the following message during the "Upgrade first master" step :</p>

<pre><code>[upgrade/apply] FATAL: couldn''t upgrade control plane.
kubeadm has tried to recover everything into the earlier state.
Errors faced: [failed to renew certificates for component "kube-apiserver":
failed to renew certificate apiserver-kubelet-client:
unable to sign certificate:
must specify at least one ExtKeyUsage,
rename /etc/kubernetes/tmp/kubeadm
-backup-manifests-2019-09-19-09-06-27/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml: no such file or directory]'
</code></pre>

<p>Trying to isolate the task and manually running the kubeadm command line leads to the same error message :</p>

<pre><code>#/usr/local/bin/kubeadm upgrade apply -y v1.15.3 --config=/etc/kubernetes/kubeadm-config.yaml --ignore-preflight-errors=all --allow-experimental-upgrades --allow-release-candidate-upgrades --etcd-upgrade=false -v 6 
</code></pre>

<p>or even trying to just manually renew the certificate :</p>

<pre><code>/etc/kubernetes/pki# kubeadm alpha certs renew apiserver-kubelet-client -v 9
I0919 14:42:11.515503   18597 initconfiguration.go:105] detected and using CRI socket: /var/run/dockershim.sock
I0919 14:42:11.515897   18597 interface.go:384] Looking for default routes with IPv4 addresses
I0919 14:42:11.515916   18597 interface.go:389] Default route transits interface “eth0”
I0919 14:42:11.516284   18597 interface.go:196] Interface eth0 is up
(...)
I0919 14:42:11.516835   18597 feature_gate.go:216] feature gates: &amp;{map[]}
failed to renew certificate apiserver-kubelet-client: unable to sign certificate: must specify at least one ExtKeyUsage
</code></pre>

<p>The solution was found eventually and posted below.</p>

<p>The issue comes from kubeadm which uses the old certificates when it has to renew them. But when these initial certificates are too old or were manually generated, they may not include some mandatory fields that needs to be there.</p>

<p>In the error message, <code>ExtKeyUsage</code> refers to the <code>X509v3 Extended Key Usage</code> field.</p>

<p>You can check that by looking into your certificates : 2 certificates are involved : <code>apiserver-kubelet-client.crt</code> and <code>front-proxy-client.crt</code></p>

<p>They are located on the master hosts at <code>/etc/kubernetes/pki</code>.</p>

<p>You can check them with </p>

<p><code># openssl x509 -in apiserver-kubelet-client.crt -text -noout</code></p>

<p>If they do not contain the following (near the end), then kubeadm will be totally unable to renew the certificate</p>

<pre><code>(...)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication
</code></pre>

<hr>

<p>TL;DR;</p>

<p>The solution is simply to create brand new certificates with the following procedure</p>

<pre><code>######### Backup your certificates (just in case)
master01:/etc/kubernetes/pki# cp -a /etc/kubernetes/pki /root/backup_cert/
######### Delete incomplete certificates
master01:/etc/kubernetes/pki# rm apiserver-kubelet-client.*
master01:/etc/kubernetes/pki# rm front-proxy-client.*
######### Then recreate them
master01:/etc/kubernetes/pki# kubeadm init phase certs apiserver-kubelet-client 
master01:/etc/kubernetes/pki# kubeadm init phase certs front-proxy-client
</code></pre>

<p>You can now restart your upgrade procedure which should be ok. (Note : if your cluster was left in a state where your first master has a SchedulingDisabled state, then do not forget to uncordon the host, because kubespray playbook won't fix that)</p>
