Repository: kubermatic/machine-controller
Pull request #755 (2020-05-14 23:09:35)

Fix setup script permissions
**What this PR does / why we need it**:
Fixed too wide permissions of the /opt/bin/setup

```release-note
NONE
```


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

This pull-request has been approved by: *<a href="https://github.com/kubermatic/machine-controller/pull/755#" title="Author self-approved">kron4eg</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/master/OWNERS)~~ [kron4eg]

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: @kron4eg: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-machine-controller-e2e-digitalocean | 10380b8340e004541d2ad538593b7983d76a8b55 | [link](https://public-prow.loodse.com/view/gcs/prow-dev-public-data/pr-logs/pull/kubermatic_machine-controller/755/pull-machine-controller-e2e-digitalocean/1261071326781640706) | `/test pull-machine-controller-e2e-digitalocean`

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

<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 -->
kron4eg: /retest 
kubermatic-bot: LGTM label has been added.  <details>Git tree hash: fa8689530797fd07cc77022ffb024859349d83b8</details>

Patch:
diff --git a/pkg/userdata/centos/provider.go b/pkg/userdata/centos/provider.go
index 6cc46c9a..4666f26e 100644
--- a/pkg/userdata/centos/provider.go
+++ b/pkg/userdata/centos/provider.go
@@ -162,7 +162,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -195,10 +195,12 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm{{ if eq .CloudProviderName "vsphere" }} \
-      open-vm-tools{{ end }}
+      {{- if eq .CloudProviderName "vsphere" }}
+      open-vm-tools \
+      {{- end }}
+      ipvsadm
 
-{{ downloadBinariesScript .KubeletVersion true | indent 4 }}
+{{ safeDownloadBinariesScript .KubeletVersion | indent 4 }}
 
     {{- if eq .CloudProviderName "vsphere" }}
     systemctl enable --now vmtoolsd.service
diff --git a/pkg/userdata/coreos/provider.go b/pkg/userdata/coreos/provider.go
index 73e288da..ee75c950 100644
--- a/pkg/userdata/coreos/provider.go
+++ b/pkg/userdata/coreos/provider.go
@@ -374,4 +374,4 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-{{ downloadBinariesScript .KubeletVersion false | indent 10 }}`
+{{ safeDownloadBinariesScript .KubeletVersion | indent 10 }}`
diff --git a/pkg/userdata/flatcar/provider.go b/pkg/userdata/flatcar/provider.go
index 1687e0c1..03cd7bce 100644
--- a/pkg/userdata/flatcar/provider.go
+++ b/pkg/userdata/flatcar/provider.go
@@ -374,4 +374,4 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-{{ downloadBinariesScript .KubeletVersion false | indent 10 }}`
+{{ safeDownloadBinariesScript .KubeletVersion | indent 10 }}`
diff --git a/pkg/userdata/helper/download_binaries_script.go b/pkg/userdata/helper/download_binaries_script.go
index c1dbebda..440fff52 100644
--- a/pkg/userdata/helper/download_binaries_script.go
+++ b/pkg/userdata/helper/download_binaries_script.go
@@ -19,10 +19,77 @@ package helper
 import (
 	"bytes"
 	"fmt"
+	"strings"
 	"text/template"
 )
 
 const (
+	safeDownloadBinariesTpl = `{{- /*setup some common directories */ -}}
+opt_bin=/opt/bin
+cni_bin_dir=/opt/cni/bin
+
+{{- /* create all the necessary dirs */}}
+mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+
+{{- /* HOST_ARCH can be defined outside of machine-controller (in kubeone for example) */}}
+arch=${HOST_ARCH:-amd64}
+
+{{- /* # CNI variables */}}
+CNI_VERSION="${CNI_VERSION:-{{ .CNIVersion }}}"
+cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+
+{{- /* download CNI */}}
+curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+
+{{- /* download CNI checksum */}}
+cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+cd "$cni_bin_dir"
+
+{{- /* verify CNI checksum */}}
+sha256sum -c <<<"$cni_sum"
+
+{{- /* unpack CNI */}}
+tar xvf "$cni_filename"
+rm -f "$cni_filename"
+cd -
+
+{{- /* kubelet */}}
+KUBE_VERSION="${KUBE_VERSION:-{{ .KubeVersion }}}"
+kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+kube_sum_file="$kube_dir/sha256"
+
+{{- /* create versioned kube dir */}}
+mkdir -p "$kube_dir"
+: >"$kube_sum_file"
+
+for bin in kubelet kubeadm kubectl; do
+    {{- /* download kube binary */}}
+    curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+    chmod +x "$kube_dir/$bin"
+
+    {{- /* download kube binary checksum */}}
+    sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+
+    {{- /* save kube binary checksum */}}
+    echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+done
+
+{{- /* check kube binaries checksum */}}
+sha256sum -c "$kube_sum_file"
+
+for bin in kubelet kubeadm kubectl; do
+    {{- /* link kube binaries from verioned dir to $opt_bin */}}
+    ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+done
+
+if [[ ! -x /opt/bin/health-monitor.sh ]]; then
+    curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
+    chmod +x /opt/bin/health-monitor.sh
+fi
+`
+
 	downloadBinariesTpl = `{{- /*setup some common directories */ -}}
 mkdir -p /opt/bin/
 mkdir -p /var/lib/calico
@@ -50,8 +117,40 @@ fi
 `
 )
 
-// DownloadBinariesScript returns the script which is responsible to download all required binaries.
-// Extracted into a dedicated function so we can use it to prepare custom images: TODO: Use it to prepare custom images...
+// SafeDownloadBinariesScript returns the script which is responsible to
+// download and check checksums of all required binaries.
+func SafeDownloadBinariesScript(kubeVersion string) (string, error) {
+	tmpl, err := template.New("download-binaries").Funcs(TxtFuncMap()).Parse(safeDownloadBinariesTpl)
+	if err != nil {
+		return "", fmt.Errorf("failed to parse download-binaries template: %v", err)
+	}
+
+	const CNIVersion = "v0.8.2"
+
+	// force v in case if it's not there
+	if !strings.HasPrefix(kubeVersion, "v") {
+		kubeVersion = "v" + kubeVersion
+	}
+
+	data := struct {
+		KubeVersion string
+		CNIVersion  string
+	}{
+		KubeVersion: kubeVersion,
+		CNIVersion:  CNIVersion,
+	}
+
+	b := &bytes.Buffer{}
+	err = tmpl.Execute(b, data)
+	if err != nil {
+		return "", fmt.Errorf("failed to execute download-binaries template: %v", err)
+	}
+
+	return b.String(), nil
+}
+
+// DownloadBinariesScript returns the script which is responsible to download
+// all required binaries.
 func DownloadBinariesScript(kubeletVersion string, downloadKubelet bool) (string, error) {
 	tmpl, err := template.New("download-binaries").Funcs(TxtFuncMap()).Parse(downloadBinariesTpl)
 	if err != nil {
diff --git a/pkg/userdata/helper/template_functions.go b/pkg/userdata/helper/template_functions.go
index c9428be2..447bf2fa 100644
--- a/pkg/userdata/helper/template_functions.go
+++ b/pkg/userdata/helper/template_functions.go
@@ -28,6 +28,7 @@ func TxtFuncMap() template.FuncMap {
 	funcMap := sprig.TxtFuncMap()
 
 	funcMap["downloadBinariesScript"] = DownloadBinariesScript
+	funcMap["safeDownloadBinariesScript"] = SafeDownloadBinariesScript
 	funcMap["kubeletSystemdUnit"] = KubeletSystemdUnit
 	funcMap["kubeletConfiguration"] = kubeletConfiguration
 	funcMap["kubeletFlags"] = KubeletFlags
diff --git a/pkg/userdata/rhel/provider.go b/pkg/userdata/rhel/provider.go
index f13c1793..5c6851ae 100644
--- a/pkg/userdata/rhel/provider.go
+++ b/pkg/userdata/rhel/provider.go
@@ -162,7 +162,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -200,10 +200,12 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm{{ if eq .CloudProviderName "vsphere" }} \
-      open-vm-tools{{ end }}
+      {{- if eq .CloudProviderName "vsphere" }}
+      open-vm-tools \
+      {{- end }}
+      ipvsadm
 
-{{ downloadBinariesScript .KubeletVersion true | indent 4 }}
+{{ safeDownloadBinariesScript .KubeletVersion | indent 4 }}
 
     {{- if eq .CloudProviderName "vsphere" }}
     systemctl enable --now vmtoolsd.service
diff --git a/pkg/userdata/sles/provider.go b/pkg/userdata/sles/provider.go
index 84af96e2..8f779bd7 100644
--- a/pkg/userdata/sles/provider.go
+++ b/pkg/userdata/sles/provider.go
@@ -114,6 +114,11 @@ hostname: {{ .MachineSpec.Name }}
 {{- /* Never set the hostname on AWS nodes. Kubernetes(kube-proxy) requires the hostname to be the private dns name */}}
 {{ end }}
 
+{{- if .OSConfig.DistUpgradeOnBoot }}
+package_upgrade: true
+package_reboot_if_required: true
+{{- end }}
+
 ssh_pwauth: no
 
 {{- if .ProviderSpec.SSHPublicKeys }}
@@ -164,16 +169,12 @@ write_files:
       e2fsprogs \
       jq \
       socat \
-      ipvsadm{{ if eq .CloudProviderName "vsphere" }} \
-      open-vm-tools{{ end }}
-    {{- if .OSConfig.DistUpgradeOnBoot }}
-    zypper --non-interactive --quiet --color dup
-    {{- end }}
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
-
-{{ downloadBinariesScript .KubeletVersion true | indent 4 }}
+      {{- if eq .CloudProviderName "vsphere" }}
+      open-vm-tools \
+      {{- end }}
+      ipvsadm
+
+{{ safeDownloadBinariesScript .KubeletVersion | indent 4 }}
 
     systemctl enable --now docker
     systemctl enable --now kubelet
diff --git a/pkg/userdata/ubuntu/provider.go b/pkg/userdata/ubuntu/provider.go
index 7b76f797..3f9509ac 100644
--- a/pkg/userdata/ubuntu/provider.go
+++ b/pkg/userdata/ubuntu/provider.go
@@ -114,6 +114,11 @@ hostname: {{ .MachineSpec.Name }}
 {{- /* Never set the hostname on AWS nodes. Kubernetes(kube-proxy) requires the hostname to be the private dns name */}}
 {{ end }}
 
+{{- if .OSConfig.DistUpgradeOnBoot }}
+package_upgrade: true
+package_reboot_if_required: true
+{{- end }}
+
 ssh_pwauth: no
 
 {{- if .ProviderSpec.SSHPublicKeys }}
@@ -242,8 +247,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -257,17 +263,15 @@ write_files:
       socat \
       util-linux \
       ${CR_PKG} \
-      ipvsadm{{ if eq .CloudProviderName "vsphere" }} \
-      open-vm-tools{{ end }}
+      {{- if eq .CloudProviderName "vsphere" }}
+      open-vm-tools \
+      {{- end }}
+      ipvsadm
 
 {{- /* If something failed during package installation but docker got installed, we need to put it on hold */}}
     apt-mark hold docker.io || true
     apt-mark hold docker-ce || true
 
-    {{- if .OSConfig.DistUpgradeOnBoot }}
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade -y
-    {{- end }}
-
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
     {{ if eq .CloudProviderName "alibaba" }}
@@ -278,11 +282,8 @@ write_files:
       touch /var/run/reboot-required
     fi
     {{ end }}
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-{{ downloadBinariesScript .KubeletVersion true | indent 4 }}
+{{ safeDownloadBinariesScript .KubeletVersion | indent 4 }}
 
     systemctl enable --now docker
     systemctl enable --now kubelet


Test patch:
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.10-aws.yaml b/pkg/userdata/centos/testdata/kubelet-v1.10-aws.yaml
index c7528536..25c2e1d3 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.10-aws.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.10-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -82,18 +82,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.10.2}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.11-aws.yaml b/pkg/userdata/centos/testdata/kubelet-v1.11-aws.yaml
index 4f5f1ec2..6b154881 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.11-aws.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.11-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -82,18 +82,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.12-aws-external.yaml b/pkg/userdata/centos/testdata/kubelet-v1.12-aws-external.yaml
index c4fc2d72..93b3e9da 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.12-aws-external.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.12-aws-external.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -82,18 +82,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.12-aws.yaml b/pkg/userdata/centos/testdata/kubelet-v1.12-aws.yaml
index e22865a3..969ee44f 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.12-aws.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.12-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -82,18 +82,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-mirrors.yaml b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-mirrors.yaml
index 570472fa..070a2cb7 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-mirrors.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-mirrors.yaml
@@ -65,7 +65,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -92,21 +92,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-proxy.yaml b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-proxy.yaml
index f1f91eb8..3314756e 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-proxy.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere-proxy.yaml
@@ -65,7 +65,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -92,21 +92,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere.yaml b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere.yaml
index dfdf7d2c..1e6b5cad 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.12-vsphere.yaml
@@ -57,7 +57,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -84,21 +84,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/centos/testdata/kubelet-v1.9-aws.yaml b/pkg/userdata/centos/testdata/kubelet-v1.9-aws.yaml
index 3933c7cc..0ac555b3 100644
--- a/pkg/userdata/centos/testdata/kubelet-v1.9-aws.yaml
+++ b/pkg/userdata/centos/testdata/kubelet-v1.9-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -82,18 +82,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.9.2/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml b/pkg/userdata/coreos/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
index db632cae..e5994b71 100644
--- a/pkg/userdata/coreos/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
+++ b/pkg/userdata/coreos/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
@@ -340,14 +340,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml b/pkg/userdata/coreos/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
index ae5a5879..2bc9f2bf 100644
--- a/pkg/userdata/coreos/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
+++ b/pkg/userdata/coreos/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
@@ -342,14 +342,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.10.3}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.11.2-vsphere-static-ipconfig.yaml b/pkg/userdata/coreos/testdata/v1.11.2-vsphere-static-ipconfig.yaml
index 85951602..1ec1dd46 100644
--- a/pkg/userdata/coreos/testdata/v1.11.2-vsphere-static-ipconfig.yaml
+++ b/pkg/userdata/coreos/testdata/v1.11.2-vsphere-static-ipconfig.yaml
@@ -360,14 +360,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.11.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-mirrors.yaml b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-mirrors.yaml
index 44d75e28..19e0ae19 100644
--- a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-mirrors.yaml
+++ b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-mirrors.yaml
@@ -377,14 +377,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
index a5230ede..49b93c08 100644
--- a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
+++ b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
@@ -361,14 +361,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-proxy.yaml b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-proxy.yaml
index 1d1e95c1..801c4dc3 100644
--- a/pkg/userdata/coreos/testdata/v1.12.0-vsphere-proxy.yaml
+++ b/pkg/userdata/coreos/testdata/v1.12.0-vsphere-proxy.yaml
@@ -377,14 +377,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.15.0-vsphere.yaml b/pkg/userdata/coreos/testdata/v1.15.0-vsphere.yaml
index e7d40307..850dd532 100644
--- a/pkg/userdata/coreos/testdata/v1.15.0-vsphere.yaml
+++ b/pkg/userdata/coreos/testdata/v1.15.0-vsphere.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.15.0-beta.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.17.0.yaml b/pkg/userdata/coreos/testdata/v1.17.0.yaml
index 9c7ba7cc..2245afbe 100644
--- a/pkg/userdata/coreos/testdata/v1.17.0.yaml
+++ b/pkg/userdata/coreos/testdata/v1.17.0.yaml
@@ -359,14 +359,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.17.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws-external.yaml b/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws-external.yaml
index 26ebcac9..4439943c 100644
--- a/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws-external.yaml
+++ b/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws-external.yaml
@@ -337,14 +337,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws.yaml b/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws.yaml
index 861e75bf..0b27e725 100644
--- a/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws.yaml
+++ b/pkg/userdata/coreos/testdata/v1.9.2-disable-auto-update-aws.yaml
@@ -338,14 +338,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.9.2-disable-locksmith-aws.yaml b/pkg/userdata/coreos/testdata/v1.9.2-disable-locksmith-aws.yaml
index 2e968bdb..2c8836ce 100644
--- a/pkg/userdata/coreos/testdata/v1.9.2-disable-locksmith-aws.yaml
+++ b/pkg/userdata/coreos/testdata/v1.9.2-disable-locksmith-aws.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/coreos/testdata/v1.9.2-disable-update-engine-aws.yaml b/pkg/userdata/coreos/testdata/v1.9.2-disable-update-engine-aws.yaml
index 0a218013..3842af38 100644
--- a/pkg/userdata/coreos/testdata/v1.9.2-disable-update-engine-aws.yaml
+++ b/pkg/userdata/coreos/testdata/v1.9.2-disable-update-engine-aws.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml b/pkg/userdata/flatcar/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
index 72ab05ff..1318865f 100644
--- a/pkg/userdata/flatcar/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
+++ b/pkg/userdata/flatcar/testdata/auto-update-openstack-kubelet-v-version-prefix.yaml
@@ -340,14 +340,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml b/pkg/userdata/flatcar/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
index 8b6c2986..f7623d4a 100644
--- a/pkg/userdata/flatcar/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.10.3-auto-update-openstack-multiple-dns.yaml
@@ -342,14 +342,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.10.3}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.11.2-vsphere-static-ipconfig.yaml b/pkg/userdata/flatcar/testdata/v1.11.2-vsphere-static-ipconfig.yaml
index 26442e53..73ac348c 100644
--- a/pkg/userdata/flatcar/testdata/v1.11.2-vsphere-static-ipconfig.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.11.2-vsphere-static-ipconfig.yaml
@@ -360,14 +360,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.11.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-mirrors.yaml b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-mirrors.yaml
index abba53f1..276ad5c2 100644
--- a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-mirrors.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-mirrors.yaml
@@ -377,14 +377,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
index 7ac46c62..25d4a46f 100644
--- a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-overwrite-cloudconfig.yaml
@@ -361,14 +361,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-proxy.yaml b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-proxy.yaml
index bdb51aa5..cdc966f5 100644
--- a/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-proxy.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.12.0-vsphere-proxy.yaml
@@ -377,14 +377,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.15.0-vsphere.yaml b/pkg/userdata/flatcar/testdata/v1.15.0-vsphere.yaml
index 9e06ee29..88cff238 100644
--- a/pkg/userdata/flatcar/testdata/v1.15.0-vsphere.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.15.0-vsphere.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.15.0-beta.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.17.0.yaml b/pkg/userdata/flatcar/testdata/v1.17.0.yaml
index b39452ce..d66f1a1f 100644
--- a/pkg/userdata/flatcar/testdata/v1.17.0.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.17.0.yaml
@@ -359,14 +359,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.17.0}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws-external.yaml b/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws-external.yaml
index b27cebfd..4949c3d6 100644
--- a/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws-external.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws-external.yaml
@@ -337,14 +337,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws.yaml b/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws.yaml
index 62ef0fa0..ce7dd87c 100644
--- a/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.9.2-disable-auto-update-aws.yaml
@@ -338,14 +338,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.9.2-disable-locksmith-aws.yaml b/pkg/userdata/flatcar/testdata/v1.9.2-disable-locksmith-aws.yaml
index 0a51ea1a..b60f4ba0 100644
--- a/pkg/userdata/flatcar/testdata/v1.9.2-disable-locksmith-aws.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.9.2-disable-locksmith-aws.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/flatcar/testdata/v1.9.2-disable-update-engine-aws.yaml b/pkg/userdata/flatcar/testdata/v1.9.2-disable-update-engine-aws.yaml
index b1d1c474..3ec33e5e 100644
--- a/pkg/userdata/flatcar/testdata/v1.9.2-disable-update-engine-aws.yaml
+++ b/pkg/userdata/flatcar/testdata/v1.9.2-disable-update-engine-aws.yaml
@@ -336,14 +336,38 @@ storage:
         inline: |
           #!/bin/bash
           set -xeuo pipefail
