2017-10-31 13:55:35 +00:00
|
|
|
package pki
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2018-01-10 23:03:08 +00:00
|
|
|
"crypto/rsa"
|
2017-10-31 13:55:35 +00:00
|
|
|
"fmt"
|
2017-11-01 21:46:43 +00:00
|
|
|
"io/ioutil"
|
2017-11-29 20:33:08 +00:00
|
|
|
"os"
|
2018-01-10 23:03:08 +00:00
|
|
|
"path"
|
|
|
|
"strings"
|
2017-10-31 13:55:35 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
|
|
"github.com/rancher/rke/docker"
|
|
|
|
"github.com/rancher/rke/hosts"
|
2018-01-09 22:10:56 +00:00
|
|
|
"github.com/rancher/rke/log"
|
2017-11-13 21:28:38 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2018-01-10 23:03:08 +00:00
|
|
|
"k8s.io/client-go/util/cert"
|
2017-10-31 13:55:35 +00:00
|
|
|
)
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func DeployCertificatesOnMasters(ctx context.Context, cpHosts []*hosts.Host, crtMap map[string]CertificatePKI, certDownloaderImage string) error {
|
2017-11-10 02:39:10 +00:00
|
|
|
// list of certificates that should be deployed on the masters
|
|
|
|
crtList := []string{
|
|
|
|
CACertName,
|
|
|
|
KubeAPICertName,
|
|
|
|
KubeControllerName,
|
|
|
|
KubeSchedulerName,
|
|
|
|
KubeProxyName,
|
|
|
|
KubeNodeName,
|
|
|
|
}
|
|
|
|
env := []string{}
|
|
|
|
for _, crtName := range crtList {
|
|
|
|
c := crtMap[crtName]
|
|
|
|
env = append(env, c.ToEnv()...)
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
2017-11-10 02:39:10 +00:00
|
|
|
|
2017-11-02 10:07:10 +00:00
|
|
|
for i := range cpHosts {
|
2018-01-09 22:10:56 +00:00
|
|
|
err := doRunDeployer(ctx, cpHosts[i], env, certDownloaderImage)
|
2017-10-31 13:55:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func DeployCertificatesOnWorkers(ctx context.Context, workerHosts []*hosts.Host, crtMap map[string]CertificatePKI, certDownloaderImage string) error {
|
2017-11-10 02:39:10 +00:00
|
|
|
// list of certificates that should be deployed on the workers
|
|
|
|
crtList := []string{
|
|
|
|
CACertName,
|
|
|
|
KubeProxyName,
|
|
|
|
KubeNodeName,
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
2017-11-10 02:39:10 +00:00
|
|
|
env := []string{}
|
|
|
|
for _, crtName := range crtList {
|
|
|
|
c := crtMap[crtName]
|
|
|
|
env = append(env, c.ToEnv()...)
|
|
|
|
}
|
|
|
|
|
2017-11-02 10:07:10 +00:00
|
|
|
for i := range workerHosts {
|
2018-01-09 22:10:56 +00:00
|
|
|
err := doRunDeployer(ctx, workerHosts[i], env, certDownloaderImage)
|
2017-10-31 13:55:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func doRunDeployer(ctx context.Context, host *hosts.Host, containerEnv []string, certDownloaderImage string) error {
|
2018-01-10 23:03:08 +00:00
|
|
|
// remove existing container. Only way it's still here is if previous deployment failed
|
|
|
|
isRunning := false
|
|
|
|
isRunning, err := docker.IsContainerRunning(ctx, host.DClient, host.Address, CrtDownloaderContainer, true)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if isRunning {
|
|
|
|
if err := docker.RemoveContainer(ctx, host.DClient, host.Address, CrtDownloaderContainer); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
if err := docker.UseLocalOrPull(ctx, host.DClient, host.Address, certDownloaderImage, CertificatesServiceName); err != nil {
|
2017-10-31 13:55:35 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
imageCfg := &container.Config{
|
2017-12-05 01:29:29 +00:00
|
|
|
Image: certDownloaderImage,
|
2017-10-31 13:55:35 +00:00
|
|
|
Env: containerEnv,
|
|
|
|
}
|
|
|
|
hostCfg := &container.HostConfig{
|
|
|
|
Binds: []string{
|
|
|
|
"/etc/kubernetes:/etc/kubernetes",
|
|
|
|
},
|
2017-11-30 23:16:45 +00:00
|
|
|
Privileged: true,
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
resp, err := host.DClient.ContainerCreate(ctx, imageCfg, hostCfg, nil, CrtDownloaderContainer)
|
2017-10-31 13:55:35 +00:00
|
|
|
if err != nil {
|
2017-11-28 17:45:24 +00:00
|
|
|
return fmt.Errorf("Failed to create Certificates deployer container on host [%s]: %v", host.Address, err)
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
if err := host.DClient.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
|
2017-11-28 17:45:24 +00:00
|
|
|
return fmt.Errorf("Failed to start Certificates deployer container on host [%s]: %v", host.Address, err)
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
|
|
|
logrus.Debugf("[certificates] Successfully started Certificate deployer container: %s", resp.ID)
|
|
|
|
for {
|
2018-01-09 22:10:56 +00:00
|
|
|
isDeployerRunning, err := docker.IsContainerRunning(ctx, host.DClient, host.Address, CrtDownloaderContainer, false)
|
2017-10-31 13:55:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if isDeployerRunning {
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
continue
|
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
if err := host.DClient.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{}); err != nil {
|
2017-11-28 17:45:24 +00:00
|
|
|
return fmt.Errorf("Failed to delete Certificates deployer container on host [%s]: %v", host.Address, err)
|
2017-10-31 13:55:35 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2017-11-01 21:46:43 +00:00
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func DeployAdminConfig(ctx context.Context, kubeConfig, localConfigPath string) error {
|
2017-11-01 21:46:43 +00:00
|
|
|
logrus.Debugf("Deploying admin Kubeconfig locally: %s", kubeConfig)
|
2017-11-15 01:12:33 +00:00
|
|
|
err := ioutil.WriteFile(localConfigPath, []byte(kubeConfig), 0640)
|
2017-11-02 10:07:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Failed to create local admin kubeconfig file: %v", err)
|
2017-11-01 21:46:43 +00:00
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "Successfully Deployed local admin kubeconfig at [%s]", localConfigPath)
|
2017-11-01 21:46:43 +00:00
|
|
|
return nil
|
|
|
|
}
|
2017-11-29 20:33:08 +00:00
|
|
|
|
2018-01-09 22:10:56 +00:00
|
|
|
func RemoveAdminConfig(ctx context.Context, localConfigPath string) {
|
|
|
|
log.Infof(ctx, "Removing local admin Kubeconfig: %s", localConfigPath)
|
2017-11-29 20:33:08 +00:00
|
|
|
if err := os.Remove(localConfigPath); err != nil {
|
2017-12-08 23:38:44 +00:00
|
|
|
logrus.Warningf("Failed to remove local admin Kubeconfig file: %v", err)
|
|
|
|
return
|
2017-11-29 20:33:08 +00:00
|
|
|
}
|
2018-01-09 22:10:56 +00:00
|
|
|
log.Infof(ctx, "Local admin Kubeconfig removed successfully")
|
2017-11-29 20:33:08 +00:00
|
|
|
}
|
2018-01-10 23:03:08 +00:00
|
|
|
|
|
|
|
func DeployCertificatesOnHost(ctx context.Context, host *hosts.Host, crtMap map[string]CertificatePKI, certDownloaderImage string) error {
|
|
|
|
crtList := []string{
|
|
|
|
CACertName,
|
|
|
|
KubeAPICertName,
|
|
|
|
KubeControllerName,
|
|
|
|
KubeSchedulerName,
|
|
|
|
KubeProxyName,
|
|
|
|
KubeNodeName,
|
|
|
|
KubeAdminCommonName,
|
|
|
|
}
|
|
|
|
|
|
|
|
env := []string{
|
|
|
|
"CRTS_DEPLOY_PATH=" + TempCertPath,
|
|
|
|
}
|
|
|
|
for _, crtName := range crtList {
|
|
|
|
c := crtMap[crtName]
|
|
|
|
// We don't need to edit the cert paths, they are not used in deployment
|
|
|
|
env = append(env, c.ToEnv()...)
|
|
|
|
}
|
|
|
|
return doRunDeployer(ctx, host, env, certDownloaderImage)
|
|
|
|
}
|
|
|
|
|
|
|
|
func FetchCertificatesFromHost(ctx context.Context, host *hosts.Host, image, localConfigPath string) (map[string]CertificatePKI, error) {
|
|
|
|
// rebuilding the certificates. This should look better after refactoring pki
|
|
|
|
tmpCerts := make(map[string]CertificatePKI)
|
|
|
|
|
|
|
|
certEnvMap := map[string][]string{
|
|
|
|
CACertName: []string{CACertPath, CAKeyPath},
|
|
|
|
KubeAPICertName: []string{KubeAPICertPath, KubeAPIKeyPath},
|
|
|
|
KubeControllerName: []string{KubeControllerCertPath, KubeControllerKeyPath, KubeControllerConfigPath},
|
|
|
|
KubeSchedulerName: []string{KubeSchedulerCertPath, KubeSchedulerKeyPath, KubeSchedulerConfigPath},
|
|
|
|
KubeProxyName: []string{KubeProxyCertPath, KubeProxyKeyPath, KubeProxyConfigPath},
|
|
|
|
KubeNodeName: []string{KubeNodeCertPath, KubeNodeKeyPath, KubeNodeConfigPath},
|
|
|
|
KubeAdminCommonName: []string{"kube-admin.pem", "kube-admin-key.pem", "kubecfg-admin.yaml"},
|
|
|
|
}
|
|
|
|
// get files from hosts
|
|
|
|
|
|
|
|
for crtName, certEnv := range certEnvMap {
|
|
|
|
certificate := CertificatePKI{}
|
|
|
|
crt, err := fetchFileFromHost(ctx, getTempPath(certEnv[0]), image, host)
|
|
|
|
if err != nil {
|
|
|
|
if strings.Contains(err.Error(), "no such file or directory") {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
key, err := fetchFileFromHost(ctx, getTempPath(certEnv[1]), image, host)
|
|
|
|
|
|
|
|
if len(certEnv) > 2 {
|
|
|
|
config, err := fetchFileFromHost(ctx, getTempPath(certEnv[2]), image, host)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
certificate.Config = config
|
|
|
|
}
|
|
|
|
parsedCert, err := cert.ParseCertsPEM([]byte(crt))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
parsedKey, err := cert.ParsePrivateKeyPEM([]byte(key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
certificate.Certificate = parsedCert[0]
|
|
|
|
certificate.Key = parsedKey.(*rsa.PrivateKey)
|
|
|
|
tmpCerts[crtName] = certificate
|
|
|
|
logrus.Debugf("[certificates] Recovered certificate: %s", crtName)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := docker.RemoveContainer(ctx, host.DClient, host.Address, CertFetcherContainer); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return populateCertMap(tmpCerts, localConfigPath), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchFileFromHost(ctx context.Context, filePath, image string, host *hosts.Host) (string, error) {
|
|
|
|
|
|
|
|
imageCfg := &container.Config{
|
|
|
|
Image: image,
|
|
|
|
}
|
|
|
|
hostCfg := &container.HostConfig{
|
|
|
|
Binds: []string{
|
|
|
|
"/etc/kubernetes:/etc/kubernetes",
|
|
|
|
},
|
|
|
|
Privileged: true,
|
|
|
|
}
|
|
|
|
isRunning, err := docker.IsContainerRunning(ctx, host.DClient, host.Address, CertFetcherContainer, true)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if !isRunning {
|
|
|
|
if err := docker.DoRunContainer(ctx, host.DClient, imageCfg, hostCfg, CertFetcherContainer, host.Address, "certificates"); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
file, err := docker.ReadFileFromContainer(ctx, host.DClient, host.Address, CertFetcherContainer, filePath)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return file, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTempPath(s string) string {
|
|
|
|
return TempCertPath + path.Base(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func populateCertMap(tmpCerts map[string]CertificatePKI, localConfigPath string) map[string]CertificatePKI {
|
|
|
|
certs := make(map[string]CertificatePKI)
|
|
|
|
//CACert
|
|
|
|
certs[CACertName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[CACertName].Certificate,
|
|
|
|
Key: tmpCerts[CACertName].Key,
|
|
|
|
Name: CACertName,
|
|
|
|
EnvName: CACertENVName,
|
|
|
|
KeyEnvName: CAKeyENVName,
|
|
|
|
Path: CACertPath,
|
|
|
|
KeyPath: CAKeyPath,
|
|
|
|
}
|
|
|
|
//KubeAPI
|
|
|
|
certs[KubeAPICertName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeAPICertName].Certificate,
|
|
|
|
Key: tmpCerts[KubeAPICertName].Key,
|
|
|
|
Name: KubeAPICertName,
|
|
|
|
EnvName: KubeAPICertENVName,
|
|
|
|
KeyEnvName: KubeAPIKeyENVName,
|
|
|
|
Path: KubeAPICertPath,
|
|
|
|
KeyPath: KubeAPIKeyPath,
|
|
|
|
}
|
|
|
|
//kubeController
|
|
|
|
certs[KubeControllerName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeControllerName].Certificate,
|
|
|
|
Key: tmpCerts[KubeControllerName].Key,
|
|
|
|
Config: tmpCerts[KubeControllerName].Config,
|
|
|
|
Name: KubeControllerName,
|
|
|
|
CommonName: KubeControllerCommonName,
|
|
|
|
EnvName: KubeControllerCertENVName,
|
|
|
|
KeyEnvName: KubeControllerKeyENVName,
|
|
|
|
Path: KubeControllerCertPath,
|
|
|
|
KeyPath: KubeControllerKeyPath,
|
|
|
|
ConfigEnvName: KubeControllerConfigENVName,
|
|
|
|
ConfigPath: KubeControllerConfigPath,
|
|
|
|
}
|
|
|
|
//KubeScheduler
|
|
|
|
certs[KubeSchedulerName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeSchedulerName].Certificate,
|
|
|
|
Key: tmpCerts[KubeSchedulerName].Key,
|
|
|
|
Config: tmpCerts[KubeSchedulerName].Config,
|
|
|
|
Name: KubeSchedulerName,
|
|
|
|
CommonName: KubeSchedulerCommonName,
|
|
|
|
EnvName: KubeSchedulerCertENVName,
|
|
|
|
KeyEnvName: KubeSchedulerKeyENVName,
|
|
|
|
Path: KubeSchedulerCertPath,
|
|
|
|
KeyPath: KubeSchedulerKeyPath,
|
|
|
|
ConfigEnvName: KubeSchedulerConfigENVName,
|
|
|
|
ConfigPath: KubeSchedulerConfigPath,
|
|
|
|
}
|
|
|
|
// KubeProxy
|
|
|
|
certs[KubeProxyName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeProxyName].Certificate,
|
|
|
|
Key: tmpCerts[KubeProxyName].Key,
|
|
|
|
Config: tmpCerts[KubeProxyName].Config,
|
|
|
|
Name: KubeProxyName,
|
|
|
|
CommonName: KubeProxyCommonName,
|
|
|
|
EnvName: KubeProxyCertENVName,
|
|
|
|
Path: KubeProxyCertPath,
|
|
|
|
KeyEnvName: KubeProxyKeyENVName,
|
|
|
|
KeyPath: KubeProxyKeyPath,
|
|
|
|
ConfigEnvName: KubeProxyConfigENVName,
|
|
|
|
ConfigPath: KubeProxyConfigPath,
|
|
|
|
}
|
|
|
|
// KubeNode
|
|
|
|
certs[KubeNodeName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeNodeName].Certificate,
|
|
|
|
Key: tmpCerts[KubeNodeName].Key,
|
|
|
|
Config: tmpCerts[KubeNodeName].Config,
|
|
|
|
Name: KubeNodeName,
|
|
|
|
CommonName: KubeNodeCommonName,
|
|
|
|
OUName: KubeNodeOrganizationName,
|
|
|
|
EnvName: KubeNodeCertENVName,
|
|
|
|
KeyEnvName: KubeNodeKeyENVName,
|
|
|
|
Path: KubeNodeCertPath,
|
|
|
|
KeyPath: KubeNodeKeyPath,
|
|
|
|
ConfigEnvName: KubeNodeConfigENVName,
|
|
|
|
ConfigPath: KubeNodeCommonName,
|
|
|
|
}
|
|
|
|
|
|
|
|
certs[KubeAdminCommonName] = CertificatePKI{
|
|
|
|
Certificate: tmpCerts[KubeAdminCommonName].Certificate,
|
|
|
|
Key: tmpCerts[KubeAdminCommonName].Key,
|
|
|
|
Config: tmpCerts[KubeAdminCommonName].Config,
|
|
|
|
CommonName: KubeAdminCommonName,
|
|
|
|
OUName: KubeAdminOrganizationName,
|
|
|
|
ConfigEnvName: KubeAdminConfigENVName,
|
|
|
|
ConfigPath: localConfigPath,
|
|
|
|
EnvName: KubeAdminCertEnvName,
|
|
|
|
KeyEnvName: KubeAdminKeyEnvName,
|
|
|
|
}
|
|
|
|
return certs
|
|
|
|
}
|