diff --git a/pkg/localkube/apiserver.go b/pkg/localkube/apiserver.go index b8b1f9fa812a..5e0784d9d812 100644 --- a/pkg/localkube/apiserver.go +++ b/pkg/localkube/apiserver.go @@ -46,6 +46,8 @@ func StartAPIServer(lk LocalkubeServer) func() error { config.Authentication.ClientCert.ClientCA = lk.GetCAPublicKeyCertPath() + config.Authorization.Mode = "RBAC" + config.SecureServing.ServerCert.CertKey.CertFile = lk.GetPublicKeyCertPath() config.SecureServing.ServerCert.CertKey.KeyFile = lk.GetPrivateKeyCertPath() config.Admission.PluginNames = []string{ diff --git a/pkg/minikube/bootstrapper/localkube/localkube.go b/pkg/minikube/bootstrapper/localkube/localkube.go index c7032a28421f..7efa700b2af3 100644 --- a/pkg/minikube/bootstrapper/localkube/localkube.go +++ b/pkg/minikube/bootstrapper/localkube/localkube.go @@ -19,6 +19,7 @@ package localkube import ( "fmt" "strings" + "time" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" @@ -29,6 +30,7 @@ import ( "github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine/state" "github.com/pkg/errors" + "k8s.io/minikube/pkg/util" ) type LocalkubeBootstrapper struct { @@ -97,6 +99,11 @@ func (lk *LocalkubeBootstrapper) StartCluster(kubernetesConfig bootstrapper.Kube if err != nil { return errors.Wrapf(err, "Error running ssh command: %s", startCommand) } + // try to elevate kube-system privileges so that the dashboard (among other + // components) can execute queries + if err := util.RetryAfter(100, elevateKubeSystemPrivileges, time.Millisecond*500); err != nil { + return errors.Wrap(err, "timed out waiting to elevate kube-system RBAC privileges") + } return nil } diff --git a/pkg/minikube/bootstrapper/localkube/privileges.go b/pkg/minikube/bootstrapper/localkube/privileges.go new file mode 100644 index 000000000000..22a88f606117 --- /dev/null +++ b/pkg/minikube/bootstrapper/localkube/privileges.go @@ -0,0 +1,37 @@ +package localkube + +import ( + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1" + rbacv1beta1 "k8s.io/client-go/pkg/apis/rbac/v1beta1" + "k8s.io/minikube/pkg/minikube/service" +) + +func elevateKubeSystemPrivileges() error { + k8s := service.K8sClientGetter{} + client, err := k8s.GetRBACV1Beta1Client() + if err != nil { + return err + } + clusterRoleBinding := &rbacv1beta1.ClusterRoleBinding{ + ObjectMeta: v1.ObjectMeta{ + Name: "minikube-rbac", + }, + Subjects: []rbacv1beta1.Subject{ + { + Kind: "ServiceAccount", + Name: "default", + Namespace: "kube-system", + }, + }, + RoleRef: rbacv1beta1.RoleRef{ + Kind: "ClusterRole", + Name: "cluster-admin", + }, + } + + if _, err := client.ClusterRoleBindings().Create(clusterRoleBinding); err != nil { + return errors.Wrap(err, "creating clusterrolebinding") + } + return nil +} diff --git a/pkg/minikube/service/service.go b/pkg/minikube/service/service.go index cf3dc2b63903..7ee6345ba4c3 100644 --- a/pkg/minikube/service/service.go +++ b/pkg/minikube/service/service.go @@ -30,6 +30,7 @@ import ( meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" + rbacv1beta1typed "k8s.io/client-go/kubernetes/typed/rbac/v1beta1" "k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/tools/clientcmd" @@ -52,7 +53,9 @@ func init() { k8s = &K8sClientGetter{} } -func (*K8sClientGetter) GetCoreClient() (corev1.CoreV1Interface, error) { +// getClientset returns the root Kubernetes Clientset from the default loaded +// configuration +func (*K8sClientGetter) getClientset() (*kubernetes.Clientset, error) { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() configOverrides := &clientcmd.ConfigOverrides{} kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) @@ -64,7 +67,27 @@ func (*K8sClientGetter) GetCoreClient() (corev1.CoreV1Interface, error) { if err != nil { return nil, errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()") } - return client.Core(), nil + return client, nil +} + +// GetRBACV1Beta1Client returns an RbacV1beta1Interface from the default Kubernetes +// Clientset +func (k *K8sClientGetter) GetRBACV1Beta1Client() (rbacv1beta1typed.RbacV1beta1Interface, error) { + clientset, err := k.getClientset() + if err != nil { + return nil, err + } + return clientset.RbacV1beta1(), nil +} + +// GetCoreClient returns a CoreV1Interface from the default Kubernetes +// Clientset +func (k *K8sClientGetter) GetCoreClient() (corev1.CoreV1Interface, error) { + clientset, err := k.getClientset() + if err != nil { + return nil, err + } + return clientset.Core(), nil } type ServiceURL struct {