Use Secrets for files that self-hosted pods depend on

pull/6/head
Andrew Rynhard 2017-03-04 17:54:41 -08:00 committed by Andrew Rynhard
parent 7df2bce1ec
commit 38c6e83033
9 changed files with 622 additions and 35 deletions

View File

@ -271,7 +271,7 @@ func (i *Init) Run(out io.Writer) error {
// Temporary control plane is up, now we create our self hosted control
// plane components and remove the static manifests:
fmt.Println("[self-hosted] Creating self-hosted control plane...")
if err := selfhostingphase.CreateSelfHostedControlPlane(client); err != nil {
if err := selfhostingphase.CreateSelfHostedControlPlane(i.cfg, client); err != nil {
return err
}
}

View File

@ -19,23 +19,30 @@ package phases
import (
"github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/pkg/api"
)
// NewCmdSelfhosting returns the self-hosting Cobra command
func NewCmdSelfhosting() *cobra.Command {
var kubeConfigFile string
cfg := &kubeadmapiext.MasterConfiguration{}
cmd := &cobra.Command{
Use: "selfhosting",
Aliases: []string{"selfhosted"},
Short: "Make a kubeadm cluster self-hosted.",
Run: func(cmd *cobra.Command, args []string) {
api.Scheme.Default(cfg)
internalcfg := &kubeadmapi.MasterConfiguration{}
api.Scheme.Convert(cfg, internalcfg, nil)
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err)
err = selfhosting.CreateSelfHostedControlPlane(client)
err = selfhosting.CreateSelfHostedControlPlane(internalcfg, client)
kubeadmutil.CheckErr(err)
},
}

View File

@ -13,10 +13,12 @@ go_test(
srcs = [
"podspec_mutation_test.go",
"selfhosting_test.go",
"selfhosting_volumes_test.go",
],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
@ -28,9 +30,11 @@ go_library(
srcs = [
"podspec_mutation.go",
"selfhosting.go",
"selfhosting_volumes.go",
],
tags = ["automanaged"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//pkg/api:go_default_library",

View File

@ -18,38 +18,42 @@ package selfhosting
import (
"k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
// mutatePodSpec makes a Static Pod-hosted PodSpec suitable for self-hosting
func mutatePodSpec(name string, podSpec *v1.PodSpec) {
mutators := map[string][]func(*v1.PodSpec){
func mutatePodSpec(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) {
mutators := map[string][]func(*kubeadmapi.MasterConfiguration, *v1.PodSpec){
kubeAPIServer: {
addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec,
setVolumesOnKubeAPIServerPodSpec,
},
kubeControllerManager: {
addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec,
setVolumesOnKubeControllerManagerPodSpec,
},
kubeScheduler: {
addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec,
setVolumesOnKubeSchedulerPodSpec,
},
}
// Get the mutator functions for the component in question, then loop through and execute them
mutatorsForComponent := mutators[name]
for _, mutateFunc := range mutatorsForComponent {
mutateFunc(podSpec)
mutateFunc(cfg, podSpec)
}
}
// addNodeSelectorToPodSpec makes Pod require to be scheduled on a node marked with the master label
func addNodeSelectorToPodSpec(podSpec *v1.PodSpec) {
func addNodeSelectorToPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
if podSpec.NodeSelector == nil {
podSpec.NodeSelector = map[string]string{kubeadmconstants.LabelNodeRoleMaster: ""}
return
@ -59,7 +63,7 @@ func addNodeSelectorToPodSpec(podSpec *v1.PodSpec) {
}
// setMasterTolerationOnPodSpec makes the Pod tolerate the master taint
func setMasterTolerationOnPodSpec(podSpec *v1.PodSpec) {
func setMasterTolerationOnPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
if podSpec.Tolerations == nil {
podSpec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration}
return
@ -69,6 +73,38 @@ func setMasterTolerationOnPodSpec(podSpec *v1.PodSpec) {
}
// setRightDNSPolicyOnPodSpec makes sure the self-hosted components can look up things via kube-dns if necessary
func setRightDNSPolicyOnPodSpec(podSpec *v1.PodSpec) {
func setRightDNSPolicyOnPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
podSpec.DNSPolicy = v1.DNSClusterFirstWithHostNet
}
// setVolumesOnKubeAPIServerPodSpec makes sure the self-hosted api server has the required files
func setVolumesOnKubeAPIServerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(apiServerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
// setVolumesOnKubeControllerManagerPodSpec makes sure the self-hosted controller manager has the required files
func setVolumesOnKubeControllerManagerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(controllerManagerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
// setVolumesOnKubeSchedulerPodSpec makes sure the self-hosted scheduler has the required files
func setVolumesOnKubeSchedulerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(schedulerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
func setK8sVolume(cb func(cfg *kubeadmapi.MasterConfiguration) v1.Volume, cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
for i, v := range podSpec.Volumes {
if v.Name == "k8s" {
podSpec.Volumes[i] = cb(cfg)
}
}
}

View File

@ -21,6 +21,7 @@ import (
"testing"
"k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
@ -71,8 +72,9 @@ func TestMutatePodSpec(t *testing.T) {
},
}
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests {
mutatePodSpec(rt.component, rt.podSpec)
mutatePodSpec(cfg, rt.component, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed mutatePodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -108,8 +110,9 @@ func TestAddNodeSelectorToPodSpec(t *testing.T) {
},
}
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests {
addNodeSelectorToPodSpec(rt.podSpec)
addNodeSelectorToPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed addNodeSelectorToPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -145,8 +148,9 @@ func TestSetMasterTolerationOnPodSpec(t *testing.T) {
},
}
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests {
setMasterTolerationOnPodSpec(rt.podSpec)
setMasterTolerationOnPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed setMasterTolerationOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -175,8 +179,9 @@ func TestSetRightDNSPolicyOnPodSpec(t *testing.T) {
},
}
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests {
setRightDNSPolicyOnPodSpec(rt.podSpec)
setRightDNSPolicyOnPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed setRightDNSPolicyOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)

View File

@ -29,6 +29,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kuberuntime "k8s.io/apimachinery/pkg/runtime"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/api"
@ -53,7 +54,15 @@ const (
// 7. The self-hosted containers should now step up and take over.
// 8. In order to avoid race conditions, we're still making sure the API /healthz endpoint is healthy
// 9. Do that for the kube-apiserver, kube-controller-manager and kube-scheduler in a loop
func CreateSelfHostedControlPlane(client *clientset.Clientset) error {
func CreateSelfHostedControlPlane(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
if err := createTLSSecrets(cfg, client); err != nil {
return err
}
if err := createOpaqueSecrets(cfg, client); err != nil {
return err
}
// The sequence here isn't set in stone, but seems to work well to start with the API server
components := []string{kubeAPIServer, kubeControllerManager, kubeScheduler}
@ -69,7 +78,7 @@ func CreateSelfHostedControlPlane(client *clientset.Clientset) error {
}
// Build a DaemonSet object from the loaded PodSpec
ds := buildDaemonSet(componentName, podSpec)
ds := buildDaemonSet(cfg, componentName, podSpec)
// Create the DaemonSet in the API Server
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(ds); err != nil {
@ -100,9 +109,9 @@ func CreateSelfHostedControlPlane(client *clientset.Clientset) error {
}
// buildDaemonSet is responsible for mutating the PodSpec and return a DaemonSet which is suitable for the self-hosting purporse
func buildDaemonSet(name string, podSpec *v1.PodSpec) *extensions.DaemonSet {
func buildDaemonSet(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) *extensions.DaemonSet {
// Mutate the PodSpec so it's suitable for self-hosting
mutatePodSpec(name, podSpec)
mutatePodSpec(cfg, name, podSpec)
// Return a DaemonSet based on that Spec
return &extensions.DaemonSet{

View File

@ -24,6 +24,7 @@ import (
"testing"
"github.com/ghodss/yaml"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
)
const (
@ -90,9 +91,49 @@ spec:
name: pki
hostNetwork: true
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.crt
path: apiserver.crt
- key: tls.key
path: apiserver.key
name: apiserver
- secret:
items:
- key: tls.crt
path: apiserver-kubelet-client.crt
- key: tls.key
path: apiserver-kubelet-client.key
name: apiserver-kubelet-client
- secret:
items:
- key: tls.crt
path: sa.pub
- key: tls.key
path: sa.key
name: sa
- secret:
items:
- key: tls.crt
path: front-proxy-ca.crt
name: front-proxy-ca
- secret:
items:
- key: tls.crt
path: front-proxy-client.crt
- key: tls.key
path: front-proxy-client.key
name: front-proxy-client
- hostPath:
path: /etc/ssl/certs
name: certs
@ -171,9 +212,49 @@ spec:
- effect: NoSchedule
key: node-role.kubernetes.io/master
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.crt
path: apiserver.crt
- key: tls.key
path: apiserver.key
name: apiserver
- secret:
items:
- key: tls.crt
path: apiserver-kubelet-client.crt
- key: tls.key
path: apiserver-kubelet-client.key
name: apiserver-kubelet-client
- secret:
items:
- key: tls.crt
path: sa.pub
- key: tls.key
path: sa.key
name: sa
- secret:
items:
- key: tls.crt
path: front-proxy-ca.crt
name: front-proxy-ca
- secret:
items:
- key: tls.crt
path: front-proxy-client.crt
- key: tls.key
path: front-proxy-client.key
name: front-proxy-client
- hostPath:
path: /etc/ssl/certs
name: certs
@ -237,9 +318,23 @@ spec:
name: pki
hostNetwork: true
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
name: controller-manager.conf
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.key
path: sa.key
name: sa
- hostPath:
path: /etc/ssl/certs
name: certs
@ -304,9 +399,23 @@ spec:
- effect: NoSchedule
key: node-role.kubernetes.io/master
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
name: controller-manager.conf
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.key
path: sa.key
name: sa
- hostPath:
path: /etc/ssl/certs
name: certs
@ -360,9 +469,11 @@ spec:
readOnly: true
hostNetwork: true
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
name: scheduler.conf
status: {}
`
@ -411,9 +522,11 @@ spec:
- effect: NoSchedule
key: node-role.kubernetes.io/master
volumes:
- hostPath:
path: /etc/kubernetes
name: k8s
- name: k8s
projected:
sources:
- secret:
name: scheduler.conf
updateStrategy: {}
status:
currentNumberScheduled: 0
@ -455,7 +568,8 @@ func TestBuildDaemonSet(t *testing.T) {
t.Fatalf("couldn't load the specified Pod")
}
ds := buildDaemonSet(rt.component, podSpec)
cfg := &kubeadmapi.MasterConfiguration{}
ds := buildDaemonSet(cfg, rt.component, podSpec)
dsBytes, err := yaml.Marshal(ds)
if err != nil {
t.Fatalf("failed to marshal daemonset to YAML: %v", err)

View File

@ -0,0 +1,340 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package selfhosting
import (
"fmt"
"io/ioutil"
"path"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
type tlsKeyPair struct {
name string
cert string
key string
}
func k8sSelfHostedVolumeMount() v1.VolumeMount {
return v1.VolumeMount{
Name: "k8s",
MountPath: kubeadmapi.GlobalEnvParams.KubernetesDir,
ReadOnly: true,
}
}
func apiServerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.CACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CACertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CAKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.APIServerCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKubeletClientCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKubeletClientKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ServiceAccountKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPublicKeyName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPrivateKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyCACertName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyClientCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyClientKeyName),
},
},
},
},
},
},
},
}
}
func schedulerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.SchedulerKubeConfigFileName,
},
},
},
},
},
},
}
}
func controllerManagerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ControllerManagerKubeConfigFileName,
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.CACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CACertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CAKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ServiceAccountKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPrivateKeyName),
},
},
},
},
},
},
},
}
}
func createTLSSecrets(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
for _, tlsKeyPair := range getTLSKeyPairs() {
secret, err := createTLSSecretFromFiles(
tlsKeyPair.name,
path.Join(cfg.CertificatesDir, tlsKeyPair.cert),
path.Join(cfg.CertificatesDir, tlsKeyPair.key),
)
if err != nil {
return err
}
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err != nil {
return err
}
fmt.Printf("[self-hosted] Created TLS secret %q from %s and %s\n", tlsKeyPair.name, tlsKeyPair.cert, tlsKeyPair.key)
}
return nil
}
func createOpaqueSecrets(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
files := []string{
kubeadmconstants.SchedulerKubeConfigFileName,
kubeadmconstants.ControllerManagerKubeConfigFileName,
}
for _, file := range files {
secret, err := createOpaqueSecretFromFile(
file,
path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, file),
)
if err != nil {
return err
}
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err != nil {
return err
}
fmt.Printf("[self-hosted] Created secret %q\n", file)
}
return nil
}
func createTLSSecretFromFiles(secretName, crt, key string) (*v1.Secret, error) {
crtBytes, err := ioutil.ReadFile(crt)
if err != nil {
return nil, err
}
keyBytes, err := ioutil.ReadFile(key)
if err != nil {
return nil, err
}
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: metav1.NamespaceSystem,
},
Type: v1.SecretTypeTLS,
Data: map[string][]byte{
v1.TLSCertKey: crtBytes,
v1.TLSPrivateKeyKey: keyBytes,
},
}, nil
}
func createOpaqueSecretFromFile(secretName, file string) (*v1.Secret, error) {
fileBytes, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: metav1.NamespaceSystem,
},
Type: v1.SecretTypeOpaque,
Data: map[string][]byte{
path.Base(file): fileBytes,
},
}, nil
}
func getTLSKeyPairs() []*tlsKeyPair {
return []*tlsKeyPair{
{
name: kubeadmconstants.CACertAndKeyBaseName,
cert: kubeadmconstants.CACertName,
key: kubeadmconstants.CAKeyName,
},
{
name: kubeadmconstants.APIServerCertAndKeyBaseName,
cert: kubeadmconstants.APIServerCertName,
key: kubeadmconstants.APIServerKeyName,
},
{
name: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
cert: kubeadmconstants.APIServerKubeletClientCertName,
key: kubeadmconstants.APIServerKubeletClientKeyName,
},
{
name: kubeadmconstants.ServiceAccountKeyBaseName,
cert: kubeadmconstants.ServiceAccountPublicKeyName,
key: kubeadmconstants.ServiceAccountPrivateKeyName,
},
{
name: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
cert: kubeadmconstants.FrontProxyCACertName,
key: kubeadmconstants.FrontProxyCAKeyName,
},
{
name: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
cert: kubeadmconstants.FrontProxyClientCertName,
key: kubeadmconstants.FrontProxyClientKeyName,
},
}
}

View File

@ -0,0 +1,72 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package selfhosting
import (
"io/ioutil"
"log"
"os"
"testing"
)
func createTemporaryFile(name string) *os.File {
content := []byte("foo")
tmpfile, err := ioutil.TempFile("", name)
if err != nil {
log.Fatal(err)
}
if _, err := tmpfile.Write(content); err != nil {
log.Fatal(err)
}
return tmpfile
}
func TestCreateTLSSecretFromFile(t *testing.T) {
tmpCert := createTemporaryFile("foo.crt")
defer os.Remove(tmpCert.Name())
tmpKey := createTemporaryFile("foo.key")
defer os.Remove(tmpKey.Name())
_, err := createTLSSecretFromFiles("foo", tmpCert.Name(), tmpKey.Name())
if err != nil {
log.Fatal(err)
}
if err := tmpCert.Close(); err != nil {
log.Fatal(err)
}
if err := tmpKey.Close(); err != nil {
log.Fatal(err)
}
}
func TestCreateOpaqueSecretFromFile(t *testing.T) {
tmpFile := createTemporaryFile("foo")
defer os.Remove(tmpFile.Name())
_, err := createOpaqueSecretFromFile("foo", tmpFile.Name())
if err != nil {
log.Fatal(err)
}
if err := tmpFile.Close(); err != nil {
log.Fatal(err)
}
}