-          mkdir -p /opt/bin/
-          mkdir -p /var/lib/calico
-          mkdir -p /etc/kubernetes/manifests
-          mkdir -p /etc/cni/net.d
-          mkdir -p /opt/cni/bin
-          if [ ! -f /opt/cni/bin/loopback ]; then
-              curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-          fi
+          opt_bin=/opt/bin
+          cni_bin_dir=/opt/cni/bin
+          mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+          arch=${HOST_ARCH:-amd64}
+          CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+          cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+          cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+          curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+          cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+          cd "$cni_bin_dir"
+          sha256sum -c <<<"$cni_sum"
+          tar xvf "$cni_filename"
+          rm -f "$cni_filename"
+          cd -
+          KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+          kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+          kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+          kube_sum_file="$kube_dir/sha256"
+          mkdir -p "$kube_dir"
+          : >"$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+              chmod +x "$kube_dir/$bin"
+              sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+              echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+          done
+          sha256sum -c "$kube_sum_file"
+
+          for bin in kubelet kubeadm kubectl; do
+              ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+          done
 
           if [[ ! -x /opt/bin/health-monitor.sh ]]; then
               curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/helper/download_binaries_script_test.go b/pkg/userdata/helper/download_binaries_script_test.go
index f4294159..33063708 100644
--- a/pkg/userdata/helper/download_binaries_script_test.go
+++ b/pkg/userdata/helper/download_binaries_script_test.go
@@ -36,3 +36,15 @@ func TestDownloadBinariesScript(t *testing.T) {
 		})
 	}
 }
