mirror of https://github.com/kubernetes/kops.git
feat: Support multiple token verifiers in kops-controller
This will allow us to support nodes running in multiple clouds. If we don't configure multiple verifiers, this should be a no-op.
This commit is contained in:
parent
6f7fcb0a9a
commit
592b575412
|
|
@ -124,52 +124,67 @@ func main() {
|
|||
vfsContext := vfs.NewVFSContext()
|
||||
|
||||
if opt.Server != nil {
|
||||
var verifier bootstrap.Verifier
|
||||
var verifiers []bootstrap.Verifier
|
||||
var err error
|
||||
if opt.Server.Provider.AWS != nil {
|
||||
verifier, err = awsup.NewAWSVerifier(opt.Server.Provider.AWS)
|
||||
verifier, err := awsup.NewAWSVerifier(opt.Server.Provider.AWS)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.GCE != nil {
|
||||
verifier, err = gcetpmverifier.NewTPMVerifier(opt.Server.Provider.GCE)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.GCE != nil {
|
||||
verifier, err := gcetpmverifier.NewTPMVerifier(opt.Server.Provider.GCE)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.Hetzner != nil {
|
||||
verifier, err = hetzner.NewHetznerVerifier(opt.Server.Provider.Hetzner)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.Hetzner != nil {
|
||||
verifier, err := hetzner.NewHetznerVerifier(opt.Server.Provider.Hetzner)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.OpenStack != nil {
|
||||
verifier, err = openstack.NewOpenstackVerifier(opt.Server.Provider.OpenStack)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.OpenStack != nil {
|
||||
verifier, err := openstack.NewOpenstackVerifier(opt.Server.Provider.OpenStack)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.DigitalOcean != nil {
|
||||
verifier, err = do.NewVerifier(ctx, opt.Server.Provider.DigitalOcean)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.DigitalOcean != nil {
|
||||
verifier, err := do.NewVerifier(ctx, opt.Server.Provider.DigitalOcean)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.Scaleway != nil {
|
||||
verifier, err = scaleway.NewScalewayVerifier(ctx, opt.Server.Provider.Scaleway)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.Scaleway != nil {
|
||||
verifier, err := scaleway.NewScalewayVerifier(ctx, opt.Server.Provider.Scaleway)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else if opt.Server.Provider.Azure != nil {
|
||||
verifier, err = azure.NewAzureVerifier(ctx, opt.Server.Provider.Azure)
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
if opt.Server.Provider.Azure != nil {
|
||||
verifier, err := azure.NewAzureVerifier(ctx, opt.Server.Provider.Azure)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create verifier")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
klog.Fatalf("server cloud provider config not provided")
|
||||
verifiers = append(verifiers, verifier)
|
||||
}
|
||||
|
||||
if len(verifiers) == 0 {
|
||||
klog.Fatalf("server verifiers not provided")
|
||||
}
|
||||
|
||||
uncachedClient, err := client.New(mgr.GetConfig(), client.Options{
|
||||
|
|
@ -181,6 +196,8 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
verifier := bootstrap.NewChainVerifier(verifiers...)
|
||||
|
||||
srv, err := server.NewServer(vfsContext, &opt, verifier, uncachedClient)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create server")
|
||||
|
|
|
|||
|
|
@ -49,5 +49,12 @@ type VerifyResult struct {
|
|||
|
||||
// Verifier verifies authentication credentials for requests.
|
||||
type Verifier interface {
|
||||
// VerifyToken performs full validation of the provided token, often making cloud API calls to verify the caller.
|
||||
// It should return either an error or a validated VerifyResult.
|
||||
// If the token looks like it is intended for a different verifier
|
||||
// (for example it has the wrong prefix), we should return ErrNotThisVerifier
|
||||
VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*VerifyResult, error)
|
||||
}
|
||||
|
||||
// ErrNotThisVerifier is returned when a verifier receives a token that is not intended for it.
|
||||
var ErrNotThisVerifier = errors.New("token not valid for this verifier")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
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 bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// NewChainVerifier creates a new Verifier that will return the first positive verification from the provided Verifiers.
|
||||
func NewChainVerifier(chain ...Verifier) Verifier {
|
||||
return &ChainVerifier{chain: chain}
|
||||
}
|
||||
|
||||
// ChainVerifier wraps multiple Verifiers; the first positive verification from any Verifier will be returned.
|
||||
type ChainVerifier struct {
|
||||
chain []Verifier
|
||||
}
|
||||
|
||||
// VerifyToken will return the first positive verification from any Verifier in the chain.
|
||||
func (v *ChainVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*VerifyResult, error) {
|
||||
for _, verifier := range v.chain {
|
||||
result, err := verifier.VerifyToken(ctx, rawRequest, token, body)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if err == ErrNotThisVerifier {
|
||||
continue
|
||||
}
|
||||
klog.Infof("failed to verify token: %v", err)
|
||||
}
|
||||
return nil, fmt.Errorf("unable to verify token")
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ type ResponseMetadata struct {
|
|||
|
||||
func (a awsVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, AWSAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
token = strings.TrimPrefix(token, AWSAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func NewAzureVerifier(ctx context.Context, opt *AzureVerifierOptions) (bootstrap
|
|||
|
||||
func (a azureVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, AzureAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
|
||||
v := strings.Split(strings.TrimPrefix(token, AzureAuthenticationTokenPrefix), " ")
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func NewVerifier(ctx context.Context, opt *DigitalOceanVerifierOptions) (bootstr
|
|||
|
||||
func (o digitalOceanVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, DOAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
serverIDString := strings.TrimPrefix(token, DOAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ func (v *tpmVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request,
|
|||
// Thankfully the GCE SDK does seem to escape the parameters correctly, for example.
|
||||
|
||||
if !strings.HasPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
authToken = strings.TrimPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func NewHetznerVerifier(opt *HetznerVerifierOptions) (bootstrap.Verifier, error)
|
|||
|
||||
func (h hetznerVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, HetznerAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
token = strings.TrimPrefix(token, HetznerAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ func readKubeConfig() (*restclient.Config, error) {
|
|||
|
||||
func (o openstackVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, OpenstackAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
serverID := strings.TrimPrefix(token, OpenstackAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func NewScalewayVerifier(ctx context.Context, opt *ScalewayVerifierOptions) (boo
|
|||
|
||||
func (v scalewayVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
|
||||
if !strings.HasPrefix(token, ScalewayAuthenticationTokenPrefix) {
|
||||
return nil, fmt.Errorf("incorrect authorization type")
|
||||
return nil, bootstrap.ErrNotThisVerifier
|
||||
}
|
||||
serverID := strings.TrimPrefix(token, ScalewayAuthenticationTokenPrefix)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue