From 2a0daf92786278dd0280a024f2a40d235372ce0b Mon Sep 17 00:00:00 2001 From: Phillip Schichtel Date: Sun, 26 May 2024 01:38:14 +0200 Subject: [PATCH] replace BindAddress by Address and OnlyBindToAddress Signed-off-by: Phillip Schichtel --- cmd/controller/certificates.go | 2 +- cmd/controller/controller.go | 1 - docs/configuration.md | 19 ++++++------ inttest/bind-address/bind_address_test.go | 3 +- pkg/apis/k0s/v1beta1/api.go | 31 +++++++------------ pkg/apis/k0s/v1beta1/api_test.go | 16 +--------- pkg/component/controller/apiserver.go | 6 ++-- .../k0s.k0sproject.io_clusterconfigs.yaml | 8 ++--- 8 files changed, 33 insertions(+), 53 deletions(-) diff --git a/cmd/controller/certificates.go b/cmd/controller/certificates.go index 3ecce1d83e45..30ce5e0284df 100644 --- a/cmd/controller/certificates.go +++ b/cmd/controller/certificates.go @@ -64,7 +64,7 @@ func (c *Certificates) Init(ctx context.Context) error { } c.CACert = string(cert) // Changing the URL here also requires changes in the "k0s kubeconfig admin" subcommand. - kubeConfigAPIUrl := fmt.Sprintf("https://%s:%d", c.ClusterSpec.API.APIServerAddress(), c.ClusterSpec.API.Port) + kubeConfigAPIUrl := fmt.Sprintf("https://%s:%d", c.ClusterSpec.API.Address, c.ClusterSpec.API.Port) eg.Go(func() error { // Front proxy CA if err := c.CertManager.EnsureCA("front-proxy-ca", "kubernetes-front-proxy-ca"); err != nil { diff --git a/cmd/controller/controller.go b/cmd/controller/controller.go index 4bbd01127ef0..acfaa0581906 100644 --- a/cmd/controller/controller.go +++ b/cmd/controller/controller.go @@ -185,7 +185,6 @@ func (c *command) start(ctx context.Context) error { } logrus.Infof("using api address: %s", nodeConfig.Spec.API.Address) - logrus.Infof("using api bind-address: %s", nodeConfig.Spec.API.BindAddress) logrus.Infof("using listen port: %d", nodeConfig.Spec.API.Port) logrus.Infof("using sans: %s", nodeConfig.Spec.API.SANs) diff --git a/docs/configuration.md b/docs/configuration.md index aa6209b296da..52afd07e9892 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -52,6 +52,7 @@ metadata: spec: api: address: 192.168.68.104 + onlyBindToAddress: false k0sApiPort: 9443 port: 6443 bindAddress: 192.0.2.1 @@ -113,15 +114,15 @@ spec: ### `spec.api` -| Element | Description | -|--------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `externalAddress` | The loadbalancer address (for k0s controllers running behind a loadbalancer). Configures all cluster components to connect to this address and also configures this address for use when joining new nodes to the cluster. | -| `address` | Local address on which to bind an API. Also serves as one of the addresses pushed on the k0s create service certificate on the API. Defaults to first non-local address found on the node. | -| `bindAddress` | The IP address for the Kubernetes API server to to listen on. The associated interface(s) must be reachable by the rest of the cluster. Will be added as an additional subject alternative name to the API server's TLS certificate. If blank or an unspecified address (`0.0.0.0` or `::`), all interfaces and IP address families will be used. This is effectively the value for the API server's `--bind-address` CLI flag. | -| `sans` | List of additional addresses to push to API servers serving the certificate. | -| `extraArgs` | Map of key-values (strings) for any extra arguments to pass down to Kubernetes api-server process. | -| `port`¹ | Custom port for kube-api server to listen on (default: 6443) | -| `k0sApiPort`¹ | Custom port for k0s-api server to listen on (default: 9443) | +| Element | Description | +|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `address` | Local address on which to bind an API. Also serves as one of the addresses pushed on the k0s create service certificate on the API. Defaults to first non-local address found on the node. | +| `onlyBindToAddress` | Whether to bind only to the IP address given by the `address` option, instead of binding to all addresses. | +| `externalAddress` | The loadbalancer address (for k0s controllers running behind a loadbalancer). Configures all cluster components to connect to this address and also configures this address for use when joining new nodes to the cluster. | +| `sans` | List of additional addresses to push to API servers serving the certificate. | +| `extraArgs` | Map of key-values (strings) for any extra arguments to pass down to Kubernetes api-server process. | +| `port`¹ | Custom port for kube-api server to listen on (default: 6443) | +| `k0sApiPort`¹ | Custom port for k0s-api server to listen on (default: 9443) | ¹ If `port` and `k0sApiPort` are used with the `externalAddress` element, the loadbalancer serving at `externalAddress` must listen on the same ports. diff --git a/inttest/bind-address/bind_address_test.go b/inttest/bind-address/bind_address_test.go index dbf9bc781f00..6756dbfcf762 100644 --- a/inttest/bind-address/bind_address_test.go +++ b/inttest/bind-address/bind_address_test.go @@ -53,6 +53,7 @@ func (s *suite) TestCustomizedBindAddress() { API: func() *v1beta1.APISpec { apiSpec := v1beta1.DefaultAPISpec() apiSpec.Address = s.GetIPAddress(s.ControllerNode(i)) + apiSpec.OnlyToBindAddress = true return apiSpec }(), WorkerProfiles: v1beta1.WorkerProfiles{ @@ -172,7 +173,7 @@ func TestCustomizedBindAddressSuite(t *testing.T) { s := suite{ common.BootlooseSuite{ ControllerCount: 3, - WorkerCount: 2, + WorkerCount: 1, }, } testifysuite.Run(t, &s) diff --git a/pkg/apis/k0s/v1beta1/api.go b/pkg/apis/k0s/v1beta1/api.go index 32822d4fe3dd..eed460893e83 100644 --- a/pkg/apis/k0s/v1beta1/api.go +++ b/pkg/apis/k0s/v1beta1/api.go @@ -37,9 +37,9 @@ type APISpec struct { // Address on which to connect to the API server. Address string `json:"address,omitempty"` - // The IP address for the Kubernetes API server to listen on. + // Whether to only bind to the IP given by the address option. // +optional - BindAddress string `json:"bindAddress,omitempty"` + OnlyToBindAddress bool `json:"onlyBindToAddress,omitempty"` // The loadbalancer address (for k0s controllers running behind a loadbalancer) ExternalAddress string `json:"externalAddress,omitempty"` @@ -97,9 +97,6 @@ func (a *APISpec) K0sControlPlaneAPIAddress() string { func (a *APISpec) getExternalURIForPort(port int) string { addr := a.Address - if a.BindAddress != "" { - addr = a.BindAddress - } if a.ExternalAddress != "" { addr = a.ExternalAddress } @@ -109,21 +106,10 @@ func (a *APISpec) getExternalURIForPort(port int) string { return fmt.Sprintf("https://%s:%d", addr, port) } -// APIServerAddress returns the address the API is listening on -func (a *APISpec) APIServerAddress() string { - if a.BindAddress == "" { - return "localhost" - } - return a.BindAddress -} - // Sans return the given SANS plus all local addresses and externalAddress if given func (a *APISpec) Sans() []string { sans, _ := iface.AllAddresses() sans = append(sans, a.Address) - if a.BindAddress != "" { - sans = append(sans, a.BindAddress) - } sans = append(sans, a.SANs...) if a.ExternalAddress != "" { sans = append(sans, a.ExternalAddress) @@ -132,6 +118,10 @@ func (a *APISpec) Sans() []string { return stringslice.Unique(sans) } +func isAnyAddress(address string) bool { + return address == "0.0.0.0" || address == "::" +} + // Validate validates APISpec struct func (a *APISpec) Validate() []error { if a == nil { @@ -143,6 +133,9 @@ func (a *APISpec) Validate() []error { if !govalidator.IsIP(a.Address) { errors = append(errors, field.Invalid(field.NewPath("address"), a.Address, "invalid IP address")) } + if isAnyAddress(a.Address) { + errors = append(errors, field.Invalid(field.NewPath("address"), a.Address, "invalid INADDR_ANY")) + } validateIPAddressOrDNSName := func(path *field.Path, san string) { if govalidator.IsIP(san) || govalidator.IsDNSName(san) { @@ -153,6 +146,9 @@ func (a *APISpec) Validate() []error { if a.ExternalAddress != "" { validateIPAddressOrDNSName(field.NewPath("externalAddress"), a.ExternalAddress) + if isAnyAddress(a.ExternalAddress) { + errors = append(errors, field.Invalid(field.NewPath("externalAddress"), a.Address, "invalid INADDR_ANY")) + } } for _, msg := range validation.IsValidPortNum(a.K0sAPIPort) { @@ -168,9 +164,6 @@ func (a *APISpec) Validate() []error { validateIPAddressOrDNSName(sansPath.Index(idx), san) } - if a.BindAddress != "" && !govalidator.IsIP(a.BindAddress) { - errors = append(errors, field.Invalid(field.NewPath("bindAddress"), a.BindAddress, "invalid IP address")) - } return errors } diff --git a/pkg/apis/k0s/v1beta1/api_test.go b/pkg/apis/k0s/v1beta1/api_test.go index 52d90acb7919..dc96828ce6e0 100644 --- a/pkg/apis/k0s/v1beta1/api_test.go +++ b/pkg/apis/k0s/v1beta1/api_test.go @@ -45,8 +45,7 @@ func (s *APISuite) TestValidation() { s.Run("invalid_api_address", func() { a := APISpec{ - Address: "something.that.is.not.valid//(())", - BindAddress: "0.0.0.0", + Address: "something.that.is.not.valid//(())", } a.setDefaults() @@ -59,7 +58,6 @@ func (s *APISuite) TestValidation() { s.Run("invalid_sans_address", func() { a := APISpec{ - BindAddress: "0.0.0.0", SANs: []string{ "something.that.is.not.valid//(())", }, @@ -72,18 +70,6 @@ func (s *APISuite) TestValidation() { s.ErrorContains(errors[0], `sans[0]: Invalid value: "something.that.is.not.valid//(())": invalid IP address / DNS name`) } }) - - s.T().Run("invalid_api_bind_address", func(t *testing.T) { - a := APISpec{ - Address: "1.2.3.4", - BindAddress: "something.that.is.not.valid//(())", - } - - errors := a.Validate() - s.NotNil(errors) - s.Len(errors, 1) - s.Contains(errors[0].Error(), "invalid IP address") - }) } func TestApiSuite(t *testing.T) { diff --git a/pkg/component/controller/apiserver.go b/pkg/component/controller/apiserver.go index 8b29a5efac48..d9d22f4dc40c 100644 --- a/pkg/component/controller/apiserver.go +++ b/pkg/component/controller/apiserver.go @@ -125,8 +125,8 @@ func (a *APIServer) Start(_ context.Context) error { "enable-admission-plugins": "NodeRestriction", } - if a.ClusterConfig.Spec.API.BindAddress != "" { - args["bind-address"] = a.ClusterConfig.Spec.API.BindAddress + if a.ClusterConfig.Spec.API.OnlyToBindAddress { + args["bind-address"] = a.ClusterConfig.Spec.API.Address } apiAudiences := []string{"https://kubernetes.default.svc"} @@ -233,7 +233,7 @@ func (a *APIServer) Ready() error { TLSClientConfig: tlsConfig, } client := &http.Client{Transport: tr} - resp, err := client.Get(fmt.Sprintf("https://%s:%d/readyz?verbose", a.ClusterConfig.Spec.API.APIServerAddress(), a.ClusterConfig.Spec.API.Port)) + resp, err := client.Get(fmt.Sprintf("https://%s:%d/readyz?verbose", a.ClusterConfig.Spec.API.Address, a.ClusterConfig.Spec.API.Port)) if err != nil { return err } diff --git a/static/manifests/k0s/CustomResourceDefinition/k0s.k0sproject.io_clusterconfigs.yaml b/static/manifests/k0s/CustomResourceDefinition/k0s.k0sproject.io_clusterconfigs.yaml index 261cb6aad3d4..a6b5039a832c 100644 --- a/static/manifests/k0s/CustomResourceDefinition/k0s.k0sproject.io_clusterconfigs.yaml +++ b/static/manifests/k0s/CustomResourceDefinition/k0s.k0sproject.io_clusterconfigs.yaml @@ -45,10 +45,6 @@ spec: address: description: Address on which to connect to the API server. type: string - bindAddress: - description: The IP address for the Kubernetes API server to listen - on. - type: string externalAddress: description: The loadbalancer address (for k0s controllers running behind a loadbalancer) @@ -66,6 +62,10 @@ spec: maximum: 65535 minimum: 1 type: integer + onlyBindToAddress: + description: Whether to only bind to the IP given by the address + option. + type: boolean port: default: 6443 description: 'Custom port for kube-api server to listen on (default: