Skip to content

Commit

Permalink
feat: add api-server authorization config
Browse files Browse the repository at this point in the history
Add support for configuring KubeAPIServer authorization config.

Fixes: #9791

Signed-off-by: Noel Georgi <[email protected]>
  • Loading branch information
frezbo committed Nov 28, 2024
1 parent db1c707 commit e905846
Show file tree
Hide file tree
Showing 29 changed files with 2,467 additions and 1,083 deletions.
13 changes: 13 additions & 0 deletions api/resource/definitions/k8s/k8s.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ message AuditPolicyConfigSpec {
google.protobuf.Struct config = 1;
}

// AuthorizationAuthorizersSpec is a configuration of authorization authorizers.
message AuthorizationAuthorizersSpec {
string type = 1;
string name = 2;
google.protobuf.Struct webhook = 3;
}

// AuthorizationConfigSpec is authorization configuration for kube-apiserver.
message AuthorizationConfigSpec {
string image = 1;
repeated AuthorizationAuthorizersSpec config = 2;
}

// BootstrapManifestsConfigSpec is configuration for bootstrap manifests.
message BootstrapManifestsConfigSpec {
string server = 1;
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ require (
github.com/containerd/containerd/api v1.8.0
github.com/containerd/containerd/v2 v2.0.0
github.com/containerd/errdefs v1.0.0
github.com/containerd/log v0.1.0
github.com/containerd/platforms v1.0.0-rc.0
github.com/containerd/typeurl/v2 v2.2.3
github.com/containernetworking/cni v1.2.3
github.com/containernetworking/plugins v1.6.0
github.com/coredns/coredns v1.11.3
github.com/coreos/go-iptables v0.8.0
github.com/cosi-project/runtime v0.7.1
github.com/cosi-project/runtime v0.7.2
github.com/distribution/reference v0.6.0
github.com/docker/cli v27.3.1+incompatible
github.com/docker/docker v27.3.1+incompatible
Expand Down Expand Up @@ -148,7 +149,7 @@ require (
github.com/siderolabs/go-debug v0.4.0
github.com/siderolabs/go-kmsg v0.1.4
github.com/siderolabs/go-kubeconfig v0.1.0
github.com/siderolabs/go-kubernetes v0.2.16
github.com/siderolabs/go-kubernetes v0.2.17
github.com/siderolabs/go-loadbalancer v0.3.4
github.com/siderolabs/go-pcidb v0.3.0
github.com/siderolabs/go-pointer v1.0.0
Expand All @@ -163,9 +164,10 @@ require (
github.com/siderolabs/proto-codec v0.1.1
github.com/siderolabs/siderolink v0.3.11
github.com/siderolabs/talos/pkg/machinery v1.9.0-alpha.3
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.10.0
github.com/thejerf/suture/v4 v4.0.5
github.com/u-root/u-root v0.14.0
github.com/ulikunitz/xz v0.5.12
Expand Down Expand Up @@ -233,7 +235,6 @@ require (
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/go-cni v1.1.10 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/plugin v1.0.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/containerd/ttrpc v1.2.6 // indirect
Expand Down Expand Up @@ -328,7 +329,6 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/siderolabs/protoenc v0.2.1 // indirect
github.com/siderolabs/tcpproxy v0.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cosi-project/runtime v0.7.1 h1:cOF2/ljLa0NPQV6/S1RZHcSUXM0UyOlD5F3fwwYSQEg=
github.com/cosi-project/runtime v0.7.1/go.mod h1:EMLs8a55tJ6zA4UyDbRsTvXBd6UIlNwZfCVGvCyiXK8=
github.com/cosi-project/runtime v0.7.2 h1:b8/v/YpP75LNYLyP5x0+EdqPWtNn6sfJggGGzkqZ0H4=
github.com/cosi-project/runtime v0.7.2/go.mod h1:EMLs8a55tJ6zA4UyDbRsTvXBd6UIlNwZfCVGvCyiXK8=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
Expand Down Expand Up @@ -662,8 +662,8 @@ github.com/siderolabs/go-kmsg v0.1.4 h1:RLAa90O9bWuhA3pXPAYAdrI+kzcqTshZASRA5yso
github.com/siderolabs/go-kmsg v0.1.4/go.mod h1:BLkt2N2DHT0wsFMz32lMw6vNEZL90c8ZnBjpIUoBb/M=
github.com/siderolabs/go-kubeconfig v0.1.0 h1:t/2oMWkLSdWHXglKPMz8ySXnx6ZjHckeGY79NaDcBTo=
github.com/siderolabs/go-kubeconfig v0.1.0/go.mod h1:eM3mO02Td6wYDvdi9zTbMrj1Q4WqEFN8XQ6pNjCUWkI=
github.com/siderolabs/go-kubernetes v0.2.16 h1:sTvxsqx07zgPZRz2/vXKXRWV304biQ0JMnHckTVWrtg=
github.com/siderolabs/go-kubernetes v0.2.16/go.mod h1:ElwMMmkNLrSRdAMqOouN9RZbO4G3CM5fJ0F5CBRsGRE=
github.com/siderolabs/go-kubernetes v0.2.17 h1:xxwDtoPQx032Ot6zAhDyOssfMazZG57gjzDGkpaVJuE=
github.com/siderolabs/go-kubernetes v0.2.17/go.mod h1:ac3dMOOYWdFvaBUfVvlJoc0ifFVHBdqth1CPsxSFaGA=
github.com/siderolabs/go-loadbalancer v0.3.4 h1:clxUefcY20djLdHMrh2j3rjVYDwDApXh1us/6cgrgoo=
github.com/siderolabs/go-loadbalancer v0.3.4/go.mod h1:v0ziDvpArNRSF5LO0PIPQIPIYYHxX/fk+Vlg0wuSIiM=
github.com/siderolabs/go-pcidb v0.3.0 h1:jR4w1YLNY8Cv1o5jnoQ2Q+pbxcosO2FVFrAAp1RURnw=
Expand Down Expand Up @@ -730,8 +730,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/thejerf/suture/v4 v4.0.5 h1:F1E/4FZwXWqvlWDKEUo6/ndLtxGAUzMmNqkrMknZbAA=
Expand Down
26 changes: 26 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,32 @@ preface = """
* runc: 1.2.1
Talos is built with Go 1.23.3.
"""

[notes.machineConfigKubeAPIServer]
title = "Kube APIServer Authorization Config"
description = """\
Starting with Talos 1.9, `.cluster.apiServer.authorizationConfig` field supports setting [Kubernetes API server authorization modes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#using-configuration-file-for-authorization)
using the `--authorization-config` flag.
The machine config field supports a list of `authorizers`. For eg:
```yaml
cluster:
apiServer:
authorizationConfig:
- type: Node
name: Node
- type RBAC
name: rbac
```
For new cluster if the Kubernetes API server supports the `--authorization-config` flag, it'll be used by default instead of the `--authorization-mode` flag.
By default Talos will always add the `Node` and ` RBAC` authorizers to the list.
When upgrading if either a user-provided `authorization-mode` or `authorization-webhook-*` flag is set via `.cluster.apiServer.extraArgs`, it'll be used instead of the new `AuthorizationConfig`.
Current authorization config can be viewed by running: `talosctl get authorizationconfigs.kubernetes.talos.dev -o yaml`
"""

[notes.drm]
Expand Down
47 changes: 47 additions & 0 deletions internal/app/machined/pkg/controllers/k8s/control_plane.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import (
"github.com/cosi-project/runtime/pkg/controller/generic/transform"
"github.com/siderolabs/gen/optional"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/go-kubernetes/kubernetes/compatibility"
"go.uber.org/zap"
v1 "k8s.io/api/core/v1"

"github.com/siderolabs/talos/pkg/argsbuilder"
"github.com/siderolabs/talos/pkg/images"
"github.com/siderolabs/talos/pkg/kubernetes"
talosconfig "github.com/siderolabs/talos/pkg/machinery/config/config"
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
Expand Down Expand Up @@ -101,6 +103,51 @@ func NewControlPlaneAuditPolicyController() *ControlPlaneAuditPolicyController {
)
}

// ControlPlaneAuthorizationController manages k8s.AuthorizationConfig based on configuration.
type ControlPlaneAuthorizationController = transform.Controller[*config.MachineConfig, *k8s.AuthorizationConfig]

// NewControlPlaneAuthorizationController instanciates the controller.
func NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationController {
return transform.NewController(
transform.Settings[*config.MachineConfig, *k8s.AuthorizationConfig]{
Name: "k8s.ControlPlaneAuthorizationPolicyController",
MapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewAuthorizationConfig()),
TransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.AuthorizationConfig) error {
cfgProvider := machineConfig.Config()

res.TypedSpec().Image = cfgProvider.Cluster().APIServer().Image()

if !compatibility.VersionFromImageRef(cfgProvider.Cluster().APIServer().Image()).KubeAPIServerSupportsAuthorizationConfigFile() {
return nil
}

if cfgProvider.Cluster().APIServer().AuthorizationConfig() == nil {
res.TypedSpec().Config = v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers

return nil
}

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
}

res.TypedSpec().Config = append(res.TypedSpec().Config, k8s.AuthorizationAuthorizersSpec{
Type: authorizer.Type(),
Name: authorizer.Name(),
Webhook: authorizer.Webhook(),
})
}

res.TypedSpec().Config = append(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, res.TypedSpec().Config...)

return nil
},
},
)
}

// ControlPlaneAPIServerController manages k8s.APIServerConfig based on configuration.
type ControlPlaneAPIServerController = transform.Controller[*config.MachineConfig, *k8s.APIServerConfig]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,6 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context
// Do not accept anonymous requests by default. Otherwise the kube-apiserver will set the request's group to system:unauthenticated exposing endpoints like /version etc.
"anonymous-auth": "false",
"api-audiences": cfg.ControlPlaneEndpoint,
"authorization-mode": "Node,RBAC",
"bind-address": "0.0.0.0",
"client-ca-file": filepath.Join(constants.KubernetesAPIServerSecretsDir, "ca.crt"),
"enable-admission-plugins": strings.Join(enabledAdmissionPlugins, ","),
Expand Down Expand Up @@ -408,6 +407,10 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context
builder.Set("cloud-provider", cfg.CloudProvider)
}

