Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

pinniped-components: Extract GetPinnipedKubeconfig and oFromCluster to shared lib #4533

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 5 additions & 66 deletions cli/core/pkg/auth/tkg/kube_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,27 @@
package tkgauth

import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"

"github.com/pkg/errors"

"k8s.io/client-go/discovery"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

kubeutils "github.com/vmware-tanzu/tanzu-framework/cli/core/pkg/auth/utils/kubeconfig"
"github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/pinnipedinfo"

pinnipedkubeconfig "github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/kubeconfig"
)

const (
// ConciergeAuthenticatorType is the pinniped concierge authenticator type
ConciergeAuthenticatorType = "jwt"

// ConciergeAuthenticatorName is the pinniped concierge authenticator object name
ConciergeAuthenticatorName = "tkg-jwt-authenticator"

// PinnipedOIDCScopes are the scopes of pinniped oidc
PinnipedOIDCScopes = "offline_access,openid,pinniped:request-audience"

// TanzuLocalKubeDir is the local config directory
TanzuLocalKubeDir = ".kube-tanzu"

// TanzuKubeconfigFile is the name the of the kubeconfig file
TanzuKubeconfigFile = "config"

// DefaultPinnipedLoginTimeout is the default login timeout
DefaultPinnipedLoginTimeout = time.Minute

// DefaultClusterInfoConfigMap is the default ConfigMap looked up in the kube-public namespace when generating a kubeconfig.
DefaultClusterInfoConfigMap = "cluster-info"
)
Expand Down Expand Up @@ -76,7 +61,7 @@ func KubeconfigWithPinnipedAuthLoginPlugin(endpoint string, options *KubeConfigO
return
}

config, err := GetPinnipedKubeconfig(clusterInfo, pinnipedInfo, pinnipedInfo.ClusterName, pinnipedInfo.Issuer)
config, err := pinnipedkubeconfig.GetPinnipedKubeconfig(clusterInfo, pinnipedInfo, pinnipedInfo.ClusterName, pinnipedInfo.Issuer)
if err != nil {
err = errors.Wrap(err, "unable to get the kubeconfig")
return
Expand Down Expand Up @@ -121,7 +106,7 @@ func GetServerKubernetesVersion(kubeconfigPath, context string) (string, error)
return "", errors.Errorf("Unable to set up rest config due to : %v", err)
}
// set the timeout to give user sufficient time to enter the login credentials
restConfig.Timeout = DefaultPinnipedLoginTimeout
restConfig.Timeout = pinnipedkubeconfig.DefaultPinnipedLoginTimeout

