Add authorization mode to kubeadm

pull/6/head
Andrew Rynhard 2017-01-16 16:41:56 -08:00
parent dd2cca470f
commit f46bf42ba0
28 changed files with 322 additions and 71 deletions

View File

@ -36,6 +36,7 @@ filegroup(
"//cmd/kubeadm/app/images:all-srcs",
"//cmd/kubeadm/app/master:all-srcs",
"//cmd/kubeadm/app/node:all-srcs",
"//cmd/kubeadm/app/phases/apiconfig:all-srcs",
"//cmd/kubeadm/app/phases/certs:all-srcs",
"//cmd/kubeadm/app/phases/kubeconfig:all-srcs",
"//cmd/kubeadm/app/preflight:all-srcs",

View File

@ -39,6 +39,7 @@ type MasterConfiguration struct {
Networking Networking
KubernetesVersion string
CloudProvider string
AuthorizationMode string
}
type API struct {

View File

@ -19,6 +19,7 @@ go_library(
tags = ["automanaged"],
deps = [
"//pkg/api/v1:go_default_library",
"//pkg/kubeapiserver/authorizer:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",

View File

@ -18,6 +18,7 @@ package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
)
const (
@ -27,6 +28,7 @@ const (
DefaultKubernetesFallbackVersion = "v1.5.0"
DefaultAPIBindPort = 6443
DefaultDiscoveryBindPort = 9898
DefaultAuthorizationMode = authorizer.ModeRBAC
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@ -56,4 +58,8 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
if obj.Discovery.Token == nil && obj.Discovery.File == nil && obj.Discovery.HTTPS == nil {
obj.Discovery.Token = &TokenDiscovery{}
}
if obj.AuthorizationMode == "" {
obj.AuthorizationMode = DefaultAuthorizationMode
}
}

View File

@ -29,6 +29,7 @@ type MasterConfiguration struct {
Networking Networking `json:"networking"`
KubernetesVersion string `json:"kubernetesVersion"`
CloudProvider string `json:"cloudProvider"`
AuthorizationMode string `json:"authorizationMode"`
}
type API struct {

View File

@ -27,6 +27,7 @@ go_library(
"//cmd/kubeadm/app/discovery:go_default_library",
"//cmd/kubeadm/app/master:go_default_library",
"//cmd/kubeadm/app/node:go_default_library",
"//cmd/kubeadm/app/phases/apiconfig:go_default_library",
"//cmd/kubeadm/app/phases/certs:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
"//cmd/kubeadm/app/preflight:go_default_library",
@ -34,6 +35,7 @@ go_library(
"//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/fields:go_default_library",
"//pkg/kubeapiserver/authorizer:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/util/flag:go_default_library",
@ -54,7 +56,10 @@ go_test(
],
library = ":go_default_library",
tags = ["automanaged"],
deps = ["//cmd/kubeadm/app/preflight:go_default_library"],
deps = [
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
"//cmd/kubeadm/app/preflight:go_default_library",
],
)
filegroup(

View File

@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/flags"
"k8s.io/kubernetes/cmd/kubeadm/app/discovery"
kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig"
certphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
@ -41,6 +42,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
)
var (
@ -183,6 +185,7 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight
}
cfg.KubernetesVersion = ver
fmt.Println("[init] Using Kubernetes version:", ver)
fmt.Println("[init] Using Authorization mode:", cfg.AuthorizationMode)
// Warn about the limitations with the current cloudprovider solution.
if cfg.CloudProvider != "" {
@ -255,6 +258,24 @@ func (i *Init) Run(out io.Writer) error {
return err
}
if i.cfg.AuthorizationMode == authorizer.ModeRBAC {
err = apiconfig.CreateBootstrapRBACClusterRole(client)
if err != nil {
return err
}
err = apiconfig.CreateKubeDNSRBACClusterRole(client)
if err != nil {
return err
}
// TODO: remove this when https://github.com/kubernetes/kubeadm/issues/114 is fixed
err = apiconfig.CreateKubeProxyClusterRoleBinding(client)
if err != nil {
return err
}
}
if err := kubemaster.UpdateMasterRoleLabelsAndTaints(client, false); err != nil {
return err
}

View File

@ -27,6 +27,7 @@ import (
"github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/util/initsystem"
@ -150,7 +151,7 @@ func drainAndRemoveNode(removeNode bool) error {
hostname = strings.ToLower(hostname)
// TODO: Use the "native" k8s client for this once we're confident the versioned is working
kubeConfigPath := path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")
kubeConfigPath := path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName)
getNodesCmd := fmt.Sprintf("kubectl --kubeconfig %s get nodes | grep %s", kubeConfigPath, hostname)
output, err := exec.Command("sh", "-c", getNodesCmd).Output()
@ -219,8 +220,8 @@ func resetConfigDir(configPathDir, pkiPathDir string) {
}
filesToClean := []string{
path.Join(configPathDir, "admin.conf"),
path.Join(configPathDir, "kubelet.conf"),
path.Join(configPathDir, kubeconfig.AdminKubeConfigFileName),
path.Join(configPathDir, kubeconfig.KubeletKubeConfigFileName),
}
fmt.Printf("[reset] Deleting files: %v\n", filesToClean)
for _, path := range filesToClean {

View File

@ -22,6 +22,7 @@ import (
"path/filepath"
"testing"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
)
@ -63,8 +64,8 @@ func TestConfigDirCleaner(t *testing.T) {
"manifests/etcd.json",
"manifests/kube-apiserver.json",
"pki/ca.pem",
"admin.conf",
"kubelet.conf",
kubeconfig.AdminKubeConfigFileName,
kubeconfig.KubeletKubeConfigFileName,
},
verifyExists: []string{
"manifests",
@ -77,7 +78,7 @@ func TestConfigDirCleaner(t *testing.T) {
},
setupFiles: []string{
"pki/ca.pem",
"kubelet.conf",
kubeconfig.KubeletKubeConfigFileName,
},
verifyExists: []string{
"pki",
@ -95,8 +96,8 @@ func TestConfigDirCleaner(t *testing.T) {
"manifests/etcd.json",
"manifests/kube-apiserver.json",
"pki/ca.pem",
"admin.conf",
"kubelet.conf",
kubeconfig.AdminKubeConfigFileName,
kubeconfig.KubeletKubeConfigFileName,
"cloud-config",
},
verifyExists: []string{
@ -115,8 +116,8 @@ func TestConfigDirCleaner(t *testing.T) {
"manifests/etcd.json",
"manifests/kube-apiserver.json",
"pki/ca.pem",
"admin.conf",
"kubelet.conf",
kubeconfig.AdminKubeConfigFileName,
kubeconfig.KubeletKubeConfigFileName,
".cloud-config",
".mydir/.myfile",
},
@ -166,8 +167,8 @@ func TestConfigDirCleaner(t *testing.T) {
// Verify the files we cleanup implicitly in every test:
assertExists(t, tmpDir)
assertNotExists(t, filepath.Join(tmpDir, "admin.conf"))
assertNotExists(t, filepath.Join(tmpDir, "kubelet.conf"))
assertNotExists(t, filepath.Join(tmpDir, kubeconfig.AdminKubeConfigFileName))
assertNotExists(t, filepath.Join(tmpDir, kubeconfig.KubeletKubeConfigFileName))
assertDirEmpty(t, filepath.Join(tmpDir, "manifests"))
assertDirEmpty(t, filepath.Join(tmpDir, "pki"))

View File

@ -29,6 +29,7 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubemaster "k8s.io/kubernetes/cmd/kubeadm/app/master"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
@ -123,7 +124,7 @@ func NewCmdTokenGenerate(out io.Writer) *cobra.Command {
// RunCreateToken generates a new bootstrap token and stores it as a secret on the server.
func RunCreateToken(out io.Writer, cmd *cobra.Command, tokenDuration time.Duration, token string) error {
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf"))
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName))
if err != nil {
return err
}
@ -156,7 +157,7 @@ func RunGenerateToken(out io.Writer) error {
// RunListTokens lists details on all existing bootstrap tokens on the server.
func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error {
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf"))
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName))
if err != nil {
return err
}
@ -215,7 +216,7 @@ func RunDeleteToken(out io.Writer, cmd *cobra.Command, tokenId string) error {
return err
}
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf"))
client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName))
if err != nil {
return err
}

View File

@ -22,6 +22,7 @@ go_library(
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
"//cmd/kubeadm/app/images:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/resource:go_default_library",
@ -30,6 +31,7 @@ go_library(
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/client/unversioned/clientcmd/api:go_default_library",
"//pkg/kubeapiserver/authorizer:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/registry/core/service/ipallocator:go_default_library",
"//pkg/util/cert:go_default_library",

View File

@ -23,6 +23,7 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/images"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/v1"
@ -31,6 +32,8 @@ import (
"k8s.io/kubernetes/pkg/util/intstr"
)
const KubeDNS = "kube-dns"
func createKubeProxyPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
privilegedTrue := true
return v1.PodSpec{
@ -68,7 +71,7 @@ func createKubeProxyPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")},
HostPath: &v1.HostPathVolumeSource{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName)},
},
},
{
@ -86,6 +89,7 @@ func createKubeDNSPodSpec(cfg *kubeadmapi.MasterConfiguration) v1.PodSpec {
dnsmasqPort := int32(53)
return v1.PodSpec{
ServiceAccountName: KubeDNS,
Containers: []v1.Container{
// DNS server
{
@ -250,7 +254,7 @@ func createKubeDNSServiceSpec(cfg *kubeadmapi.MasterConfiguration) (*v1.ServiceS
}
return &v1.ServiceSpec{
Selector: map[string]string{"name": "kube-dns"},
Selector: map[string]string{"name": KubeDNS},
Ports: []v1.ServicePort{
{Name: "dns", Port: 53, Protocol: v1.ProtocolUDP},
{Name: "dns-tcp", Port: 53, Protocol: v1.ProtocolTCP},
@ -270,10 +274,14 @@ func CreateEssentialAddons(cfg *kubeadmapi.MasterConfiguration, client *clientse
fmt.Println("[addons] Created essential addon: kube-proxy")
kubeDNSDeployment := NewDeployment("kube-dns", 1, createKubeDNSPodSpec(cfg))
kubeDNSDeployment := NewDeployment(KubeDNS, 1, createKubeDNSPodSpec(cfg))
SetMasterTaintTolerations(&kubeDNSDeployment.Spec.Template.ObjectMeta)
SetNodeAffinity(&kubeDNSDeployment.Spec.Template.ObjectMeta, NativeArchitectureNodeAffinity())
kubeDNSServiceAccount := &v1.ServiceAccount{}
kubeDNSServiceAccount.ObjectMeta.Name = KubeDNS
if _, err := client.ServiceAccounts(api.NamespaceSystem).Create(kubeDNSServiceAccount); err != nil {
return fmt.Errorf("failed creating kube-dns service account [%v]", err)
}
if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kubeDNSDeployment); err != nil {
return fmt.Errorf("failed creating essential kube-dns addon [%v]", err)
}
@ -283,7 +291,7 @@ func CreateEssentialAddons(cfg *kubeadmapi.MasterConfiguration, client *clientse
return fmt.Errorf("failed creating essential kube-dns addon [%v]", err)
}
kubeDNSService := NewService("kube-dns", *kubeDNSServiceSpec)
kubeDNSService := NewService(KubeDNS, *kubeDNSServiceSpec)
kubeDNSService.ObjectMeta.Labels["kubernetes.io/name"] = "KubeDNS"
if _, err := client.Services(api.NamespaceSystem).Create(kubeDNSService); err != nil {
return fmt.Errorf("failed creating essential kube-dns addon [%v]", err)

View File

@ -69,10 +69,15 @@ func CreateClientAndWaitForAPI(file string) (*clientset.Clientset, error) {
start := time.Now()
wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
// TODO: use /healthz API instead of this
cs, err := client.ComponentStatuses().List(v1.ListOptions{})
if err != nil {
if apierrs.IsForbidden(err) {
fmt.Print("\r[apiclient] Waiting for the API server to create RBAC policies")
}
return false, nil
}
fmt.Println("\n[apiclient] RBAC policies created")
// TODO(phase2) must revisit this when we implement HA
if len(cs.Items) < 3 {
fmt.Println("[apiclient] Not all control plane components are ready yet")

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/images"
"k8s.io/kubernetes/pkg/api/resource"
api "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/intstr"
@ -40,15 +41,17 @@ const (
DefaultClusterName = "kubernetes"
DefaultCloudConfigPath = "/etc/kubernetes/cloud-config"
etcd = "etcd"
apiServer = "apiserver"
controllerManager = "controller-manager"
scheduler = "scheduler"
proxy = "proxy"
kubeAPIServer = "kube-apiserver"
kubeControllerManager = "kube-controller-manager"
kubeScheduler = "kube-scheduler"
kubeProxy = "kube-proxy"
etcd = "etcd"
apiServer = "apiserver"
controllerManager = "controller-manager"
scheduler = "scheduler"
proxy = "proxy"
kubeAPIServer = "kube-apiserver"
kubeControllerManager = "kube-controller-manager"
kubeScheduler = "kube-scheduler"
kubeProxy = "kube-proxy"
authorizationPolicyFile = "abac_policy.json"
authorizationWebhookConfigFile = "webhook_authz.conf"
)
var (
@ -296,6 +299,16 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
"--allow-privileged",
)
if cfg.AuthorizationMode != "" {
command = append(command, "--authorization-mode="+cfg.AuthorizationMode)
switch cfg.AuthorizationMode {
case authorizer.ModeABAC:
command = append(command, "--authorization-policy-file="+path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, authorizationPolicyFile))
case authorizer.ModeWebhook:
command = append(command, "--authorization-webhook-config-file="+path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, authorizationWebhookConfigFile))
}
}
// Use first address we are given
if len(cfg.API.AdvertiseAddresses) > 0 {
command = append(command, fmt.Sprintf("--advertise-address=%s", cfg.API.AdvertiseAddresses[0]))
@ -357,7 +370,7 @@ func getControllerManagerCommand(cfg *kubeadmapi.MasterConfiguration) []string {
"--service-account-private-key-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/apiserver-key.pem",
"--cluster-signing-cert-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/ca.pem",
"--cluster-signing-key-file="+kubeadmapi.GlobalEnvParams.HostPKIPath+"/ca-key.pem",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
)
if cfg.CloudProvider != "" {

View File

@ -484,7 +484,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-key.pem",
"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.pem",
"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca-key.pem",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
},
},
{
@ -499,7 +499,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-key.pem",
"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.pem",
"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca-key.pem",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
"--cloud-provider=foo",
},
},
@ -515,7 +515,7 @@ func TestGetControllerManagerCommand(t *testing.T) {
"--service-account-private-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/apiserver-key.pem",
"--cluster-signing-cert-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca.pem",
"--cluster-signing-key-file=" + kubeadmapi.GlobalEnvParams.HostPKIPath + "/ca-key.pem",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=system:kubelet-bootstrap",
"--insecure-experimental-approve-all-kubelet-csrs-for-group=kubeadm:kubelet-bootstrap",
"--allocate-node-cidrs=true",
"--cluster-cidr=bar",
},

View File

@ -32,7 +32,7 @@ func CreateTokenAuthFile(bt string) error {
if err := os.MkdirAll(kubeadmapi.GlobalEnvParams.HostPKIPath, 0700); err != nil {
return fmt.Errorf("failed to create directory %q [%v]", kubeadmapi.GlobalEnvParams.HostPKIPath, err)
}
serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,system:kubelet-bootstrap\n", bt, uuid.NewUUID()))
serialized := []byte(fmt.Sprintf("%s,kubeadm-node-csr,%s,kubeadm:kubelet-bootstrap\n", bt, uuid.NewUUID()))
// DumpReaderToFile create a file with mode 0600
if err := cmdutil.DumpReaderToFile(bytes.NewReader(serialized), tokenAuthFilePath); err != nil {
return fmt.Errorf("failed to save token auth file (%q) [%v]", tokenAuthFilePath, err)

View File

@ -20,7 +20,6 @@ go_library(
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/certificates:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
@ -28,6 +27,8 @@ go_library(
"//pkg/kubelet/util/csr:go_default_library",
"//pkg/util/cert:go_default_library",
"//vendor:github.com/square/go-jose",
"//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/util/wait",
],

View File

@ -22,12 +22,13 @@ import (
"sync"
"time"
apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/certificates"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
@ -128,14 +129,9 @@ func checkForNodeNameDuplicates(clientSet *clientset.Clientset) error {
if err != nil {
return fmt.Errorf("Failed to get node hostname [%v]", err)
}
nodeList, err := clientSet.Nodes().List(v1.ListOptions{})
if err != nil {
return fmt.Errorf("Failed to list the nodes in the cluster: [%v]\n", err)
}
for _, node := range nodeList.Items {
if hostName == node.Name {
return fmt.Errorf("Node with name [%q] already exists.", node.Name)
}
_, err = clientSet.Nodes().Get(hostName, metav1.GetOptions{})
if err != nil && !apierrs.IsNotFound(err) {
return err
}
return nil
}

View File

@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["clusterroles.go"],
tags = ["automanaged"],
deps = [
"//cmd/kubeadm/app/master:go_default_library",
"//pkg/api:go_default_library",
"//pkg/apis/rbac/v1beta1:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,136 @@
/*
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 apiconfig
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/cmd/kubeadm/app/master"
"k8s.io/kubernetes/pkg/api"
rbac "k8s.io/kubernetes/pkg/apis/rbac/v1beta1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)
// CreateBootstrapRBACClusterRole creates the necessary ClusterRole for bootstrapping
func CreateBootstrapRBACClusterRole(clientset *clientset.Clientset) error {
clusterRole := rbac.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: "kubeadm:kubelet-bootstrap"},
Rules: []rbac.PolicyRule{
rbac.NewRule("get").Groups("").Resources("nodes").RuleOrDie(),
rbac.NewRule("create", "watch").Groups("certificates.k8s.io").Resources("certificatesigningrequests").RuleOrDie(),
},
}
if _, err := clientset.Rbac().ClusterRoles().Create(&clusterRole); err != nil {
return err
}
subject := rbac.Subject{
Kind: "Group",
Name: "kubeadm:kubelet-bootstrap",
}
clusterRoleBinding := rbac.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "kubeadm:kubelet-bootstrap",
},
RoleRef: rbac.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "kubeadm:kubelet-bootstrap",
},
Subjects: []rbac.Subject{subject},
}
if _, err := clientset.Rbac().ClusterRoleBindings().Create(&clusterRoleBinding); err != nil {
return err
}
fmt.Println("[apiconfig] Created kubelet-bootstrap RBAC rules")
return nil
}
// CreateKubeDNSRBACClusterRole creates the necessary ClusterRole for kube-dns
func CreateKubeDNSRBACClusterRole(clientset *clientset.Clientset) error {
clusterRole := rbac.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: "kubeadm:" + master.KubeDNS},
Rules: []rbac.PolicyRule{
rbac.NewRule("list", "watch").Groups("").Resources("endpoints", "services").RuleOrDie(),
// TODO: remove watch rule when https://github.com/kubernetes/kubernetes/pull/38816 gets merged
rbac.NewRule("get", "list", "watch").Groups("").Resources("configmaps").RuleOrDie(),
},
}
if _, err := clientset.Rbac().ClusterRoles().Create(&clusterRole); err != nil {
return err
}
subject := rbac.Subject{
Kind: "ServiceAccount",
Name: master.KubeDNS,
Namespace: api.NamespaceSystem,
}
clusterRoleBinding := rbac.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "kubeadm:" + master.KubeDNS,
},
RoleRef: rbac.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "kubeadm:" + master.KubeDNS,
},
Subjects: []rbac.Subject{subject},
}
if _, err := clientset.Rbac().ClusterRoleBindings().Create(&clusterRoleBinding); err != nil {
return err
}
fmt.Println("[apiconfig] Created kube-dns RBAC rules")
return nil
}
// CreateKubeProxyClusterRoleBinding creates the necessary ClusterRole for kube-dns
func CreateKubeProxyClusterRoleBinding(clientset *clientset.Clientset) error {
systemKubeProxySubject := rbac.Subject{
Kind: "User",
Name: "system:kube-proxy",
Namespace: api.NamespaceSystem,
}
systemNodesSubject := rbac.Subject{
Kind: "Group",
Name: "system:nodes",
Namespace: api.NamespaceSystem,
}
clusterRoleBinding := rbac.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "system:node-proxier",
},
RoleRef: rbac.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "system:node-proxier",
},
Subjects: []rbac.Subject{systemKubeProxySubject, systemNodesSubject},
}
if _, err := clientset.Rbac().ClusterRoleBindings().Update(&clusterRoleBinding); err != nil {
return err
}
fmt.Println("[apiconfig] Created kube-proxy RBAC rules")
return nil
}

View File

@ -34,7 +34,6 @@ func newCertificateAuthority() (*rsa.PrivateKey, *x509.Certificate, error) {
config := certutil.Config{
CommonName: "kubernetes",
}
cert, err := certutil.NewSelfSignedCACert(config, key)
if err != nil {
return nil, nil, fmt.Errorf("unable to create self-signed certificate [%v]", err)
@ -61,16 +60,13 @@ func newServerKeyAndCert(caCert *x509.Certificate, caKey *rsa.PrivateKey, altNam
return key, cert, nil
}
func NewClientKeyAndCert(caCert *x509.Certificate, caKey *rsa.PrivateKey) (*rsa.PrivateKey, *x509.Certificate, error) {
func NewClientKeyAndCert(config *certutil.Config, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*rsa.PrivateKey, *x509.Certificate, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, nil, fmt.Errorf("unable to create private key [%v]", err)
}
config := certutil.Config{
CommonName: "kubernetes-client",
}
cert, err := certutil.NewSignedCert(config, key, caCert, caKey)
cert, err := certutil.NewSignedCert(*config, key, caCert, caKey)
if err != nil {
return nil, nil, fmt.Errorf("unable to sign certificate [%v]", err)
}

View File

@ -105,7 +105,11 @@ func TestNewClientKeyAndCert(t *testing.T) {
t.Fatalf("Couldn't create rsa Private Key")
}
caCert := &x509.Certificate{}
_, _, actual := NewClientKeyAndCert(caCert, caKey)
config := &certutil.Config{
CommonName: "test",
Organization: []string{"test"},
}
_, _, actual := NewClientKeyAndCert(config, caCert, caKey)
if (actual == nil) != rt.expected {
t.Errorf(
"failed NewClientKeyAndCert:\n\texpected: %t\n\t actual: %t",

View File

@ -31,9 +31,11 @@ import (
)
const (
KubernetesDirPermissions = 0700
AdminKubeConfigFileName = "admin.conf"
KubeletKubeConfigFileName = "kubelet.conf"
KubernetesDirPermissions = 0700
AdminKubeConfigFileName = "admin.conf"
AdminKubeConfigClientName = "kubernetes-admin"
KubeletKubeConfigFileName = "kubelet.conf"
KubeletKubeConfigClientName = "kubelet"
)
// This function is called from the main init and does the work for the default phase behaviour
@ -68,36 +70,47 @@ func CreateAdminAndKubeletKubeConfig(masterEndpoint, pkiDir, outDir string) erro
}
// User admin should have full access to the cluster
if err := createKubeConfigFileForClient(masterEndpoint, "admin", outDir, caCert, caKey); err != nil {
return fmt.Errorf("couldn't create a kubeconfig file for admin: %v", err)
adminCertConfig := &certutil.Config{
CommonName: AdminKubeConfigClientName,
Organization: []string{"system:masters"},
}
adminKubeConfigFilePath := path.Join(outDir, AdminKubeConfigFileName)
if err := createKubeConfigFileForClient(masterEndpoint, adminKubeConfigFilePath, adminCertConfig, caCert, caKey); err != nil {
return fmt.Errorf("couldn't create config for %s: %v", AdminKubeConfigClientName, err)
}
// TODO: The kubelet should have limited access to the cluster
if err := createKubeConfigFileForClient(masterEndpoint, "kubelet", outDir, caCert, caKey); err != nil {
return fmt.Errorf("couldn't create a kubeconfig file for kubelet: %v", err)
// The kubelet should have limited access to the cluster
kubeletCertConfig := &certutil.Config{
CommonName: KubeletKubeConfigClientName,
Organization: []string{"system:nodes"},
}
kubeletKubeConfigFilePath := path.Join(outDir, KubeletKubeConfigFileName)
if err := createKubeConfigFileForClient(masterEndpoint, kubeletKubeConfigFilePath, kubeletCertConfig, caCert, caKey); err != nil {
return fmt.Errorf("couldn't create config for %s: %v", KubeletKubeConfigClientName, err)
}
// TODO make credentials for the controller manager and kube proxy
return nil
}
func createKubeConfigFileForClient(masterEndpoint, client, outDir string, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
key, cert, err := certphase.NewClientKeyAndCert(caCert, caKey)
func createKubeConfigFileForClient(masterEndpoint, kubeConfigFilePath string, config *certutil.Config, caCert *x509.Certificate, caKey *rsa.PrivateKey) error {
key, cert, err := certphase.NewClientKeyAndCert(config, caCert, caKey)
if err != nil {
return fmt.Errorf("failure while creating %s client certificate [%v]", client, err)
return fmt.Errorf("failure while creating %s client certificate [%v]", config.CommonName, err)
}
config := MakeClientConfigWithCerts(
kubeConfig := MakeClientConfigWithCerts(
masterEndpoint,
"kubernetes",
client,
config.CommonName,
certutil.EncodeCertPEM(caCert),
certutil.EncodePrivateKeyPEM(key),
certutil.EncodeCertPEM(cert),
)
// Write it now to a file
filepath := path.Join(outDir, fmt.Sprintf("%s.conf", client))
return WriteKubeconfigToDisk(filepath, config)
return WriteKubeconfigToDisk(kubeConfigFilePath, kubeConfig)
}
func WriteKubeconfigToDisk(filepath string, kubeconfig *clientcmdapi.Config) error {

View File

@ -14,6 +14,7 @@ go_library(
tags = ["automanaged"],
deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
"//pkg/api/validation:go_default_library",
"//pkg/util/initsystem:go_default_library",
"//pkg/util/node:go_default_library",

View File

@ -29,6 +29,7 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/util/initsystem"
"k8s.io/kubernetes/pkg/util/node"
@ -320,8 +321,8 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error {
DirAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")},
DirAvailableCheck{Path: kubeadmapi.GlobalEnvParams.HostPKIPath},
DirAvailableCheck{Path: "/var/lib/kubelet"},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf")},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.AdminKubeConfigFileName)},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName)},
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
InPathCheck{executable: "ip", mandatory: true},
InPathCheck{executable: "iptables", mandatory: true},
@ -355,7 +356,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error {
PortOpenCheck{port: 10250},
DirAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "manifests")},
DirAvailableCheck{Path: "/var/lib/kubelet"},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "kubelet.conf")},
FileAvailableCheck{Path: path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, kubeconfig.KubeletKubeConfigFileName)},
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
InPathCheck{executable: "ip", mandatory: true},
InPathCheck{executable: "iptables", mandatory: true},

View File

@ -27,6 +27,7 @@ cmd/kube-proxy
cmd/kubeadm
cmd/kubeadm
cmd/kubeadm/app/apis/kubeadm/install
cmd/kubeadm/app/phases/apiconfig
cmd/kubectl
cmd/kubelet
cmd/libs/go2idl/client-gen

View File

@ -562,6 +562,7 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
obj.API.Port = 20
obj.Networking.ServiceSubnet = "foo"
obj.Networking.DNSDomain = "foo"
obj.AuthorizationMode = "foo"
obj.Discovery.Token = &kubeadm.TokenDiscovery{}
},
func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) {

View File

@ -90,7 +90,7 @@ func NewSignedCert(cfg Config, key *rsa.PrivateKey, caCert *x509.Certificate, ca
certTmpl := x509.Certificate{
Subject: pkix.Name{
CommonName: cfg.CommonName,
Organization: caCert.Subject.Organization,
Organization: cfg.Organization,
},
DNSNames: cfg.AltNames.DNSNames,
IPAddresses: cfg.AltNames.IPs,