2024-04-25 01:02:05 +00:00
package https
import (
"context"
"net/http"
"strconv"
"sync"
"github.com/gorilla/mux"
"github.com/k3s-io/k3s/pkg/daemons/config"
"github.com/k3s-io/k3s/pkg/generated/clientset/versioned/scheme"
"github.com/k3s-io/k3s/pkg/util"
"github.com/k3s-io/k3s/pkg/version"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer"
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
)
// RouterFunc provides a hook for components to register additional routes to a request router
type RouterFunc func ( ctx context . Context , nodeConfig * config . Node ) ( * mux . Router , error )
var once sync . Once
var router * mux . Router
var err error
// Start returns a router with authn/authz filters applied.
// The first time it is called, the router is created and a new HTTPS listener is started if the handler is nil.
// Subsequent calls will return the same router.
func Start ( ctx context . Context , nodeConfig * config . Node , runtime * config . ControlRuntime ) ( * mux . Router , error ) {
once . Do ( func ( ) {
router = mux . NewRouter ( ) . SkipClean ( true )
config := server . Config { }
if runtime == nil {
// If we do not have an existing handler, set up a new listener
2024-06-13 20:27:33 +00:00
tcp , lerr := util . ListenWithLoopback ( ctx , nodeConfig . AgentConfig . ListenAddress , strconv . Itoa ( nodeConfig . SupervisorPort ) )
2024-04-25 01:02:05 +00:00
if lerr != nil {
err = lerr
return
}
serving := options . NewSecureServingOptions ( )
serving . Listener = tcp
serving . CipherSuites = nodeConfig . AgentConfig . CipherSuites
serving . MinTLSVersion = nodeConfig . AgentConfig . MinTLSVersion
serving . ServerCert = options . GeneratableKeyCert {
CertKey : options . CertKey {
CertFile : nodeConfig . AgentConfig . ServingKubeletCert ,
KeyFile : nodeConfig . AgentConfig . ServingKubeletKey ,
} ,
}
if aerr := serving . ApplyTo ( & config . SecureServing ) ; aerr != nil {
err = aerr
return
}
} else {
// If we have an existing handler, wrap it
router . NotFoundHandler = runtime . Handler
runtime . Handler = router
}
authn := options . NewDelegatingAuthenticationOptions ( )
authn . DisableAnonymous = true
authn . SkipInClusterLookup = true
authn . ClientCert = options . ClientCertAuthenticationOptions {
ClientCA : nodeConfig . AgentConfig . ClientCA ,
}
authn . RemoteKubeConfigFile = nodeConfig . AgentConfig . KubeConfigKubelet
if applyErr := authn . ApplyTo ( & config . Authentication , config . SecureServing , nil ) ; applyErr != nil {
err = applyErr
return
}
authz := options . NewDelegatingAuthorizationOptions ( )
2024-05-30 19:00:47 +00:00
authz . AlwaysAllowPaths = [ ] string { // skip authz for paths that should not use SubjectAccessReview; basically everything that will use this router other than metrics
"/v1-" + version . Program + "/p2p" , // spegel libp2p peer discovery
"/v2/*" , // spegel registry mirror
"/debug/pprof/*" , // profiling
}
2024-04-25 01:02:05 +00:00
authz . RemoteKubeConfigFile = nodeConfig . AgentConfig . KubeConfigKubelet
if applyErr := authz . ApplyTo ( & config . Authorization ) ; applyErr != nil {
err = applyErr
return
}
router . Use ( filterChain ( config . Authentication . Authenticator , config . Authorization . Authorizer ) )
if config . SecureServing != nil {
_ , _ , err = config . SecureServing . Serve ( router , 0 , ctx . Done ( ) )
}
} )
return router , err
}
// filterChain runs the kubernetes authn/authz filter chain using the mux middleware API
func filterChain ( authn authenticator . Request , authz authorizer . Authorizer ) mux . MiddlewareFunc {
return func ( handler http . Handler ) http . Handler {
requestInfoResolver := & apirequest . RequestInfoFactory { }
failedHandler := genericapifilters . Unauthorized ( scheme . Codecs )
handler = genericapifilters . WithAuthorization ( handler , authz , scheme . Codecs )
handler = genericapifilters . WithAuthentication ( handler , authn , failedHandler , nil , nil )
handler = genericapifilters . WithRequestInfo ( handler , requestInfoResolver )
handler = genericapifilters . WithCacheControl ( handler )
return handler
}
}