diff --git a/api/v1alpha1/ionoscloudclustertemplate_types.go b/api/v1alpha1/ionoscloudclustertemplate_types.go new file mode 100644 index 00000000..cbce26a8 --- /dev/null +++ b/api/v1alpha1/ionoscloudclustertemplate_types.go @@ -0,0 +1,54 @@ +/* +Copyright 2024 IONOS Cloud. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// IonosCloudClusterTemplateSpec defines the desired state of IonosCloudClusterTemplate. +type IonosCloudClusterTemplateSpec struct { + Template IonosCloudClusterTemplateResource `json:"template"` +} + +// IonosCloudClusterTemplateResource describes the data for creating a IonosCloudCluster from a template. +type IonosCloudClusterTemplateResource struct { + Spec IonosCloudClusterSpec `json:"spec"` +} + +//+kubebuilder:object:root=true + +// IonosCloudClusterTemplate is the Schema for the ionoscloudclustertemplates API. +type IonosCloudClusterTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec IonosCloudClusterTemplateSpec `json:"spec,omitempty"` +} + +//+kubebuilder:object:root=true + +// IonosCloudClusterTemplateList contains a list of IonosCloudClusterTemplate. +type IonosCloudClusterTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IonosCloudCluster `json:"items"` +} + +func init() { + objectTypes = append(objectTypes, &IonosCloudClusterTemplate{}, &IonosCloudClusterTemplateList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 9aef4f4c..2dce7758 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -151,6 +151,96 @@ func (in *IonosCloudClusterStatus) DeepCopy() *IonosCloudClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IonosCloudClusterTemplate) DeepCopyInto(out *IonosCloudClusterTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IonosCloudClusterTemplate. +func (in *IonosCloudClusterTemplate) DeepCopy() *IonosCloudClusterTemplate { + if in == nil { + return nil + } + out := new(IonosCloudClusterTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IonosCloudClusterTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IonosCloudClusterTemplateList) DeepCopyInto(out *IonosCloudClusterTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IonosCloudCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IonosCloudClusterTemplateList. +func (in *IonosCloudClusterTemplateList) DeepCopy() *IonosCloudClusterTemplateList { + if in == nil { + return nil + } + out := new(IonosCloudClusterTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IonosCloudClusterTemplateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IonosCloudClusterTemplateResource) DeepCopyInto(out *IonosCloudClusterTemplateResource) { + *out = *in + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IonosCloudClusterTemplateResource. +func (in *IonosCloudClusterTemplateResource) DeepCopy() *IonosCloudClusterTemplateResource { + if in == nil { + return nil + } + out := new(IonosCloudClusterTemplateResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IonosCloudClusterTemplateSpec) DeepCopyInto(out *IonosCloudClusterTemplateSpec) { + *out = *in + out.Template = in.Template +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IonosCloudClusterTemplateSpec. +func (in *IonosCloudClusterTemplateSpec) DeepCopy() *IonosCloudClusterTemplateSpec { + if in == nil { + return nil + } + out := new(IonosCloudClusterTemplateSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IonosCloudMachine) DeepCopyInto(out *IonosCloudMachine) { *out = *in diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml new file mode 100644 index 00000000..75fee1b4 --- /dev/null +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml @@ -0,0 +1,120 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ionoscloudclustertemplates.infrastructure.cluster.x-k8s.io +spec: + group: infrastructure.cluster.x-k8s.io + names: + kind: IonosCloudClusterTemplate + listKind: IonosCloudClusterTemplateList + plural: ionoscloudclustertemplates + singular: ionoscloudclustertemplate + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IonosCloudClusterTemplate is the Schema for the ionoscloudclustertemplates + API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IonosCloudClusterTemplateSpec defines the desired state of + IonosCloudClusterTemplate. + properties: + template: + description: IonosCloudClusterTemplateResource describes the data + for creating a IonosCloudCluster from a template. + properties: + spec: + description: IonosCloudClusterSpec defines the desired state of + IonosCloudCluster. + properties: + contractNumber: + description: Contract number is the contract number of the + IONOS Cloud account. + type: string + x-kubernetes-validations: + - message: contractNumber is immutable + rule: self == oldSelf + controlPlaneEndpoint: + description: |- + ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. + + + TODO(gfariasalves): as of now, IP must be provided by the user as we still don't insert the + provider-provided block IP into the kube-vip manifest. + properties: + host: + description: The hostname on which the API server is serving. + type: string + port: + description: The port on which the API server is serving. + format: int32 + type: integer + required: + - host + - port + type: object + x-kubernetes-validations: + - message: control plane endpoint host cannot be updated + rule: self.host == oldSelf.host || oldSelf.host == '' + - message: control plane endpoint port cannot be updated + rule: self.port == oldSelf.port || oldSelf.port == 0 + credentialsRef: + description: CredentialsRef is a reference to the secret containing + the credentials to access the IONOS Cloud API. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + x-kubernetes-validations: + - message: credentialsRef.name must be provided + rule: has(self.name) && self.name != '' + location: + description: Location is the location where the data centers + should be located. + example: de/txl + minLength: 1 + type: string + x-kubernetes-validations: + - message: location is immutable + rule: self == oldSelf + required: + - contractNumber + - credentialsRef + - location + type: object + required: + - spec + type: object + required: + - template + type: object + type: object + served: true + storage: true diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index b4b34cab..59e9227f 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,6 +3,7 @@ # It should be run by config/default resources: - bases/infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml +- bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml - bases/infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml - bases/infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml #+kubebuilder:scaffold:crdkustomizeresource diff --git a/templates/cluster-template-topology.yaml b/templates/cluster-template-topology.yaml new file mode 100644 index 00000000..92bef270 --- /dev/null +++ b/templates/cluster-template-topology.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + labels: + cluster.x-k8s.io/cluster-name: '${CLUSTER_NAME}' + name: '${CLUSTER_NAME}' + namespace: '${NAMESPACE}' +spec: + topology: + class: '${CLUSTER_CLASS_NAME}' + controlPlane: + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + variables: + - name: sshKey + value: '${VSPHERE_SSH_AUTHORIZED_KEY}' + - name: controlPlaneIpAddr + value: ${CONTROL_PLANE_ENDPOINT_IP} + - name: controlPlanePort + value: ${CONTROL_PLANE_ENDPOINT_PORT:-6443} + - name: credsSecretName + value: '${CLUSTER_NAME}' + - name: datacenterID + value: '${IONOSCLOUD_DATACENTER_ID}' + - name: contractNumber + value: '${IONOSCLOUD_CONTRACT_NUMBER}' + - name: location + value: '${CONTROL_PLANE_ENDPOINT_LOCATION}' + version: '${KUBERNETES_VERSION}' + workers: + machineDeployments: + - class: ${CLUSTER_CLASS_NAME}-worker + metadata: {} + name: md-0 + replicas: ${WORKER_MACHINE_COUNT} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "${CLUSTER_NAME}-credentials" + namespace: '${NAMESPACE}' +type: Opaque +stringData: + token: "${IONOS_TOKEN}" + apiURL: "${IONOS_API_URL:-https://api.ionos.com/cloudapi/v6}" \ No newline at end of file diff --git a/templates/clusterclass-template.yaml b/templates/clusterclass-template.yaml new file mode 100644 index 00000000..4eb0cba5 --- /dev/null +++ b/templates/clusterclass-template.yaml @@ -0,0 +1,523 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 +kind: IonosCloudClusterTemplate +metadata: + name: '${CLUSTER_CLASS_NAME}' + namespace: '${NAMESPACE}' +spec: + template: + spec: + credentialsRef: {} +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + name: '${CLUSTER_CLASS_NAME}' + namespace: '${NAMESPACE}' +spec: + controlPlane: + machineInfrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudMachineTemplate + name: ${CLUSTER_CLASS_NAME}-template + namespace: '${NAMESPACE}' + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + name: ${CLUSTER_CLASS_NAME}-controlplane + namespace: '${NAMESPACE}' + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudClusterTemplate + name: '${CLUSTER_CLASS_NAME}' + namespace: '${NAMESPACE}' + patches: + - definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/kubeadmConfigSpec/users + valueFrom: + template: | + - name: capv + sshAuthorizedKeys: + - '{{ .sshKey }}' + sudo: ALL=(ALL) NOPASSWD:ALL + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + - jsonPatches: + - op: add + path: /spec/template/spec/users + valueFrom: + template: | + - name: capv + sshAuthorizedKeys: + - '{{ .sshKey }}' + sudo: ALL=(ALL) NOPASSWD:ALL + selector: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: KubeadmConfigTemplate + matchResources: + machineDeploymentClass: + names: + - ${CLUSTER_CLASS_NAME}-worker + enabledIf: '{{ if .sshKey }}true{{end}}' + name: enableSSHIntoNodes + - definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/kubeadmConfigSpec/files/- + valueFrom: + template: | + # CSI Metadata config + content: | + { + "datacenter-id": "{{ .datacenterID }}" + } + owner: root:root + path: /etc/ie-csi/cfg.json + permissions: '0644' + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + - jsonPatches: + - op: add + path: /spec/template/spec/files/- + valueFrom: + template: | + # CSI Metadata config + content: | + { + "datacenter-id": "{{ .datacenterID }}" + } + owner: root:root + path: /etc/ie-csi/cfg.json + permissions: '0644' + selector: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: KubeadmConfigTemplate + matchResources: + machineDeploymentClass: + names: + - ${CLUSTER_CLASS_NAME}-worker + - jsonPatches: + - op: add + path: /spec/template/spec/datacenterID + valueFrom: + variable: datacenterID + selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudMachineTemplate + matchResources: + controlPlane: true + - jsonPatches: + - op: add + path: /spec/template/spec/datacenterID + valueFrom: + variable: datacenterID + selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudMachineTemplate + matchResources: + machineDeploymentClass: + names: + - ${CLUSTER_CLASS_NAME}-worker + name: datacenterIdSubstitutionsOnKubeadm + - definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/kubeadmConfigSpec/initConfiguration/localAPIEndpoint/bindPort + valueFrom: + variable: controlPlanePort + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + - jsonPatches: + - op: add + path: /spec/template/spec/controlPlaneEndpoint + valueFrom: + template: | + host: '{{ .controlPlaneHost | default .controlPlaneIpAddr }}' + port: {{ .controlPlanePort }} + - op: add + path: /spec/template/spec/credentialsRef/name + valueFrom: + variable: credsSecretName + - op: add + path: /spec/template/spec/location + valueFrom: + variable: location + - op: add + path: /spec/template/spec/contractNumber + valueFrom: + variable: contractNumber + selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudClusterTemplate + matchResources: + infrastructureCluster: true + name: infraClusterSubstitutions + - definitions: + - jsonPatches: + - op: add + path: /spec/template/spec/kubeadmConfigSpec/files/- + valueFrom: + template: |- + owner: "root:root" + path: "/etc/kubernetes/manifests/kube-vip.yaml" + content: | + apiVersion: v1 + kind: Pod + metadata: + name: kube-vip + namespace: kube-system + spec: + containers: + - args: + - manager + env: + - name: cp_enable + value: "true" + - name: vip_interface + value: ${VIP_NETWORK_INTERFACE=""} + - name: address + value: ${CONTROL_PLANE_ENDPOINT_IP} + - name: port + value: "${CONTROL_PLANE_ENDPOINT_PORT:-6443}" + - name: vip_arp + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "15" + - name: vip_renewdeadline + value: "10" + - name: vip_retryperiod + value: "2" + image: ghcr.io/kube-vip/kube-vip:v0.7.1 + imagePullPolicy: IfNotPresent + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + - localhost + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + type: FileOrCreate + name: kubeconfig + status: {} + permissions: "0644" + - op: add + path: /spec/template/spec/kubeadmConfigSpec/files/- + valueFrom: + template: | + content: | + #!/bin/bash + + # Copyright 2020 The Kubernetes Authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + set -e + + # Configure the workaround required for kubeadm init with kube-vip: + # xref: https://github.com/kube-vip/kube-vip/issues/684 + + # Nothing to do for kubernetes < v1.29 + KUBEADM_MINOR="$(kubeadm version -o short | cut -d '.' -f 2)" + if [[ "$KUBEADM_MINOR" -lt "29" ]]; then + exit 0 + fi + + IS_KUBEADM_INIT="false" + + # cloud-init kubeadm init + if [[ -f /run/kubeadm/kubeadm.yaml ]]; then + IS_KUBEADM_INIT="true" + fi + + # ignition kubeadm init + if [[ -f /etc/kubeadm.sh ]] && grep -q -e "kubeadm init" /etc/kubeadm.sh; then + IS_KUBEADM_INIT="true" + fi + + if [[ "$IS_KUBEADM_INIT" == "true" ]]; then + sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' \ + /etc/kubernetes/manifests/kube-vip.yaml + fi + owner: root:root + path: /etc/pre-kubeadm-commands/50-kube-vip-prepare.sh + permissions: "0700" + selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + name: kubeVipPodManifest + variables: + - metadata: {} + name: sshKey + required: false + schema: + openAPIV3Schema: + description: Public key to SSH onto the cluster nodes. + type: string + - metadata: {} + name: datacenterID + required: true + schema: + openAPIV3Schema: + description: datacenterID for IONOS + type: string + - metadata: {} + name: controlPlaneIpAddr + required: true + schema: + openAPIV3Schema: + description: Floating VIP for the control plane. + type: string + - metadata: {} + name: controlPlaneHost + required: false + schema: + openAPIV3Schema: + description: FQDN for the control plane. + type: string + - metadata: {} + name: controlPlanePort + required: true + schema: + openAPIV3Schema: + description: Port for the control plane endpoint. + type: integer + - metadata: {} + name: credsSecretName + required: true + schema: + openAPIV3Schema: + description: Secret containing the credentials for the infra cluster. + type: string + - metadata: {} + name: location + required: true + schema: + openAPIV3Schema: + description: cluster location on IONOS + type: string + - metadata: {} + name: contractNumber + required: true + schema: + openAPIV3Schema: + description: contract number to use on IONOS + type: string + workers: + machineDeployments: + - class: ${CLUSTER_CLASS_NAME}-worker + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: KubeadmConfigTemplate + name: ${CLUSTER_CLASS_NAME}-worker + namespace: '${NAMESPACE}' + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: IonosCloudMachineTemplate + name: ${CLUSTER_CLASS_NAME}-worker-machinetemplate + namespace: '${NAMESPACE}' + metadata: {} +--- +kind: KubeadmControlPlaneTemplate +apiVersion: controlplane.cluster.x-k8s.io/v1beta1 +metadata: + name: "${CLUSTER_CLASS_NAME}-controlplane" + namespace: '${NAMESPACE}' +spec: + template: + spec: + kubeadmConfigSpec: + ntp: + enabled: true + servers: + - 0.de.pool.ntp.org + - 1.de.pool.ntp.org + - 2.de.pool.ntp.org + - 3.de.pool.ntp.org + files: + - path: /etc/ssh/sshd_config.d/ssh-audit_hardening.conf + owner: root:root + permissions: '0644' + content: | + # Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com + # hardening guide. + KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com + HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com + - path: /etc/sysctl.d/k8s.conf + content: | + fs.inotify.max_user_watches = 65536 + net.netfilter.nf_conntrack_max = 1000000 + - path: /etc/modules-load.d/k8s.conf + content: | + ip_vs + ip_vs_rr + ip_vs_wrr + ip_vs_sh + ip_vs_sed + # Crictl config + - path: /etc/crictl.yaml + content: | + runtime-endpoint: unix:///run/containerd/containerd.sock + timeout: 10 + preKubeadmCommands: + - systemctl restart systemd-networkd.service systemd-modules-load.service systemd-journald containerd + # disable swap + - swapoff -apostKubeadmCommands + postKubeadmCommands: + - > + sed -i 's#path: /etc/kubernetes/super-admin.conf#path: /etc/kubernetes/admin.conf#' \ + /etc/kubernetes/manifests/kube-vip.yaml + - > + systemctl disable --now udisks2 multipathd motd-news.timer fwupd-refresh.timer + packagekit ModemManager snapd snapd.socket snapd.apparmor snapd.seeded + # TODO(jriedel-ionos): remove that if we have a CCM + - export system_uuid=$(kubectl --kubeconfig /etc/kubernetes/kubelet.conf get node $(hostname) -ojsonpath='{..systemUUID }') + - > + kubectl --kubeconfig /etc/kubernetes/kubelet.conf + patch node $(hostname) + --type strategic -p '{"spec": {"providerID": "ionos://'$${system_uuid}'"}}' + nodeRegistration: + kubeletExtraArgs: + # use cloud-provider: external when using a CCM + cloud-provider: "" + initConfiguration: + localAPIEndpoint: {} + joinConfiguration: + nodeRegistration: + criSocket: unix:///run/containerd/containerd.sock +--- +kind: IonosCloudMachineTemplate +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 +metadata: + name: "${CLUSTER_CLASS_NAME}-template" + namespace: '${NAMESPACE}' +spec: + template: + spec: + numCores: ${IONOSCLOUD_MACHINE_NUM_CORES} + memoryMB: ${IONOSCLOUD_MACHINE_MEMORY_MB} + disk: + image: + id: ${IONOSCLOUD_MACHINE_IMAGE_ID} +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 +kind: IonosCloudMachineTemplate +metadata: + name: "${CLUSTER_CLASS_NAME}-worker-machinetemplate" + namespace: '${NAMESPACE}' +spec: + template: + spec: + numCores: ${IONOSCLOUD_MACHINE_NUM_CORES} + memoryMB: ${IONOSCLOUD_MACHINE_MEMORY_MB} + disk: + image: + id: ${IONOSCLOUD_MACHINE_IMAGE_ID} +--- +apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 +kind: KubeadmConfigTemplate +metadata: + name: "${CLUSTER_CLASS_NAME}-worker" + namespace: '${NAMESPACE}' +spec: + template: + spec: + ntp: + enabled: true + servers: + - 0.de.pool.ntp.org + - 1.de.pool.ntp.org + - 2.de.pool.ntp.org + - 3.de.pool.ntp.org + files: + - path: /etc/ssh/sshd_config.d/ssh-audit_hardening.conf + owner: root:root + permissions: '0644' + content: | + # Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com + # hardening guide. + KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256 + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com + HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com + - path: /etc/sysctl.d/k8s.conf + content: | + fs.inotify.max_user_watches = 65536 + net.netfilter.nf_conntrack_max = 1000000 + - path: /etc/modules-load.d/k8s.conf + content: | + ip_vs + ip_vs_rr + ip_vs_wrr + ip_vs_sh + ip_vs_sed + # Crictl config + - path: /etc/crictl.yaml + content: | + runtime-endpoint: unix:///run/containerd/containerd.sock + timeout: 10 + preKubeadmCommands: + - systemctl restart systemd-networkd.service systemd-modules-load.service systemd-journald containerd + # disable swap + - swapoff -a + - sed -i '/ swap / s/^/#/' /etc/fstab + - sysctl --system + postKubeadmCommands: + - > + systemctl disable --now udisks2 multipathd motd-news.timer fwupd-refresh.timer + packagekit ModemManager snapd snapd.socket snapd.apparmor snapd.seeded + # TODO(jriedel-ionos): remove that if we have a CCM + - export system_uuid=$(kubectl --kubeconfig /etc/kubernetes/kubelet.conf get node $(hostname) -ojsonpath='{..systemUUID }') + - > + kubectl --kubeconfig /etc/kubernetes/kubelet.conf + patch node $(hostname) + --type strategic -p '{"spec": {"providerID": "ionos://'$${system_uuid}'"}}' + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + # use cloud-provider: external when using a CCM + cloud-provider: "" + criSocket: unix:///run/containerd/containerd.sock