Skip to content

Commit

Permalink
Make /db/info available anonymously from localhost
Browse files Browse the repository at this point in the history
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
  • Loading branch information
brandond committed Apr 23, 2024
1 parent b721a3e commit b23f142
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 deletions.
18 changes: 12 additions & 6 deletions pkg/etcd/etcd.go
Expand Up @@ -664,12 +664,18 @@ func (e *ETCD) setName(force bool) error {

// handler wraps the handler with routes for database info
func (e *ETCD) handler(next http.Handler) http.Handler {
mux := mux.NewRouter().SkipClean(true)
mux.Use(auth.Middleware(e.config, version.Program+":server"))
mux.Handle("/db/info", e.infoHandler())
mux.Handle("/db/snapshot", e.snapshotHandler())
mux.NotFoundHandler = next
return mux
r := mux.NewRouter().SkipClean(true)
r.NotFoundHandler = next

ir := r.Path("/db/info").Subrouter()
ir.Use(auth.IsLocalOrHasRole(e.config, version.Program+":server"))
ir.Handle("", e.infoHandler())

sr := r.Path("/db/snapshot").Subrouter()
sr.Use(auth.HasRole(e.config, version.Program+":server"))
sr.Handle("", e.snapshotHandler())

return r
}

// infoHandler returns etcd cluster information. This is used by new members when joining the cluster.
Expand Down
21 changes: 20 additions & 1 deletion pkg/server/auth/auth.go
@@ -1,6 +1,7 @@
package auth

import (
"net"
"net/http"

"github.com/gorilla/mux"
Expand All @@ -22,6 +23,7 @@ func hasRole(mustRoles []string, roles []string) bool {
return false
}

// doAuth calls the cluster's authenticator to validate that the client has at least one of the listed roles
func doAuth(roles []string, serverConfig *config.Control, next http.Handler, rw http.ResponseWriter, req *http.Request) {
switch {
case serverConfig == nil:
Expand Down Expand Up @@ -51,10 +53,27 @@ func doAuth(roles []string, serverConfig *config.Control, next http.Handler, rw
next.ServeHTTP(rw, req)
}

func Middleware(serverConfig *config.Control, roles ...string) mux.MiddlewareFunc {
// HasRole returns a middleware function that validates that the request
// is being made with at least one of the listed roles.
func HasRole(serverConfig *config.Control, roles ...string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
doAuth(roles, serverConfig, next, rw, req)
})
}
}

// IsLocalOrHasRole returns a middleware function that validates that the request
// is from a local client or has at least one of the listed roles.
func IsLocalOrHasRole(serverConfig *config.Control, roles ...string) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
client, _, _ := net.SplitHostPort(req.RemoteAddr)
if client == "127.0.0.1" || client == "::1" {
next.ServeHTTP(rw, req)
} else {
doAuth(roles, serverConfig, next, rw, req)
}
})
}
}
8 changes: 4 additions & 4 deletions pkg/server/router.go
Expand Up @@ -52,7 +52,7 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler

prefix := "/v1-" + version.Program
authed := mux.NewRouter().SkipClean(true)
authed.Use(auth.Middleware(serverConfig, version.Program+":agent", user.NodesGroup, bootstrapapi.BootstrapDefaultGroup))
authed.Use(auth.HasRole(serverConfig, version.Program+":agent", user.NodesGroup, bootstrapapi.BootstrapDefaultGroup))
authed.Path(prefix + "/serving-kubelet.crt").Handler(servingKubeletCert(serverConfig, serverConfig.Runtime.ServingKubeletKey, nodeAuth))
authed.Path(prefix + "/client-kubelet.crt").Handler(clientKubeletCert(serverConfig, serverConfig.Runtime.ClientKubeletKey, nodeAuth))
authed.Path(prefix + "/client-kube-proxy.crt").Handler(fileHandler(serverConfig.Runtime.ClientKubeProxyCert, serverConfig.Runtime.ClientKubeProxyKey))
Expand All @@ -71,12 +71,12 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler

nodeAuthed := mux.NewRouter().SkipClean(true)
nodeAuthed.NotFoundHandler = authed
nodeAuthed.Use(auth.Middleware(serverConfig, user.NodesGroup))
nodeAuthed.Use(auth.HasRole(serverConfig, user.NodesGroup))
nodeAuthed.Path(prefix + "/connect").Handler(serverConfig.Runtime.Tunnel)

serverAuthed := mux.NewRouter().SkipClean(true)
serverAuthed.NotFoundHandler = nodeAuthed
serverAuthed.Use(auth.Middleware(serverConfig, version.Program+":server"))
serverAuthed.Use(auth.HasRole(serverConfig, version.Program+":server"))
serverAuthed.Path(prefix + "/encrypt/status").Handler(encryptionStatusHandler(serverConfig))
serverAuthed.Path(prefix + "/encrypt/config").Handler(encryptionConfigHandler(ctx, serverConfig))
serverAuthed.Path(prefix + "/cert/cacerts").Handler(caCertReplaceHandler(serverConfig))
Expand All @@ -86,7 +86,7 @@ func router(ctx context.Context, config *Config, cfg *cmds.Server) http.Handler
systemAuthed := mux.NewRouter().SkipClean(true)
systemAuthed.NotFoundHandler = serverAuthed
systemAuthed.MethodNotAllowedHandler = serverAuthed
systemAuthed.Use(auth.Middleware(serverConfig, user.SystemPrivilegedGroup))
systemAuthed.Use(auth.HasRole(serverConfig, user.SystemPrivilegedGroup))
systemAuthed.Methods(http.MethodConnect).Handler(serverConfig.Runtime.Tunnel)

staticDir := filepath.Join(serverConfig.DataDir, "static")
Expand Down

0 comments on commit b23f142

Please sign in to comment.