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

Renew expired kubeadm certs #16249

Merged
merged 4 commits into from
May 3, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions pkg/minikube/bootstrapper/bsutil/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,12 @@ package bsutil

import (
"os/exec"
"path"

"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/vmpath"
)

// KubeadmYamlPath is the path to the kubeadm configuration
var KubeadmYamlPath = path.Join(vmpath.GuestEphemeralDir, "kubeadm.yaml")

const (
// KubeletServiceFile is the file for the systemd kubelet.service
KubeletServiceFile = "/lib/systemd/system/kubelet.service"
Expand Down
44 changes: 44 additions & 0 deletions pkg/minikube/bootstrapper/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ func SetupCerts(cmd command.Runner, k8s config.ClusterConfig, n config.Node) err
if err := installCertSymlinks(cmd, caCerts); err != nil {
return errors.Wrapf(err, "certificate symlinks")
}

if err := generateKubeadmCerts(cmd, k8s); err != nil {
return fmt.Errorf("failed to renew kubeadm certs: %v", err)
}
return nil
}

Expand Down Expand Up @@ -344,6 +348,38 @@ func generateProfileCerts(cfg config.ClusterConfig, n config.Node, ccs CACerts,
return xfer, nil
}

func generateKubeadmCerts(cmd command.Runner, cc config.ClusterConfig) error {
if _, err := cmd.RunCmd(exec.Command("ls", path.Join(vmpath.GuestPersistentDir, "certs", "etcd"))); err != nil {
klog.Infof("certs directory doesn't exist, likely first start: %v", err)
return nil
}

expiredCerts := false
certs := []string{"apiserver-etcd-client", "apiserver-kubelet-client", "etcd-server", "etcd-healthcheck-client", "etcd-peer", "front-proxy-client"}
for _, cert := range certs {
certPath := []string{vmpath.GuestPersistentDir, "certs"}
// certs starting with "etcd-" are in the "etcd" dir
// ex: etcd-server => etcd/server
if strings.HasPrefix(cert, "etcd-") {
certPath = append(certPath, "etcd")
}
certPath = append(certPath, strings.TrimPrefix(cert, "etcd-")+".crt")
if !isKubeadmCertValid(cmd, path.Join(certPath...)) {
expiredCerts = true
}
}
if !expiredCerts {
return nil
}
out.WarningT("kubeadm certificates have expired. Generating new ones...")
kubeadmPath := path.Join(vmpath.GuestPersistentDir, "binaries", cc.KubernetesConfig.KubernetesVersion)
bashCmd := fmt.Sprintf("sudo env PATH=\"%s:$PATH\" kubeadm certs renew all --config %s", kubeadmPath, constants.KubeadmYamlPath)
if _, err := cmd.RunCmd(exec.Command("/bin/bash", "-c", bashCmd)); err != nil {
return fmt.Errorf("failed to renew kubeadm certs: %v", err)
}
return nil
}

