Untitled

 avatar
unknown
plain_text
a month ago
3.4 kB
4
Indexable
package handlers

import (
	"fmt"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
	"os"
	"path/filepath"
)

func (f *KubeClientFactory) setupOIDCAuth(config *rest.Config, kubeconfig *clientcmdapi.Config) error {
	// Get token from environment variable first
	if token := os.Getenv("KUBE_TOKEN"); token != "" {
		config.BearerToken = token
		return nil
	}

	// Get current context and auth info
	currentContext := kubeconfig.CurrentContext
	context := kubeconfig.Contexts[currentContext]
	if context == nil {
		return fmt.Errorf("current context not found: %s", currentContext)
	}

	authInfo := kubeconfig.AuthInfos[context.AuthInfo]
	if authInfo == nil {
		return fmt.Errorf("auth info not found for user: %s", context.AuthInfo)
	}

	// Handle OIDC auth provider
	if authInfo.AuthProvider != nil && authInfo.AuthProvider.Name == "oidc" {
		if authInfo.AuthProvider.Config == nil {
			return fmt.Errorf("oidc auth provider config is nil")
		}

		// Use id-token if available
		if idToken, ok := authInfo.AuthProvider.Config["id-token"]; ok && idToken != "" {
			config.BearerToken = idToken
			return nil
		}

		// Use refresh token if available
		if refreshToken, ok := authInfo.AuthProvider.Config["refresh-token"]; ok && refreshToken != "" {
			// TODO: Implement token refresh logic if needed
			return fmt.Errorf("token refresh not implemented")
		}
	}

	// Fallback to direct token or token file
	if authInfo.Token != "" {
		config.BearerToken = authInfo.Token
		return nil
	}

	if authInfo.TokenFile != "" {
		tokenBytes, err := os.ReadFile(authInfo.TokenFile)
		if err != nil {
			return fmt.Errorf("failed to read token file: %w", err)
		}
		config.BearerToken = string(tokenBytes)
		return nil
	}

	return fmt.Errorf("no valid authentication method found")
}

func (f *KubeClientFactory) GetClient(config ClientConfig) (KubeClient, error) {
	var kubeconfigPath string

	// For testing environment
	if config.ClusterID == "default" {
		kubeconfigPath = filepath.Join(f.kubeconfigBasePath, "kubeconfig")
	} else {
		// Production path construction
		kubeconfigPath = filepath.Join(f.kubeconfigBasePath, config.TenantID, config.ClusterID, "kubeconfig")
	}

	// Load kubeconfig
	loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfigPath}
	configOverrides := &clientcmd.ConfigOverrides{}
	
	kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		loadingRules,
		configOverrides).ClientConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to load kubeconfig: %w", err)
	}

	// Load raw kubeconfig for auth setup
	rawConfig, err := clientcmd.LoadFromFile(kubeconfigPath)
	if err != nil {
		return nil, fmt.Errorf("failed to load raw kubeconfig: %w", err)
	}

	// Setup authentication
	if err := f.setupOIDCAuth(kubeConfig, rawConfig); err != nil {
		return nil, fmt.Errorf("failed to setup auth: %w", err)
	}

	// Create clientset
	clientset, err := kubernetes.NewForConfig(kubeConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create clientset: %w", err)
	}

	// Create dynamic client
	dynamicClient, err := dynamic.NewForConfig(kubeConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create dynamic client: %w", err)
	}

	return NewKubeClientImpl(clientset, dynamicClient, &config), nil
}
Editor is loading...
Leave a Comment