279 lines
6.4 KiB
Go
279 lines
6.4 KiB
Go
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
|
|
}
|