k8sVersion := compatibility.VersionFromImageRef(cfg.Image)

handleKubeAPIServerAuthorizationFlags(k8sVersion, builder, cfg.ExtraArgs)

mergePolicies := argsbuilder.MergePolicies{
"enable-admission-plugins": argsbuilder.MergeAdditive,
"feature-gates": argsbuilder.MergeAdditive,
Expand All @@ -429,6 +432,7 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context
"service-account-signing-key-file": argsbuilder.MergeDenied,
"tls-cert-file": argsbuilder.MergeDenied,
"tls-private-key-file": argsbuilder.MergeDenied,
"authorization-config": argsbuilder.MergeDenied,
}

if err := builder.Merge(cfg.ExtraArgs, argsbuilder.WithMergePolicies(mergePolicies)); err != nil {
Expand Down Expand Up @@ -466,7 +470,7 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context
"k8s-app": k8s.APIServerID,
"component": k8s.APIServerID,
"app.kubernetes.io/name": k8s.APIServerID,
"app.kubernetes.io/version": compatibility.VersionFromImageRef(cfg.Image).String(),
"app.kubernetes.io/version": k8sVersion.String(),
"app.kubernetes.io/component": "control-plane",
"app.kubernetes.io/managed-by": "Talos",
},
Expand Down Expand Up @@ -914,3 +918,48 @@ func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context
})
})
}

