Commit af0b496e authored by Brad Davidson's avatar Brad Davidson Committed by Brad Davidson

Add client certificate authentication support to core Authenticator

This is required to make the websocket tunnel server functional on etcd-only nodes, and will save some code on the RKE2 side once pulled through. Signed-off-by: 's avatarBrad Davidson <brad.davidson@rancher.com>
parent e7437d4a
package control package authenticator
import ( import (
"strings"
"github.com/k3s-io/k3s/pkg/authenticator/basicauth" "github.com/k3s-io/k3s/pkg/authenticator/basicauth"
"github.com/k3s-io/k3s/pkg/authenticator/passwordfile" "github.com/k3s-io/k3s/pkg/authenticator/passwordfile"
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/group" "k8s.io/apiserver/pkg/authentication/group"
"k8s.io/apiserver/pkg/authentication/request/union" "k8s.io/apiserver/pkg/authentication/request/union"
"k8s.io/apiserver/pkg/authentication/request/x509"
"k8s.io/apiserver/pkg/server/dynamiccertificates"
) )
func basicAuthenticator(basicAuthFile string) (authenticator.Request, error) { func FromArgs(args []string) (authenticator.Request, error) {
if basicAuthFile == "" { var authenticators []authenticator.Request
return nil, nil basicFile := getArg("--basic-auth-file", args)
if basicFile != "" {
basicAuthenticator, err := passwordfile.NewCSV(basicFile)
if err != nil {
return nil, err
}
authenticators = append(authenticators, basicauth.New(basicAuthenticator))
}
clientCA := getArg("--client-ca-file", args)
if clientCA != "" {
ca, err := dynamiccertificates.NewDynamicCAContentFromFile("client-ca", clientCA)
if err != nil {
return nil, err
}
authenticators = append(authenticators, x509.NewDynamic(ca.VerifyOptions, x509.CommonNameUserConversion))
} }
basicAuthenticator, err := passwordfile.NewCSV(basicAuthFile)
if err != nil { return Combine(authenticators...), nil
return nil, err }
func getArg(key string, args []string) string {
for _, arg := range args {
if !strings.HasPrefix(arg, key) {
continue
}
return strings.SplitN(arg, "=", 2)[1]
} }
return basicauth.New(basicAuthenticator), nil return ""
} }
func combineAuthenticators(auths ...authenticator.Request) authenticator.Request { func Combine(auths ...authenticator.Request) authenticator.Request {
var authenticators []authenticator.Request var authenticators []authenticator.Request
for _, auth := range auths { for _, auth := range auths {
if auth != nil { if auth != nil {
......
...@@ -20,17 +20,16 @@ import ( ...@@ -20,17 +20,16 @@ import (
"errors" "errors"
"net/http" "net/http"
localAuthenticator "github.com/k3s-io/k3s/pkg/authenticator"
"k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/authenticator"
) )
// Authenticator authenticates requests using basic auth // Authenticator authenticates requests using basic auth
type Authenticator struct { type Authenticator struct {
auth localAuthenticator.Password auth Password
} }
// New returns a request authenticator that validates credentials using the provided password authenticator // New returns a request authenticator that validates credentials using the provided password authenticator
func New(auth localAuthenticator.Password) *Authenticator { func New(auth Password) *Authenticator {
return &Authenticator{auth} return &Authenticator{auth}
} }
......
...@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and ...@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package authenticator package basicauth
import ( import (
"context" "context"
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/k3s-io/k3s/pkg/authenticator"
"github.com/k3s-io/k3s/pkg/cluster" "github.com/k3s-io/k3s/pkg/cluster"
"github.com/k3s-io/k3s/pkg/daemons/config" "github.com/k3s-io/k3s/pkg/daemons/config"
"github.com/k3s-io/k3s/pkg/daemons/control/deps" "github.com/k3s-io/k3s/pkg/daemons/control/deps"
...@@ -56,11 +57,15 @@ func Server(ctx context.Context, cfg *config.Control) error { ...@@ -56,11 +57,15 @@ func Server(ctx context.Context, cfg *config.Control) error {
cfg.Runtime.Tunnel = setupTunnel() cfg.Runtime.Tunnel = setupTunnel()
proxyutil.DisableProxyHostnameCheck = true proxyutil.DisableProxyHostnameCheck = true
basicAuth, err := basicAuthenticator(cfg.Runtime.PasswdFile) authArgs := []string{
"--basic-auth-file=" + cfg.Runtime.PasswdFile,
"--client-ca-file=" + cfg.Runtime.ClientCA,
}
auth, err := authenticator.FromArgs(authArgs)
if err != nil { if err != nil {
return err return err
} }
cfg.Runtime.Authenticator = basicAuth cfg.Runtime.Authenticator = auth
if !cfg.DisableAPIServer { if !cfg.DisableAPIServer {
go waitForAPIServerHandlers(ctx, cfg.Runtime) go waitForAPIServerHandlers(ctx, cfg.Runtime)
...@@ -399,7 +404,7 @@ func waitForAPIServerHandlers(ctx context.Context, runtime *config.ControlRuntim ...@@ -399,7 +404,7 @@ func waitForAPIServerHandlers(ctx context.Context, runtime *config.ControlRuntim
if err != nil { if err != nil {
logrus.Fatalf("Failed to get request handlers from apiserver: %v", err) logrus.Fatalf("Failed to get request handlers from apiserver: %v", err)
} }
runtime.Authenticator = combineAuthenticators(runtime.Authenticator, auth) runtime.Authenticator = authenticator.Combine(runtime.Authenticator, auth)
runtime.APIServer = handler runtime.APIServer = handler
} }
......
...@@ -9,13 +9,20 @@ import ( ...@@ -9,13 +9,20 @@ import (
"github.com/rancher/remotedialer" "github.com/rancher/remotedialer"
"github.com/rancher/wrangler/pkg/kv" "github.com/rancher/wrangler/pkg/kv"
"github.com/sirupsen/logrus"
utilnet "k8s.io/apimachinery/pkg/util/net" utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/kubernetes/cmd/kube-apiserver/app" "k8s.io/kubernetes/cmd/kube-apiserver/app"
) )
func loggingErrorWriter(rw http.ResponseWriter, req *http.Request, code int, err error) {
logrus.Debugf("remoteDialer error: %d %v", code, err)
rw.WriteHeader(code)
rw.Write([]byte(err.Error()))
}
func setupTunnel() http.Handler { func setupTunnel() http.Handler {
tunnelServer := remotedialer.New(authorizer, remotedialer.DefaultErrorWriter) tunnelServer := remotedialer.New(authorizer, loggingErrorWriter)
setupProxyDialer(tunnelServer) setupProxyDialer(tunnelServer)
return tunnelServer return tunnelServer
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment