diff --git a/cmd/kube-rbac-proxy/app/kube-rbac-proxy.go b/cmd/kube-rbac-proxy/app/kube-rbac-proxy.go index 210062109..1e9b4283c 100644 --- a/cmd/kube-rbac-proxy/app/kube-rbac-proxy.go +++ b/cmd/kube-rbac-proxy/app/kube-rbac-proxy.go @@ -32,11 +32,13 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" waitgroup "k8s.io/apimachinery/pkg/util/waitgroup" "k8s.io/apiserver/pkg/authentication/authenticator" + "k8s.io/apiserver/pkg/authentication/request/bearertoken" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/union" kubefilters "k8s.io/apiserver/pkg/endpoints/filters" "k8s.io/apiserver/pkg/endpoints/request" serverconfig "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" k8sapiflag "k8s.io/component-base/cli/flag" @@ -47,7 +49,6 @@ import ( "k8s.io/klog/v2" "github.com/brancz/kube-rbac-proxy/cmd/kube-rbac-proxy/app/options" - "github.com/brancz/kube-rbac-proxy/pkg/authn" "github.com/brancz/kube-rbac-proxy/pkg/authn/identityheaders" "github.com/brancz/kube-rbac-proxy/pkg/authorization/path" "github.com/brancz/kube-rbac-proxy/pkg/authorization/rewrite" @@ -195,14 +196,14 @@ func Run(cfg *server.KubeRBACProxyConfig) error { var authenticator authenticator.Request // If OIDC configuration provided, use oidc authenticator - if cfg.KubeRBACProxyInfo.OIDC.IssuerURL != "" { - oidcAuthenticator, err := authn.NewOIDCAuthenticator(ctx, cfg.KubeRBACProxyInfo.OIDC) + if cfg.KubeRBACProxyInfo.OIDC.JWTAuthenticator.Issuer.URL != "" { + tokenAuthenticator, err := oidc.New(ctx, *cfg.KubeRBACProxyInfo.OIDC) if err != nil { - return fmt.Errorf("failed to instantiate OIDC authenticator: %w", err) + return fmt.Errorf("setting up oidc failed: %w", err) } - go oidcAuthenticator.Run(ctx) - authenticator = oidcAuthenticator + go cfg.KubeRBACProxyInfo.OIDCDynamicCAContent.Run(ctx, 1) + authenticator = bearertoken.New(tokenAuthenticator) } else { authenticator = cfg.DelegatingAuthentication.Authenticator } diff --git a/cmd/kube-rbac-proxy/app/options/oidcoptions.go b/cmd/kube-rbac-proxy/app/options/oidcoptions.go index 9ebce0678..3ce85522d 100644 --- a/cmd/kube-rbac-proxy/app/options/oidcoptions.go +++ b/cmd/kube-rbac-proxy/app/options/oidcoptions.go @@ -17,23 +17,30 @@ limitations under the License. package options import ( - "github.com/brancz/kube-rbac-proxy/pkg/authn" + "fmt" + + "k8s.io/apiserver/pkg/server/dynamiccertificates" + "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" + "github.com/brancz/kube-rbac-proxy/pkg/server" + "github.com/spf13/pflag" ) type OIDCOptions struct { - *authn.OIDCConfig + oidc.Options + + CAFile string } func (o *OIDCOptions) AddFlags(flagset *pflag.FlagSet) { //Authn OIDC flags - flagset.StringVar(&o.IssuerURL, "oidc-issuer", "", "The URL of the OpenID issuer, only HTTPS scheme will be accepted. If set, it will be used to verify the OIDC JSON Web Token (JWT).") - flagset.StringVar(&o.ClientID, "oidc-clientID", "", "The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.") - flagset.StringVar(&o.UsernameClaim, "oidc-username-claim", "email", "Identifier of the user in JWT claim, by default set to 'email'") - flagset.StringVar(&o.GroupsClaim, "oidc-groups-claim", "groups", "Identifier of groups in JWT claim, by default set to 'groups'") - flagset.StringVar(&o.UsernamePrefix, "oidc-username-prefix", "", "If provided, the username will be prefixed with this value to prevent conflicts with other authentication strategies.") - flagset.StringVar(&o.GroupsPrefix, "oidc-groups-prefix", "", "If provided, all groups will be prefixed with this value to prevent conflicts with other authentication strategies.") + flagset.StringVar(&o.JWTAuthenticator.Issuer.URL, "oidc-issuer", "", "The URL of the OpenID issuer, only HTTPS scheme will be accepted. If set, it will be used to verify the OIDC JSON Web Token (JWT).") + flagset.StringSliceVar(&o.JWTAuthenticator.Issuer.Audiences, "oidc-clientID", []string{}, "The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.") + flagset.StringVar(&o.JWTAuthenticator.ClaimMappings.Username.Claim, "oidc-username-claim", "email", "Identifier of the user in JWT claim, by default set to 'email'") + flagset.StringVar(o.JWTAuthenticator.ClaimMappings.Username.Prefix, "oidc-username-prefix", "", "If provided, the username will be prefixed with this value to prevent conflicts with other authentication strategies.") + flagset.StringVar(&o.JWTAuthenticator.ClaimMappings.Groups.Claim, "oidc-groups-claim", "groups", "Identifier of groups in JWT claim, by default set to 'groups'") + flagset.StringVar(o.JWTAuthenticator.ClaimMappings.Groups.Prefix, "oidc-groups-prefix", "", "If provided, all groups will be prefixed with this value to prevent conflicts with other authentication strategies.") flagset.StringArrayVar(&o.SupportedSigningAlgs, "oidc-sign-alg", []string{"RS256"}, "Supported signing algorithms, default RS256") flagset.StringVar(&o.CAFile, "oidc-ca-file", "", "If set, the OpenID server's certificate will be verified by one of the authorities in the oidc-ca-file, otherwise the host's root CA set will be used.") @@ -45,6 +52,19 @@ func (o *OIDCOptions) Validate() []error { } func (o *OIDCOptions) ApplyTo(c *server.KubeRBACProxyInfo) error { - c.OIDC = o.OIDCConfig + if o.JWTAuthenticator.Issuer.URL == "" { + return nil + } + + dyCA, err := dynamiccertificates.NewDynamicCAContentFromFile("oidc-ca", o.CAFile) + + if err != nil { + return fmt.Errorf("failed to create dynamic CA content: %w", err) + } + + o.CAContentProvider = dyCA + c.OIDC = &o.Options + c.OIDCDynamicCAContent = dyCA + return nil } diff --git a/cmd/kube-rbac-proxy/app/options/options.go b/cmd/kube-rbac-proxy/app/options/options.go index b2958d138..023b4cf26 100644 --- a/cmd/kube-rbac-proxy/app/options/options.go +++ b/cmd/kube-rbac-proxy/app/options/options.go @@ -19,7 +19,6 @@ package options import ( "fmt" - "github.com/brancz/kube-rbac-proxy/pkg/authn" "github.com/brancz/kube-rbac-proxy/pkg/authn/identityheaders" genericoptions "k8s.io/apiserver/pkg/server/options" kubeflags "k8s.io/component-base/cli/flag" @@ -53,9 +52,7 @@ func NewProxyRunOptions() *ProxyRunOptions { ProxyOptions: &ProxyOptions{ UpstreamHeader: &identityheaders.AuthnHeaderConfig{}, }, - OIDCOptions: &OIDCOptions{ - OIDCConfig: &authn.OIDCConfig{}, - }, + OIDCOptions: &OIDCOptions{}, } } diff --git a/pkg/authn/config.go b/pkg/authn/config.go index 216bacabd..46cb11323 100644 --- a/pkg/authn/config.go +++ b/pkg/authn/config.go @@ -16,6 +16,8 @@ limitations under the License. package authn +import "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" + // X509Config holds public client certificate used for authentication requests if specified type X509Config struct { ClientCAFile string @@ -30,12 +32,7 @@ type TokenConfig struct { // OIDCConfig represents configuration used for JWT request authentication type OIDCConfig struct { - IssuerURL string - ClientID string - CAFile string - UsernameClaim string - UsernamePrefix string - GroupsClaim string - GroupsPrefix string - SupportedSigningAlgs []string + CAFile string + + oidc.Options } diff --git a/pkg/authn/oidc.go b/pkg/authn/oidc.go deleted file mode 100644 index f5faee50b..000000000 --- a/pkg/authn/oidc.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authn - -import ( - "context" - "net/http" - - "k8s.io/apiserver/pkg/apis/apiserver" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/request/bearertoken" - "k8s.io/apiserver/pkg/server/dynamiccertificates" - "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" -) - -type OIDCAuthenticator struct { - dynamicClientCA *dynamiccertificates.DynamicFileCAContent - requestAuthenticator authenticator.Request -} - -var ( - _ (authenticator.Request) = (*OIDCAuthenticator)(nil) -) - -// NewOIDCAuthenticator returns OIDC authenticator -func NewOIDCAuthenticator(ctx context.Context, config *OIDCConfig) (*OIDCAuthenticator, error) { - dyCA, err := dynamiccertificates.NewDynamicCAContentFromFile("oidc-ca", config.CAFile) - if err != nil { - return nil, err - } - - tokenAuthenticator, err := oidc.New(ctx, oidc.Options{ - JWTAuthenticator: apiserver.JWTAuthenticator{ - Issuer: apiserver.Issuer{ - URL: config.IssuerURL, - Audiences: []string{config.ClientID}, - }, - ClaimMappings: apiserver.ClaimMappings{ - Username: apiserver.PrefixedClaimOrExpression{ - Prefix: &config.UsernamePrefix, - Claim: config.UsernameClaim, - }, - Groups: apiserver.PrefixedClaimOrExpression{ - Prefix: &config.GroupsPrefix, - Claim: config.GroupsClaim, - }, - }, - }, - CAContentProvider: dyCA, - SupportedSigningAlgs: config.SupportedSigningAlgs, - }) - if err != nil { - return nil, err - } - - return &OIDCAuthenticator{ - dynamicClientCA: dyCA, - requestAuthenticator: bearertoken.New(tokenAuthenticator), - }, nil -} - -func (o *OIDCAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { - return o.requestAuthenticator.AuthenticateRequest(req) -} - -func (o *OIDCAuthenticator) Run(ctx context.Context) { - if o.dynamicClientCA != nil { - o.dynamicClientCA.Run(ctx, 1) - } -} diff --git a/pkg/server/config.go b/pkg/server/config.go index 00cf742f2..e7b341600 100644 --- a/pkg/server/config.go +++ b/pkg/server/config.go @@ -26,8 +26,9 @@ import ( "os" serverconfig "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/dynamiccertificates" + "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" - "github.com/brancz/kube-rbac-proxy/pkg/authn" "github.com/brancz/kube-rbac-proxy/pkg/authn/identityheaders" authz "github.com/brancz/kube-rbac-proxy/pkg/authorization" "github.com/brancz/kube-rbac-proxy/pkg/authorization/rewrite" @@ -55,7 +56,8 @@ type KubeRBACProxyInfo struct { Authorization *authz.AuthzConfig - OIDC *authn.OIDCConfig + OIDC *oidc.Options + OIDCDynamicCAContent *dynamiccertificates.DynamicFileCAContent AllowPaths []string IgnorePaths []string