separate internal configs with isInternal (#8690)

client-key: /Users/aliharris/.minikube/profiles/minikube/client.key

Co-authored-by: testa113 <testa113>
pull/8720/head
Ali 2023-05-11 08:13:54 +12:00 committed by GitHub
parent 945798a662
commit 22f4c5d650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 32 additions and 30 deletions

View File

@ -110,7 +110,7 @@ func (handler *Handler) getHelmClusterAccess(r *http.Request) (*options.Kubernet
hostURL = r.Host
}
kubeConfigInternal := handler.kubeClusterAccessService.GetData(hostURL, endpoint.ID)
kubeConfigInternal := handler.kubeClusterAccessService.GetClusterDetails(hostURL, endpoint.ID, true)
return &options.KubernetesClusterAccess{
ClusterServerURL: kubeConfigInternal.ClusterServerURL,
CertificateAuthorityFile: kubeConfigInternal.CertificateAuthorityFile,

View File

@ -51,7 +51,7 @@ func (handler *Handler) getKubernetesConfig(w http.ResponseWriter, r *http.Reque
return httperror.BadRequest("empty endpoints list", errors.New("empty endpoints list"))
}
config, handlerErr := handler.buildConfig(r, tokenData, bearerToken, endpoints)
config, handlerErr := handler.buildConfig(r, tokenData, bearerToken, endpoints, false)
if handlerErr != nil {
return handlerErr
}
@ -115,7 +115,7 @@ func (handler *Handler) filterUserKubeEndpoints(r *http.Request) ([]portainer.En
return filteredEndpoints, nil
}
func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenData, bearerToken string, endpoints []portainer.Endpoint) (*clientV1.Config, *httperror.HandlerError) {
func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenData, bearerToken string, endpoints []portainer.Endpoint, isInternal bool) (*clientV1.Config, *httperror.HandlerError) {
configClusters := make([]clientV1.NamedCluster, len(endpoints))
configContexts := make([]clientV1.NamedContext, len(endpoints))
var configAuthInfos []clientV1.NamedAuthInfo
@ -125,7 +125,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
instanceID := handler.KubernetesClientFactory.GetInstanceID()
serviceAccountName := kcli.UserServiceAccountName(int(tokenData.ID), instanceID)
configClusters[idx] = handler.buildCluster(r, endpoint)
configClusters[idx] = handler.buildCluster(r, endpoint, isInternal)
configContexts[idx] = buildContext(serviceAccountName, endpoint)
if !authInfosSet[serviceAccountName] {
configAuthInfos = append(configAuthInfos, buildAuthInfo(serviceAccountName, bearerToken))
@ -143,8 +143,9 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
}, nil
}
func (handler *Handler) buildCluster(r *http.Request, endpoint portainer.Endpoint) clientV1.NamedCluster {
kubeConfigInternal := handler.kubeClusterAccessService.GetData(r.Host, endpoint.ID)
// buildCluster builds a Kubernetes cluster configuration based on the endpoint and if it's used internally or externally.
func (handler *Handler) buildCluster(r *http.Request, endpoint portainer.Endpoint, isInternal bool) clientV1.NamedCluster {
kubeConfigInternal := handler.kubeClusterAccessService.GetClusterDetails(r.Host, endpoint.ID, isInternal)
return clientV1.NamedCluster{
Name: buildClusterName(endpoint.Name),

View File

@ -171,6 +171,7 @@ func (handler *Handler) kubeClient(next http.Handler) http.Handler {
tokenData,
bearerToken,
singleEndpointList,
true,
)
if err != nil {
httperror.WriteError(

View File

@ -4,9 +4,9 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"net/url"
"os"
"strings"
"strconv"
portainer "github.com/portainer/portainer/api"
@ -17,7 +17,7 @@ import (
// KubeClusterAccessService represents a service that is responsible for centralizing kube cluster access data
type KubeClusterAccessService interface {
IsSecure() bool
GetData(hostURL string, endpointId portainer.EndpointID) kubernetesClusterAccessData
GetClusterDetails(hostURL string, endpointId portainer.EndpointID, isInternal bool) kubernetesClusterAccessData
}
// KubernetesClusterAccess represents core details which can be used to generate KubeConfig file/data
@ -89,21 +89,20 @@ func (service *kubeClusterAccessService) IsSecure() bool {
return service.certificateAuthorityData != ""
}
// GetData returns K8s cluster access details for the specified environment(endpoint).
// GetClusterDetails returns K8s cluster access details for the specified environment(endpoint).
// The struct can be used to:
// - generate a kubeconfig file
// - pass down params to binaries
func (service *kubeClusterAccessService) GetData(hostURL string, endpointID portainer.EndpointID) kubernetesClusterAccessData {
baseURL := service.baseURL
// When the api call is internal, the baseURL should not be used.
// - isInternal is used to determine whether the kubeclient is accessed internally (for example using the kube client for backend calls) or externally (for example downloading the kubeconfig file)
func (service *kubeClusterAccessService) GetClusterDetails(hostURL string, endpointID portainer.EndpointID, isInternal bool) kubernetesClusterAccessData {
if hostURL == "localhost" {
hostURL += service.httpsBindAddr
baseURL = "/"
}
if baseURL != "/" {
baseURL = fmt.Sprintf("/%s/", strings.Trim(baseURL, "/"))
baseURL := service.baseURL
// When the kubeclient call is internal, the baseURL should not be used.
if isInternal {
baseURL = ""
}
log.Debug().
@ -112,9 +111,10 @@ func (service *kubeClusterAccessService) GetData(hostURL string, endpointID port
Str("base_URL", baseURL).
Msg("kubeconfig")
clusterURL := hostURL + baseURL
clusterServerURL := fmt.Sprintf("https://%sapi/endpoints/%d/kubernetes", clusterURL, endpointID)
clusterServerURL, err := url.JoinPath("https://", hostURL, baseURL, "/api/endpoints/", strconv.Itoa(int(endpointID)), "/kubernetes")
if err != nil {
log.Error().Err(err).Msg("Failed to create Kubeconfig cluster URL")
}
return kubernetesClusterAccessData{
ClusterServerURL: clusterServerURL,

View File

@ -91,21 +91,21 @@ func TestKubeClusterAccessService_IsSecure(t *testing.T) {
func TestKubeClusterAccessService_GetKubeConfigInternal(t *testing.T) {
is := assert.New(t)
t.Run("GetData contains host address", func(t *testing.T) {
t.Run("GetClusterDetails contains host address", func(t *testing.T) {
kcs := NewKubeClusterAccessService("/", "", "")
clusterAccessDetails := kcs.GetData("mysite.com", 1)
clusterAccessDetails := kcs.GetClusterDetails("mysite.com", 1, true)
is.True(strings.Contains(clusterAccessDetails.ClusterServerURL, "https://mysite.com"), "should contain host address")
})
t.Run("GetData contains environment proxy url", func(t *testing.T) {
t.Run("GetClusterDetails contains environment proxy url", func(t *testing.T) {
kcs := NewKubeClusterAccessService("/", "", "")
clusterAccessDetails := kcs.GetData("mysite.com", 100)
clusterAccessDetails := kcs.GetClusterDetails("mysite.com", 100, true)
is.True(strings.Contains(clusterAccessDetails.ClusterServerURL, "api/endpoints/100/kubernetes"), "should contain environment proxy url")
})
t.Run("GetData returns insecure cluster access config", func(t *testing.T) {
t.Run("GetClusterDetails returns insecure cluster access config", func(t *testing.T) {
kcs := NewKubeClusterAccessService("/", ":9443", "")
clusterAccessDetails := kcs.GetData("mysite.com", 1)
clusterAccessDetails := kcs.GetClusterDetails("mysite.com", 1, true)
wantClusterAccessDetails := kubernetesClusterAccessData{
ClusterServerURL: "https://mysite.com/api/endpoints/1/kubernetes",
@ -113,14 +113,14 @@ func TestKubeClusterAccessService_GetKubeConfigInternal(t *testing.T) {
CertificateAuthorityData: "",
}
is.Equal(clusterAccessDetails, wantClusterAccessDetails)
is.Equal(wantClusterAccessDetails, clusterAccessDetails)
})
t.Run("GetData returns secure cluster access config", func(t *testing.T) {
t.Run("GetClusterDetails returns secure cluster access config", func(t *testing.T) {
filePath := createTempFile("valid-cert.crt", certData, t)
kcs := NewKubeClusterAccessService("/", "", filePath)
clusterAccessDetails := kcs.GetData("localhost", 1)
clusterAccessDetails := kcs.GetClusterDetails("localhost", 1, true)
wantClusterAccessDetails := kubernetesClusterAccessData{
ClusterServerURL: "https://localhost/api/endpoints/1/kubernetes",
@ -128,6 +128,6 @@ func TestKubeClusterAccessService_GetKubeConfigInternal(t *testing.T) {
CertificateAuthorityData: certDataString,
}
is.Equal(clusterAccessDetails, wantClusterAccessDetails)
is.Equal(wantClusterAccessDetails, clusterAccessDetails)
})
}