+
+func TestSafeDownloadBinariesScript(t *testing.T) {
+	name := "safe_download_binaries_v1.18.2"
+	t.Run(name, func(t *testing.T) {
+		script, err := SafeDownloadBinariesScript("v1.18.2")
+		if err != nil {
+			t.Error(err)
+		}
+		goldenName := name + ".golden"
+		test.CompareOutput(t, goldenName, script, *update)
+	})
+}
diff --git a/pkg/userdata/helper/testdata/safe_download_binaries_v1.18.2.golden b/pkg/userdata/helper/testdata/safe_download_binaries_v1.18.2.golden
new file mode 100644
index 00000000..310e6512
--- /dev/null
+++ b/pkg/userdata/helper/testdata/safe_download_binaries_v1.18.2.golden
@@ -0,0 +1,37 @@
+opt_bin=/opt/bin
+cni_bin_dir=/opt/cni/bin
+mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+arch=${HOST_ARCH:-amd64}
+CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+cd "$cni_bin_dir"
+sha256sum -c <<<"$cni_sum"
+tar xvf "$cni_filename"
+rm -f "$cni_filename"
+cd -
+KUBE_VERSION="${KUBE_VERSION:-v1.18.2}"
+kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+kube_sum_file="$kube_dir/sha256"
+mkdir -p "$kube_dir"
+: >"$kube_sum_file"
+
+for bin in kubelet kubeadm kubectl; do
+    curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+    chmod +x "$kube_dir/$bin"
+    sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+    echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+done
+sha256sum -c "$kube_sum_file"
+
+for bin in kubelet kubeadm kubectl; do
+    ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+done
+
+if [[ ! -x /opt/bin/health-monitor.sh ]]; then
+    curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
+    chmod +x /opt/bin/health-monitor.sh
+fi
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.10-aws.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.10-aws.yaml
index e375c35a..5216e7a5 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.10-aws.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.10-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -87,18 +87,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.10.2}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.11-aws.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.11-aws.yaml
index c7db74df..b46578b4 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.11-aws.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.11-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -87,18 +87,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.12-aws-external.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.12-aws-external.yaml
index 0781e558..b52010b4 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.12-aws-external.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.12-aws-external.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -87,18 +87,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.12-aws.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.12-aws.yaml
index 3cb355d1..35958489 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.12-aws.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.12-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -87,18 +87,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-mirrors.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-mirrors.yaml
index 8a0b8b54..4aa00b16 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-mirrors.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-mirrors.yaml
@@ -65,7 +65,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -97,21 +97,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-proxy.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-proxy.yaml
index 4a28527b..25337389 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-proxy.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere-proxy.yaml
@@ -65,7 +65,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -97,21 +97,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere.yaml
index a2813244..d2224dc2 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.12-vsphere.yaml
@@ -57,7 +57,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -89,21 +89,41 @@ write_files:
       socat \
       wget \
       curl \
