1
0
mirror of https://github.com/rancher/rke.git synced 2025-04-27 03:11:03 +00:00
rke/pki/pki.go
2021-07-29 08:59:54 +02:00

178 lines
6.4 KiB
Go

package pki
import (
"context"
"crypto/rsa"
"crypto/x509"
"fmt"
"net"
"path"
"path/filepath"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/rancher/rke/docker"
"github.com/rancher/rke/hosts"
"github.com/rancher/rke/log"
v3 "github.com/rancher/rke/types"
)
type CertificatePKI struct {
Certificate *x509.Certificate `json:"-"`
Key *rsa.PrivateKey `json:"-"`
CSR *x509.CertificateRequest `json:"-"`
CertificatePEM string `json:"certificatePEM"`
KeyPEM string `json:"keyPEM"`
CSRPEM string `json:"-"`
Config string `json:"config"`
Name string `json:"name"`
CommonName string `json:"commonName"`
OUName string `json:"ouName"`
EnvName string `json:"envName"`
Path string `json:"path"`
KeyEnvName string `json:"keyEnvName"`
KeyPath string `json:"keyPath"`
ConfigEnvName string `json:"configEnvName"`
ConfigPath string `json:"configPath"`
}
type GenFunc func(context.Context, map[string]CertificatePKI, v3.RancherKubernetesEngineConfig, string, string, bool) error
type CSRFunc func(context.Context, map[string]CertificatePKI, v3.RancherKubernetesEngineConfig) error
const (
etcdRole = "etcd"
controlRole = "controlplane"
workerRole = "worker"
BundleCertContainer = "rke-bundle-cert"
)
func GenerateRKECerts(ctx context.Context, rkeConfig v3.RancherKubernetesEngineConfig, configPath, configDir string) (map[string]CertificatePKI, error) {
certs := make(map[string]CertificatePKI)
// generate RKE CA certificates
if err := GenerateRKECACerts(ctx, certs, configPath, configDir); err != nil {
return certs, err
}
// Generating certificates for kubernetes components
if err := GenerateRKEServicesCerts(ctx, certs, rkeConfig, configPath, configDir, false); err != nil {
return certs, err
}
return certs, nil
}
func GenerateRKENodeCerts(ctx context.Context, rkeConfig v3.RancherKubernetesEngineConfig, nodeAddress string, certBundle map[string]CertificatePKI) map[string]CertificatePKI {
crtMap := make(map[string]CertificatePKI)
crtKeys := []string{}
for _, node := range rkeConfig.Nodes {
if node.Address == nodeAddress {
for _, role := range node.Role {
keys := getCertKeys(rkeConfig.Nodes, role, &rkeConfig)
crtKeys = append(crtKeys, keys...)
}
break
}
}
for _, key := range crtKeys {
crtMap[key] = certBundle[key]
}
return crtMap
}
func RegenerateEtcdCertificate(
ctx context.Context,
crtMap map[string]CertificatePKI,
etcdHost *hosts.Host,
etcdHosts []*hosts.Host,
clusterDomain string,
KubernetesServiceIP []net.IP) (map[string]CertificatePKI, error) {
etcdName := GetCrtNameForHost(etcdHost, EtcdCertName)
log.Infof(ctx, "[certificates] Regenerating new %s certificate and key", etcdName)
caCrt := crtMap[CACertName].Certificate
caKey := crtMap[CACertName].Key
etcdAltNames := GetAltNames(etcdHosts, clusterDomain, KubernetesServiceIP, []string{})
etcdCrt, etcdKey, err := GenerateSignedCertAndKey(caCrt, caKey, true, EtcdCertName, etcdAltNames, nil, nil)
if err != nil {
return nil, err
}
crtMap[etcdName] = ToCertObject(etcdName, "", "", etcdCrt, etcdKey, nil)
log.Infof(ctx, "[certificates] Successfully generated new %s certificate and key", etcdName)
return crtMap, nil
}
func SaveBackupBundleOnHost(ctx context.Context, host *hosts.Host, alpineSystemImage, etcdSnapshotPath string, prsMap map[string]v3.PrivateRegistry) error {
imageCfg := &container.Config{
Cmd: []string{
"sh",
"-c",
fmt.Sprintf("if [ -d %s ] && [ \"$(ls -A %s)\" ]; then tar czvf %s %s;fi", TempCertPath, TempCertPath, BundleCertPath, TempCertPath),
},
Image: alpineSystemImage,
}
hostCfg := &container.HostConfig{
Binds: []string{
fmt.Sprintf("%s:/etc/kubernetes:z", path.Join(host.PrefixPath, "/etc/kubernetes")),
fmt.Sprintf("%s:/backup:z", etcdSnapshotPath),
},
Privileged: true,
}
if err := docker.DoRunContainer(ctx, host.DClient, imageCfg, hostCfg, BundleCertContainer, host.Address, "certificates", prsMap); err != nil {
return err
}
status, err := docker.WaitForContainer(ctx, host.DClient, host.Address, BundleCertContainer)
if err != nil {
return err
}
if status != 0 {
return fmt.Errorf("Failed to run certificate bundle compress, exit status is: %d", status)
}
log.Infof(ctx, "[certificates] successfully saved certificate bundle [%s/pki.bundle.tar.gz] on host [%s]", etcdSnapshotPath, host.Address)
return docker.RemoveContainer(ctx, host.DClient, host.Address, BundleCertContainer)
}
func ExtractBackupBundleOnHost(ctx context.Context, host *hosts.Host, alpineSystemImage, etcdSnapshotPath string, prsMap map[string]v3.PrivateRegistry) error {
imageCfg := &container.Config{
Cmd: []string{
"sh",
"-c",
fmt.Sprintf(
"mkdir -p %s; tar xzvf %s -C %s --strip-components %d --exclude %s",
TempCertPath,
BundleCertPath,
TempCertPath,
len(strings.Split(filepath.Clean(TempCertPath), "/"))-1,
ClusterStateFile),
},
Image: alpineSystemImage,
}
hostCfg := &container.HostConfig{
Binds: []string{
fmt.Sprintf("%s:/etc/kubernetes:z", path.Join(host.PrefixPath, "/etc/kubernetes")),
fmt.Sprintf("%s:/backup:z", etcdSnapshotPath),
},
Privileged: true,
}
if err := docker.DoRunContainer(ctx, host.DClient, imageCfg, hostCfg, BundleCertContainer, host.Address, "certificates", prsMap); err != nil {
return err
}
status, err := docker.WaitForContainer(ctx, host.DClient, host.Address, BundleCertContainer)
if err != nil {
return err
}
if status != 0 {
containerErrLog, _, err := docker.GetContainerLogsStdoutStderr(ctx, host.DClient, BundleCertContainer, "5", false)
if err != nil {
return err
}
// removing the container in case of an error too
if err := docker.RemoveContainer(ctx, host.DClient, host.Address, BundleCertContainer); err != nil {
return err
}
return fmt.Errorf("Failed to run certificate bundle extract, exit status is: %d, container logs: %s", status, containerErrLog)
}
log.Infof(ctx, "[certificates] successfully extracted certificate bundle on host [%s] to backup path [%s]", host.Address, TempCertPath)
return docker.RemoveContainer(ctx, host.DClient, host.Address, BundleCertContainer)
}