util for generation of docker-compose files with auth and tls for remote workspace

This commit is contained in:
vadoli 2021-08-04 22:11:56 +00:00
parent 80559949ff
commit 093205da18

177
utils/remote.py Normal file
View file

@ -0,0 +1,177 @@
"""
Mini-utility to generate docker-compose.yaml file to launch
workspace on remote server with auth and https (self-signed)
python remote.py --workspace="base-workspace" --port="8020" --host="68.183.69.198" --user="user1" --password="pass1"
"""
import os
import yaml
import shutil
import argparse
import textwrap
import subprocess
# How much tool port is away from the start_port
port_increments = {
"DOCS_URL": 0,
"FILEBROWSER_URL": 1,
"STATICFS_URL": 2,
"CRONICLE_URL": 3,
"UNGIT_URL": 4,
"IDE_URL": 5,
"TERMINAL_URL": 6,
"MC_URL": 7,
"HTOP_URL": 8,
"FREE": 9
}
workspace_meta = {
"base-workspace": {
"port-range": 10,
"entrypoints": ["DOCS_URL", "FILEBROWSER_URL", "STATICFS_URL", "CRONICLE_URL", "UNGIT_URL", "IDE_URL", "TERMINAL_URL", "MC_URL", "HTOP_URL"]
}
}
def gen_certs():
""" Generate self-signed TLS certtificate
"""
os.mkdir("./remote/certs")
cmd = 'cd ./remote/certs && openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=workspace.com" -keyout cert.key -out cert.crt'
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read()
return
def traefik_config():
conconf = """
tls:
certificates:
- certFile: /tools/certs/cert.crt
keyFile: /tools/certs/cert.key
"""
with open("./remote/config.yml", "a") as f:
f.write(textwrap.dedent(conconf))
return
def get_workspace_labels(ep, auth_mid_name="basic-auth"):
""" Create list of Traefik labels for the Workspace service
"""
labels = [
"traefik.enable=true",
"traefik.http.middlewares.httprepl.redirectregex.regex=^http://(.*)",
"traefik.http.middlewares.httprepl.redirectregex.replacement=https://$${1}"
]
for e,p in ep.items():
eplabs = [
f"traefik.http.services.{e}http.loadbalancer.server.port={p}",
f"traefik.http.routers.{e}http.service={e}",
f"traefik.http.routers.{e}http.rule=PathPrefix(`/`)",
f"traefik.http.routers.{e}http.entrypoints={e}",
f"traefik.http.routers.{e}http.middlewares=httprepl",
f"traefik.http.services.{e}.loadbalancer.server.port={p}",
f"traefik.http.routers.{e}.service={e}",
f"traefik.http.routers.{e}.rule=PathPrefix(`/`)",
f"traefik.http.routers.{e}.entrypoints={e}",
f"traefik.http.routers.{e}.middlewares={auth_mid_name}",
f"traefik.http.routers.{e}.tls=true"
]
labels.extend(eplabs)
return labels
def make_authlabels(user, password, auth_mid_name="basic-auth"):
""" Create Traefik label for authentication
"""
auth_type = "basicauth"
cmd = f"echo $(echo '{password}' | htpasswd -nB -i {user}) | sed -e s/\\\$/\\\$\\\$/g"
result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read()
auth = result.decode("utf-8").replace("\n", "")
authlabel = f"traefik.http.middlewares.{auth_mid_name}.{auth_type}.users={auth}"
authlabels = [authlabel]
return authlabels
def get_compose_dict(workspace_name, host_ip, start_port, user, password):
""" Create dict of values for docker-compose. This dict is
to be transformed into docker-compose.yaml
"""
# Get workspace values
workspace_entrypoints = workspace_meta[workspace_name]["entrypoints"]
workspace_port_range = workspace_meta[workspace_name]["port-range"]
end_port = start_port + workspace_port_range
internal_end_port = 8020 + workspace_port_range
# Dict of entrypoints of entrypoint name and port
ep = {entrypoint:port+start_port for entrypoint,port in port_increments.items() if entrypoint in workspace_entrypoints}
traefik_command = [f"--entrypoints.{entrypoint}.address=:{port}" for entrypoint,port in ep.items()]
traefik_command += [
"--api",
"--api.dashboard",
"--api.insecure",
"--providers.docker",
"--providers.file.directory=/etc/traefik/dynamic_conf"
]
# Create dict with Traefik values
y = {}
y["version"] = "3.3"
y["services"] = {}
y["services"]["traefik"] = {}
y["services"]["traefik"]["image"] = "traefik:v2.4"
y["services"]["traefik"]["container_name"] = "container_name"
y["services"]["traefik"]["command"] = traefik_command
y["services"]["traefik"]["ports"] = [f"{start_port}-{end_port}:{8020}-{internal_end_port}", "8080:8080"]
y["services"]["traefik"]["volumes"] = [
"/var/run/docker.sock:/var/run/docker.sock:ro",
"./certs:/tools/certs",
"./config.yml:/etc/traefik/dynamic_conf/conf.yml:ro"
]
# Add Workspace values to the dict
y["services"]["workspace"] = {}
y["services"]["workspace"]["image"] = f"alnoda/{workspace_name}"
y["services"]["workspace"]["environment"] = {"WRK_HOST": host_ip}
y["services"]["workspace"]["labels"] = get_workspace_labels(ep)
# Add auth
authlabels = make_authlabels(user, password)
y["services"]["workspace"]["labels"].extend(authlabels)
return y
def main(cmd_args):
""" Create folder with everything needed to
spin up workspace with auth and TLS on remote server
"""
workspace_name = cmd_args.workspace
host_ip = cmd_args.host
start_port = int(cmd_args.port)
user = cmd_args.user
password = cmd_args.password
try:
shutil.rmtree("./remote")
except:
pass
os.mkdir("./remote")
# Generate certificate
gen_certs()
# Create Traefik config
traefik_config()
# Create docker-compose file
comp_dict = get_compose_dict(workspace_name, host_ip, start_port, user, password)
with open("./remote/docker-compose.yaml", "a") as y:
y.write(yaml.dump(comp_dict, default_style='"'))
return
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--workspace", default="base-workspace")
parser.add_argument("--port", default=8020)
parser.add_argument("--host")
parser.add_argument("--user")
parser.add_argument("--password")
cmd_args = parser.parse_args()
main(cmd_args)