-      ipvsadm \
-      open-vm-tools
-
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.0}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/rhel/testdata/kubelet-v1.9-aws.yaml b/pkg/userdata/rhel/testdata/kubelet-v1.9-aws.yaml
index 1f80c2f3..18adc327 100644
--- a/pkg/userdata/rhel/testdata/kubelet-v1.9-aws.yaml
+++ b/pkg/userdata/rhel/testdata/kubelet-v1.9-aws.yaml
@@ -55,7 +55,7 @@ write_files:
     SELINUXTYPE=targeted
 
 - path: "/opt/bin/setup"
-  permissions: "0777"
+  permissions: "0755"
   content: |
     #!/bin/bash
     set -xeuo pipefail
@@ -87,18 +87,38 @@ write_files:
       curl \
       ipvsadm
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.9.2/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.9.2}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/dist-upgrade-on-boot.yaml b/pkg/userdata/sles/testdata/dist-upgrade-on-boot.yaml
index d894cf61..92219ceb 100644
--- a/pkg/userdata/sles/testdata/dist-upgrade-on-boot.yaml
+++ b/pkg/userdata/sles/testdata/dist-upgrade-on-boot.yaml
@@ -2,6 +2,8 @@
 
 hostname: node1
 
+package_upgrade: true
+package_reboot_if_required: true
 
 ssh_pwauth: no
 ssh_authorized_keys:
