mirror of https://gerrit.hackerspace.pl/hscloud
personal/vuko/shells initial commit
Change-Id: Icba91e8d4ffe53fc8a7ab7946f3a1b45daf20290changes/19/319/1
parent
741c08f66c
commit
6c678e391e
|
@ -0,0 +1,9 @@
|
||||||
|
Hosting for Hackerspace Three Shell System announcement. Currently uploading
|
||||||
|
is performed using sftp.
|
||||||
|
|
||||||
|
.. code::bash
|
||||||
|
scp index.html shells@185.236.240.58:index.html
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
* web interface for shells rotation
|
||||||
|
* access for other members?
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
""" generate ssh keys for shells SFTP container """
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import run
|
||||||
|
import json
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
tmp = Path(tmp).absolute()
|
||||||
|
keyfile = tmp.joinpath("ssh_host_ed25519_key")
|
||||||
|
run(["ssh-keygen", "-f", keyfile, "-N", "", "-t", "ed25519"], check=True)
|
||||||
|
|
||||||
|
# https://kubernetes.io/docs/concepts/configuration/secret/#generating-a-secret-from-files
|
||||||
|
generator = {
|
||||||
|
"secretGenerator": [
|
||||||
|
{
|
||||||
|
"name": "shells-ssh-host-key",
|
||||||
|
"files": [
|
||||||
|
str(f.relative_to(tmp))
|
||||||
|
for f in [keyfile, keyfile.with_suffix(".pub")]
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
tmp.joinpath("kustomization.yaml").write_text(json.dumps(generator))
|
||||||
|
run(["kubectl", "-n", "personal-vuko", "apply", "-k", tmp], check=True)
|
|
@ -0,0 +1,163 @@
|
||||||
|
# this is libjsonnet library for kubernetes related things
|
||||||
|
local kube = import '../../../kube/kube.libsonnet';
|
||||||
|
|
||||||
|
{
|
||||||
|
local shells = self,
|
||||||
|
local cfg = shells.cfg,
|
||||||
|
|
||||||
|
# namespace defining parameters used by other functions
|
||||||
|
# double colon "::" prevents it from appearing in output file
|
||||||
|
cfg:: {
|
||||||
|
namespace: "personal-vuko",
|
||||||
|
appName: "three-shell-system",
|
||||||
|
domain: "shells.vuko.pl",
|
||||||
|
|
||||||
|
nginx_tag: "latest",
|
||||||
|
nginx_image: "nginxinc/nginx-unprivileged:stable-alpine",
|
||||||
|
|
||||||
|
storageClassName: "waw-hdd-redundant-2",
|
||||||
|
|
||||||
|
resources: {
|
||||||
|
requests: {
|
||||||
|
cpu: "25m",
|
||||||
|
memory: "50Mi",
|
||||||
|
},
|
||||||
|
limits: {
|
||||||
|
cpu: "100m",
|
||||||
|
memory: "200Mi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
# kubernete namespace personal-${name} for personal usage
|
||||||
|
namespace: kube.Namespace(cfg.namespace),
|
||||||
|
|
||||||
|
# function used for configuring components metatada
|
||||||
|
metadata(component):: {
|
||||||
|
namespace: cfg.namespace,
|
||||||
|
labels: {
|
||||||
|
"app.kubernetes.io/name": cfg.appName,
|
||||||
|
"app.kubernetes.io/managed-by": "kubecfg",
|
||||||
|
"app.kubernetes.io/component": component,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
# component - persistant (non volatile) memory
|
||||||
|
# https://kubernetes.io/docs/concepts/storage/persistent-volumes/
|
||||||
|
dataVolume: kube.PersistentVolumeClaim("html-data") {
|
||||||
|
# override default PersistentVolumeClaim metatada with values defined
|
||||||
|
# in medadata function prevoiusly created
|
||||||
|
# "+" sign before means override
|
||||||
|
metadata+: shells.metadata("html-data"),
|
||||||
|
spec+: {
|
||||||
|
storageClassName: cfg.storageClassName,
|
||||||
|
# can be connected to multiple containers
|
||||||
|
accessModes: [ "ReadWriteMany" ],
|
||||||
|
resources: {
|
||||||
|
requests: {
|
||||||
|
# amount of storage space: 500Mb
|
||||||
|
storage: "500Mi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
# deployment declares pods
|
||||||
|
# https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
|
||||||
|
deployment: kube.Deployment("shells") {
|
||||||
|
metadata+: shells.metadata("shells"),
|
||||||
|
spec+: {
|
||||||
|
replicas: 1,
|
||||||
|
template+: {
|
||||||
|
spec+: {
|
||||||
|
# names ending with _ have special meaning in this context
|
||||||
|
# this is specified in ../../../kube/kube.upstream.jsonnet
|
||||||
|
# volumes_ { key: { ... } } is converted to volumes [{ name: key, ... }]
|
||||||
|
volumes_: {
|
||||||
|
# sftp container host keys secrets saved to kubernetes semi-manually using create-secrets.py
|
||||||
|
# https://kubernetes.io/docs/concepts/configuration/secret/
|
||||||
|
host_keys: { secret: { secretName: "shells-ssh-host-key-bd65mg4gbt" } },
|
||||||
|
# sftp container authorized_keys saved to kubernetes using command:
|
||||||
|
# kubectl -n personal-vuko create secret generic shells-ssh-authorized-keys --from-file="authorized_keys=${HOME}/.ssh/id_ed25519.pub"
|
||||||
|
authorized_keys: { secret: { secretName: "shells-ssh-authorized-keys", defaultMode: 256 } },
|
||||||
|
# to use created volume in deployment we need to claim it
|
||||||
|
html: kube.PersistentVolumeClaimVolume(shells.dataVolume),
|
||||||
|
},
|
||||||
|
# here are containers defined
|
||||||
|
# when they are defined in one deployment
|
||||||
|
containers_: {
|
||||||
|
shells: kube.Container("nginx") {
|
||||||
|
image: cfg.nginx_image,
|
||||||
|
ports_: {
|
||||||
|
http: { containerPort: 80 },
|
||||||
|
},
|
||||||
|
resources: cfg.resources,
|
||||||
|
volumeMounts_: {
|
||||||
|
html: { mountPath: "/usr/share/nginx/html" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sftp: kube.Container("sftp") {
|
||||||
|
image: "registry.k0.hswaw.net/vuko/hs-shells-sftp:latest",
|
||||||
|
ports_: {
|
||||||
|
sftp: { containerPort: 2222 },
|
||||||
|
},
|
||||||
|
command: [ "/bin/start" ],
|
||||||
|
resources: cfg.resources,
|
||||||
|
securityContext: {
|
||||||
|
# specify uid of user running command
|
||||||
|
runAsUser: 1,
|
||||||
|
},
|
||||||
|
volumeMounts_: {
|
||||||
|
# here volumes defined in volumes_ can be mounted
|
||||||
|
host_keys: { mountPath: "/etc/ssh/host" },
|
||||||
|
authorized_keys: { mountPath: "/etc/ssh/auth" },
|
||||||
|
html: { mountPath: "/data" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
# defining a service of type LoadBancer gives you acces from internet
|
||||||
|
# run: kubectl -n personal-${user} get services to see ip address
|
||||||
|
svc: kube.Service("shells") {
|
||||||
|
metadata+: shells.metadata("shells"),
|
||||||
|
target_pod:: shells.deployment.spec.template,
|
||||||
|
spec+: {
|
||||||
|
ports: [
|
||||||
|
{ name: "http", port: 80, targetPort: 8080, protocol: "TCP" },
|
||||||
|
{ name: "sftp", port: 22, targetPort: 2222, protocol: "TCP" },
|
||||||
|
],
|
||||||
|
type: "LoadBalancer",
|
||||||
|
externalTrafficPolicy: "Local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
# ingress creates VirtualHost on ingress.k0.hswaw.net forwaring http(s)
|
||||||
|
# requests to your domain to specified Pod/container
|
||||||
|
ingress: kube.Ingress("frontend") {
|
||||||
|
metadata+: shells.metadata("frontend") {
|
||||||
|
annotations+: {
|
||||||
|
"kubernetes.io/tls-acme": "true",
|
||||||
|
"certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec+: {
|
||||||
|
tls: [
|
||||||
|
{ hosts: [cfg.domain], secretName: "shells-frontend-tls"}
|
||||||
|
],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
host: cfg.domain,
|
||||||
|
http: {
|
||||||
|
paths: [
|
||||||
|
{ path: "/", backend: shells.svc.name_port },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
let
|
||||||
|
#dockertarpusher = pkgs.python37Packages.buildPythonPackage {
|
||||||
|
# pname = "dockertarpusher";
|
||||||
|
# version = "0.16";
|
||||||
|
# src = pkgs.fetchFromGitHub {
|
||||||
|
# owner = "Razikus";
|
||||||
|
# repo = "dockerregistrypusher";
|
||||||
|
# rev = "217894b79181a9a02ebc6744e0628777a0f89c36";
|
||||||
|
# sha256 = "09cqzd9gz42xw30x1jp9mx056k25i20kjzzdg3bk78a4bis29kd4";
|
||||||
|
# };
|
||||||
|
# propagatedBuildInputs = with pkgs; [
|
||||||
|
# python37Packages.requests
|
||||||
|
# ];
|
||||||
|
#};
|
||||||
|
#hsregistry_push = import ./registrypush {};
|
||||||
|
config = pkgs.runCommand "sshd_config" {} ''
|
||||||
|
mkdir -p $out/etc/ssh/
|
||||||
|
cp ${./sshd_config} $out/etc/ssh/sshd_config
|
||||||
|
#cp ${./test_keys/test_host_key} $out/etc/ssh/ssh_host_ed25519_key
|
||||||
|
#cp ${./test_keys/test_host_key.pub} $out/etc/ssh/ssh_host_ed25519_key.pub
|
||||||
|
#cp ${./test_keys/authorized_keys} $out/etc/ssh/authorized_keys
|
||||||
|
'';
|
||||||
|
name = "vuko/hs-shells-sftp";
|
||||||
|
base = pkgs.dockerTools.buildImage {
|
||||||
|
name = "vuko/ssh-base";
|
||||||
|
tag = "latest";
|
||||||
|
contents = [pkgs.openssh pkgs.busybox];
|
||||||
|
};
|
||||||
|
image = pkgs.dockerTools.buildImage {
|
||||||
|
inherit name;
|
||||||
|
tag = "latest";
|
||||||
|
fromImage = base;
|
||||||
|
contents = [config];
|
||||||
|
|
||||||
|
runAsRoot = ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
mkdir /data/
|
||||||
|
#echo "root:x:0:0::/root:/bin/nologin" > /etc/passwd
|
||||||
|
echo "shells:x:1:1::/data:/bin/sh" >> /etc/passwd
|
||||||
|
mkdir -p /etc/ssh/host/
|
||||||
|
mkdir -p /etc/ssh/auth/
|
||||||
|
mkdir -m 700 /tmp
|
||||||
|
chown 1:1 /tmp
|
||||||
|
|
||||||
|
cat <<EOF > /bin/start
|
||||||
|
#!/bin/sh
|
||||||
|
cp /etc/ssh/auth/authorized_keys /tmp/authorized_keys
|
||||||
|
/bin/sshd -D -e -f /etc/ssh/sshd_config
|
||||||
|
EOF
|
||||||
|
chmod +x /bin/start
|
||||||
|
'';
|
||||||
|
|
||||||
|
#https://serverfault.com/questions/344295/is-it-possible-to-run-sshd-as-a-normal-user
|
||||||
|
config = {
|
||||||
|
Cmd = [ "/bin/start" ];
|
||||||
|
WorkingDir = "/";
|
||||||
|
ExposedPorts = {
|
||||||
|
"2222/tcp" = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
push = pkgs.writeShellScriptBin "push" ''
|
||||||
|
BASEDIR=$(realpath $(dirname ''${BASH_SOURCE}))
|
||||||
|
docker load < "''${BASEDIR}/../images/sftp.tar.gz"
|
||||||
|
docker tag ${name}:latest registry.k0.hswaw.net/${name}
|
||||||
|
docker push registry.k0.hswaw.net/${name}
|
||||||
|
#exec {hsregistry_push}/bin/hsregistry-push "$BASEDIR/../images/sftp.tar.gz" "$@"
|
||||||
|
'';
|
||||||
|
in pkgs.runCommand "hs-shells-sftp" {} ''
|
||||||
|
mkdir $out
|
||||||
|
mkdir -p $out/images $out/bin
|
||||||
|
ln -s ${image} $out/images/sftp.tar.gz
|
||||||
|
install ${push}/bin/push $out/bin/
|
||||||
|
''
|
|
@ -0,0 +1,17 @@
|
||||||
|
Port 2222
|
||||||
|
AddressFamily any
|
||||||
|
ListenAddress 0.0.0.0
|
||||||
|
#ListenAddress ::
|
||||||
|
#UsePrivilegeSeparation no
|
||||||
|
UsePAM no
|
||||||
|
PermitEmptyPasswords no
|
||||||
|
PasswordAuthentication no
|
||||||
|
AuthorizedKeysFile /tmp/authorized_keys
|
||||||
|
HostKey /etc/ssh/host/ssh_host_ed25519_key
|
||||||
|
Subsystem sftp /libexec/sftp-server
|
||||||
|
PidFile /tmp/sshd.pid
|
||||||
|
|
||||||
|
#ForceCommand internal-sftp
|
||||||
|
AllowTcpForwarding no
|
||||||
|
X11Forwarding no
|
||||||
|
PasswordAuthentication no
|
Loading…
Reference in New Issue