Skip to content

Commit

Permalink
Update kube context with certmap info if necessary
Browse files Browse the repository at this point in the history
Since the cert data and skip verify intent is captured in the certmap
for the endpoint that one `tanzu login`s to, subsequent tanzu login
to the same endpoint can succeed without providing these values.
However the kube context created with the subsequent login attempt does
not incorporate these values when they originate from the cert map.

This change addresses this inconsistency, by ensuring that these values
are incorporated unless command line arguments of alternative ones are
provided in the login command.

Signed-off-by: Vui Lam <[email protected]>
  • Loading branch information
vuil committed Nov 15, 2024
1 parent ef7601d commit c3c12f8
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 10 deletions.
34 changes: 30 additions & 4 deletions pkg/auth/tanzu/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
package tanzu

import (
"encoding/base64"
"encoding/json"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/pkg/errors"
Expand All @@ -17,6 +19,7 @@ import (
kubeutils "github.com/vmware-tanzu/tanzu-cli/pkg/auth/utils/kubeconfig"
"github.com/vmware-tanzu/tanzu-plugin-runtime/config"
configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types"
"github.com/vmware-tanzu/tanzu-plugin-runtime/log"
)

const (
Expand All @@ -27,9 +30,12 @@ const (
tanzuKubeconfigFile = "config"
)

// GetTanzuKubeconfig constructs and returns the kubeconfig that points to Tanzu Org and
// GetTanzuKubeconfig constructs and returns the kubeconfig that points to
// Tanzu Org. The constructed kubeconfig will incorporate any explicitly certdata or
// skip verify flag or rely on the same information captured in the certmap
// otherwise.
func GetTanzuKubeconfig(c *configtypes.Context, endpoint, orgID, endpointCACertPath string, skipTLSVerify bool) (string, string, string, error) {
var clusterCACertDataBytes []byte
var endpointCACertBytes []byte
var err error

clusterAPIServerURL := strings.TrimSpace(endpoint)
Expand All @@ -39,10 +45,30 @@ func GetTanzuKubeconfig(c *configtypes.Context, endpoint, orgID, endpointCACertP
clusterAPIServerURL = clusterAPIServerURL + "/org/" + orgID

if endpointCACertPath != "" {
clusterCACertDataBytes, err = os.ReadFile(endpointCACertPath)
endpointCACertBytes, err = os.ReadFile(endpointCACertPath)
if err != nil {
return "", "", "", errors.Wrapf(err, "error reading CA certificate file %s", endpointCACertPath)
}
} else if !skipTLSVerify {
// When there is no explicit provision to use custom cert or skip TLS
// verification, fall back to information captured in the cert map, if
// any

if val, ok := c.AdditionalMetadata[config.TanzuAuthEndpointKey]; ok {
endpoint := val.(string)
certInfo, _ := config.GetCert(endpoint)
if certInfo != nil {
val, err := strconv.ParseBool(certInfo.SkipCertVerify)
if err == nil {
skipTLSVerify = val
}
decodedCACertData, err := base64.StdEncoding.DecodeString(certInfo.CACertData)
if err == nil {
endpointCACertBytes = decodedCACertData
log.V(7).Infof("Using cert data for endpoint: %s", endpoint)
}
}
}
}

contextName := kubeconfigContextName(c.Name)
Expand All @@ -53,7 +79,7 @@ func GetTanzuKubeconfig(c *configtypes.Context, endpoint, orgID, endpointCACertP
Kind: "Config",
APIVersion: clientcmdapi.SchemeGroupVersion.Version,
Clusters: map[string]*clientcmdapi.Cluster{clusterName: {
CertificateAuthorityData: clusterCACertDataBytes,
CertificateAuthorityData: endpointCACertBytes,
InsecureSkipTLSVerify: skipTLSVerify,
Server: clusterAPIServerURL,
}},
Expand Down
123 changes: 117 additions & 6 deletions pkg/auth/tanzu/kubeconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
package tanzu

import (
"encoding/base64"
"fmt"
"os"
"path/filepath"
"testing"

"k8s.io/client-go/tools/clientcmd"

configlib "github.com/vmware-tanzu/tanzu-plugin-runtime/config"
configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types"

. "github.com/onsi/ginkgo/v2"
Expand All @@ -31,21 +33,22 @@ const (
var _ = Describe("Unit tests for tanzu auth", func() {
var (
err error
endpoint string
tanzuContext *configtypes.Context
oldHomeDir string
tmpHomeDir string
)

const (
fakeContextName = "fake-tanzu-context"
fakeAccessToken = "fake-access-token"
fakeOrgID = "fake-org-id"
fakeEndpoint = "fake.tanzu.cloud.vmware.com"
fakeContextName = "fake-tanzu-context"
fakeAccessToken = "fake-access-token"
fakeOrgID = "fake-org-id"
fakeEndpoint = "fake.tanzu.cloud.vmware.com"
fakeCACertContent = "-----BEGIN CERTIFICATE-----\nfake\n---"
)

Describe("GetTanzuKubeconfig()", func() {
var kubeConfigPath, kubeContext, clusterAPIServerURL string

BeforeEach(func() {
err = createTempDirectory("kubeconfig-test")
Expect(err).ToNot(HaveOccurred())
Expand Down Expand Up @@ -109,7 +112,7 @@ var _ = Describe("Unit tests for tanzu auth", func() {
})
Context("When endpointCACertPath is not provided and skipTLSVerify is set to true", func() {
BeforeEach(func() {
kubeConfigPath, kubeContext, clusterAPIServerURL, err = GetTanzuKubeconfig(tanzuContext, endpoint, fakeOrgID, "", true)
kubeConfigPath, kubeContext, clusterAPIServerURL, err = GetTanzuKubeconfig(tanzuContext, fakeEndpoint, fakeOrgID, "", true)
})
It("should not set the 'certificate-authority-data' in kubeconfig and 'insecure-skip-tls-verify' should be set", func() {
Expect(err).ToNot(HaveOccurred())
Expand All @@ -130,7 +133,115 @@ var _ = Describe("Unit tests for tanzu auth", func() {
Expect(user.Exec).To(Equal(getExecConfig(tanzuContext)))
})
})
Context("When endpointCACertPath is not provided and skipTLSVerify is set to false, but ca cert found in cert map", func() {
BeforeEach(func() {
certInfo := configtypes.Cert{
Host: fakeEndpoint,
CACertData: base64.StdEncoding.EncodeToString([]byte(fakeCACertContent)),
SkipCertVerify: "false",
}

err = configlib.SetCert(&certInfo)
Expect(err).ToNot(HaveOccurred())

tanzuContext.AdditionalMetadata = map[string]interface{}{
configlib.TanzuAuthEndpointKey: "https://" + fakeEndpoint + "/auth",
}

kubeConfigPath, kubeContext, clusterAPIServerURL, err = GetTanzuKubeconfig(tanzuContext, fakeEndpoint, fakeOrgID, "", false)
})
It("should set the 'certificate-authority-data' in kubeconfig base on the cert map contents", func() {
Expect(err).ToNot(HaveOccurred())
Expect(kubeConfigPath).Should(Equal(filepath.Join(tmpHomeDir, ".config", "tanzu", "kube", "config")))
Expect(kubeContext).Should(Equal("tanzu-cli-" + tanzuContext.Name))
config, err := clientcmd.LoadFromFile(kubeConfigPath)
Expect(err).ToNot(HaveOccurred())

gotClusterName := config.Contexts[kubeContext].Cluster
cluster := config.Clusters[config.Contexts[kubeContext].Cluster]
user := config.AuthInfos[config.Contexts[kubeContext].AuthInfo]

Expect(cluster.Server).To(Equal(clusterAPIServerURL))
Expect(config.Contexts[kubeContext].AuthInfo).To(Equal("tanzu-cli-" + tanzuContext.Name + "-user"))
Expect(gotClusterName).To(Equal("tanzu-cli-" + tanzuContext.Name))
Expect([]byte(fakeCACertContent)).To(Equal(cluster.CertificateAuthorityData))
Expect(cluster.InsecureSkipTLSVerify).To(Equal(false))
Expect(user.Exec).To(Equal(getExecConfig(tanzuContext)))
})
})
Context("When endpointCACertPath is not provided and skipTLSVerify is set to false, but skipVerify is true in cert map", func() {
BeforeEach(func() {
certInfo := configtypes.Cert{
Host: fakeEndpoint,
SkipCertVerify: "true",
}

err = configlib.SetCert(&certInfo)
Expect(err).ToNot(HaveOccurred())

tanzuContext.AdditionalMetadata = map[string]interface{}{
configlib.TanzuAuthEndpointKey: "https://" + fakeEndpoint + "/auth",
}

kubeConfigPath, kubeContext, clusterAPIServerURL, err = GetTanzuKubeconfig(tanzuContext, fakeEndpoint, fakeOrgID, "", false)
})
It("should set the 'certificate-authority-data' in kubeconfig base on the cert map contents", func() {
Expect(err).ToNot(HaveOccurred())
Expect(kubeConfigPath).Should(Equal(filepath.Join(tmpHomeDir, ".config", "tanzu", "kube", "config")))
Expect(kubeContext).Should(Equal("tanzu-cli-" + tanzuContext.Name))
config, err := clientcmd.LoadFromFile(kubeConfigPath)
Expect(err).ToNot(HaveOccurred())

gotClusterName := config.Contexts[kubeContext].Cluster
cluster := config.Clusters[config.Contexts[kubeContext].Cluster]
user := config.AuthInfos[config.Contexts[kubeContext].AuthInfo]

Expect(cluster.Server).To(Equal(clusterAPIServerURL))
Expect(config.Contexts[kubeContext].AuthInfo).To(Equal("tanzu-cli-" + tanzuContext.Name + "-user"))
Expect(gotClusterName).To(Equal("tanzu-cli-" + tanzuContext.Name))
Expect(len(cluster.CertificateAuthorityData)).To(Equal(0))
Expect(cluster.InsecureSkipTLSVerify).To(Equal(true))
Expect(user.Exec).To(Equal(getExecConfig(tanzuContext)))
})
})
Context("When the endpoint caCertPath provided exists and skipTLSVerify is set to false and there is valid certmap data", func() {
BeforeEach(func() {
certInfo := configtypes.Cert{
Host: fakeEndpoint,
CACertData: base64.StdEncoding.EncodeToString([]byte(fakeCACertContent)),
SkipCertVerify: "false",
}

err = configlib.SetCert(&certInfo)
Expect(err).ToNot(HaveOccurred())

tanzuContext.AdditionalMetadata = map[string]interface{}{
configlib.TanzuAuthEndpointKey: "https://" + fakeEndpoint + "/auth",
}

kubeConfigPath, kubeContext, clusterAPIServerURL, err = GetTanzuKubeconfig(tanzuContext, fakeEndpoint, fakeOrgID, fakeCAcertPath, false)
})
It("should set the 'certificate-authority-data' in kubeconfig based on contents of provided ca cert path", func() {
Expect(err).ToNot(HaveOccurred())
Expect(kubeConfigPath).Should(Equal(filepath.Join(tmpHomeDir, ".config", "tanzu", "kube", "config")))
Expect(kubeContext).Should(Equal(kubeconfigContextName(tanzuContext.Name)))
config, err := clientcmd.LoadFromFile(kubeConfigPath)
Expect(err).ToNot(HaveOccurred())

gotClusterName := config.Contexts[kubeContext].Cluster
cluster := config.Clusters[config.Contexts[kubeContext].Cluster]
user := config.AuthInfos[config.Contexts[kubeContext].AuthInfo]

Expect(cluster.Server).To(Equal(clusterAPIServerURL))
Expect(config.Contexts[kubeContext].AuthInfo).To(Equal(kubeconfigUserName(tanzuContext.Name)))
Expect(gotClusterName).To(Equal(kubeconfigClusterName(tanzuContext.Name)))
Expect(user.Exec).To(Equal(getExecConfig(tanzuContext)))

caCertBytes, err := os.ReadFile(fakeCAcertPath)
Expect(err).ToNot(HaveOccurred())
Expect(caCertBytes).To(Equal(cluster.CertificateAuthorityData))
})
})
})
})

Expand Down

0 comments on commit c3c12f8

Please sign in to comment.