@@ -62,23 +64,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    zypper --non-interactive --quiet --color dup
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/kubelet-version-without-v-prefix.yaml b/pkg/userdata/sles/testdata/kubelet-version-without-v-prefix.yaml
index 37c90c62..6cb91862 100644
--- a/pkg/userdata/sles/testdata/kubelet-version-without-v-prefix.yaml
+++ b/pkg/userdata/sles/testdata/kubelet-version-without-v-prefix.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/multiple-dns-servers.yaml b/pkg/userdata/sles/testdata/multiple-dns-servers.yaml
index 6263a69e..ab144f51 100644
--- a/pkg/userdata/sles/testdata/multiple-dns-servers.yaml
+++ b/pkg/userdata/sles/testdata/multiple-dns-servers.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/multiple-ssh-keys.yaml b/pkg/userdata/sles/testdata/multiple-ssh-keys.yaml
index 111abe11..13e4aa9a 100644
--- a/pkg/userdata/sles/testdata/multiple-ssh-keys.yaml
+++ b/pkg/userdata/sles/testdata/multiple-ssh-keys.yaml
@@ -64,22 +64,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/openstack-overwrite-cloud-config.yaml b/pkg/userdata/sles/testdata/openstack-overwrite-cloud-config.yaml
index 5a402323..d7a3fe9d 100644
--- a/pkg/userdata/sles/testdata/openstack-overwrite-cloud-config.yaml
+++ b/pkg/userdata/sles/testdata/openstack-overwrite-cloud-config.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/openstack.yaml b/pkg/userdata/sles/testdata/openstack.yaml
index 6d600e1b..34709e4a 100644
--- a/pkg/userdata/sles/testdata/openstack.yaml
+++ b/pkg/userdata/sles/testdata/openstack.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/version-1.10.10.yaml b/pkg/userdata/sles/testdata/version-1.10.10.yaml
index 9a0af0e2..a5967177 100644
--- a/pkg/userdata/sles/testdata/version-1.10.10.yaml
+++ b/pkg/userdata/sles/testdata/version-1.10.10.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.10.10/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.10.10}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/version-1.11.3.yaml b/pkg/userdata/sles/testdata/version-1.11.3.yaml
index 37c90c62..6cb91862 100644
--- a/pkg/userdata/sles/testdata/version-1.11.3.yaml
+++ b/pkg/userdata/sles/testdata/version-1.11.3.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/version-1.12.1.yaml b/pkg/userdata/sles/testdata/version-1.12.1.yaml
index 9bcd8c82..2f3545ca 100644
--- a/pkg/userdata/sles/testdata/version-1.12.1.yaml
+++ b/pkg/userdata/sles/testdata/version-1.12.1.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.1/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.1}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/version-1.9.10.yaml b/pkg/userdata/sles/testdata/version-1.9.10.yaml
index 4b717188..d010bc96 100644
--- a/pkg/userdata/sles/testdata/version-1.9.10.yaml
+++ b/pkg/userdata/sles/testdata/version-1.9.10.yaml
@@ -62,22 +62,39 @@ write_files:
       jq \
       socat \
       ipvsadm
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.9.10/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.9.10}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/vsphere-mirrors.yaml b/pkg/userdata/sles/testdata/vsphere-mirrors.yaml
index 02c97161..aba32e2c 100644
--- a/pkg/userdata/sles/testdata/vsphere-mirrors.yaml
+++ b/pkg/userdata/sles/testdata/vsphere-mirrors.yaml
@@ -70,24 +70,41 @@ write_files:
       e2fsprogs \
       jq \
       socat \
