penguin/monok8s

k8s image for Mono Gateway Dev Kit

clitools/pkg/render/sshd.go

raw ยท 6559 bytes

package render

import (
	"bytes"
	"fmt"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer/json"
	"k8s.io/apimachinery/pkg/util/intstr"

	monov1alpha1 "example.com/monok8s/pkg/apis/monok8s/v1alpha1"
	"example.com/monok8s/pkg/templates"
)

const (
	sshdName       = "sshd"
	sshdConfigName = "sshd-authorized-keys"
	sshdNodePort   = int32(30022)
)

func RenderSSHDDeployments(namespace, authKeys string) (string, error) {
	vals := templates.LoadTemplateValuesFromEnv()

	labels := map[string]string{
		"app.kubernetes.io/name":       sshdName,
		"app.kubernetes.io/component":  "host-access",
		"app.kubernetes.io/part-of":    "monok8s",
		"app.kubernetes.io/managed-by": monov1alpha1.NodeControlName,
	}

	objs := []runtime.Object{
		buildSSHDConfigMap(authKeys, namespace, labels),
		buildSSHDService(vals, namespace, labels),
		buildSSHDDeployment(vals, namespace, labels),
	}

	s := runtime.NewScheme()
	_ = corev1.AddToScheme(s)
	_ = rbacv1.AddToScheme(s)
	_ = appsv1.AddToScheme(s)

	serializer := json.NewYAMLSerializer(json.DefaultMetaFactory, s, s)

	var buf bytes.Buffer

	for i, obj := range objs {
		if i > 0 {
			if _, err := fmt.Fprintln(&buf, "---"); err != nil {
				return "", err
			}
		}
		if err := serializer.Encode(obj, &buf); err != nil {
			return "", err
		}
	}

	return buf.String(), nil
}

func buildSSHDConfigMap(
	authorizedKeys string,
	namespace string,
	labels map[string]string,
) *corev1.ConfigMap {

	return &corev1.ConfigMap{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "v1",
			Kind:       "ConfigMap",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      sshdConfigName,
			Namespace: namespace,
			Labels:    labels,
		},
		Data: map[string]string{
			"authorized_keys": authorizedKeys,
		},
	}
}

func buildSSHDService(
	tVals templates.TemplateValues,
	namespace string,
	labels map[string]string,
) *corev1.Service {
	selectorLabels := map[string]string{
		monov1alpha1.NodeControlKey: "true",
		"kubernetes.io/hostname":    tVals.NodeName,
	}

	return &corev1.Service{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "v1",
			Kind:       "Service",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      sshdName,
			Namespace: namespace,
			Labels:    labels,
		},
		Spec: corev1.ServiceSpec{
			Type:     corev1.ServiceTypeNodePort,
			Selector: selectorLabels,
			Ports: []corev1.ServicePort{
				{
					Name:       "ssh",
					Protocol:   corev1.ProtocolTCP,
					Port:       22,
					TargetPort: intstr.FromInt32(22),
					NodePort:   sshdNodePort,
				},
			},
		},
	}
}

func buildSSHDDeployment(
	tVals templates.TemplateValues,
	namespace string,
	labels map[string]string,
) *appsv1.Deployment {
	replicas := int32(1)

	selectorLabels := map[string]string{
		monov1alpha1.NodeControlKey: "true",
		"kubernetes.io/hostname":    tVals.NodeName,
	}

	podLabels := mergeStringMaps(labels, selectorLabels)

	runAsUser := int64(0)
	runAsNonRoot := false
	privileged := true
	allowPrivilegeEscalation := true
	readOnlyRootFilesystem := false

	return &appsv1.Deployment{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "apps/v1",
			Kind:       "Deployment",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      sshdName,
			Namespace: namespace,
			Labels:    labels,
		},
		Spec: appsv1.DeploymentSpec{
			Replicas: &replicas,
			Selector: &metav1.LabelSelector{
				MatchLabels: selectorLabels,
			},
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: podLabels,
				},
				Spec: corev1.PodSpec{
					NodeSelector: selectorLabels,
					Containers: []corev1.Container{
						{
							Name:  sshdName,
							Image: "alpine:latest",
							Command: []string{
								"/bin/sh",
								"-ceu",
								`
apk add --no-cache openssh-server

mkdir -p /run/sshd
mkdir -p /root/.ssh

cp /authorized-keys/authorized_keys /root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys

ssh-keygen -A

exec /usr/sbin/sshd \
  -D \
  -e \
  -p 22 \
  -o PermitRootLogin=prohibit-password \
  -o PasswordAuthentication=no \
  -o KbdInteractiveAuthentication=no \
  -o PubkeyAuthentication=yes \
  -o AuthorizedKeysFile=/root/.ssh/authorized_keys
`,
							},
							Ports: []corev1.ContainerPort{
								{
									Name:          "ssh",
									ContainerPort: 22,
									Protocol:      corev1.ProtocolTCP,
								},
							},
							SecurityContext: &corev1.SecurityContext{
								RunAsUser:                &runAsUser,
								RunAsNonRoot:             &runAsNonRoot,
								Privileged:               &privileged,
								AllowPrivilegeEscalation: &allowPrivilegeEscalation,
								ReadOnlyRootFilesystem:   &readOnlyRootFilesystem,
							},
							Resources: corev1.ResourceRequirements{
								Requests: corev1.ResourceList{
									corev1.ResourceCPU:    resource.MustParse("10m"),
									corev1.ResourceMemory: resource.MustParse("32Mi"),
								},
								Limits: corev1.ResourceList{
									corev1.ResourceCPU:    resource.MustParse("200m"),
									corev1.ResourceMemory: resource.MustParse("128Mi"),
								},
							},
							VolumeMounts: []corev1.VolumeMount{
								{
									Name:      "authorized-keys",
									MountPath: "/authorized-keys",
									ReadOnly:  true,
								},
								{
									Name:      "host-etc",
									MountPath: "/host/etc",
								},
								{
									Name:      "host-var",
									MountPath: "/host/var",
								},
							},
						},
					},
					Volumes: []corev1.Volume{
						{
							Name: "authorized-keys",
							VolumeSource: corev1.VolumeSource{
								ConfigMap: &corev1.ConfigMapVolumeSource{
									LocalObjectReference: corev1.LocalObjectReference{
										Name: sshdConfigName,
									},
									DefaultMode: ptrInt32(0600),
								},
							},
						},
						{
							Name: "host-etc",
							VolumeSource: corev1.VolumeSource{
								HostPath: &corev1.HostPathVolumeSource{
									Path: "/etc",
									Type: ptrHostPathType(corev1.HostPathDirectory),
								},
							},
						},
						{
							Name: "host-var",
							VolumeSource: corev1.VolumeSource{
								HostPath: &corev1.HostPathVolumeSource{
									Path: "/var",
									Type: ptrHostPathType(corev1.HostPathDirectory),
								},
							},
						},
					},
				},
			},
		},
	}
}

func ptrInt32(v int32) *int32 {
	return &v
}

func ptrHostPathType(v corev1.HostPathType) *corev1.HostPathType {
	return &v
}