Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvements in cmd/kube-rbac-proxy #243

Merged
merged 5 commits into from
Jul 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 83 additions & 93 deletions cmd/kube-rbac-proxy/app/kube-rbac-proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ import (
"net/http"
"net/http/httputil"
"os"
"os/signal"
"syscall"
"time"

"github.com/oklog/run"
"github.com/spf13/cobra"
"golang.org/x/net/http2"

utilerrors "k8s.io/apimachinery/pkg/util/errors"
waitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/authorization/union"
Expand Down Expand Up @@ -90,16 +88,15 @@ that can perform RBAC authorization against the Kubernetes API using SubjectAcce
return utilerrors.NewAggregate(errs)
}

return Run(completedOptions)
},
Args: func(cmd *cobra.Command, args []string) error {
for _, arg := range args {
if len(arg) > 0 {
return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
}
// create the KubeRBACProxyConfig based on the completed options
proxyCfg, err := completedOptions.ProxyConfig()
if err != nil {
return err
}
return nil

return Run(proxyCfg)
},
Args: cobra.NoArgs,
}

fs := cmd.Flags()
Expand Down Expand Up @@ -132,6 +129,40 @@ func (o *completedProxyRunOptions) Validate() []error {
return errs
}

func (opts *completedProxyRunOptions) ProxyConfig() (*server.KubeRBACProxyConfig, error) {
proxyConfig := server.NewConfig()
if err := opts.SecureServing.ApplyTo(&proxyConfig.SecureServing); err != nil {
return nil, err
}

if opts.ProxySecureServing != nil {
if err := opts.ProxySecureServing.ApplyTo(&proxyConfig.KubeRBACProxyInfo.ProxyEndpointsSecureServing); err != nil {
return nil, err
}
}
if err := opts.DelegatingAuthentication.ApplyTo(
proxyConfig.DelegatingAuthentication,
proxyConfig.SecureServing,
nil,
); err != nil {
return nil, err
}

if err := opts.DelegatingAuthorization.ApplyTo(proxyConfig.DelegatingAuthorization); err != nil {
return nil, err
}

if err := opts.ProxyOptions.ApplyTo(proxyConfig.KubeRBACProxyInfo, proxyConfig.DelegatingAuthentication); err != nil {
return nil, err
}

if err := opts.OIDCOptions.ApplyTo(proxyConfig.KubeRBACProxyInfo); err != nil {
return nil, err
}

return proxyConfig, nil
}

// Complete sets defaults for the ProxyRunOptions.
// Should be called after the flags are parsed.
func Complete(o *options.ProxyRunOptions) (*completedProxyRunOptions, error) {
Expand Down Expand Up @@ -159,13 +190,8 @@ func Complete(o *options.ProxyRunOptions) (*completedProxyRunOptions, error) {
return completed, nil
}

func Run(opts *completedProxyRunOptions) error {
cfg, err := createKubeRBACProxyConfig(opts)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
func Run(cfg *server.KubeRBACProxyConfig) error {
ctx := serverconfig.SetupSignalContext()

var authenticator authenticator.Request
// If OIDC configuration provided, use oidc authenticator
Expand Down Expand Up @@ -207,100 +233,64 @@ func Run(opts *completedProxyRunOptions) error {
handler := identityheaders.WithAuthHeaders(proxy, cfg.KubeRBACProxyInfo.UpstreamHeaders)
handler = kubefilters.WithAuthorization(handler, authz, scheme.Codecs)
handler = kubefilters.WithAuthentication(handler, authenticator, http.HandlerFunc(filters.UnauthorizedHandler), cfg.DelegatingAuthentication.APIAudiences)
// passing an empty RequestInfoFactory results in attaching a non-resource RequestInfo to the context
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ibihim I'm not sure if I'm missing any other implication of passing an empty RequestInfoFactory, please advise :)

handler = kubefilters.WithRequestInfo(handler, &request.RequestInfoFactory{})
handler = rewrite.WithKubeRBACProxyParamsHandler(handler, cfg.KubeRBACProxyInfo.Authorization.RewriteAttributesConfig)

var wg waitgroup.SafeWaitGroup
serverCtx, cancel := context.WithCancel(ctx)
defer cancel()

// listener for proxying HTTPS with authentication and authorization (on port --secure-port)
mux := http.NewServeMux()
mux.Handle("/", handler)

gr := &run.Group{}
{
gr.Add(secureServerRunner(ctx, cfg.SecureServing, mux))

if cfg.KubeRBACProxyInfo.ProxyEndpointsSecureServing != nil {
proxyEndpointsMux := http.NewServeMux()
proxyEndpointsMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("ok")) })

gr.Add(secureServerRunner(ctx, cfg.KubeRBACProxyInfo.ProxyEndpointsSecureServing, proxyEndpointsMux))
}
}
{
sig := make(chan os.Signal, 1)
gr.Add(func() error {
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
klog.Info("received interrupt, shutting down")
return nil
}, func(err error) {
close(sig)
})
}