-      ipvsadm \
-      open-vm-tools
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/vsphere-proxy.yaml b/pkg/userdata/sles/testdata/vsphere-proxy.yaml
index 65457083..c7aaacaa 100644
--- a/pkg/userdata/sles/testdata/vsphere-proxy.yaml
+++ b/pkg/userdata/sles/testdata/vsphere-proxy.yaml
@@ -70,24 +70,41 @@ write_files:
       e2fsprogs \
       jq \
       socat \
-      ipvsadm \
-      open-vm-tools
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/sles/testdata/vsphere.yaml b/pkg/userdata/sles/testdata/vsphere.yaml
index 988e7ea2..e298419f 100644
--- a/pkg/userdata/sles/testdata/vsphere.yaml
+++ b/pkg/userdata/sles/testdata/vsphere.yaml
@@ -61,24 +61,41 @@ write_files:
       e2fsprogs \
       jq \
       socat \
-      ipvsadm \
-      open-vm-tools
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
+      open-vm-tools \
+      ipvsadm
+
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/dist-upgrade-on-boot.yaml b/pkg/userdata/ubuntu/testdata/dist-upgrade-on-boot.yaml
index feb837e5..4bdad161 100644
--- a/pkg/userdata/ubuntu/testdata/dist-upgrade-on-boot.yaml
+++ b/pkg/userdata/ubuntu/testdata/dist-upgrade-on-boot.yaml
@@ -2,6 +2,8 @@
 
 hostname: node1
 
