Repository: kubermatic/machine-controller
Pull request #1631 (2023-05-09 10:04:43)

Add documentation for community providers
**What this PR does / why we need it**:
After discussions on SIG Cluster Management, this is the short-term change we have come up with to clarify that some providers have been contributed by the community and don't get the same maintenance care from the development team as others (because we cannot test them).

This PR also moves the providers into a dedicated `communityProviders` map to codify the distinction, but from a user perspective, nothing changes.

It's a follow-up to #1622.

**Which issue(s) this PR fixes**:
<!--optional, in `fixes #<issue number>` format, will close the issue(s) when PR gets merged-->
Fixes #

**What type of PR is this?**
/kind documentation

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change? Then add your Release Note here**:
<!--
Write your release note:
1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required".
2. If no release note is required, just write "NONE".
-->
```release-note
Clarify provider status for Linode, Vultr and OpenNebula as community providers
```

**Documentation**:
<!--
Please do one of the following options:
- Add a link to the existing documentation
- Add a link to the kubermatic/docs pull request
- If no documentation change is applicable then add:
  - TBD (documentation will be added later)
  - NONE (no documentation needed for this PR)
-->
```documentation
NONE
```


kubermatic-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubermatic/machine-controller/pull/1631#" title="Author self-approved">embik</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubermatic%2Fmachine-controller).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubermatic/machine-controller/blob/main/OWNERS)~~ [embik]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
kubermatic-bot: @embik: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-machine-controller-e2e-ubuntu-upgrade | f8c315217706029e1bf66c833324346489eac439 | [link](https://public-prow.loodse.com/view/gs/prow-dev-public-data/pr-logs/pull/kubermatic_machine-controller/1631/pull-machine-controller-e2e-ubuntu-upgrade/1655876464437891072) | true | `/test pull-machine-controller-e2e-ubuntu-upgrade`

[Full PR test history](https://public-prow.loodse.com/pr-history?org=kubermatic&repo=machine-controller&pr=1631)

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
kubermatic-bot: @embik: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-machine-controller-e2e-ubuntu-upgrade | f8c315217706029e1bf66c833324346489eac439 | [link](https://public-prow.loodse.com/view/gs/prow-dev-public-data/pr-logs/pull/kubermatic_machine-controller/1631/pull-machine-controller-e2e-ubuntu-upgrade/1655876464437891072) | true | `/test pull-machine-controller-e2e-ubuntu-upgrade`
pull-machine-controller-e2e-aws-spot-instance | f8c315217706029e1bf66c833324346489eac439 | [link](https://public-prow.loodse.com/view/gs/prow-dev-public-data/pr-logs/pull/kubermatic_machine-controller/1631/pull-machine-controller-e2e-aws-spot-instance/1655876464559525888) | true | `/test pull-machine-controller-e2e-aws-spot-instance`

[Full PR test history](https://public-prow.loodse.com/pr-history?org=kubermatic&repo=machine-controller&pr=1631)

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/.prow/postsubmits.yaml b/.prow/postsubmits.yaml
index f4ecca9d..da280c4d 100644
--- a/.prow/postsubmits.yaml
+++ b/.prow/postsubmits.yaml
@@ -26,7 +26,7 @@ postsubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - /bin/bash
             - -c
@@ -54,7 +54,7 @@ postsubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/upload-gocache.sh"
           resources:
diff --git a/.prow/provider-alibaba.yaml b/.prow/provider-alibaba.yaml
index a424ee67..a0719456 100644
--- a/.prow/provider-alibaba.yaml
+++ b/.prow/provider-alibaba.yaml
@@ -29,7 +29,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-anexia.yaml b/.prow/provider-anexia.yaml
index 99f79b4a..02afe578 100644
--- a/.prow/provider-anexia.yaml
+++ b/.prow/provider-anexia.yaml
@@ -31,7 +31,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-aws.yaml b/.prow/provider-aws.yaml
index dc4a5a3f..9203abd0 100644
--- a/.prow/provider-aws.yaml
+++ b/.prow/provider-aws.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -60,7 +60,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           env:
             - name: OPERATING_SYSTEM_MANAGER
               value: "false"
@@ -93,7 +93,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -124,7 +124,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -156,7 +156,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -187,7 +187,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -218,7 +218,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -249,7 +249,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-azure.yaml b/.prow/provider-azure.yaml
index 95780707..f3e02990 100644
--- a/.prow/provider-azure.yaml
+++ b/.prow/provider-azure.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -60,7 +60,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -93,7 +93,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-digitalocean.yaml b/.prow/provider-digitalocean.yaml
index 44e09b82..fd84cc73 100644
--- a/.prow/provider-digitalocean.yaml
+++ b/.prow/provider-digitalocean.yaml
@@ -27,7 +27,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-equinix-metal.yaml b/.prow/provider-equinix-metal.yaml
index 6659d980..f1c6f4ba 100644
--- a/.prow/provider-equinix-metal.yaml
+++ b/.prow/provider-equinix-metal.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-gcp.yaml b/.prow/provider-gcp.yaml
index 21ee1756..5631bf42 100644
--- a/.prow/provider-gcp.yaml
+++ b/.prow/provider-gcp.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-hetzner.yaml b/.prow/provider-hetzner.yaml
index 0200e89e..7e7a9e95 100644
--- a/.prow/provider-hetzner.yaml
+++ b/.prow/provider-hetzner.yaml
@@ -26,7 +26,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-kubevirt.yaml b/.prow/provider-kubevirt.yaml
index 4ae7aed9..64234992 100644
--- a/.prow/provider-kubevirt.yaml
+++ b/.prow/provider-kubevirt.yaml
@@ -29,7 +29,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-linode.yaml b/.prow/provider-linode.yaml
index 80276976..f6bea60f 100644
--- a/.prow/provider-linode.yaml
+++ b/.prow/provider-linode.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-nutanix.yaml b/.prow/provider-nutanix.yaml
index 44a2e5f3..149c649d 100644
--- a/.prow/provider-nutanix.yaml
+++ b/.prow/provider-nutanix.yaml
@@ -27,7 +27,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-openstack.yaml b/.prow/provider-openstack.yaml
index 0a73d28f..e59fde74 100644
--- a/.prow/provider-openstack.yaml
+++ b/.prow/provider-openstack.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -60,7 +60,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-scaleway.yaml b/.prow/provider-scaleway.yaml
index 3897873b..c1c35947 100644
--- a/.prow/provider-scaleway.yaml
+++ b/.prow/provider-scaleway.yaml
@@ -27,7 +27,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-vmware-cloud-director.yaml b/.prow/provider-vmware-cloud-director.yaml
index 73e7f4a6..25b63cee 100644
--- a/.prow/provider-vmware-cloud-director.yaml
+++ b/.prow/provider-vmware-cloud-director.yaml
@@ -29,7 +29,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/provider-vsphere.yaml b/.prow/provider-vsphere.yaml
index 2099a030..4c4df817 100644
--- a/.prow/provider-vsphere.yaml
+++ b/.prow/provider-vsphere.yaml
@@ -28,7 +28,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -60,7 +60,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -92,7 +92,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/.prow/verify.yaml b/.prow/verify.yaml
index ad2f4885..d0745f3e 100644
--- a/.prow/verify.yaml
+++ b/.prow/verify.yaml
@@ -21,7 +21,7 @@ presubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: golang:1.20.3
+        - image: golang:1.20.4
           command:
             - make
           args:
@@ -42,7 +42,7 @@ presubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: golang:1.20.3
+        - image: golang:1.20.4
           command:
             - make
           args:
@@ -149,7 +149,7 @@ presubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - ./hack/verify-licenses.sh
           resources:
@@ -165,7 +165,7 @@ presubmits:
       preset-goproxy: "true"
     spec:
       containers:
-        - image: golang:1.20.3
+        - image: golang:1.20.4
           command:
             - make
           args:
diff --git a/Dockerfile b/Dockerfile
index 2d0c45d2..7329a4f1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG GO_VERSION=1.20.3
+ARG GO_VERSION=1.20.4
 FROM docker.io/golang:${GO_VERSION} AS builder
 WORKDIR /go/src/github.com/kubermatic/machine-controller
 COPY . .
diff --git a/Makefile b/Makefile
index e6f40e70..5c39b60b 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@
 
 SHELL = /bin/bash -eu -o pipefail
 
-GO_VERSION ?= 1.20.3
+GO_VERSION ?= 1.20.4
 
 GOOS ?= $(shell go env GOOS)
 
@@ -58,7 +58,7 @@ machine-controller-userdata-%: cmd/userdata/% $(shell find cmd/userdata/$* pkg -
 		github.com/kubermatic/machine-controller/cmd/$*
 
 .PHONY: clean
-clean: clean-certs
+clean:
 	rm -f machine-controller \
 		webhook \
 		$(USERDATA_BIN)
@@ -102,45 +102,6 @@ build-tests:
 	go test -run nope ./...
 	go test -tags e2e -run nope ./...
 
-examples/ca-key.pem:
-	openssl genrsa -out examples/ca-key.pem 4096
-
-examples/ca-cert.pem: examples/ca-key.pem
-	openssl req -x509 -new -nodes -key examples/ca-key.pem \
-    -subj "/C=US/ST=CA/O=Acme/CN=k8s-machine-controller-ca" \
-		-sha256 -days 10000 -out examples/ca-cert.pem
-
-examples/admission-key.pem: examples/ca-cert.pem
-	openssl genrsa -out examples/admission-key.pem 2048
-	chmod 0600 examples/admission-key.pem
-
-examples/admission-cert.pem: examples/admission-key.pem
-	openssl req -new -sha256 \
-		-key examples/admission-key.pem \
-		-config examples/webhook-certificate.cnf -extensions v3_req \
-		-out examples/admission.csr
-	openssl x509 -req \
-		-sha256 \
-		-days 10000 \
-		-extensions v3_req \
-		-extfile examples/webhook-certificate.cnf \
-		-in examples/admission.csr \
-		-CA examples/ca-cert.pem \
-		-CAkey examples/ca-key.pem \
-		-CAcreateserial \
-		-out examples/admission-cert.pem
-
-clean-certs:
-	cd examples/ && rm -f admission.csr admission-cert.pem admission-key.pem ca-cert.pem ca-key.pem
-
-.PHONY: deploy
-deploy: examples/admission-cert.pem
-	@cat examples/machine-controller.yaml \
-		|sed "s/__admission_ca_cert__/$(shell cat examples/ca-cert.pem|$(BASE64_ENC))/g" \
-		|sed "s/__admission_cert__/$(shell cat examples/admission-cert.pem|$(BASE64_ENC))/g" \
-		|sed "s/__admission_key__/$(shell cat examples/admission-key.pem|$(BASE64_ENC))/g" \
-		|kubectl apply -f -
-
 .PHONY: check-dependencies
 check-dependencies:
 	go mod verify
diff --git a/README.md b/README.md
index aadaf94c..b1da95a6 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,42 @@
 # Kubermatic machine-controller
 
+**Important Note: User data plugins for machine-controller are deprecated and will soon be removed. [Operating System Manager](https://github.com/kubermatic/operating-system-manager) is the successor of user data plugins. It's responsible for creating and managing the required configurations for worker nodes in a Kubernetes cluster with better modularity and extensibility. Please refer to [Operating System Manager][8] for more details.**
+
 ## Table of Contents
 
 - [Kubermatic machine-controller](#kubermatic-machine-controller)
   - [Table of Contents](#table-of-contents)
   - [Features](#features)
-    - [What works](#what-works)
-    - [Supported Kubernetes versions](#supported-kubernetes-versions)
-  - [What does not work](#what-does-not-work)
+    - [What Works](#what-works)
+    - [Supported Kubernetes Versions](#supported-kubernetes-versions)
+    - [Community Providers](#community-providers)
+  - [What doesn't Work](#what-doesnt-work)
   - [Quickstart](#quickstart)
-    - [Deploy the machine-controller](#deploy-the-machine-controller)
-    - [Creating a machineDeployment](#creating-a-machinedeployment)
-  - [Advanced usage](#advanced-usage)
-    - [Specifying the apiserver endpoint](#specifying-the-apiserver-endpoint)
-    - [CA-data](#ca-data)
-    - [Apiserver endpoint](#apiserver-endpoint)
+    - [Deploy machine-controller](#deploy-the-machine-controller)
+    - [Creating a MachineDeployment](#creating-a-machinedeployment)
+  - [Advanced Usage](#advanced-usage)
+    - [Specifying the Apiserver Endpoint](#specifying-the-apiserver-endpoint)
+    - [CA Data](#ca-data)
+    - [Apiserver Endpoint](#apiserver-endpoint)
       - [Example cluster-info ConfigMap](#example-cluster-info-configmap)
   - [Development](#development)
     - [Testing](#testing)
-      - [Unittests](#unittests)
-      - [End-to-End locally](#end-to-end-locally)
+      - [Unit Tests](#unit-tests)
+      - [End-to-End Locally](#end-to-end-locally)
   - [Troubleshooting](#troubleshooting)
   - [Contributing](#contributing)
-    - [Before you start](#before-you-start)
-    - [Pull requests](#pull-requests)
+    - [Before You Start](#before-you-start)
+    - [Pull Requests](#pull-requests)
   - [Changelog](#changelog)
 
 ## Features
 
-### What works
+### What Works
 
-- Creation of worker nodes on AWS, Digitalocean, Openstack, Azure, Google Cloud Platform, Nutanix, VMWare Cloud Director, VMWare Vsphere, Linode, Hetzner cloud and Kubevirt (experimental)
-- Using Ubuntu, Flatcar or CentOS 7 distributions ([not all distributions work on all providers](/docs/operating-system.md))
+- Creation of worker nodes on AWS, Digitalocean, Openstack, Azure, Google Cloud Platform, Nutanix, VMWare Cloud Director, VMWare vSphere, Hetzner Cloud and Kubevirt
+- Using Ubuntu, Flatcar, CentOS 7 or Rocky Linux 8 distributions ([not all distributions work on all providers](/docs/operating-system.md))
 
-### Supported Kubernetes versions
+### Supported Kubernetes Versions
 
 machine-controller tries to follow the Kubernetes version
 [support policy](https://kubernetes.io/docs/setup/release/version-skew-policy/) as close as possible.
@@ -45,26 +48,45 @@ Currently supported K8S versions are:
 - 1.25
 - 1.24
 
-## What does not work
+### Community Providers
+
+Some cloud providers implemented in machine-controller have been graciously contributed by community members. Those cloud providers are not part of the automated end-to-end
+tests run by the machine-controller developers and thus, their status cannot be guaranteed. The machine-controller developers assume that they are functional, but can only
+offer limited support for new features or bugfixes in those providers.
+
+The current list of community providers is:
+
+- Linode
+- Vultr
+- OpenNebula
+
+## What Doesn't Work
 
 - Master creation (Not planned at the moment)
 
 ## Quickstart
 
-### Deploy the machine-controller
+### Deploy machine-controller
+
+- Install [cert-manager](https://cert-manager.io/) for generating certificates used by webhooks since they serve using HTTPS
+
+```terminal
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.2/cert-manager.yaml
+```
 
-`make deploy`
+- Run `kubectl apply -f examples/operating-system-manager.yaml` to deploy the operating-system-manager which is responsible for managing user data for worker machines.
+- Run `kubectl apply -f examples/machine-controller.yaml` to deploy the machine-controller.
 
-### Creating a machineDeployment
+### Creating a `MachineDeployment`
 
 ```bash
 # edit examples/$cloudprovider-machinedeployment.yaml & create the machineDeployment
 kubectl create -f examples/$cloudprovider-machinedeployment.yaml
 ```
 
-## Advanced usage
+## Advanced Usage
 
-### Specifying the apiserver endpoint
+### Specifying the Apiserver Endpoint
 
 By default the controller looks for a `cluster-info` ConfigMap within the `kube-public` Namespace.
 If one is found which contains a minimal kubeconfig (kubeadm cluster have them by default), this kubeconfig will be used for the node bootstrapping.
@@ -75,11 +97,11 @@ The kubeconfig only needs to contain two things:
 
 If no ConfigMap can be found:
 
-### CA-data
+### CA Data
 
-The CA will be loaded from the passed kubeconfig when running outside the cluster or from `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` when running inside the cluster.
+The Certificate Authority (CA) will be loaded from the passed kubeconfig when running outside the cluster or from `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` when running inside the cluster.
 
-### Apiserver endpoint
+### Apiserver Endpoint
 
 The first endpoint from the kubernetes endpoints will be taken. `kubectl get endpoints kubernetes -o yaml`
 
@@ -110,11 +132,11 @@ data:
 
 ### Testing
 
-#### Unittests
+#### Unit Tests
 
 Simply run `make test-unit`
 
-#### End-to-End locally
+#### End-to-End Locally
 
 **_[WIP]_**
 
@@ -126,13 +148,13 @@ If you encounter issues [file an issue][1] or talk to us on the [#kubermatic cha
 
 Thanks for taking the time to join our community and start contributing!
 
-### Before you start
+### Before You Start
 
 - Please familiarize yourself with the [Code of Conduct][4] before contributing.
 - See [CONTRIBUTING.md][5] for instructions on the developer certificate of origin that we require.
 - Read how [we're using ZenHub][6] for project and roadmap planning
 
-### Pull requests
+### Pull Requests
 
 - We welcome pull requests. Feel free to dig through the [issues][1] and jump in.
 
@@ -147,3 +169,4 @@ See [the list of releases][7] to find out about feature changes.
 [5]: CONTRIBUTING.md
 [6]: Zenhub.md
 [7]: https://github.com/kubermatic/machine-controller/releases
+[8]: https://docs.kubermatic.com/operatingsystemmanager
\ No newline at end of file
diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go
index f9c6d823..d501bafa 100644
--- a/cmd/webhook/main.go
+++ b/cmd/webhook/main.go
@@ -63,8 +63,8 @@ func main() {
 		flag.StringVar(&opt.masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
 	}
 	flag.StringVar(&opt.admissionListenAddress, "listen-address", ":9876", "The address on which the MutatingWebhook will listen on")
-	flag.StringVar(&opt.admissionTLSCertPath, "tls-cert-path", "/tmp/cert/cert.pem", "The path of the TLS cert for the MutatingWebhook")
-	flag.StringVar(&opt.admissionTLSKeyPath, "tls-key-path", "/tmp/cert/key.pem", "The path of the TLS key for the MutatingWebhook")
+	flag.StringVar(&opt.admissionTLSCertPath, "tls-cert-path", "/tmp/cert/tls.crt", "The path of the TLS cert for the MutatingWebhook")
+	flag.StringVar(&opt.admissionTLSKeyPath, "tls-key-path", "/tmp/cert/tls.key", "The path of the TLS key for the MutatingWebhook")
 	flag.StringVar(&opt.caBundleFile, "ca-bundle", "", "path to a file containing all PEM-encoded CA certificates (will be used instead of the host's certificates if set)")
 	flag.StringVar(&opt.namespace, "namespace", "kubermatic", "The namespace where the webhooks will run")
 	flag.StringVar(&opt.workerClusterKubeconfig, "worker-cluster-kubeconfig", "", "Path to kubeconfig of worker/user cluster where machines and machinedeployments exist. If not specified, value from --kubeconfig or in-cluster config will be used")
diff --git a/docs/cloud-provider.md b/docs/cloud-provider.md
index 2d882241..74edb7a4 100644
--- a/docs/cloud-provider.md
+++ b/docs/cloud-provider.md
@@ -148,6 +148,8 @@ tags:
 
 ## OpenNebula
 
+**Note:** This is a [community provider](../README.md#community-providers).
+
 ### machine.spec.providerConfig.cloudProviderSpec
 
 ```yaml
@@ -233,6 +235,8 @@ labels:
 
 ## Linode
 
+**Note:** This is a [community provider](../README.md#community-providers).
+
 ### machine.spec.providerConfig.cloudProviderSpec
 ```yaml
 # your linode token
@@ -361,6 +365,8 @@ Refer to the [VSphere](./vsphere.md#provider-configuration) specific documentati
 
 ## Vultr
 
+**Note:** This is a [community provider](../README.md#community-providers).
+
 ### machine.spec.providerConfig.cloudProviderSpec
 ```yaml
 apiKey: "<< VULTR_API_KEY >>"
diff --git a/examples/machine-controller.yaml b/examples/machine-controller.yaml
index 957deca4..e3848f2f 100644
--- a/examples/machine-controller.yaml
+++ b/examples/machine-controller.yaml
@@ -155,6 +155,28 @@ spec:
           jsonPath: .metadata.deletionTimestamp
           priority: 1
 ---
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+  name: machine-controller-selfsigned-issuer
+  namespace: kube-system
+spec:
+  selfSigned: {}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: machine-controller-serving-cert
+  namespace: kube-system
+spec:
+  dnsNames:
+    - "machine-controller-webhook.kube-system.svc"
+    - "machine-controller-webhook.kube-system.svc.cluster.local"
+  issuerRef:
+    kind: Issuer
+    name: machine-controller-selfsigned-issuer
+  secretName: machine-controller-webhook-server-cert
+---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
@@ -267,7 +289,8 @@ spec:
             - -listen-address=0.0.0.0:9876
           volumeMounts:
             - name: machine-controller-admission-cert
-              mountPath: /tmp/cert
+              mountPath: /tmp/cert/
+              readOnly: true
           livenessProbe:
             httpGet:
               path: /healthz
@@ -284,16 +307,8 @@ spec:
       volumes:
         - name: machine-controller-admission-cert
           secret:
-            secretName: machine-controller-admission-cert
----
-apiVersion: v1
-kind: Secret
-metadata:
-  name: machine-controller-admission-cert
-  namespace: kube-system
-data:
-  "cert.pem": __admission_cert__
-  "key.pem": __admission_key__
+            defaultMode: 420
+            secretName: machine-controller-webhook-server-cert
 ---
 apiVersion: v1
 kind: Service
@@ -602,6 +617,8 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: MutatingWebhookConfiguration
 metadata:
   name: machinedeployments.machine-controller.kubermatic.io
+  annotations:
+    cert-manager.io/inject-ca-from: kube-system/machine-controller-serving-cert
 webhooks:
 - name: machinedeployments.machine-controller.kubermatic.io
   failurePolicy: Fail
@@ -622,7 +639,6 @@ webhooks:
       namespace: kube-system
       name: machine-controller-webhook
       path: /machinedeployments
-    caBundle: __admission_ca_cert__
 - name: machines.machine-controller.kubermatic.io
   failurePolicy: Fail
   sideEffects: None
@@ -642,4 +658,3 @@ webhooks:
       namespace: kube-system
       name: machine-controller-webhook
       path: /machines
-    caBundle: __admission_ca_cert__
diff --git a/go.mod b/go.mod
index 883941e8..8418da9a 100644
--- a/go.mod
+++ b/go.mod
@@ -99,7 +99,7 @@ require (
 	github.com/coreos/go-semver v0.3.0 // indirect
 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
-	github.com/docker/distribution v2.8.1+incompatible // indirect
+	github.com/docker/distribution v2.8.2+incompatible // indirect
 	github.com/emicklei/go-restful/v3 v3.10.1 // indirect
 	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
 	github.com/evanphx/json-patch/v5 v5.6.0 // indirect
diff --git a/go.sum b/go.sum
index ef4c0062..ab7ec118 100644
--- a/go.sum
+++ b/go.sum
@@ -205,8 +205,8 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
 github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
-github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
-github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
+github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
 github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
diff --git a/hack/ci/setup-machine-controller-in-kind.sh b/hack/ci/setup-machine-controller-in-kind.sh
index 011644a4..29cb6cf9 100755
--- a/hack/ci/setup-machine-controller-in-kind.sh
+++ b/hack/ci/setup-machine-controller-in-kind.sh
@@ -26,6 +26,16 @@ export OPERATING_SYSTEM_MANAGER="${OPERATING_SYSTEM_MANAGER:-true}"
 OSM_REPO_URL="${OSM_REPO_URL:-https://github.com/kubermatic/operating-system-manager.git}"
 OSM_REPO_TAG="${OSM_REPO_TAG:-main}"
 
+# cert-manager is required by OSM for generating TLS Certificates
+echodate "Installing cert-manager"
+(
+  kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.2/cert-manager.yaml
+  # Wait for cert-manager to be ready
+  kubectl -n cert-manager rollout status deploy/cert-manager
+  kubectl -n cert-manager rollout status deploy/cert-manager-cainjector
+  kubectl -n cert-manager rollout status deploy/cert-manager-webhook
+)
+
 # Build the Docker image for machine-controller
 beforeDockerBuild=$(nowms)
 
@@ -57,23 +67,13 @@ if [ ! -f machine-controller-deployed ]; then
   # e2e tests logs are primarily read by humans, if ever
   sed -i 's/log-format=json/log-format=console/g' examples/machine-controller.yaml
 
-  make deploy
+  kubectl apply -f examples/machine-controller.yaml
   touch machine-controller-deployed
 
   protokol --kubeconfig "$KUBECONFIG" --flat --output "$ARTIFACTS/logs" --namespace kube-system 'machine-controller-*' > /dev/null 2>&1 &
 fi
 
 if [[ "$OPERATING_SYSTEM_MANAGER" == "true" ]]; then
-  # cert-manager is required by OSM for generating TLS Certificates
-  echodate "Installing cert-manager"
-  (
-    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.7.1/cert-manager.yaml
-    # Wait for cert-manager to be ready
-    kubectl -n cert-manager rollout status deploy/cert-manager
-    kubectl -n cert-manager rollout status deploy/cert-manager-cainjector
-    kubectl -n cert-manager rollout status deploy/cert-manager-webhook
-  )
-
   OSM_TMP_DIR=/tmp/osm
   echodate "Clone OSM respository"
   (
diff --git a/hack/update-fixtures.sh b/hack/update-fixtures.sh
index 790c2e14..b34ec94b 100755
--- a/hack/update-fixtures.sh
+++ b/hack/update-fixtures.sh
@@ -19,7 +19,7 @@ set -euo pipefail
 cd $(dirname $0)/..
 source hack/lib.sh
 
-CONTAINERIZE_IMAGE=golang:1.20.3 containerize ./hack/update-fixtures.sh
+CONTAINERIZE_IMAGE=golang:1.20.4 containerize ./hack/update-fixtures.sh
 
 go test ./... -v -update || go test ./...
 
diff --git a/pkg/cloudprovider/provider.go b/pkg/cloudprovider/provider.go
index 1c20a2a3..28161700 100644
--- a/pkg/cloudprovider/provider.go
+++ b/pkg/cloudprovider/provider.go
@@ -66,9 +66,6 @@ var (
 		providerconfigtypes.CloudProviderHetzner: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
 			return hetzner.New(cvr)
 		},
-		providerconfigtypes.CloudProviderLinode: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
-			return linode.New(cvr)
-		},
 		providerconfigtypes.CloudProviderVsphere: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
 			return vsphere.New(cvr)
 		},
@@ -78,9 +75,6 @@ var (
 		providerconfigtypes.CloudProviderEquinixMetal: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
 			return equinixmetal.New(cvr)
 		},
-		providerconfigtypes.CloudProviderVultr: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
-			return vultr.New(cvr)
-		},
 		// NB: This is explicitly left to allow old Packet machines to be deleted.
 		// We can handle those machines in the same way as Equinix Metal machines
 		// because there are no API changes.
@@ -113,6 +107,17 @@ var (
 		providerconfigtypes.CloudProviderVMwareCloudDirector: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
 			return vcd.New(cvr)
 		},
+	}
+
+	// communityProviders holds a map of cloud providers that have been implemented by community members and
+	// contributed to machine-controller. They are not end-to-end tested by the machine-controller development team.
+	communityProviders = map[providerconfigtypes.CloudProvider]func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider{
+		providerconfigtypes.CloudProviderLinode: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
+			return linode.New(cvr)
+		},
+		providerconfigtypes.CloudProviderVultr: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
+			return vultr.New(cvr)
+		},
 		providerconfigtypes.CloudProviderOpenNebula: func(cvr *providerconfig.ConfigVarResolver) cloudprovidertypes.Provider {
 			return opennebula.New(cvr)
 		},
@@ -124,5 +129,8 @@ func ForProvider(p providerconfigtypes.CloudProvider, cvr *providerconfig.Config
 	if p, found := providers[p]; found {
 		return NewValidationCacheWrappingCloudProvider(p(cvr)), nil
 	}
+	if p, found := communityProviders[p]; found {
+		return NewValidationCacheWrappingCloudProvider(p(cvr)), nil
+	}
 	return nil, ErrProviderNotFound
 }
diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go
index 6b51e714..8b2ca206 100644
--- a/pkg/cloudprovider/provider/anexia/provider.go
+++ b/pkg/cloudprovider/provider/anexia/provider.go
@@ -96,17 +96,18 @@ func (p *provider) Create(ctx context.Context, log *zap.SugaredLogger, machine *
 	// ensure conditions are present on machine
 	ensureConditions(&status)
 
-	config, _, err := p.getConfig(ctx, log, machine.Spec.ProviderSpec)
+	config, providerCfg, err := p.getConfig(ctx, log, machine.Spec.ProviderSpec)
 	if err != nil {
 		return nil, fmt.Errorf("failed to get provider config: %w", err)
 	}
 
 	ctx = createReconcileContext(ctx, reconcileContext{
-		Status:       &status,
-		UserData:     userdata,
-		Config:       *config,
-		ProviderData: data,
-		Machine:      machine,
+		Status:         &status,
+		UserData:       userdata,
+		Config:         *config,
+		ProviderData:   data,
+		ProviderConfig: providerCfg,
+		Machine:        machine,
 	})
 
 	_, client, err := getClient(config.Token)
@@ -165,6 +166,19 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C
 
 		vm.Script = base64.StdEncoding.EncodeToString([]byte(reconcileContext.UserData))
 
+		for index, dnsServer := range reconcileContext.ProviderConfig.Network.DNS.Servers {
+			switch index {
+			case 0:
+				vm.DNS1 = dnsServer
+			case 1:
+				vm.DNS2 = dnsServer
+			case 2:
+				vm.DNS3 = dnsServer
+			case 3:
+				vm.DNS4 = dnsServer
+			}
+		}
+
 		// We generate a fresh SSH key but will never actually use it - we just want a valid public key to disable password authentication for our fresh VM.
 		sshKey, err := ssh.NewKey()
 		if err != nil {
diff --git a/pkg/cloudprovider/provider/anexia/reconcile_context.go b/pkg/cloudprovider/provider/anexia/reconcile_context.go
index dea3577c..2a14d872 100644
--- a/pkg/cloudprovider/provider/anexia/reconcile_context.go
+++ b/pkg/cloudprovider/provider/anexia/reconcile_context.go
@@ -22,6 +22,7 @@ import (
 	"github.com/kubermatic/machine-controller/pkg/apis/cluster/v1alpha1"
 	anxtypes "github.com/kubermatic/machine-controller/pkg/cloudprovider/provider/anexia/types"
 	cloudprovidertypes "github.com/kubermatic/machine-controller/pkg/cloudprovider/types"
+	providerconfigtypes "github.com/kubermatic/machine-controller/pkg/providerconfig/types"
 )
 
 type contextKey byte
@@ -29,11 +30,12 @@ type contextKey byte
 const machineReconcileContextKey contextKey = 0
 
 type reconcileContext struct {
-	Machine      *v1alpha1.Machine
-	Status       *anxtypes.ProviderStatus
-	UserData     string
-	Config       resolvedConfig
-	ProviderData *cloudprovidertypes.ProviderData
+	Machine        *v1alpha1.Machine
+	Status         *anxtypes.ProviderStatus
+	UserData       string
+	Config         resolvedConfig
+	ProviderData   *cloudprovidertypes.ProviderData
+	ProviderConfig *providerconfigtypes.Config
 }
 
 func createReconcileContext(ctx context.Context, cc reconcileContext) context.Context {
diff --git a/pkg/cloudprovider/provider/aws/types/cloudconfig.go b/pkg/cloudprovider/provider/aws/types/cloudconfig.go
index 2fca4788..40de3715 100644
--- a/pkg/cloudprovider/provider/aws/types/cloudconfig.go
+++ b/pkg/cloudprovider/provider/aws/types/cloudconfig.go
@@ -36,7 +36,9 @@ RoleARN={{ .Global.RoleARN | iniEscape }}
 KubernetesClusterID={{ .Global.KubernetesClusterID | iniEscape }}
 DisableSecurityGroupIngress={{ .Global.DisableSecurityGroupIngress }}
 ElbSecurityGroup={{ .Global.ElbSecurityGroup | iniEscape }}
-DisableStrictZoneCheck={{ .Global.DisableStrictZoneCheck }}
+{{- if .Global.DisableStrictZoneCheck }}
+DisableStrictZoneCheck=true
+{{- end }}
 {{- range .Global.NodeIPFamilies }}
 NodeIPFamilies={{ . | iniEscape}}
 {{- end }}
@@ -57,8 +59,10 @@ type GlobalOpts struct {
 	KubernetesClusterID         string
 	ElbSecurityGroup            string
 	DisableSecurityGroupIngress bool
-	DisableStrictZoneCheck      bool
-	NodeIPFamilies              []string
+	// DisableStrictZoneCheck has been removed in Kubernetes 1.27+.
+	// See https://github.com/kubernetes/cloud-provider-aws/pull/573 for more information.
+	DisableStrictZoneCheck bool
+	NodeIPFamilies         []string
 }
 
 func CloudConfigToString(c *CloudConfig) (string, error) {


Test patch:
diff --git a/.prow/e2e-features.yaml b/.prow/e2e-features.yaml
index 769eb361..66551674 100644
--- a/.prow/e2e-features.yaml
+++ b/.prow/e2e-features.yaml
@@ -34,7 +34,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -63,7 +63,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -91,7 +91,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
@@ -118,7 +118,7 @@ presubmits:
       preset-kubeconfig-ci: "true"
     spec:
       containers:
-        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-1
+        - image: quay.io/kubermatic/build:go-1.20-node-18-kind-0.18-3
           command:
             - "./hack/ci/run-e2e-tests.sh"
           args:
diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go
index 085aa70d..b0faddd7 100644
--- a/pkg/cloudprovider/provider/anexia/provider_test.go
+++ b/pkg/cloudprovider/provider/anexia/provider_test.go
@@ -45,6 +45,7 @@ import (
 	cloudprovidererrors "github.com/kubermatic/machine-controller/pkg/cloudprovider/errors"
 	anxtypes "github.com/kubermatic/machine-controller/pkg/cloudprovider/provider/anexia/types"
 	cloudprovidertypes "github.com/kubermatic/machine-controller/pkg/cloudprovider/types"
+	providerconfigtypes "github.com/kubermatic/machine-controller/pkg/providerconfig/types"
 
 	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -107,6 +108,11 @@ func TestAnexiaProvider(t *testing.T) {
 			testhelper.AssertEquals(t, expectedJSON["cpu_performance_type"], jsonBody["cpu_performance_type"])
 			testhelper.AssertEquals(t, expectedJSON["hostname"], jsonBody["hostname"])
 			testhelper.AssertEquals(t, expectedJSON["memory_mb"], jsonBody["memory_mb"])
+
+			testhelper.AssertEquals(t, jsonBody["dns1"], "1.1.1.1")
+			testhelper.AssertEquals(t, jsonBody["dns2"], nil)
+			testhelper.AssertEquals(t, jsonBody["dns3"], "192.168.0.1")
+			testhelper.AssertEquals(t, jsonBody["dns4"], "192.168.0.2")
 			testhelper.AssertEquals(t, expectedJSON["count"], jsonBody["count"])
 
 			expectedNetwork := expectedJSON["network"].([]jsonObject)[0]
@@ -165,6 +171,19 @@ func TestAnexiaProvider(t *testing.T) {
 					return nil
 				},
 			},
+			ProviderConfig: &providerconfigtypes.Config{
+				Network: &providerconfigtypes.NetworkConfig{
+					DNS: providerconfigtypes.DNSConfig{
+						Servers: []string{
+							"1.1.1.1",
+							"",
+							"192.168.0.1",
+							"192.168.0.2",
+							"192.168.0.3",
+						},
+					},
+				},
+			},
 		})
 
 		err := provisionVM(ctx, log, client)
diff --git a/test/e2e/provisioning/testdata/machinedeployment-aws-ebs-encryption-enabled.yaml b/test/e2e/provisioning/testdata/machinedeployment-aws-ebs-encryption-enabled.yaml
index cb22438f..9b5653b9 100644
--- a/test/e2e/provisioning/testdata/machinedeployment-aws-ebs-encryption-enabled.yaml
+++ b/test/e2e/provisioning/testdata/machinedeployment-aws-ebs-encryption-enabled.yaml
@@ -29,9 +29,9 @@ spec:
             accessKeyId: << AWS_ACCESS_KEY_ID >>
             secretAccessKey: << AWS_SECRET_ACCESS_KEY >>
             region: "eu-central-1"
-            availabilityZone: "eu-central-1a"
+            availabilityZone: "eu-central-1b"
             vpcId: "vpc-079f7648481a11e77"
-            instanceType: "t3a.small"
+            instanceType: "t2.medium"
             instanceProfile: "kubernetes-v1"
             diskSize: 50
             diskType: "gp2"
diff --git a/test/e2e/provisioning/testdata/machinedeployment-aws-spot-instances.yaml b/test/e2e/provisioning/testdata/machinedeployment-aws-spot-instances.yaml
index 2b93bc7a..bce0b19c 100644
--- a/test/e2e/provisioning/testdata/machinedeployment-aws-spot-instances.yaml
+++ b/test/e2e/provisioning/testdata/machinedeployment-aws-spot-instances.yaml
@@ -29,9 +29,9 @@ spec:
             accessKeyId: << AWS_ACCESS_KEY_ID >>
             secretAccessKey: << AWS_SECRET_ACCESS_KEY >>
             region: "eu-central-1"
-            availabilityZone: "eu-central-1a"
+            availabilityZone: "eu-central-1b"
             vpcId: "vpc-079f7648481a11e77"
-            instanceType: "t3a.small"
+            instanceType: "t2.medium"
             instanceProfile: "kubernetes-v1"
             diskSize: 50
             diskType: "gp2"
diff --git a/test/e2e/provisioning/testdata/machinedeployment-aws.yaml b/test/e2e/provisioning/testdata/machinedeployment-aws.yaml
index e9ef7ba4..6f7a7c2d 100644
--- a/test/e2e/provisioning/testdata/machinedeployment-aws.yaml
+++ b/test/e2e/provisioning/testdata/machinedeployment-aws.yaml
@@ -31,9 +31,9 @@ spec:
             assumeRoleARN: "<< AWS_ASSUME_ROLE_ARN >>"
             assumeRoleExternalID: "<< AWS_ASSUME_ROLE_EXTERNAL_ID >>"
             region: "eu-central-1"
-            availabilityZone: "eu-central-1a"
+            availabilityZone: "eu-central-1b"
             vpcId: "vpc-079f7648481a11e77"
-            instanceType: "t3a.small"
+            instanceType: "t2.medium"
             instanceProfile: "kubernetes-v1"
             diskSize: 50
             diskType: "gp2"