if err := gr.Run(); err != nil {
return fmt.Errorf("failed to run groups: %w", err)
if err := wg.Add(1); err != nil {
return err
}

return nil
}

func createKubeRBACProxyConfig(opts *completedProxyRunOptions) (*server.KubeRBACProxyConfig, error) {
proxyConfig := server.NewConfig()
if err := opts.SecureServing.ApplyTo(&proxyConfig.SecureServing); err != nil {
return nil, err
}
go func() {
defer wg.Done()
defer cancel()

if opts.ProxySecureServing != nil {
if err := opts.ProxySecureServing.ApplyTo(&proxyConfig.KubeRBACProxyInfo.ProxyEndpointsSecureServing); err != nil {
return nil, err
stoppedCh, listenerStoppedCh, err := cfg.SecureServing.Serve(mux, 10*time.Second, serverCtx.Done())
if err != nil {
klog.Errorf("%v", err)
return
}
}
if err := opts.DelegatingAuthentication.ApplyTo(
proxyConfig.DelegatingAuthentication,
proxyConfig.SecureServing,
nil,
); err != nil {
return nil, err
}

if err := opts.DelegatingAuthorization.ApplyTo(proxyConfig.DelegatingAuthorization); err != nil {
return nil, err
}

if err := opts.ProxyOptions.ApplyTo(proxyConfig.KubeRBACProxyInfo, proxyConfig.DelegatingAuthentication); err != nil {
return nil, err
}

if err := opts.OIDCOptions.ApplyTo(proxyConfig.KubeRBACProxyInfo); err != nil {
return nil, err
}

return proxyConfig, nil
}
<-listenerStoppedCh
<-stoppedCh
}()

func secureServerRunner(
ctx context.Context,
config *serverconfig.SecureServingInfo,
handler http.Handler,
) (func() error, func(error)) {
serverStopCtx, serverCtxCancel := context.WithCancel(ctx)
if cfg.KubeRBACProxyInfo.ProxyEndpointsSecureServing != nil {
// we need a second listener in order to serve proxy-specific endpoints
// on a different port (--proxy-endpoints-port)
proxyEndpointsMux := http.NewServeMux()
proxyEndpointsMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("ok")) })

runner := func() error {
stoppedCh, listenerStoppedCh, err := config.Serve(handler, 10*time.Second, serverStopCtx.Done())
if err != nil {
serverCtxCancel()
if err := wg.Add(1); err != nil {
return err
}

<-listenerStoppedCh
<-stoppedCh
return err
}
go func() {
defer wg.Done()
defer cancel()

stoppedCh, listenerStoppedCh, err := cfg.KubeRBACProxyInfo.ProxyEndpointsSecureServing.Serve(proxyEndpointsMux, 10*time.Second, serverCtx.Done())
if err != nil {
klog.Errorf("%v", err)
return
}

interrupter := func(err error) {
serverCtxCancel()
<-listenerStoppedCh
<-stoppedCh
}()
}

return runner, interrupter
wg.Wait()

return nil
}

func setupAuthorizer(krbInfo *server.KubeRBACProxyInfo, delegatedAuthz *serverconfig.AuthorizationInfo) (authorizer.Authorizer, error) {
Expand Down
Loading