+package_upgrade: true
+package_reboot_if_required: true
 
 ssh_pwauth: no
 ssh_authorized_keys:
@@ -138,8 +140,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -156,27 +159,43 @@ write_files:
       ipvsadm
     apt-mark hold docker.io || true
     apt-mark hold docker-ce || true
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade -y
 
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/kubelet-version-without-v-prefix.yaml b/pkg/userdata/ubuntu/testdata/kubelet-version-without-v-prefix.yaml
index fd235b05..43ac0ee6 100644
--- a/pkg/userdata/ubuntu/testdata/kubelet-version-without-v-prefix.yaml
+++ b/pkg/userdata/ubuntu/testdata/kubelet-version-without-v-prefix.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/multiple-dns-servers.yaml b/pkg/userdata/ubuntu/testdata/multiple-dns-servers.yaml
index f2d9122c..3b7646e0 100644
--- a/pkg/userdata/ubuntu/testdata/multiple-dns-servers.yaml
+++ b/pkg/userdata/ubuntu/testdata/multiple-dns-servers.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/multiple-ssh-keys.yaml b/pkg/userdata/ubuntu/testdata/multiple-ssh-keys.yaml
index 2c4fbcef..9e75d609 100644
--- a/pkg/userdata/ubuntu/testdata/multiple-ssh-keys.yaml
+++ b/pkg/userdata/ubuntu/testdata/multiple-ssh-keys.yaml
@@ -140,8 +140,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -162,22 +163,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/openstack-overwrite-cloud-config.yaml b/pkg/userdata/ubuntu/testdata/openstack-overwrite-cloud-config.yaml
index fbbcc5b9..778b284b 100644
--- a/pkg/userdata/ubuntu/testdata/openstack-overwrite-cloud-config.yaml
+++ b/pkg/userdata/ubuntu/testdata/openstack-overwrite-cloud-config.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/openstack.yaml b/pkg/userdata/ubuntu/testdata/openstack.yaml
index a9b0fccc..99eee26b 100644
--- a/pkg/userdata/ubuntu/testdata/openstack.yaml
+++ b/pkg/userdata/ubuntu/testdata/openstack.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/version-1.10.10.yaml b/pkg/userdata/ubuntu/testdata/version-1.10.10.yaml
index 9bf37568..0ea2f283 100644
--- a/pkg/userdata/ubuntu/testdata/version-1.10.10.yaml
+++ b/pkg/userdata/ubuntu/testdata/version-1.10.10.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.10.10/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.10.10}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/version-1.11.3.yaml b/pkg/userdata/ubuntu/testdata/version-1.11.3.yaml
index fd235b05..43ac0ee6 100644
--- a/pkg/userdata/ubuntu/testdata/version-1.11.3.yaml
+++ b/pkg/userdata/ubuntu/testdata/version-1.11.3.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/version-1.12.1.yaml b/pkg/userdata/ubuntu/testdata/version-1.12.1.yaml
index 86df7f90..8a13d834 100644
--- a/pkg/userdata/ubuntu/testdata/version-1.12.1.yaml
+++ b/pkg/userdata/ubuntu/testdata/version-1.12.1.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.12.1/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.12.1}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/version-1.9.10.yaml b/pkg/userdata/ubuntu/testdata/version-1.9.10.yaml
index f11ea0be..619bd0ce 100644
--- a/pkg/userdata/ubuntu/testdata/version-1.9.10.yaml
+++ b/pkg/userdata/ubuntu/testdata/version-1.9.10.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -160,22 +161,39 @@ write_files:
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.9.10/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.9.10}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/vsphere-mirrors.yaml b/pkg/userdata/ubuntu/testdata/vsphere-mirrors.yaml
index b030a442..7f5b29cf 100644
--- a/pkg/userdata/ubuntu/testdata/vsphere-mirrors.yaml
+++ b/pkg/userdata/ubuntu/testdata/vsphere-mirrors.yaml
@@ -147,8 +147,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -162,30 +163,47 @@ write_files:
       socat \
       util-linux \
       ${CR_PKG} \
