Skip to content

Commit

Permalink
Merge pull request #2312 from lonelyCZ/pr-cluster-info
Browse files Browse the repository at this point in the history
Set open cluster-info to distribute root CA certificates
  • Loading branch information
karmada-bot authored Aug 19, 2022
2 parents 822abc5 + 37247f6 commit 303d465
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
k8s.io/apiserver v0.24.2
k8s.io/cli-runtime v0.24.2
k8s.io/client-go v0.24.2
k8s.io/cluster-bootstrap v0.24.2
k8s.io/code-generator v0.24.2
k8s.io/component-base v0.24.2
k8s.io/component-helpers v0.24.2
Expand Down Expand Up @@ -161,7 +162,6 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/cluster-bootstrap v0.24.2 // indirect
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
Expand Down
99 changes: 99 additions & 0 deletions pkg/karmadactl/cmdinit/bootstraptoken/clusterinfo/clusterinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package clusterinfo

import (
"fmt"

corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
"k8s.io/klog/v2"

"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
)

const (
// BootstrapSignerClusterRoleName sets the name for the ClusterRole that allows access to ConfigMaps in the kube-public ns
BootstrapSignerClusterRoleName = "karmada:bootstrap-signer-clusterinfo"
)

// CreateBootstrapConfigMapIfNotExists creates the kube-public ConfigMap if it doesn't exist already
func CreateBootstrapConfigMapIfNotExists(clientSet *kubernetes.Clientset, file string) error {
klog.V(1).Infoln("[bootstrap-token] loading karmada admin kubeconfig")
adminConfig, err := clientcmd.LoadFromFile(file)
if err != nil {
return fmt.Errorf("failed to load admin kubeconfig, %w", err)
}
if err = clientcmdapi.FlattenConfig(adminConfig); err != nil {
return err
}

adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
// Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL
klog.V(1).Infoln("[bootstrap-token] copying the cluster from admin.conf to the bootstrap kubeconfig")
bootstrapConfig := &clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{
"": adminConfig.Clusters[adminCluster],
},
}
bootstrapBytes, err := clientcmd.Write(*bootstrapConfig)
if err != nil {
return err
}

// Create or update the ConfigMap in the kube-public namespace
klog.V(1).Infoln("[bootstrap-token] creating/updating ConfigMap in kube-public namespace")
return utils.CreateOrUpdateConfigMap(clientSet, &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: bootstrapapi.ConfigMapClusterInfo,
Namespace: metav1.NamespacePublic,
},
Data: map[string]string{
bootstrapapi.KubeConfigKey: string(bootstrapBytes),
},
})
}

// CreateClusterInfoRBACRules creates the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace to unauthenticated users
func CreateClusterInfoRBACRules(clientSet *kubernetes.Clientset) error {
klog.V(1).Infoln("creating the RBAC rules for exposing the cluster-info ConfigMap in the kube-public namespace")
err := utils.CreateOrUpdateRole(clientSet, &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: BootstrapSignerClusterRoleName,
Namespace: metav1.NamespacePublic,
},
Rules: []rbacv1.PolicyRule{
{
Verbs: []string{"get"},
APIGroups: []string{""},
Resources: []string{"configmaps"},
ResourceNames: []string{bootstrapapi.ConfigMapClusterInfo},
},
},
})
if err != nil {
return err
}

return utils.CreateOrUpdateRoleBinding(clientSet, &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: BootstrapSignerClusterRoleName,
Namespace: metav1.NamespacePublic,
},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacv1.GroupName,
Kind: "Role",
Name: BootstrapSignerClusterRoleName,
},
Subjects: []rbacv1.Subject{
{
Kind: rbacv1.UserKind,
Name: user.Anonymous,
},
},
})
}
18 changes: 18 additions & 0 deletions pkg/karmadactl/cmdinit/karmada/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
"sigs.k8s.io/yaml"

"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/bootstraptoken/clusterinfo"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/options"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
)
Expand Down Expand Up @@ -98,11 +99,28 @@ func InitKarmadaResources(dir, caBase64, systemNamespace string) error {
klog.Exitln(err)
}

if err = createExtralResources(clientSet, dir); err != nil {
klog.Exitln(err)
}

return nil
}

func createExtralResources(clientSet *kubernetes.Clientset, dir string) error {
// grant proxy permission to "system:admin".
if err := grantProxyPermissionToAdmin(clientSet); err != nil {
return err
}

// Create the cluster-info ConfigMap with the associated RBAC rules
if err := clusterinfo.CreateBootstrapConfigMapIfNotExists(clientSet, filepath.Join(dir, options.KarmadaKubeConfigName)); err != nil {
return fmt.Errorf("error creating bootstrap ConfigMap: %v", err)
}

if err := clusterinfo.CreateClusterInfoRBACRules(clientSet); err != nil {
return fmt.Errorf("error creating clusterinfo RBAC rules: %v", err)
}

return nil
}

Expand Down
28 changes: 28 additions & 0 deletions pkg/karmadactl/cmdinit/utils/configmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package utils

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
)

// CreateOrUpdateConfigMap creates a ConfigMap if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateConfigMap(clientSet *kubernetes.Clientset, cm *corev1.ConfigMap) error {
if _, err := clientSet.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Create(context.TODO(), cm, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create ConfigMap: %v", err)
}

if _, err := clientSet.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(context.TODO(), cm, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update ConfigMap: %v", err)
}
}
klog.Infof("ConfigMap %s/%s has been created or updated.", cm.ObjectMeta.Namespace, cm.ObjectMeta.Name)

return nil
}
32 changes: 32 additions & 0 deletions pkg/karmadactl/cmdinit/utils/rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,35 @@ func CreateIfNotExistClusterRoleBinding(clientSet *kubernetes.Clientset, binding

return nil
}

// CreateOrUpdateRole creates a Role if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRole(clientSet *kubernetes.Clientset, role *rbacv1.Role) error {
if _, err := clientSet.RbacV1().Roles(role.ObjectMeta.Namespace).Create(context.TODO(), role, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC role: %v", err)
}

if _, err := clientSet.RbacV1().Roles(role.ObjectMeta.Namespace).Update(context.TODO(), role, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC role: %v", err)
}
}
klog.Infof("Role %s%s has been created or updated.", role.ObjectMeta.Namespace, role.ObjectMeta.Name)

return nil
}

// CreateOrUpdateRoleBinding creates a RoleBinding if the target resource doesn't exist. If the resource exists already, this function will update the resource instead.
func CreateOrUpdateRoleBinding(clientSet *kubernetes.Clientset, roleBinding *rbacv1.RoleBinding) error {
if _, err := clientSet.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Create(context.TODO(), roleBinding, metav1.CreateOptions{}); err != nil {
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("unable to create RBAC rolebinding: %v", err)
}

if _, err := clientSet.RbacV1().RoleBindings(roleBinding.ObjectMeta.Namespace).Update(context.TODO(), roleBinding, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to update RBAC rolebinding: %v", err)
}
}
klog.Infof("RoleBinding %s/%s has been created or updated.", roleBinding.ObjectMeta.Namespace, roleBinding.ObjectMeta.Name)

return nil
}

0 comments on commit 303d465

Please sign in to comment.