Skip to content

Commit

Permalink
fix: kube-apiserver authorizers order
Browse files Browse the repository at this point in the history
Fixes handling of `kube-apiserver` authorization config authorizers.
order.

Fixes: #10110

Signed-off-by: Noel Georgi <[email protected]>
  • Loading branch information
frezbo committed Jan 14, 2025
1 parent db4ca56 commit e41a995
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 8 deletions.
30 changes: 30 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ preface = """
Talos is built with Go 1.23.4.
"""

[notes.driver-rebind]
title = "Driver Rebind"
description = """\
Expand All @@ -44,6 +45,35 @@ The kernel argument `talos.unified_cgroup_hierarchy` is now ignored.
Kernel parameter `talos.auditd.disabled=1` can be used to disable Talos built-in `auditd` service.
"""

[notes.kube-apiserver-authorization-config]
title = "kube-apiserver Authorization Config"
description = """\
When using `.cluster.apiServer.authorizationConfig` the user provided order for the authorizers is honoured and `Node` and `RBAC` authorizers are always added to the end if not explicitly specified.
Eg: If user provides only `Webhook` authorizer, the final order will be `Webhook`, `Node`, `RBAC`.
To provide a specific order for `Node` or `RBAC` explicitly, user can provide the authorizer in the order they want.
Eg:
```yaml
cluster:
apiServer:
authorizationConfig:
- type: Node
name: Node
- type: Webhook
name: Webhook
webhook:
connectionInfo:
type: InClusterConfig
...
- type: RBAC
name: rbac
```
Usage of `authorization-mode` CLI argument will not support this form of customization.
[make_deps]
[make_deps.tools]
Expand Down
25 changes: 19 additions & 6 deletions internal/app/machined/pkg/controllers/k8s/control_plane.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,6 @@ func NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationControll
var authorizers []k8s.AuthorizationAuthorizersSpec

for _, authorizer := range cfgProvider.Cluster().APIServer().AuthorizationConfig() {
// skip Node and RBAC authorizers as we add them by default later on.
if authorizer.Type() == "Node" || authorizer.Type() == "RBAC" {
continue
}

authorizers = slices.Concat(authorizers, []k8s.AuthorizationAuthorizersSpec{
{
Type: authorizer.Type(),
Expand All @@ -145,7 +140,25 @@ func NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationControll
})
}

res.TypedSpec().Config = slices.Concat(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, authorizers)
if !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool {
return a.Type == "Node"
}) {
authorizers = slices.Insert(authorizers, 0, k8s.AuthorizationAuthorizersSpec{
Type: "Node",
Name: "node",
})
}

if !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool {
return a.Type == "RBAC"
}) {
authorizers = slices.Insert(authorizers, 1, k8s.AuthorizationAuthorizersSpec{
Type: "RBAC",
Name: "rbac",
})
}

res.TypedSpec().Config = authorizers

return nil
},
Expand Down
90 changes: 88 additions & 2 deletions internal/app/machined/pkg/controllers/k8s/control_plane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,88 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut
},
},
},
{
AuthorizerType: "Node",
AuthorizerName: "bar",
},
},
},
},
},
),
)

suite.setupMachine(cfg)

expectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{
{
Type: "RBAC",
Name: "foo",
},
{
Type: "Webhook",
Name: "webhook",
Webhook: map[string]any{
"timeout": "3s",
"subjectAccessReviewVersion": "v1",
"matchConditionSubjectAccessReviewVersion": "v1",
"failurePolicy": "NoOpinion",
"connectionInfo": map[string]any{
"type": "InClusterConfig",
},
},
},
{
Type: "Node",
Name: "bar",
},
}

rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},
func(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {
assert.Equal(expectedAuthorizers, authorizationConfig.TypedSpec().Config)
},
)
}

func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAuthorizersWithOnlyNodeSet() {
u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err)

cfg := config.NewMachineConfig(
container.NewV1Alpha1(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineType: "controlplane",
},
ClusterConfig: &v1alpha1.ClusterConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
APIServerConfig: &v1alpha1.APIServerConfig{
AuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{
{
AuthorizerType: "Node",
AuthorizerName: "foo",
},
{
AuthorizerType: "Webhook",
AuthorizerName: "webhook",
AuthorizerWebhook: v1alpha1.Unstructured{
Object: map[string]any{
"timeout": "3s",
"subjectAccessReviewVersion": "v1",
"matchConditionSubjectAccessReviewVersion": "v1",
"failurePolicy": "NoOpinion",
"connectionInfo": map[string]any{
"type": "InClusterConfig",
},
},
},
},
},
},
},
Expand All @@ -283,7 +361,15 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut

suite.setupMachine(cfg)

expectedAuthorizers := slices.Concat(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, []k8s.AuthorizationAuthorizersSpec{
expectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{
{
Type: "Node",
Name: "foo",
},
{
Type: "RBAC",
Name: "rbac",
},
{
Type: "Webhook",
Name: "webhook",
Expand All @@ -297,7 +383,7 @@ func (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAut
},
},
},
})
}

rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},
func(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {
Expand Down

0 comments on commit e41a995

Please sign in to comment.