// isValidPEMCertificate checks whether the input file is a valid PEM certificate (with at least one CERTIFICATE block)
func isValidPEMCertificate(filePath string) (bool, error) {
fileBytes, err := os.ReadFile(filePath)
Expand Down Expand Up @@ -545,3 +581,11 @@ func isValid(certPath, keyPath string) bool {

return true
}

func isKubeadmCertValid(cmd command.Runner, certPath string) bool {
Copy link
Member

@medyagh medyagh Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about using linux to check if a cert is valid or not to avoid time zone difference between minikube and the host

Open a terminal window in Linux.

Type the following command, replacing <cert-file> with the path and name of the certificate file you want to check:
openssl x509 -enddate -noout -in <cert-file>
Press Enter.

The output of the command will display the end date of the certificate in the format notAfter=YYYYMMDDHHMMSSZ.

For example:

notAfter=20230410000000Z
Check the end date of the certificate. If the end date is in the past, then the certificate has expired.

For example, in the output above, the certificate will expire on April 10, 2023, at midnight UTC. If today's date is after April 10, 2023, then the certificate has expired.

_, err := cmd.RunCmd(exec.Command("openssl", "x509", "-noout", "-in", certPath, "-checkend", "86400"))
if err != nil {
klog.Infof("%v", err)
}
return err == nil
}
2 changes: 2 additions & 0 deletions pkg/minikube/bootstrapper/certs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"
"path/filepath"
"testing"
"time"

"k8s.io/minikube/pkg/minikube/command"
"k8s.io/minikube/pkg/minikube/config"
Expand Down Expand Up @@ -55,6 +56,7 @@ func TestSetupCerts(t *testing.T) {
expected := map[string]string{
`sudo /bin/bash -c "test -s /usr/share/ca-certificates/mycert.pem && ln -fs /usr/share/ca-certificates/mycert.pem /etc/ssl/certs/mycert.pem"`: "-",
`sudo /bin/bash -c "test -s /usr/share/ca-certificates/minikubeCA.pem && ln -fs /usr/share/ca-certificates/minikubeCA.pem /etc/ssl/certs/minikubeCA.pem"`: "-",
`date -u +%d-%m-%y-%T`: time.Now().Format("02-01-06-15:04:05"),
}
f := command.NewFakeCommandRunner()
f.SetCommandToOutput(expected)
Expand Down
8 changes: 4 additions & 4 deletions pkg/minikube/bootstrapper/kubeadm/kubeadm.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func (k *Bootstrapper) init(cfg config.ClusterConfig) error {
return errors.Wrap(err, "clearing stale configs")
}

conf := bsutil.KubeadmYamlPath
conf := constants.KubeadmYamlPath
ctx, cancel := context.WithTimeout(context.Background(), initTimeoutMinutes*time.Minute)
defer cancel()
kr, kw := io.Pipe()
Expand Down Expand Up @@ -429,7 +429,7 @@ func (k *Bootstrapper) StartCluster(cfg config.ClusterConfig) error {
// Fall-through to init
}

conf := bsutil.KubeadmYamlPath
conf := constants.KubeadmYamlPath
if _, err := k.c.RunCmd(exec.Command("sudo", "cp", conf+".new", conf)); err != nil {
return errors.Wrap(err, "cp")
}
Expand Down Expand Up @@ -678,7 +678,7 @@ func (k *Bootstrapper) restartControlPlane(cfg config.ClusterConfig) error {
}

// If the cluster is running, check if we have any work to do.
conf := bsutil.KubeadmYamlPath
conf := constants.KubeadmYamlPath

if !k.needsReconfigure(conf, hostname, port, client, cfg.KubernetesConfig.KubernetesVersion) {
klog.Infof("Taking a shortcut, as the cluster seems to be properly configured")
Expand Down Expand Up @@ -982,7 +982,7 @@ func (k *Bootstrapper) UpdateNode(cfg config.ClusterConfig, n config.Node, r cru
}

if n.ControlPlane {
files = append(files, assets.NewMemoryAssetTarget(kubeadmCfg, bsutil.KubeadmYamlPath+".new", "0640"))
files = append(files, assets.NewMemoryAssetTarget(kubeadmCfg, constants.KubeadmYamlPath+".new", "0640"))
}

// Installs compatibility shims for non-systemd environments
Expand Down
5 changes: 5 additions & 0 deletions pkg/minikube/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ package constants

import (
"errors"
"path"
"path/filepath"
"time"

"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/minikube/pkg/minikube/vmpath"
)

var (
Expand Down Expand Up @@ -203,4 +205,7 @@ var (

// ErrMachineMissing is returned when virtual machine does not exist due to user interrupt cancel(i.e. Ctrl + C)
ErrMachineMissing = errors.New("machine does not exist")

// KubeadmYamlPath is the path to the kubeadm configuration
KubeadmYamlPath = path.Join(vmpath.GuestEphemeralDir, "kubeadm.yaml")
)
1 change: 1 addition & 0 deletions translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,7 @@
"invalid kubernetes version": "Invalide Kubernetes Version",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "Halte den kube-context aktiv, wenn der Cluster gestoppt ist. Default: false",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "kubeadm erkannte einen TCP Port Konflikt mit anderen Prozessen: wahrscheinlich eine andere lokale Kubernetes Installation. Führe lsof -p\u003cport\u003e aus um den Prozess zu finden und zu töten",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "Konfiguration von Kubectl und minikube wird in {{.home_folder}} gespeichert",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "kubectl nicht gefunden. Falls Sie es benötigen, versuchen Sie 'minikube kubectl -- get pods -A' aufzurufen",
Expand Down
1 change: 1 addition & 0 deletions translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@
"invalid kubernetes version": "",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "La configuración de kubectl y de minikube se almacenará en {{.home_folder}}",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "",
Expand Down
1 change: 1 addition & 0 deletions translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@
"invalid kubernetes version": "version kubernetes invalide",
"json encoding failure": "échec de l'encodage json",
"keep the kube-context active after cluster is stopped. Defaults to false.": "garder le kube-context actif après l'arrêt du cluster. La valeur par défaut est false.",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "kubeadm a détecté un conflit de port TCP avec un autre processus : probablement une autre installation locale de Kubernetes. Exécutez lsof -p\u003cport\u003e pour trouver le processus et le tuer",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "Les configurations kubectl et minikube seront stockées dans le dossier {{.home_folder}}.",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "kubectl introuvable. Si vous en avez besoin, essayez : 'minikube kubectl -- get pods -A'",
Expand Down
1 change: 1 addition & 0 deletions translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,7 @@
"invalid kubernetes version": "無効な Kubernetes バージョン",
"json encoding failure": "json エンコード失敗",
"keep the kube-context active after cluster is stopped. Defaults to false.": "クラスター停止後に kube-context をアクティブのままにします。デフォルトは false です。",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "kubeadm が他のプロセス (おそらくローカルにインストールされた他の Kubernetes) との TCP ポート衝突を検出しました。 lsof -p\u003cport\u003e を実行してそのプロセスを特定し、停止してください",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "kubectl と minikube の構成は {{.home_folder}} に保存されます",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "kubectl が見つかりません。kubectl が必要な場合、'minikube kubectl -- get pods -A' を試してください",
Expand Down
1 change: 1 addition & 0 deletions translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,7 @@
"invalid kubernetes version": "",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "kubectl 과 minikube 환경 정보는 {{.home_folder}} 에 저장될 것입니다",
"kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "kubectl 이 PATH 에 없습니다, 하지만 이는 대시보드에서 필요로 합니다. 설치 가이드:https://kubernetes.io/docs/tasks/tools/install-kubectl/",
Expand Down
1 change: 1 addition & 0 deletions translations/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@
"invalid kubernetes version": "Nieprawidłowa wersja Kubernetesa",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "konfiguracja minikube i kubectl będzie przechowywana w katalogu {{.home_folder}}",
"kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/": "kubectl nie zostało odnalezione w zmiennej środowiskowej ${PATH}. Instrukcja instalacji: https://kubernetes.io/docs/tasks/tools/install-kubectl/",
Expand Down
1 change: 1 addition & 0 deletions translations/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@
"invalid kubernetes version": "",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "",
Expand Down
1 change: 1 addition & 0 deletions translations/strings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@
"invalid kubernetes version": "",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "",
Expand Down
1 change: 1 addition & 0 deletions translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@
"invalid kubernetes version": "",
"json encoding failure": "",
"keep the kube-context active after cluster is stopped. Defaults to false.": "",
"kubeadm certificates have expired. Generating new ones...": "",
"kubeadm detected a TCP port conflict with another process: probably another local Kubernetes installation. Run lsof -p\u003cport\u003e to find the process and kill it": "kubeadm 检测一个到与其他进程的 TCP 端口冲突:或许是另外的本地安装的 Kubernetes 导致。执行 lsof -p\u003cport\u003e 查找并杀死这些进程",
"kubectl and minikube configuration will be stored in {{.home_folder}}": "kubectl 和 minikube 配置将存储在 {{.home_folder}} 中",
"kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'": "",
Expand Down