func kubeAPIServerExtraArgsHasAuthorizationWebhooFlags(extraArgs map[string]string) bool {
return slices.ContainsFunc(maps.Keys(extraArgs), func(arg string) bool {
return strings.HasPrefix(arg, "authorization-webhook-")
})
}

func kubeAPIServerExtraArgsHasAuthorizationModeFlag(extraArgs map[string]string) bool {
_, ok := extraArgs["authorization-mode"]

return ok
}

func handleKubeAPIServerAuthorizationFlags(kubeVersion compatibility.Version, argBuilder argsbuilder.Args, extraArgs map[string]string) {
// this handle multiple cases:
// 1. user already has set `authorization-mode` flag, we'll just merge our default `authorization-mode` flag
if kubeAPIServerExtraArgsHasAuthorizationModeFlag(extraArgs) {
argBuilder.Set("authorization-mode", "Node,RBAC")

return
}

// 2. user has set `authorization-webhook-*` flags, we'll just merge our default `authorization-mode` flag
if kubeAPIServerExtraArgsHasAuthorizationWebhooFlags(extraArgs) {
argBuilder.Set("authorization-mode", "Node,RBAC")

return
}

// 3. user has not set `authorization-mode` flag and the kube-apiserver version doesn't support `authorization-config` flag
// machine config validation should handle the case where either of `authorization-mode` or `authorization-webhook-*` flags are set
// along with `authorizationConfig`
if !kubeVersion.KubeAPIServerSupportsAuthorizationConfigFile() {
argBuilder.Set("authorization-mode", "Node,RBAC")

return
}

if !kubeVersion.FeatureFlagStructuredAuthorizationConfigurationEnabledByDefault() {
// feature-gates flag can be set multiple times, since it has merge addictive policy
argBuilder.Set("feature-gates", "StructuredAuthorizationConfiguration=true")
}

argBuilder.Set("authorization-config", filepath.Join(constants.KubernetesAPIServerConfigDir, "authorization-config.yaml"))
}
Loading

0 comments on commit e905846

Please sign in to comment.