151 lines
6.7 KiB
Go
151 lines
6.7 KiB
Go
package multiclustermanager
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
"github.com/rancher/apiserver/pkg/parse"
|
|
"github.com/rancher/rancher/pkg/api/norman"
|
|
"github.com/rancher/rancher/pkg/api/norman/customization/aks"
|
|
"github.com/rancher/rancher/pkg/api/norman/customization/clusterregistrationtokens"
|
|
"github.com/rancher/rancher/pkg/api/norman/customization/gke"
|
|
"github.com/rancher/rancher/pkg/api/norman/customization/oci"
|
|
"github.com/rancher/rancher/pkg/api/norman/customization/vsphere"
|
|
managementapi "github.com/rancher/rancher/pkg/api/norman/server"
|
|
"github.com/rancher/rancher/pkg/api/steve/supportconfigs"
|
|
"github.com/rancher/rancher/pkg/auth/providers/publicapi"
|
|
"github.com/rancher/rancher/pkg/auth/providers/saml"
|
|
"github.com/rancher/rancher/pkg/auth/requests"
|
|
"github.com/rancher/rancher/pkg/auth/requests/sar"
|
|
"github.com/rancher/rancher/pkg/auth/tokens"
|
|
"github.com/rancher/rancher/pkg/auth/webhook"
|
|
"github.com/rancher/rancher/pkg/channelserver"
|
|
"github.com/rancher/rancher/pkg/clustermanager"
|
|
rancherdialer "github.com/rancher/rancher/pkg/dialer"
|
|
"github.com/rancher/rancher/pkg/httpproxy"
|
|
k8sProxyPkg "github.com/rancher/rancher/pkg/k8sproxy"
|
|
"github.com/rancher/rancher/pkg/metrics"
|
|
"github.com/rancher/rancher/pkg/multiclustermanager/whitelist"
|
|
"github.com/rancher/rancher/pkg/rbac"
|
|
"github.com/rancher/rancher/pkg/rkenodeconfigserver"
|
|
"github.com/rancher/rancher/pkg/telemetry"
|
|
"github.com/rancher/rancher/pkg/tunnelserver/mcmauthorizer"
|
|
"github.com/rancher/rancher/pkg/types/config"
|
|
"github.com/rancher/rancher/pkg/version"
|
|
"github.com/rancher/steve/pkg/auth"
|
|
)
|
|
|
|
func router(ctx context.Context, localClusterEnabled bool, tunnelAuthorizer *mcmauthorizer.Authorizer, scaledContext *config.ScaledContext, clusterManager *clustermanager.Manager) (func(http.Handler) http.Handler, error) {
|
|
var (
|
|
k8sProxy = k8sProxyPkg.New(scaledContext, scaledContext.Dialer, clusterManager)
|
|
connectHandler = scaledContext.Dialer.(*rancherdialer.Factory).TunnelServer
|
|
connectConfigHandler = rkenodeconfigserver.Handler(tunnelAuthorizer, scaledContext)
|
|
clusterImport = clusterregistrationtokens.ClusterImport{Clusters: scaledContext.Management.Clusters("")}
|
|
)
|
|
|
|
tokenAPI, err := tokens.NewAPIHandler(ctx, scaledContext, norman.ConfigureAPIUI)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
publicAPI, err := publicapi.NewHandler(ctx, scaledContext, norman.ConfigureAPIUI)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
managementAPI, err := managementapi.New(ctx, scaledContext, clusterManager, k8sProxy, localClusterEnabled)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
metaProxy, err := httpproxy.NewProxy("/proxy/", whitelist.Proxy.Get, scaledContext)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
metricsHandler := metrics.NewMetricsHandler(scaledContext, clusterManager, promhttp.Handler())
|
|
|
|
channelserver := channelserver.NewHandler(ctx)
|
|
|
|
supportConfigGenerator := supportconfigs.NewHandler(scaledContext)
|
|
// Unauthenticated routes
|
|
unauthed := mux.NewRouter()
|
|
unauthed.UseEncodedPath()
|
|
|
|
unauthed.Path("/").MatcherFunc(parse.MatchNotBrowser).Handler(managementAPI)
|
|
unauthed.Handle("/v3/connect/config", connectConfigHandler)
|
|
unauthed.Handle("/v3/connect", connectHandler)
|
|
unauthed.Handle("/v3/connect/register", connectHandler)
|
|
unauthed.Handle("/v3/import/{token}_{clusterId}.yaml", http.HandlerFunc(clusterImport.ClusterImportHandler))
|
|
unauthed.Handle("/v3/settings/cacerts", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/first-login", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/ui-banners", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/ui-issues", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/ui-pl", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/ui-brand", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/v3/settings/ui-default-landing", managementAPI).MatcherFunc(onlyGet)
|
|
unauthed.Handle("/rancherversion", version.NewVersionHandler())
|
|
unauthed.PathPrefix("/v1-{prefix}-release/channel").Handler(channelserver)
|
|
unauthed.PathPrefix("/v1-{prefix}-release/release").Handler(channelserver)
|
|
unauthed.PathPrefix("/v1-saml").Handler(saml.AuthHandler())
|
|
unauthed.PathPrefix("/v3-public").Handler(publicAPI)
|
|
|
|
// Authenticated routes
|
|
impersonatingAuth := auth.ToMiddleware(requests.NewImpersonatingAuth(sar.NewSubjectAccessReview(clusterManager)))
|
|
saAuth := auth.ToMiddleware(requests.NewServiceAccountAuth(scaledContext, clustermanager.ToRESTConfig))
|
|
accessControlHandler := rbac.NewAccessControlHandler()
|
|
|
|
saauthed := mux.NewRouter()
|
|
saauthed.UseEncodedPath()
|
|
saauthed.PathPrefix("/k8s/clusters/{clusterID}").Handler(k8sProxy)
|
|
saauthed.Use(mux.MiddlewareFunc(saAuth.Chain(impersonatingAuth)))
|
|
saauthed.Use(mux.MiddlewareFunc(accessControlHandler))
|
|
saauthed.Use(requests.NewAuthenticatedFilter)
|
|
|
|
authed := mux.NewRouter()
|
|
authed.UseEncodedPath()
|
|
|
|
authed.Use(mux.MiddlewareFunc(impersonatingAuth))
|
|
authed.Use(mux.MiddlewareFunc(accessControlHandler))
|
|
authed.Use(requests.NewAuthenticatedFilter)
|
|
|
|
authed.Path("/meta/{resource:aks.+}").Handler(aks.NewAKSHandler(scaledContext))
|
|
authed.Path("/meta/{resource:gke.+}").Handler(gke.NewGKEHandler(scaledContext))
|
|
authed.Path("/meta/oci/{resource}").Handler(oci.NewOCIHandler(scaledContext))
|
|
authed.Path("/meta/vsphere/{field}").Handler(vsphere.NewVsphereHandler(scaledContext))
|
|
authed.Path("/v3/tokenreview").Methods(http.MethodPost).Handler(&webhook.TokenReviewer{})
|
|
authed.Path("/metrics/{clusterID}").Handler(metricsHandler)
|
|
authed.Path(supportconfigs.Endpoint).Handler(&supportConfigGenerator)
|
|
authed.PathPrefix("/meta/proxy").Handler(metaProxy)
|
|
authed.PathPrefix("/v1-telemetry").Handler(telemetry.NewProxy())
|
|
authed.PathPrefix("/v3/identit").Handler(tokenAPI)
|
|
authed.PathPrefix("/v3/token").Handler(tokenAPI)
|
|
authed.PathPrefix("/v3").Handler(managementAPI)
|
|
|
|
// Metrics authenticated route
|
|
metricsAuthed := mux.NewRouter()
|
|
metricsAuthed.UseEncodedPath()
|
|
tokenReviewAuth := auth.ToMiddleware(requests.NewTokenReviewAuth(scaledContext.K8sClient.AuthenticationV1()))
|
|
metricsAuthed.Use(mux.MiddlewareFunc(tokenReviewAuth.Chain(impersonatingAuth)))
|
|
metricsAuthed.Use(mux.MiddlewareFunc(accessControlHandler))
|
|
metricsAuthed.Use(requests.NewAuthenticatedFilter)
|
|
|
|
metricsAuthed.Path("/metrics").Handler(metricsHandler)
|
|
|
|
unauthed.NotFoundHandler = saauthed
|
|
saauthed.NotFoundHandler = authed
|
|
authed.NotFoundHandler = metricsAuthed
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
metricsAuthed.NotFoundHandler = next
|
|
return unauthed
|
|
}, nil
|
|
}
|
|
|
|
// onlyGet will match only GET but will not return a 405 like route.Methods and instead just not match
|
|
func onlyGet(req *http.Request, m *mux.RouteMatch) bool {
|
|
return req.Method == http.MethodGet
|
|
}
|