1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 07:49:41 +02:00

fix(kube): Use KubeClusterAccessService for Helm operations [EE-2500] (#6559)

This commit is contained in:
Marcelo Rydel 2022-03-21 09:51:29 -03:00 committed by GitHub
parent cf7746082b
commit c486130a9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 103 deletions

View file

@ -2,6 +2,7 @@ package helm
import (
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/portainer/libhelm"
@ -14,10 +15,6 @@ import (
"github.com/portainer/portainer/api/kubernetes"
)
const (
handlerActivityContext = "Kubernetes"
)
type requestBouncer interface {
AuthenticatedAccess(h http.Handler) http.Handler
}
@ -25,24 +22,24 @@ type requestBouncer interface {
// Handler is the HTTP handler used to handle environment(endpoint) group operations.
type Handler struct {
*mux.Router
requestBouncer requestBouncer
dataStore dataservices.DataStore
jwtService dataservices.JWTService
kubeConfigService kubernetes.KubeConfigService
kubernetesDeployer portainer.KubernetesDeployer
helmPackageManager libhelm.HelmPackageManager
requestBouncer requestBouncer
dataStore dataservices.DataStore
jwtService dataservices.JWTService
kubeClusterAccessService kubernetes.KubeClusterAccessService
kubernetesDeployer portainer.KubernetesDeployer
helmPackageManager libhelm.HelmPackageManager
}
// NewHandler creates a handler to manage endpoint group operations.
func NewHandler(bouncer requestBouncer, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubernetesDeployer portainer.KubernetesDeployer, helmPackageManager libhelm.HelmPackageManager, kubeConfigService kubernetes.KubeConfigService) *Handler {
func NewHandler(bouncer requestBouncer, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubernetesDeployer portainer.KubernetesDeployer, helmPackageManager libhelm.HelmPackageManager, kubeClusterAccessService kubernetes.KubeClusterAccessService) *Handler {
h := &Handler{
Router: mux.NewRouter(),
requestBouncer: bouncer,
dataStore: dataStore,
jwtService: jwtService,
kubernetesDeployer: kubernetesDeployer,
helmPackageManager: helmPackageManager,
kubeConfigService: kubeConfigService,
Router: mux.NewRouter(),
requestBouncer: bouncer,
dataStore: dataStore,
jwtService: jwtService,
kubernetesDeployer: kubernetesDeployer,
helmPackageManager: helmPackageManager,
kubeClusterAccessService: kubeClusterAccessService,
}
h.Use(middlewares.WithEndpoint(dataStore.Endpoint(), "id"))
@ -104,10 +101,20 @@ func (handler *Handler) getHelmClusterAccess(r *http.Request) (*options.Kubernet
return nil, &httperror.HandlerError{http.StatusUnauthorized, "Unauthorized", err}
}
kubeConfigInternal := handler.kubeConfigService.GetKubeConfigInternal(endpoint.ID, bearerToken)
sslSettings, err := handler.dataStore.SSLSettings().Settings()
if err != nil {
return nil, &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve settings from the database", err}
}
hostURL := "localhost"
if !sslSettings.SelfSigned {
hostURL = strings.Split(r.Host, ":")[0]
}
kubeConfigInternal := handler.kubeClusterAccessService.GetData(hostURL, endpoint.ID)
return &options.KubernetesClusterAccess{
ClusterServerURL: kubeConfigInternal.ClusterServerURL,
CertificateAuthorityFile: kubeConfigInternal.CertificateAuthorityFile,
AuthToken: kubeConfigInternal.AuthToken,
AuthToken: bearerToken,
}, nil
}

View file

@ -36,8 +36,8 @@ func Test_helmDelete(t *testing.T) {
kubernetesDeployer := exectest.NewKubernetesDeployer()
helmPackageManager := test.NewMockHelmBinaryPackageManager("")
kubeConfigService := kubernetes.NewKubeConfigCAService("", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeConfigService)
kubeClusterAccessService := kubernetes.NewKubeClusterAccessService("", "", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeClusterAccessService)
is.NotNil(h, "Handler should not fail")

View file

@ -39,8 +39,8 @@ func Test_helmInstall(t *testing.T) {
kubernetesDeployer := exectest.NewKubernetesDeployer()
helmPackageManager := test.NewMockHelmBinaryPackageManager("")
kubeConfigService := kubernetes.NewKubeConfigCAService("", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeConfigService)
kubeClusterAccessService := kubernetes.NewKubeClusterAccessService("", "", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeClusterAccessService)
is.NotNil(h, "Handler should not fail")

View file

@ -38,8 +38,8 @@ func Test_helmList(t *testing.T) {
kubernetesDeployer := exectest.NewKubernetesDeployer()
helmPackageManager := test.NewMockHelmBinaryPackageManager("")
kubeConfigService := kubernetes.NewKubeConfigCAService("", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeConfigService)
kubeClusterAccessService := kubernetes.NewKubeClusterAccessService("", "", "")
h := NewHandler(helper.NewTestRequestBouncer(), store, jwtService, kubernetesDeployer, helmPackageManager, kubeClusterAccessService)
// Install a single chart. We expect to get these values back
options := options.InstallOptions{Name: "nginx-1", Chart: "nginx", Namespace: "default"}

View file

@ -2,6 +2,7 @@ package kubernetes
import (
"errors"
"github.com/portainer/portainer/api/kubernetes"
"net/http"
"github.com/gorilla/mux"
@ -17,21 +18,22 @@ import (
// Handler is the HTTP handler which will natively deal with to external environments(endpoints).
type Handler struct {
*mux.Router
dataStore dataservices.DataStore
kubernetesClientFactory *cli.ClientFactory
authorizationService *authorization.Service
JwtService dataservices.JWTService
BaseURL string
authorizationService *authorization.Service
dataStore dataservices.DataStore
jwtService dataservices.JWTService
kubernetesClientFactory *cli.ClientFactory
kubeClusterAccessService kubernetes.KubeClusterAccessService
}
// NewHandler creates a handler to process pre-proxied requests to external APIs.
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore dataservices.DataStore, kubernetesClientFactory *cli.ClientFactory, baseURL string) *Handler {
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubeClusterAccessService kubernetes.KubeClusterAccessService, kubernetesClientFactory *cli.ClientFactory) *Handler {
h := &Handler{
Router: mux.NewRouter(),
dataStore: dataStore,
kubernetesClientFactory: kubernetesClientFactory,
authorizationService: authorizationService,
BaseURL: baseURL,
Router: mux.NewRouter(),
authorizationService: authorizationService,
dataStore: dataStore,
jwtService: jwtService,
kubeClusterAccessService: kubeClusterAccessService,
kubernetesClientFactory: kubernetesClientFactory,
}
kubeRouter := h.PathPrefix("/kubernetes").Subrouter()

View file

@ -39,7 +39,7 @@ func (handler *Handler) getKubernetesConfig(w http.ResponseWriter, r *http.Reque
if err != nil {
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to access environment", err}
}
bearerToken, err := handler.JwtService.GenerateTokenForKubeconfig(tokenData)
bearerToken, err := handler.jwtService.GenerateTokenForKubeconfig(tokenData)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to generate JWT token", err}
}
@ -126,7 +126,7 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
instanceID := handler.kubernetesClientFactory.GetInstanceID()
serviceAccountName := kcli.UserServiceAccountName(int(tokenData.ID), instanceID)
configClusters[idx] = buildCluster(r, handler.BaseURL, endpoint)
configClusters[idx] = handler.buildCluster(r, endpoint)
configContexts[idx] = buildContext(serviceAccountName, endpoint)
if !authInfosSet[serviceAccountName] {
configAuthInfos = append(configAuthInfos, buildAuthInfo(serviceAccountName, bearerToken))
@ -144,15 +144,13 @@ func (handler *Handler) buildConfig(r *http.Request, tokenData *portainer.TokenD
}, nil
}
func buildCluster(r *http.Request, baseURL string, endpoint portainer.Endpoint) clientV1.NamedCluster {
if baseURL != "/" {
baseURL = fmt.Sprintf("/%s/", strings.Trim(baseURL, "/"))
}
proxyURL := fmt.Sprintf("https://%s%sapi/endpoints/%d/kubernetes", r.Host, baseURL, endpoint.ID)
func (handler *Handler) buildCluster(r *http.Request, endpoint portainer.Endpoint) clientV1.NamedCluster {
hostURL := strings.Split(r.Host, ":")[0]
kubeConfigInternal := handler.kubeClusterAccessService.GetData(hostURL, endpoint.ID)
return clientV1.NamedCluster{
Name: buildClusterName(endpoint.Name),
Cluster: clientV1.Cluster{
Server: proxyURL,
Server: kubeConfigInternal.ClusterServerURL,
InsecureSkipTLSVerify: true,
},
}