mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-29 21:29:24 +00:00
*: add webhook implementation of authorizer.Authorizer plugin
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer/union"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/webhook"
|
||||
)
|
||||
|
||||
// Attributes implements authorizer.Attributes interface.
|
||||
@@ -60,15 +61,28 @@ const (
|
||||
ModeAlwaysAllow string = "AlwaysAllow"
|
||||
ModeAlwaysDeny string = "AlwaysDeny"
|
||||
ModeABAC string = "ABAC"
|
||||
ModeWebhook string = "Webhook"
|
||||
)
|
||||
|
||||
// Keep this list in sync with constant list above.
|
||||
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC}
|
||||
var AuthorizationModeChoices = []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC, ModeWebhook}
|
||||
|
||||
type AuthorizationConfig struct {
|
||||
// Options for ModeABAC
|
||||
|
||||
// Path to a ABAC policy file.
|
||||
PolicyFile string
|
||||
|
||||
// Options for ModeWebhook
|
||||
|
||||
// Kubeconfig file for Webhook authorization plugin.
|
||||
WebhookConfigFile string
|
||||
}
|
||||
|
||||
// NewAuthorizerFromAuthorizationConfig returns the right sort of union of multiple authorizer.Authorizer objects
|
||||
// based on the authorizationMode or an error. authorizationMode should be a comma separated values
|
||||
// of AuthorizationModeChoices.
|
||||
func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, authorizationPolicyFile string) (authorizer.Authorizer, error) {
|
||||
func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, config AuthorizationConfig) (authorizer.Authorizer, error) {
|
||||
|
||||
if len(authorizationModes) == 0 {
|
||||
return nil, errors.New("Atleast one authorization mode should be passed")
|
||||
@@ -88,23 +102,35 @@ func NewAuthorizerFromAuthorizationConfig(authorizationModes []string, authoriza
|
||||
case ModeAlwaysDeny:
|
||||
authorizers = append(authorizers, NewAlwaysDenyAuthorizer())
|
||||
case ModeABAC:
|
||||
if authorizationPolicyFile == "" {
|
||||
if config.PolicyFile == "" {
|
||||
return nil, errors.New("ABAC's authorization policy file not passed")
|
||||
}
|
||||
abacAuthorizer, err := abac.NewFromFile(authorizationPolicyFile)
|
||||
abacAuthorizer, err := abac.NewFromFile(config.PolicyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorizers = append(authorizers, abacAuthorizer)
|
||||
case ModeWebhook:
|
||||
if config.WebhookConfigFile == "" {
|
||||
return nil, errors.New("Webhook's configuration file not passed")
|
||||
}
|
||||
webhookAuthorizer, err := webhook.New(config.WebhookConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorizers = append(authorizers, webhookAuthorizer)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown authorization mode %s specified", authorizationMode)
|
||||
}
|
||||
authorizerMap[authorizationMode] = true
|
||||
}
|
||||
|
||||
if !authorizerMap[ModeABAC] && authorizationPolicyFile != "" {
|
||||
if !authorizerMap[ModeABAC] && config.PolicyFile != "" {
|
||||
return nil, errors.New("Cannot specify --authorization-policy-file without mode ABAC")
|
||||
}
|
||||
if !authorizerMap[ModeWebhook] && config.WebhookConfigFile != "" {
|
||||
return nil, errors.New("Cannot specify --authorization-webhook-config-file without mode Webhook")
|
||||
}
|
||||
|
||||
return union.New(authorizers...), nil
|
||||
}
|
||||
|
||||
@@ -41,31 +41,75 @@ func TestNewAlwaysDenyAuthorizer(t *testing.T) {
|
||||
// NewAuthorizerFromAuthorizationConfig has multiple return possibilities. This test
|
||||
// validates that errors are returned only when proper.
|
||||
func TestNewAuthorizerFromAuthorizationConfig(t *testing.T) {
|
||||
// Unknown modes should return errors
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{"DoesNotExist"}, ""); err == nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig using a fake mode should have returned an error")
|
||||
|
||||
examplePolicyFile := "../auth/authorizer/abac/example_policy_file.jsonl"
|
||||
|
||||
tests := []struct {
|
||||
modes []string
|
||||
config AuthorizationConfig
|
||||
wantErr bool
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
// Unknown modes should return errors
|
||||
modes: []string{"DoesNotExist"},
|
||||
wantErr: true,
|
||||
msg: "using a fake mode should have returned an error",
|
||||
},
|
||||
{
|
||||
// ModeAlwaysAllow and ModeAlwaysDeny should return without authorizationPolicyFile
|
||||
// but error if one is given
|
||||
modes: []string{ModeAlwaysAllow, ModeAlwaysDeny},
|
||||
msg: "returned an error for valid config",
|
||||
},
|
||||
{
|
||||
// ModeABAC requires a policy file
|
||||
modes: []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC},
|
||||
wantErr: true,
|
||||
msg: "specifying ABAC with no policy file should return an error",
|
||||
},
|
||||
{
|
||||
// ModeABAC should not error if a valid policy path is provided
|
||||
modes: []string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC},
|
||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
||||
msg: "errored while using a valid policy file",
|
||||
},
|
||||
{
|
||||
|
||||
// Authorization Policy file cannot be used without ModeABAC
|
||||
modes: []string{ModeAlwaysAllow, ModeAlwaysDeny},
|
||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
||||
wantErr: true,
|
||||
msg: "should have errored when Authorization Policy File is used without ModeABAC",
|
||||
},
|
||||
{
|
||||
// Atleast one authorizationMode is necessary
|
||||
modes: []string{},
|
||||
config: AuthorizationConfig{PolicyFile: examplePolicyFile},
|
||||
wantErr: true,
|
||||
msg: "should have errored when no authorization modes are passed",
|
||||
},
|
||||
{
|
||||
// ModeWebhook requires at minimum a target.
|
||||
modes: []string{ModeWebhook},
|
||||
wantErr: true,
|
||||
msg: "should have errored when config was empty with ModeWebhook",
|
||||
},
|
||||
{
|
||||
// Cannot provide webhook flags without ModeWebhook
|
||||
modes: []string{ModeAlwaysAllow},
|
||||
config: AuthorizationConfig{WebhookConfigFile: "authz_webhook_config.yml"},
|
||||
wantErr: true,
|
||||
msg: "should have errored when Webhook config file is used without ModeWebhook",
|
||||
},
|
||||
}
|
||||
|
||||
// ModeAlwaysAllow and ModeAlwaysDeny should return without authorizationPolicyFile
|
||||
// but error if one is given
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{ModeAlwaysAllow, ModeAlwaysDeny}, ""); err != nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig returned an error: %s", err)
|
||||
}
|
||||
|
||||
// ModeABAC requires a policy file
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC}, ""); err == nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig using a fake mode should have returned an error")
|
||||
}
|
||||
// ModeABAC should not error if a valid policy path is provided
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{ModeAlwaysAllow, ModeAlwaysDeny, ModeABAC}, "../auth/authorizer/abac/example_policy_file.jsonl"); err != nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig errored while using a valid policy file: %s", err)
|
||||
}
|
||||
// Authorization Policy file cannot be used without ModeABAC
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{ModeAlwaysAllow, ModeAlwaysDeny}, "../auth/authorizer/abac/example_policy_file.jsonl"); err == nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig should have errored when Authorization Policy File is used without ModeABAC")
|
||||
}
|
||||
// Atleast one authorizationMode is necessary
|
||||
if _, err := NewAuthorizerFromAuthorizationConfig([]string{}, "../auth/authorizer/abac/example_policy_file.jsonl"); err == nil {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig should have errored when no authorization modes are passed")
|
||||
for _, tt := range tests {
|
||||
_, err := NewAuthorizerFromAuthorizationConfig(tt.modes, tt.config)
|
||||
if tt.wantErr && (err == nil) {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig %s", tt.msg)
|
||||
} else if !tt.wantErr && (err != nil) {
|
||||
t.Errorf("NewAuthorizerFromAuthorizationConfig %s: %v", tt.msg, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user