Skip to content

Commit d26c154

Browse files
authored
Merge pull request kubernetes#121818 from liggitt/authz-config-rbac-anonymous
Test authz config file with RBAC and anonymous auth
2 parents eb6fece + 819d190 commit d26c154

File tree

5 files changed

+63
-23
lines changed

5 files changed

+63
-23
lines changed

hack/local-up-cluster.sh

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ ENABLE_TRACING=${ENABLE_TRACING:-false}
9999
# enable Kubernetes-CSI snapshotter
100100
ENABLE_CSI_SNAPSHOTTER=${ENABLE_CSI_SNAPSHOTTER:-false}
101101

102-
# RBAC Mode options
103-
AUTHORIZATION_MODE=${AUTHORIZATION_MODE:-"Node,RBAC"}
104102
KUBECONFIG_TOKEN=${KUBECONFIG_TOKEN:-""}
105103
AUTH_ARGS=${AUTH_ARGS:-""}
106104

@@ -494,10 +492,19 @@ function start_apiserver {
494492
# Append security_admission plugin
495493
ENABLE_ADMISSION_PLUGINS="${ENABLE_ADMISSION_PLUGINS}${security_admission}"
496494

497-
authorizer_arg=""
498-
if [[ -n "${AUTHORIZATION_MODE}" ]]; then
499-
authorizer_arg="--authorization-mode=${AUTHORIZATION_MODE}"
495+
authorizer_args=()
496+
if [[ -n "${AUTHORIZATION_CONFIG:-}" ]]; then
497+
authorizer_args+=("--authorization-config=${AUTHORIZATION_CONFIG}")
498+
else
499+
if [[ -n "${AUTHORIZATION_MODE:-Node,RBAC}" ]]; then
500+
authorizer_args+=("--authorization-mode=${AUTHORIZATION_MODE:-Node,RBAC}")
501+
fi
502+
authorizer_args+=(
503+
"--authorization-webhook-config-file=${AUTHORIZATION_WEBHOOK_CONFIG_FILE}"
504+
"--authentication-token-webhook-config-file=${AUTHENTICATION_WEBHOOK_CONFIG_FILE}"
505+
)
500506
fi
507+
501508
priv_arg=""
502509
if [[ -n "${ALLOW_PRIVILEGED}" ]]; then
503510
priv_arg="--allow-privileged=${ALLOW_PRIVILEGED}"
@@ -570,16 +577,14 @@ EOF
570577

571578
APISERVER_LOG=${LOG_DIR}/kube-apiserver.log
572579
# shellcheck disable=SC2086
573-
${CONTROLPLANE_SUDO} "${GO_OUT}/kube-apiserver" "${authorizer_arg}" "${priv_arg}" ${runtime_config} \
580+
${CONTROLPLANE_SUDO} "${GO_OUT}/kube-apiserver" "${authorizer_args[@]}" "${priv_arg}" ${runtime_config} \
574581
${cloud_config_arg} \
575582
"${advertise_address}" \
576583
"${node_port_range}" \
577584
--v="${LOG_LEVEL}" \
578585
--vmodule="${LOG_SPEC}" \
579586
--audit-policy-file="${AUDIT_POLICY_FILE}" \
580587
--audit-log-path="${LOG_DIR}/kube-apiserver-audit.log" \
581-
--authorization-webhook-config-file="${AUTHORIZATION_WEBHOOK_CONFIG_FILE}" \
582-
--authentication-token-webhook-config-file="${AUTHENTICATION_WEBHOOK_CONFIG_FILE}" \
583588
--cert-dir="${CERT_DIR}" \
584589
--egress-selector-config-file="${EGRESS_SELECTOR_CONFIG_FILE:-}" \
585590
--client-ca-file="${CERT_DIR}/client-ca.crt" \
@@ -613,14 +618,15 @@ EOF
613618
--cors-allowed-origins="${API_CORS_ALLOWED_ORIGINS}" >"${APISERVER_LOG}" 2>&1 &
614619
APISERVER_PID=$!
615620

621+
# Create kubeconfigs for all components, using client certs
622+
kube::util::write_client_kubeconfig "${CONTROLPLANE_SUDO}" "${CERT_DIR}" "${ROOT_CA_FILE}" "${API_HOST}" "${API_SECURE_PORT}" admin
623+
${CONTROLPLANE_SUDO} chown "${USER}" "${CERT_DIR}/client-admin.key" # make readable for kubectl
624+
616625
# Wait for kube-apiserver to come up before launching the rest of the components.
617626
echo "Waiting for apiserver to come up"
618627
kube::util::wait_for_url "https://${API_HOST_IP}:${API_SECURE_PORT}/healthz" "apiserver: " 1 "${WAIT_FOR_URL_API_SERVER}" "${MAX_TIME_FOR_URL_API_SERVER}" \
619628
|| { echo "check apiserver logs: ${APISERVER_LOG}" ; exit 1 ; }
620629

621-
# Create kubeconfigs for all components, using client certs
622-
kube::util::write_client_kubeconfig "${CONTROLPLANE_SUDO}" "${CERT_DIR}" "${ROOT_CA_FILE}" "${API_HOST}" "${API_SECURE_PORT}" admin
623-
${CONTROLPLANE_SUDO} chown "${USER}" "${CERT_DIR}/client-admin.key" # make readable for kubectl
624630
kube::util::write_client_kubeconfig "${CONTROLPLANE_SUDO}" "${CERT_DIR}" "${ROOT_CA_FILE}" "${API_HOST}" "${API_SECURE_PORT}" controller
625631
kube::util::write_client_kubeconfig "${CONTROLPLANE_SUDO}" "${CERT_DIR}" "${ROOT_CA_FILE}" "${API_HOST}" "${API_SECURE_PORT}" scheduler
626632

pkg/controlplane/apiserver/config.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,13 @@ func BuildGenericConfig(
147147
return
148148
}
149149

150-
genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, err = BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers)
150+
var enablesRBAC bool
151+
genericConfig.Authorization.Authorizer, genericConfig.RuleResolver, enablesRBAC, err = BuildAuthorizer(s, genericConfig.EgressSelector, versionedInformers)
151152
if err != nil {
152153
lastErr = fmt.Errorf("invalid authorization config: %v", err)
153154
return
154155
}
155-
if s.Authorization != nil && !sets.NewString(s.Authorization.Modes...).Has(modes.ModeRBAC) {
156+
if s.Authorization != nil && !enablesRBAC {
156157
genericConfig.DisabledPostStartHooks.Insert(rbacrest.PostStartHookName)
157158
}
158159

@@ -168,25 +169,35 @@ func BuildGenericConfig(
168169
return
169170
}
170171

171-
// BuildAuthorizer constructs the authorizer. If authorization is not set in s, it returns nil, nil, nil
172-
func BuildAuthorizer(s controlplaneapiserver.CompletedOptions, EgressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
172+
// BuildAuthorizer constructs the authorizer. If authorization is not set in s, it returns nil, nil, false, nil
173+
func BuildAuthorizer(s controlplaneapiserver.CompletedOptions, egressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, bool, error) {
173174
authorizationConfig, err := s.Authorization.ToAuthorizationConfig(versionedInformers)
174175
if err != nil {
175-
return nil, nil, err
176+
return nil, nil, false, err
176177
}
177178
if authorizationConfig == nil {
178-
return nil, nil, nil
179+
return nil, nil, false, nil
179180
}
180181

181-
if EgressSelector != nil {
182-
egressDialer, err := EgressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext())
182+
if egressSelector != nil {
183+
egressDialer, err := egressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext())
183184
if err != nil {
184-
return nil, nil, err
185+
return nil, nil, false, err
185186
}
186187
authorizationConfig.CustomDial = egressDialer
187188
}
188189

189-
return authorizationConfig.New()
190+
enablesRBAC := false
191+
for _, a := range authorizationConfig.AuthorizationConfiguration.Authorizers {
192+
if string(a.Type) == modes.ModeRBAC {
193+
enablesRBAC = true
194+
break
195+
}
196+
}
197+
198+
authorizer, ruleResolver, err := authorizationConfig.New()
199+
200+
return authorizer, ruleResolver, enablesRBAC, err
190201
}
191202

192203
// CreatePeerEndpointLeaseReconciler creates a apiserver endpoint lease reconciliation loop

pkg/controlplane/apiserver/options/options.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ func (o *Options) Complete(alternateDNS []string, alternateIPs []net.IP) (Comple
222222
klog.Infof("external host was not specified, using %v", completed.GenericServerRunOptions.ExternalHost)
223223
}
224224

225+
// put authorization options in final state
226+
completed.Authorization.Complete()
227+
// adjust authentication for completed authorization
225228
completed.Authentication.ApplyAuthorization(completed.Authorization)
226229

227230
// Use (ServiceAccountSigningKeyFile != "") as a proxy to the user enabling

pkg/kubeapiserver/options/authorization.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,22 @@ type BuiltInAuthorizationOptions struct {
8080
// NewBuiltInAuthorizationOptions create a BuiltInAuthorizationOptions with default value
8181
func NewBuiltInAuthorizationOptions() *BuiltInAuthorizationOptions {
8282
return &BuiltInAuthorizationOptions{
83-
Modes: []string{authzmodes.ModeAlwaysAllow},
83+
Modes: []string{},
8484
WebhookVersion: "v1beta1",
8585
WebhookCacheAuthorizedTTL: 5 * time.Minute,
8686
WebhookCacheUnauthorizedTTL: 30 * time.Second,
8787
WebhookRetryBackoff: genericoptions.DefaultAuthWebhookRetryBackoff(),
8888
}
8989
}
9090

91+
// Complete modifies authorization options
92+
func (o *BuiltInAuthorizationOptions) Complete() []error {
93+
if len(o.AuthorizationConfigurationFile) == 0 && len(o.Modes) == 0 {
94+
o.Modes = []string{authzmodes.ModeAlwaysAllow}
95+
}
96+
return nil
97+
}
98+
9199
// Validate checks invalid config combination
92100
func (o *BuiltInAuthorizationOptions) Validate() []error {
93101
if o == nil {
@@ -185,7 +193,7 @@ func (o *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
185193
}
186194

187195
fs.StringSliceVar(&o.Modes, authorizationModeFlag, o.Modes, ""+
188-
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: "+
196+
"Ordered list of plug-ins to do authorization on secure port. Defaults to AlwaysAllow if --authorization-config is not used. Comma-delimited list of: "+
189197
strings.Join(authzmodes.AuthorizationModeChoices, ",")+".")
190198

191199
fs.StringVar(&o.PolicyFile, authorizationPolicyFileFlag, o.PolicyFile, ""+

test/integration/auth/authz_config_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package auth
1818

1919
import (
20+
"bytes"
2021
"context"
2122
"encoding/json"
2223
"fmt"
@@ -34,6 +35,7 @@ import (
3435
"k8s.io/apiserver/pkg/features"
3536
utilfeature "k8s.io/apiserver/pkg/util/feature"
3637
clientset "k8s.io/client-go/kubernetes"
38+
"k8s.io/client-go/rest"
3739
featuregatetesting "k8s.io/component-base/featuregate/testing"
3840
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
3941
"k8s.io/kubernetes/test/integration/authutil"
@@ -63,6 +65,16 @@ authorizers:
6365
)
6466
t.Cleanup(server.TearDownFn)
6567

68+
// Make sure anonymous requests work
69+
anonymousClient := clientset.NewForConfigOrDie(rest.AnonymousClientConfig(server.ClientConfig))
70+
healthzResult, err := anonymousClient.DiscoveryClient.RESTClient().Get().AbsPath("/healthz").Do(context.TODO()).Raw()
71+
if !bytes.Equal(healthzResult, []byte(`ok`)) {
72+
t.Fatalf("expected 'ok', got %s", string(healthzResult))
73+
}
74+
if err != nil {
75+
t.Fatal(err)
76+
}
77+
6678
adminClient := clientset.NewForConfigOrDie(server.ClientConfig)
6779

6880
sar := &authorizationv1.SubjectAccessReview{Spec: authorizationv1.SubjectAccessReviewSpec{

0 commit comments

Comments
 (0)