-      ipvsadm \
-      open-vm-tools
+      open-vm-tools \
+      ipvsadm
     apt-mark hold docker.io || true
     apt-mark hold docker-ce || true
 
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/vsphere-proxy.yaml b/pkg/userdata/ubuntu/testdata/vsphere-proxy.yaml
index a02d2dcb..903106e5 100644
--- a/pkg/userdata/ubuntu/testdata/vsphere-proxy.yaml
+++ b/pkg/userdata/ubuntu/testdata/vsphere-proxy.yaml
@@ -147,8 +147,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -162,30 +163,47 @@ write_files:
       socat \
       util-linux \
       ${CR_PKG} \
-      ipvsadm \
-      open-vm-tools
+      open-vm-tools \
+      ipvsadm
     apt-mark hold docker.io || true
     apt-mark hold docker-ce || true
 
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh
diff --git a/pkg/userdata/ubuntu/testdata/vsphere.yaml b/pkg/userdata/ubuntu/testdata/vsphere.yaml
index 841b33b2..baec4652 100644
--- a/pkg/userdata/ubuntu/testdata/vsphere.yaml
+++ b/pkg/userdata/ubuntu/testdata/vsphere.yaml
@@ -138,8 +138,9 @@ write_files:
     swapoff -a
 
     export CR_PKG='docker-ce=5:18.09.9~3-0~ubuntu-bionic'
+    export DEBIAN_FRONTEND=noninteractive
 
-    DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
+    apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y \
       curl \
       ca-certificates \
       conntrack \
@@ -153,30 +154,47 @@ write_files:
       socat \
       util-linux \
       ${CR_PKG} \
-      ipvsadm \
-      open-vm-tools
+      open-vm-tools \
+      ipvsadm
     apt-mark hold docker.io || true
     apt-mark hold docker-ce || true
 
     # Update grub to include kernel command options to enable swap accounting.
     # Exclude alibaba cloud until this is fixed https://github.com/kubermatic/machine-controller/issues/682
 
-    if [[ -e /var/run/reboot-required ]]; then
-      reboot
-    fi
 
-    mkdir -p /opt/bin/
-    mkdir -p /var/lib/calico
-    mkdir -p /etc/kubernetes/manifests
-    mkdir -p /etc/cni/net.d
-    mkdir -p /opt/cni/bin
-    if [ ! -f /opt/cni/bin/loopback ]; then
-        curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz | tar -xvzC /opt/cni/bin -f -
-    fi
-    if [ ! -f /opt/bin/kubelet ]; then
-        curl -Lfo /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubelet
-        chmod +x /opt/bin/kubelet
-    fi
+    opt_bin=/opt/bin
+    cni_bin_dir=/opt/cni/bin
+    mkdir -p /etc/cni/net.d /etc/kubernetes/dynamic-config-dir /etc/kubernetes/manifests "$opt_bin" "$cni_bin_dir"
+    arch=${HOST_ARCH:-amd64}
+    CNI_VERSION="${CNI_VERSION:-v0.8.2}"
+    cni_base_url="https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION"
+    cni_filename="cni-plugins-linux-$arch-$CNI_VERSION.tgz"
+    curl -Lfo "$cni_bin_dir/$cni_filename" "$cni_base_url/$cni_filename"
+    cni_sum=$(curl -Lf "$cni_base_url/$cni_filename.sha256")
+    cd "$cni_bin_dir"
+    sha256sum -c <<<"$cni_sum"
+    tar xvf "$cni_filename"
+    rm -f "$cni_filename"
+    cd -
+    KUBE_VERSION="${KUBE_VERSION:-v1.11.3}"
+    kube_dir="$opt_bin/kubernetes-$KUBE_VERSION"
+    kube_base_url="https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$arch"
+    kube_sum_file="$kube_dir/sha256"
+    mkdir -p "$kube_dir"
+    : >"$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        curl -Lfo "$kube_dir/$bin" "$kube_base_url/$bin"
+        chmod +x "$kube_dir/$bin"
+        sum=$(curl -Lf "$kube_base_url/$bin.sha256")
+        echo "$sum  $kube_dir/$bin" >>"$kube_sum_file"
+    done
+    sha256sum -c "$kube_sum_file"
+
+    for bin in kubelet kubeadm kubectl; do
+        ln -sf "$kube_dir/$bin" "$opt_bin"/$bin
+    done
 
     if [[ ! -x /opt/bin/health-monitor.sh ]]; then
         curl -Lfo /opt/bin/health-monitor.sh https://raw.githubusercontent.com/kubermatic/machine-controller/8b5b66e4910a6228dfaecccaa0a3b05ec4902f8e/pkg/userdata/scripts/health-monitor.sh