Merge pull request #42557 from xilabao/use-authorizationModes

Automatic merge from submit-queue

Allow multiple providers for authorizationMode

fixes https://github.com/kubernetes/kubeadm/issues/177
This commit is contained in:
Kubernetes Submit Queue 2017-04-06 08:03:04 -07:00 committed by GitHub
commit 2d66f7bd28
10 changed files with 87 additions and 64 deletions

View File

@ -32,7 +32,7 @@ func KubeadmFuzzerFuncs(t apitesting.TestingCommon) []interface{} {
obj.API.AdvertiseAddress = "foo" obj.API.AdvertiseAddress = "foo"
obj.Networking.ServiceSubnet = "foo" obj.Networking.ServiceSubnet = "foo"
obj.Networking.DNSDomain = "foo" obj.Networking.DNSDomain = "foo"
obj.AuthorizationMode = "foo" obj.AuthorizationModes = []string{"foo"}
obj.CertificatesDir = "foo" obj.CertificatesDir = "foo"
obj.APIServerCertSANs = []string{} obj.APIServerCertSANs = []string{}
obj.Token = "foo" obj.Token = "foo"

View File

@ -33,12 +33,12 @@ type EnvParams struct {
type MasterConfiguration struct { type MasterConfiguration struct {
metav1.TypeMeta metav1.TypeMeta
API API API API
Etcd Etcd Etcd Etcd
Networking Networking Networking Networking
KubernetesVersion string KubernetesVersion string
CloudProvider string CloudProvider string
AuthorizationMode string AuthorizationModes []string
Token string Token string
TokenTTL time.Duration TokenTTL time.Duration

View File

@ -59,8 +59,8 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
obj.Networking.DNSDomain = DefaultServiceDNSDomain obj.Networking.DNSDomain = DefaultServiceDNSDomain
} }
if obj.AuthorizationMode == "" { if len(obj.AuthorizationModes) == 0 {
obj.AuthorizationMode = DefaultAuthorizationMode obj.AuthorizationModes = []string{DefaultAuthorizationMode}
} }
if obj.CertificatesDir == "" { if obj.CertificatesDir == "" {

View File

@ -25,12 +25,12 @@ import (
type MasterConfiguration struct { type MasterConfiguration struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
API API `json:"api"` API API `json:"api"`
Etcd Etcd `json:"etcd"` Etcd Etcd `json:"etcd"`
Networking Networking `json:"networking"` Networking Networking `json:"networking"`
KubernetesVersion string `json:"kubernetesVersion"` KubernetesVersion string `json:"kubernetesVersion"`
CloudProvider string `json:"cloudProvider"` CloudProvider string `json:"cloudProvider"`
AuthorizationMode string `json:"authorizationMode"` AuthorizationModes []string `json:"authorizationModes"`
Token string `json:"token"` Token string `json:"token"`
TokenTTL time.Duration `json:"tokenTTL"` TokenTTL time.Duration `json:"tokenTTL"`

View File

@ -52,7 +52,7 @@ var cloudproviders = []string{
func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList { func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudprovider"))...) allErrs = append(allErrs, ValidateCloudProvider(c.CloudProvider, field.NewPath("cloudprovider"))...)
allErrs = append(allErrs, ValidateAuthorizationMode(c.AuthorizationMode, field.NewPath("authorization-mode"))...) allErrs = append(allErrs, ValidateAuthorizationModes(c.AuthorizationModes, field.NewPath("authorization-mode"))...)
allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...) allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...)
allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...) allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...)
allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...) allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...)
@ -70,11 +70,23 @@ func ValidateNodeConfiguration(c *kubeadm.NodeConfiguration) field.ErrorList {
return allErrs return allErrs
} }
func ValidateAuthorizationMode(authzMode string, fldPath *field.Path) field.ErrorList { func ValidateAuthorizationModes(authzModes []string, fldPath *field.Path) field.ErrorList {
if !authzmodes.IsValidAuthorizationMode(authzMode) { allErrs := field.ErrorList{}
return field.ErrorList{field.Invalid(fldPath, authzMode, "invalid authorization mode")} for _, authzMode := range authzModes {
if !authzmodes.IsValidAuthorizationMode(authzMode) {
allErrs = append(allErrs, field.Invalid(fldPath, authzMode, "invalid authorization mode"))
}
} }
return field.ErrorList{}
found := map[string]bool{}
for _, authzMode := range authzModes {
if found[authzMode] {
allErrs = append(allErrs, field.Invalid(fldPath, authzMode, "duplicate authorization mode"))
continue
}
found[authzMode] = true
}
return allErrs
} }
func ValidateDiscovery(c *kubeadm.NodeConfiguration, fldPath *field.Path) field.ErrorList { func ValidateDiscovery(c *kubeadm.NodeConfiguration, fldPath *field.Path) field.ErrorList {

View File

@ -45,23 +45,26 @@ func TestValidateTokenDiscovery(t *testing.T) {
} }
} }
func TestValidateAuthorizationMode(t *testing.T) { func TestValidateAuthorizationModes(t *testing.T) {
var tests = []struct { var tests = []struct {
s string s []string
f *field.Path f *field.Path
expected bool expected bool
}{ }{
{"", nil, false}, {[]string{""}, nil, false},
{"rBAC", nil, false}, // not supported {[]string{"rBAC"}, nil, false}, // not supported
{"not valid", nil, false}, // not supported {[]string{"rBAC", "Webhook"}, nil, false}, // not supported
{"RBAC", nil, true}, // supported {[]string{"RBAC", "Webhook", "Webhook"}, nil, false}, // not supported
{"Webhook", nil, true}, // supported {[]string{"not valid"}, nil, false}, // not supported
{[]string{"RBAC"}, nil, true}, // supported
{[]string{"Webhook"}, nil, true}, // supported
{[]string{"RBAC", "Webhook"}, nil, true}, // supported
} }
for _, rt := range tests { for _, rt := range tests {
actual := ValidateAuthorizationMode(rt.s, rt.f) actual := ValidateAuthorizationModes(rt.s, rt.f)
if (len(actual) == 0) != rt.expected { if (len(actual) == 0) != rt.expected {
t.Errorf( t.Errorf(
"failed ValidateAuthorizationMode:\n\texpected: %t\n\t actual: %t", "failed ValidateAuthorizationModes:\n\texpected: %t\n\t actual: %t",
rt.expected, rt.expected,
(len(actual) == 0), (len(actual) == 0),
) )
@ -172,7 +175,7 @@ func TestValidateMasterConfiguration(t *testing.T) {
}{ }{
{&kubeadm.MasterConfiguration{}, false}, {&kubeadm.MasterConfiguration{}, false},
{&kubeadm.MasterConfiguration{ {&kubeadm.MasterConfiguration{
AuthorizationMode: "RBAC", AuthorizationModes: []string{"RBAC"},
Networking: kubeadm.Networking{ Networking: kubeadm.Networking{
ServiceSubnet: "10.96.0.1/12", ServiceSubnet: "10.96.0.1/12",
DNSDomain: "cluster.local", DNSDomain: "cluster.local",
@ -180,7 +183,7 @@ func TestValidateMasterConfiguration(t *testing.T) {
CertificatesDir: "/some/cert/dir", CertificatesDir: "/some/cert/dir",
}, false}, }, false},
{&kubeadm.MasterConfiguration{ {&kubeadm.MasterConfiguration{
AuthorizationMode: "RBAC", AuthorizationModes: []string{"RBAC"},
Networking: kubeadm.Networking{ Networking: kubeadm.Networking{
ServiceSubnet: "10.96.0.1/12", ServiceSubnet: "10.96.0.1/12",
DNSDomain: "cluster.local", DNSDomain: "cluster.local",

View File

@ -58,7 +58,7 @@ func setInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error {
} }
fmt.Printf("[init] Using Kubernetes version: %s\n", cfg.KubernetesVersion) fmt.Printf("[init] Using Kubernetes version: %s\n", cfg.KubernetesVersion)
fmt.Printf("[init] Using Authorization mode: %s\n", cfg.AuthorizationMode) fmt.Printf("[init] Using Authorization mode: %v\n", cfg.AuthorizationModes)
// Warn about the limitations with the current cloudprovider solution. // Warn about the limitations with the current cloudprovider solution.
if cfg.CloudProvider != "" { if cfg.CloudProvider != "" {

View File

@ -330,7 +330,7 @@ func getAPIServerCommand(cfg *kubeadmapi.MasterConfiguration, selfHosted bool) [
command = getComponentBaseCommand(apiServer) command = getComponentBaseCommand(apiServer)
command = append(command, getExtraParameters(cfg.APIServerExtraArgs, defaultArguments)...) command = append(command, getExtraParameters(cfg.APIServerExtraArgs, defaultArguments)...)
command = append(command, getAuthzParameters(cfg.AuthorizationMode)...) command = append(command, getAuthzParameters(cfg.AuthorizationModes)...)
if selfHosted { if selfHosted {
command = append(command, "--advertise-address=$(POD_IP)") command = append(command, "--advertise-address=$(POD_IP)")
@ -460,22 +460,23 @@ func getSelfHostedAPIServerEnv() []api.EnvVar {
return append(getProxyEnvVars(), podIPEnvVar) return append(getProxyEnvVars(), podIPEnvVar)
} }
func getAuthzParameters(authzMode string) []string { func getAuthzParameters(modes []string) []string {
command := []string{} command := []string{}
// RBAC is always on. If the user specified // RBAC is always on. If the user specified
authzModes := []string{authzmodes.ModeRBAC} authzModes := []string{authzmodes.ModeRBAC}
if len(authzMode) != 0 && authzMode != authzmodes.ModeRBAC { for _, authzMode := range modes {
authzModes = append(authzModes, authzMode) if len(authzMode) != 0 && authzMode != authzmodes.ModeRBAC {
authzModes = append(authzModes, authzMode)
}
switch authzMode {
case authzmodes.ModeABAC:
command = append(command, "--authorization-policy-file="+kubeadmconstants.AuthorizationPolicyPath)
case authzmodes.ModeWebhook:
command = append(command, "--authorization-webhook-config-file="+kubeadmconstants.AuthorizationWebhookConfigPath)
}
} }
command = append(command, "--authorization-mode="+strings.Join(authzModes, ",")) command = append(command, "--authorization-mode="+strings.Join(authzModes, ","))
switch authzMode {
case authzmodes.ModeABAC:
command = append(command, "--authorization-policy-file="+kubeadmconstants.AuthorizationPolicyPath)
case authzmodes.ModeWebhook:
command = append(command, "--authorization-webhook-config-file="+kubeadmconstants.AuthorizationWebhookConfigPath)
}
return command return command
} }

View File

@ -652,44 +652,53 @@ func TestGetSchedulerCommand(t *testing.T) {
func TestGetAuthzParameters(t *testing.T) { func TestGetAuthzParameters(t *testing.T) {
var tests = []struct { var tests = []struct {
authMode string authMode []string
expected []string expected []string
}{ }{
{ {
authMode: "", authMode: []string{},
expected: []string{ expected: []string{
"--authorization-mode=RBAC", "--authorization-mode=RBAC",
}, },
}, },
{ {
authMode: "RBAC", authMode: []string{"RBAC"},
expected: []string{ expected: []string{
"--authorization-mode=RBAC", "--authorization-mode=RBAC",
}, },
}, },
{ {
authMode: "AlwaysAllow", authMode: []string{"AlwaysAllow"},
expected: []string{ expected: []string{
"--authorization-mode=RBAC,AlwaysAllow", "--authorization-mode=RBAC,AlwaysAllow",
}, },
}, },
{ {
authMode: "AlwaysDeny", authMode: []string{"AlwaysDeny"},
expected: []string{ expected: []string{
"--authorization-mode=RBAC,AlwaysDeny", "--authorization-mode=RBAC,AlwaysDeny",
}, },
}, },
{ {
authMode: "ABAC", authMode: []string{"ABAC"},
expected: []string{ expected: []string{
"--authorization-mode=RBAC,ABAC", "--authorization-mode=RBAC,ABAC",
"--authorization-policy-file=/etc/kubernetes/abac_policy.json", "--authorization-policy-file=/etc/kubernetes/abac_policy.json",
}, },
}, },
{ {
authMode: "Webhook", authMode: []string{"ABAC", "Webhook"},
expected: []string{ expected: []string{
"--authorization-mode=RBAC,Webhook", "--authorization-mode=RBAC,ABAC,Webhook",
"--authorization-policy-file=/etc/kubernetes/abac_policy.json",
"--authorization-webhook-config-file=/etc/kubernetes/webhook_authz.conf",
},
},
{
authMode: []string{"ABAC", "RBAC", "Webhook"},
expected: []string{
"--authorization-mode=RBAC,ABAC,Webhook",
"--authorization-policy-file=/etc/kubernetes/abac_policy.json",
"--authorization-webhook-config-file=/etc/kubernetes/webhook_authz.conf", "--authorization-webhook-config-file=/etc/kubernetes/webhook_authz.conf",
}, },
}, },
@ -697,14 +706,10 @@ func TestGetAuthzParameters(t *testing.T) {
for _, rt := range tests { for _, rt := range tests {
actual := getAuthzParameters(rt.authMode) actual := getAuthzParameters(rt.authMode)
for i := range actual { sort.Strings(actual)
if actual[i] != rt.expected[i] { sort.Strings(rt.expected)
t.Errorf( if !reflect.DeepEqual(actual, rt.expected) {
"failed getAuthzParameters:\n\texpected: %s\n\t actual: %s", t.Errorf("failed getAuthzParameters:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
rt.expected[i],
actual[i],
)
}
} }
} }
} }

View File

@ -525,11 +525,13 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error {
} }
// Check the config for authorization mode // Check the config for authorization mode
switch cfg.AuthorizationMode { for _, authzMode := range cfg.AuthorizationModes {
case authzmodes.ModeABAC: switch authzMode {
checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationPolicyPath}) case authzmodes.ModeABAC:
case authzmodes.ModeWebhook: checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationPolicyPath})
checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationWebhookConfigPath}) case authzmodes.ModeWebhook:
checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationWebhookConfigPath})
}
} }
return RunChecks(checks, os.Stderr) return RunChecks(checks, os.Stderr)