discoveryClient, err = discovery.NewDiscoveryClientForConfig(restConfig)
if err != nil {
Expand All @@ -148,52 +133,6 @@ func loadKubeconfigAndEnsureContext(kubeConfigPath, context string) ([]byte, err
return clientcmd.Write(*config)
}

// GetPinnipedKubeconfig generate kubeconfig given cluster-info and pinniped-info and the requested audience
func GetPinnipedKubeconfig(cluster *clientcmdapi.Cluster, pinnipedInfo *pinnipedinfo.PinnipedInfo, clustername, audience string) (*clientcmdapi.Config, error) {
execConfig := clientcmdapi.ExecConfig{
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
Args: []string{},
Env: []clientcmdapi.ExecEnvVar{},
}

execConfig.Command = "tanzu"
execConfig.Args = append([]string{"pinniped-auth", "login"}, execConfig.Args...)

conciergeEndpoint := cluster.Server
if pinnipedInfo.ConciergeEndpoint != "" {
conciergeEndpoint = pinnipedInfo.ConciergeEndpoint
}

// configure concierge
execConfig.Args = append(execConfig.Args,
"--enable-concierge",
"--concierge-authenticator-name="+ConciergeAuthenticatorName,
"--concierge-authenticator-type="+ConciergeAuthenticatorType,
"--concierge-endpoint="+conciergeEndpoint,
"--concierge-ca-bundle-data="+base64.StdEncoding.EncodeToString(cluster.CertificateAuthorityData),
"--issuer="+pinnipedInfo.Issuer, // configure OIDC
"--scopes="+PinnipedOIDCScopes,
"--ca-bundle-data="+pinnipedInfo.IssuerCABundleData,
"--request-audience="+audience,
)

if os.Getenv("TANZU_CLI_PINNIPED_AUTH_LOGIN_SKIP_BROWSER") != "" {
execConfig.Args = append(execConfig.Args, "--skip-browser")
}

username := "tanzu-cli-" + clustername
contextName := fmt.Sprintf("%s@%s", username, clustername)

return &clientcmdapi.Config{
Kind: "Config",
APIVersion: clientcmdapi.SchemeGroupVersion.Version,
Clusters: map[string]*clientcmdapi.Cluster{clustername: cluster},
AuthInfos: map[string]*clientcmdapi.AuthInfo{username: {Exec: &execConfig}},
Contexts: map[string]*clientcmdapi.Context{contextName: {Cluster: clustername, AuthInfo: username}},
CurrentContext: contextName,
}, nil
}

// TanzuLocalKubeConfigPath returns the local tanzu kubeconfig path
func TanzuLocalKubeConfigPath() (path string, err error) {
home, err := os.UserHomeDir()
Expand Down
11 changes: 5 additions & 6 deletions cli/core/pkg/auth/tkg/kube_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ import (
"path/filepath"
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/onsi/gomega/ghttp"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

tkgauth "github.com/vmware-tanzu/tanzu-framework/cli/core/pkg/auth/tkg"
"github.com/vmware-tanzu/tanzu-framework/cli/core/pkg/fakes/helper"
pinnipedkubeconfig "github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/kubeconfig"

"github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/pinnipedinfo"
)

Expand Down Expand Up @@ -197,12 +196,12 @@ func getExpectedExecConfig(endpoint string, issuer string, issuerCA string, serv
args := []string{
"pinniped-auth", "login",
"--enable-concierge",
"--concierge-authenticator-name=" + tkgauth.ConciergeAuthenticatorName,
"--concierge-authenticator-type=" + tkgauth.ConciergeAuthenticatorType,
"--concierge-authenticator-name=" + pinnipedkubeconfig.ConciergeAuthenticatorName,
"--concierge-authenticator-type=" + pinnipedkubeconfig.ConciergeAuthenticatorType,
"--concierge-endpoint=" + endpoint,
"--concierge-ca-bundle-data=" + base64.StdEncoding.EncodeToString(certBytes),
"--issuer=" + issuer,
"--scopes=" + tkgauth.PinnipedOIDCScopes,
"--scopes=" + pinnipedkubeconfig.PinnipedOIDCScopes,
"--ca-bundle-data=" + issuerCA,
"--request-audience=" + issuer,
}
Expand Down
12 changes: 8 additions & 4 deletions cmd/cli/plugin/cluster/kubeconfig_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (

configapi "github.com/vmware-tanzu/tanzu-framework/cli/runtime/apis/config/v1alpha1"
"github.com/vmware-tanzu/tanzu-framework/cli/runtime/config"
tkgauth "github.com/vmware-tanzu/tanzu-framework/tkg/auth"

tkgclient "github.com/vmware-tanzu/tanzu-framework/tkg/client"
"github.com/vmware-tanzu/tanzu-framework/tkg/tkgctl"

pinnipedkubeconfig "github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/kubeconfig"
)

type getClusterKubeconfigOptions struct {
Expand Down Expand Up @@ -102,8 +102,12 @@ func getPinnipedKubeconfig(tkgctlClient tkgctl.TKGClient, workloadClusterName st
audience = *clusterPinnipedInfo.ClusterAudience
}

kubeconfig, err := tkgauth.GetPinnipedKubeconfig(clusterPinnipedInfo.ClusterInfo, clusterPinnipedInfo.PinnipedInfo,
clusterPinnipedInfo.ClusterName, audience)
kubeconfig, err := pinnipedkubeconfig.GetPinnipedKubeconfig(
clusterPinnipedInfo.ClusterInfo,
clusterPinnipedInfo.PinnipedInfo,
clusterPinnipedInfo.ClusterName,
audience,
)

if err != nil {
return errors.Wrap(err, "unable to get kubeconfig")
Expand Down
4 changes: 4 additions & 0 deletions cmd/cli/plugin/login/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ func createServerWithEndpoint() (server *configapi.Server, err error) {
return nil, err
}
} else {
// TODO(BEN): this func has more complicated dependencies, but is obviouisly pinniped related, and it is
Copy link
Contributor

@prkalle prkalle Mar 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this func is refactored, it would really help core CLI to fetch pinniped kubeconfig by providing the endpoint.
Infact Core CLI would really need this functionality (in pinniped-components/common) where given endpoint to TKG/TKGs cluster library would return the pinniped kubeconfig. So that CLI could fully depend on the library and remove duplicated code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@prkalle if you happen to already have a good eye on all the require() and replace() across this repo and the various modules from you previous work, would love any pointers. I think some of the replace() statements are causing incompatibility issues. Tracking that down next, is breaking the build.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure @benjaminapetersen. We can discuss offline.

// duplicated. we need to decide how to factor it out.
kubeConfig, kubecontext, err = tkgauth.KubeconfigWithPinnipedAuthLoginPlugin(endpoint, nil, tkgauth.DiscoveryStrategy{ClusterInfoConfigMap: tkgauth.DefaultClusterInfoConfigMap})
if err != nil {
log.Fatalf("Error creating kubeconfig with tanzu pinniped-auth login plugin: %v", err)
Expand Down Expand Up @@ -528,6 +530,8 @@ func getDiscoveryHTTPClient() *http.Client {

func vSphereSupervisorLogin(endpoint string) (mergeFilePath, currentContext string, err error) {
port := 443
// TODO(BEN): this func is trickier, it has more dependencies on things that we likely don't
// want to pull into <TF>/pinniped-components/common.
kubeConfig, kubecontext, err := tkgauth.KubeconfigWithPinnipedAuthLoginPlugin(endpoint, nil, tkgauth.DiscoveryStrategy{DiscoveryPort: &port, ClusterInfoConfigMap: wcpauth.SupervisorVIPConfigMapName})
if err != nil {
log.Fatalf("Error creating kubeconfig with tanzu pinniped-auth login plugin: %v", err)
Expand Down
11 changes: 8 additions & 3 deletions cmd/cli/plugin/managementcluster/kubeconfig_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (

configapi "github.com/vmware-tanzu/tanzu-framework/cli/runtime/apis/config/v1alpha1"
"github.com/vmware-tanzu/tanzu-framework/cli/runtime/config"
tkgauth "github.com/vmware-tanzu/tanzu-framework/tkg/auth"

pinnipedkubeconfig "github.com/vmware-tanzu/tanzu-framework/pinniped-components/common/pkg/kubeconfig"
)

type getClusterKubeconfigOptions struct {
Expand Down Expand Up @@ -102,8 +103,12 @@ func getPinnipedKubeconfig(tkgctlClient tkgctl.TKGClient, mcClustername string)
// for management cluster the audience would be set to IssuerURL
audience := clusterPinnipedInfo.PinnipedInfo.Issuer

kubeconfig, _ := tkgauth.GetPinnipedKubeconfig(clusterPinnipedInfo.ClusterInfo, clusterPinnipedInfo.PinnipedInfo,
clusterPinnipedInfo.ClusterName, audience)
kubeconfig, _ := pinnipedkubeconfig.GetPinnipedKubeconfig(
clusterPinnipedInfo.ClusterInfo,
clusterPinnipedInfo.PinnipedInfo,
clusterPinnipedInfo.ClusterName,
audience,
)

kubeconfigbytes, err := json.Marshal(kubeconfig)
if err != nil {
Expand Down
35 changes: 34 additions & 1 deletion pinniped-components/common/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,37 @@ module github.com/vmware-tanzu/tanzu-framework/pinniped-components/common

go 1.18

require github.com/pkg/errors v0.9.1
require (
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.24.1
github.com/pkg/errors v0.9.1
k8s.io/client-go v0.26.3
)

require (
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/rogpeppe/go-internal v1.6.2 // indirect
github.com/stretchr/testify v1.8.1 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.26.3 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
Loading