@@ -15,10 +15,14 @@ import (
1515 call "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/call-log"
1616 idrv "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces"
1717 irs "github.com/cloud-barista/cb-spider/cloud-control-manager/cloud-driver/interfaces/resources"
18+ o2 "golang.org/x/oauth2"
19+ goo "golang.org/x/oauth2/google"
1820 compute "google.golang.org/api/compute/v1"
1921 container "google.golang.org/api/container/v1"
20- goo "golang.org/x/oauth2/google"
21- o2 "golang.org/x/oauth2"
22+ rbacv1 "k8s.io/api/rbac/v1"
23+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+ "k8s.io/client-go/kubernetes"
25+ "k8s.io/client-go/tools/clientcmd"
2226)
2327
2428const (
@@ -278,6 +282,11 @@ func (ClusterHandler *GCPClusterHandler) CreateCluster(clusterReqInfo irs.Cluste
278282 return irs.ClusterInfo {}, err
279283 }
280284
285+ err = ClusterHandler .grantClusterAdminPermission (clusterInfo )
286+ if err != nil {
287+ cblogger .Warn (fmt .Sprintf ("Failed to grant cluster-admin permission (non-critical): %v" , err ))
288+ }
289+
281290 return clusterInfo , nil
282291}
283292
@@ -1587,7 +1596,7 @@ func (ClusterHandler *GCPClusterHandler) hasActiveOperations(projectID, zone, cl
15871596// GCP uses OAuth2 access token for GKE cluster access
15881597func (ClusterHandler * GCPClusterHandler ) GenerateClusterToken (clusterIID irs.IID ) (string , error ) {
15891598 cblogger .Info ("call GenerateClusterToken()" )
1590-
1599+
15911600 // Create JWT config from credential info
15921601 gcpType := "service_account"
15931602 data := make (map [string ]string )
@@ -1616,6 +1625,120 @@ func (ClusterHandler *GCPClusterHandler) GenerateClusterToken(clusterIID irs.IID
16161625 cblogger .Errorf ("Failed to get access token: %v" , err )
16171626 return "" , fmt .Errorf ("failed to get access token: %w" , err )
16181627 }
1619-
1628+
16201629 return token .AccessToken , nil
16211630}
1631+
1632+ func (ClusterHandler * GCPClusterHandler ) createK8sClientFromKubeconfig (kubeconfigContent string ) (* kubernetes.Clientset , error ) {
1633+ config , err := clientcmd .RESTConfigFromKubeConfig ([]byte (kubeconfigContent ))
1634+ if err != nil {
1635+ return nil , fmt .Errorf ("failed to create REST config from kubeconfig: %w" , err )
1636+ }
1637+
1638+ token , err := ClusterHandler .GenerateClusterToken (irs.IID {})
1639+ if err != nil {
1640+ return nil , fmt .Errorf ("failed to generate cluster token: %w" , err )
1641+ }
1642+ config .BearerToken = token
1643+
1644+ clientset , err := kubernetes .NewForConfig (config )
1645+ if err != nil {
1646+ return nil , fmt .Errorf ("failed to create Kubernetes clientset: %w" , err )
1647+ }
1648+
1649+ return clientset , nil
1650+ }
1651+
1652+ func (ClusterHandler * GCPClusterHandler ) getServiceAccountUserID () (string , error ) {
1653+ gcpType := "service_account"
1654+ data := make (map [string ]string )
1655+ data ["type" ] = gcpType
1656+ data ["private_key" ] = ClusterHandler .Credential .PrivateKey
1657+ data ["client_email" ] = ClusterHandler .Credential .ClientEmail
1658+
1659+ res , err := json .Marshal (data )
1660+ if err != nil {
1661+ return "" , fmt .Errorf ("failed to marshal credential data: %w" , err )
1662+ }
1663+
1664+ authURL := "https://www.googleapis.com/auth/cloud-platform"
1665+ conf , err := goo .JWTConfigFromJSON (res , authURL )
1666+ if err != nil {
1667+ return "" , fmt .Errorf ("failed to create JWT config: %w" , err )
1668+ }
1669+
1670+ tokenSource := conf .TokenSource (o2 .NoContext )
1671+ token , err := tokenSource .Token ()
1672+ if err != nil {
1673+ return "" , fmt .Errorf ("failed to get access token: %w" , err )
1674+ }
1675+
1676+ if token .Extra ("id_token" ) != nil {
1677+ if idToken , ok := token .Extra ("id_token" ).(string ); ok {
1678+ parts := strings .Split (idToken , "." )
1679+ if len (parts ) > 1 {
1680+ return parts [1 ], nil
1681+ }
1682+ }
1683+ }
1684+
1685+ return ClusterHandler .Credential .ClientEmail , nil
1686+ }
1687+
1688+ func (ClusterHandler * GCPClusterHandler ) grantClusterAdminPermission (clusterInfo irs.ClusterInfo ) error {
1689+ kubeconfigContent := clusterInfo .AccessInfo .Kubeconfig
1690+ if kubeconfigContent == "" {
1691+ return fmt .Errorf ("kubeconfig is empty" )
1692+ }
1693+
1694+ clientset , err := ClusterHandler .createK8sClientFromKubeconfig (kubeconfigContent )
1695+ if err != nil {
1696+ return fmt .Errorf ("failed to create Kubernetes client: %w" , err )
1697+ }
1698+
1699+ userName , err := ClusterHandler .getServiceAccountUserID ()
1700+ if err != nil {
1701+ return fmt .Errorf ("failed to get service account user ID: %w" , err )
1702+ }
1703+
1704+ crbName := "cb-spider-admin"
1705+
1706+ existingCRB , err := clientset .RbacV1 ().ClusterRoleBindings ().Get (
1707+ context .TODO (),
1708+ crbName ,
1709+ metav1.GetOptions {},
1710+ )
1711+ if err == nil && existingCRB != nil {
1712+ cblogger .Info (fmt .Sprintf ("ClusterRoleBinding '%s' already exists, skipping creation" , crbName ))
1713+ return nil
1714+ }
1715+
1716+ crb := & rbacv1.ClusterRoleBinding {
1717+ ObjectMeta : metav1.ObjectMeta {
1718+ Name : crbName ,
1719+ },
1720+ Subjects : []rbacv1.Subject {
1721+ {
1722+ Kind : "User" ,
1723+ Name : userName ,
1724+ },
1725+ },
1726+ RoleRef : rbacv1.RoleRef {
1727+ Kind : "ClusterRole" ,
1728+ Name : "cluster-admin" ,
1729+ APIGroup : "rbac.authorization.k8s.io" ,
1730+ },
1731+ }
1732+
1733+ _ , err = clientset .RbacV1 ().ClusterRoleBindings ().Create (
1734+ context .TODO (),
1735+ crb ,
1736+ metav1.CreateOptions {},
1737+ )
1738+ if err != nil {
1739+ return fmt .Errorf ("failed to create ClusterRoleBinding: %w" , err )
1740+ }
1741+
1742+ cblogger .Info (fmt .Sprintf ("Successfully created ClusterRoleBinding '%s' for user '%s'" , crbName , userName ))
1743+ return nil
1744+ }
0 commit comments