Init
Signed-off-by: Georg <georg@lysergic.dev>
This commit is contained in:
commit
c27753da86
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
||||
Hosts configurations related to our POC shell service.
|
13
dockersh/install-custom.sh
Normal file
13
dockersh/install-custom.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Original by https://github.com/sleeepyjack/dockersh
|
||||
# Modified by georg@lysergic.dev
|
||||
|
||||
pip3 install --upgrade -r requirements.txt
|
||||
if [ -z "$1" ]; then
|
||||
activate-global-python-argcomplete
|
||||
else
|
||||
activate-global-python-argcomplete --dest=$1
|
||||
fi
|
||||
cp dockersh /opt/dockersh/bin/
|
||||
chmod +x /opt/dockersh/bin/dockersh
|
||||
cp -n dockersh.ini /opt/dockersh/etc/
|
29
etc/dockersh.ini
Normal file
29
etc/dockersh.ini
Normal file
@ -0,0 +1,29 @@
|
||||
[ADMIN]
|
||||
command = admin
|
||||
shell = /bin/bash
|
||||
names =
|
||||
cranberry-adm
|
||||
mogad0n-adm
|
||||
maintenance = off
|
||||
maintenance_scp = on
|
||||
maintenance_text = This Maschine is in Maintanence Mode. However, you can copy files with `scp`, `rsync`, `sftp` or list files with `ls` without connecting to the maschine. I.e.
|
||||
ssh ${HOSTNAME} ls -la
|
||||
|
||||
[DEFAULT]
|
||||
image = ubuntu_user
|
||||
suffix = _${USER}
|
||||
homedir = /home/${USER}
|
||||
shell = /bin/bash
|
||||
greeting = Ready.
|
||||
|
||||
[test01]
|
||||
image = test01
|
||||
|
||||
[test02]
|
||||
image = test02
|
||||
|
||||
[test03]
|
||||
image = test03
|
||||
|
||||
[cranberry-test]
|
||||
image = cranberry-test
|
23
etc/motd
Normal file
23
etc/motd
Normal file
@ -0,0 +1,23 @@
|
||||
#################################################################
|
||||
## ##
|
||||
## --- https://liberta.casa --- ##
|
||||
## ##
|
||||
## - This is an EXPERIMENTAL, Proof Of Concept, environment. ##
|
||||
## - You are being offered an isolated container which ##
|
||||
## you are free to experiment in. ##
|
||||
## - Sudo is not configured by default, but you may ##
|
||||
## use root password ` freedom `. ##
|
||||
## - Containers stay running/online for a while ##
|
||||
## after `exit`ing. ##
|
||||
## - The memory shown in common CLI tools is NOT accurate - ##
|
||||
## if you exceed 512MB, processes may get killed. ##
|
||||
## - At this stage, shells may be reset at any time. ##
|
||||
## - If you encounter issues, please let us know. ##
|
||||
## ##
|
||||
## For your sanity: ##
|
||||
## - Do NOT consider this a secure environment. ##
|
||||
## - Do NOT consider this a reliable environment. ##
|
||||
## - Be considerate, don't waste other users resources. ##
|
||||
## - Help: Type ` help.sh ` or join #help on irc.liberta.casa ##
|
||||
## ##
|
||||
#################################################################
|
2
etc/sshd/sshd-banner
Normal file
2
etc/sshd/sshd-banner
Normal file
@ -0,0 +1,2 @@
|
||||
You are connecting to the LibertaCasa public shell infrastructure.
|
||||
If you do not have an account yet, please request one in #libcasa.info on irc.liberta.casa (Webchat: https://liberta.casa/gamja).
|
4
lcpubsh/bin/adduser.sh
Normal file
4
lcpubsh/bin/adduser.sh
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# georg@lysergic.dev
|
||||
# The filename is flawed, however changing it would likely break scripts in three other places.
|
||||
echo "$1:$2" | chpasswd
|
48
lcpubsh/bin/generate.sh
Normal file
48
lcpubsh/bin/generate.sh
Normal file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# georg@lysergic.dev
|
||||
set -e
|
||||
echo "Shell generation invoked." | nc -N 127.0.0.2 2424
|
||||
if [ ! "$#" -eq 0 ]; then
|
||||
user="$(echo "$1" |tr '[:upper:]' '[:lower:]')"
|
||||
case "$2" in
|
||||
"archlinux")
|
||||
os="archlinux"
|
||||
image="lc-archlinux-userbase-v2:sh0"
|
||||
;;
|
||||
"ubuntu")
|
||||
os="ubuntu"
|
||||
image="lcbase_ubuntu_14082021_2:sh0"
|
||||
;;
|
||||
*)
|
||||
echo "Choose between archlinux or ubuntu"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fingerprint_ecdsa="$(ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub)"
|
||||
if id "$1" &>/dev/null; then
|
||||
echo "Aborted. Username is already taken."
|
||||
echo "Aborted: $user is already taken." | nc -N 127.0.0.2 2424
|
||||
else
|
||||
echo "Hang on ..."
|
||||
echo "Creating $user locally." | nc -N 127.0.0.2 2424
|
||||
sudo useradd -mUs /opt/lcpubsh/bin/pubsh -G docker $user
|
||||
pass=$(shuf -n2 /usr/share/dict/words | tr -d '\n')
|
||||
echo "Appending to config." | nc -N 127.0.0.2 2424
|
||||
echo "" >> /etc/dockersh.ini
|
||||
echo "[$user]" >> /etc/dockersh.ini
|
||||
echo "image = $user" >> /etc/dockersh.ini
|
||||
echo "Forking Docker base image ($image)." | nc -N 127.0.0.2 2424
|
||||
/opt/lcpubsh/bin/make_lc_user_image.sh $user $image | nc -N 127.0.0.2 2424
|
||||
echo "Setting password." | nc -N 127.0.0.2 2424
|
||||
sudo /opt/adduser.sh $user $pass
|
||||
echo "@$user ssh -p 2222 $user@sh.lib.casa" | nc -N 127.0.0.2 2424
|
||||
echo "@$user $fingerprint_ecdsa" | nc -N 127.0.0.2 2424
|
||||
echo "@$user $pass" | nc -N 127.0.0.2 2424
|
||||
echo "#universe $pass" | nc -N 127.0.0.2 2424
|
||||
echo "Done." | nc -N 127.0.0.2 2424
|
||||
echo "OK. Details sent to user and/or admins."
|
||||
fi
|
||||
else
|
||||
echo "No argument supplied."
|
||||
fi
|
||||
|
12
lcpubsh/bin/make_lc_user_image.sh
Normal file
12
lcpubsh/bin/make_lc_user_image.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# Original by https://github.com/sleeepyjack/dockersh
|
||||
# Modified by georg@lysergic.dev
|
||||
|
||||
if [ -z "$1" -o -z "$2" ]; then
|
||||
echo "./make_user_image.sh [name] [source-image]"; exit 100
|
||||
fi
|
||||
|
||||
sed -i "1s/.*/FROM $2/" /opt/dockersh/dockersh-git/image_template/Dockerfile
|
||||
cd /opt/dockersh/dockersh-git/image_template
|
||||
docker build -t $1:sh0 .
|
||||
|
274
lcpubsh/bin/pubsh
Executable file
274
lcpubsh/bin/pubsh
Executable file
@ -0,0 +1,274 @@
|
||||
#!/usr/bin/env python3
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
# Original by https://github.com/sleeepyjack/dockersh
|
||||
# Modified by georg@lysergic.dev
|
||||
# POC / IN DEVELOPMENT
|
||||
# Do NOT use this in insecure environments
|
||||
import os
|
||||
os.environ['TERM'] = 'xterm' # removes warning on non-tty commands
|
||||
|
||||
import argparse
|
||||
#import argcomplete
|
||||
#from argcomplete.completers import ChoicesCompleter
|
||||
from configparser import ConfigParser, ExtendedInterpolation
|
||||
import docker
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
from pwd import getpwnam
|
||||
import socket
|
||||
import os
|
||||
import getpass
|
||||
|
||||
prog = 'dockersh'
|
||||
version = prog + " v1.0"
|
||||
config_file = "/etc/dockersh.ini"
|
||||
|
||||
user = getpass.getuser()
|
||||
hostname = socket.gethostname()
|
||||
|
||||
cli = docker.APIClient()
|
||||
|
||||
def containers(image_filter='', container_filter='', sort_by='Created', all=True):
|
||||
cs = cli.containers(all=all, filters={'label': "user="+user})
|
||||
cs.sort(key=lambda c: c[sort_by])
|
||||
cs = [c for c in cs if str(c['Image']+':sh0').startswith(image_filter)]
|
||||
cs = [c for c in cs if c['Names'][0][1:].startswith(container_filter)]
|
||||
return cs
|
||||
|
||||
def random_string(length):
|
||||
def random_char():
|
||||
return random.choice(string.ascii_uppercase + string.digits)
|
||||
return ''.join(random_char() for _ in range(length))
|
||||
|
||||
def strip(s, suffix=''):
|
||||
for c in ['/', ':', '.', ' ']: #QUESTION does this suffice?
|
||||
s = s.replace(c, '')
|
||||
if s.endswith(suffix):
|
||||
s = s[:len(s)-len(suffix)]
|
||||
return s
|
||||
|
||||
def pull(image):
|
||||
if not image in image_names:
|
||||
s = image.split(':')
|
||||
if len(s) > 1:
|
||||
cli.pull(s[0], s[1])
|
||||
else:
|
||||
cli.pull(s[0])
|
||||
|
||||
def image_split(s):
|
||||
sp = s.split(':')
|
||||
if len(sp) == 1:
|
||||
return sp[0], 'sh0'
|
||||
else:
|
||||
return sp[0], sp[1]
|
||||
|
||||
def selection_menu(choices):
|
||||
if len(choices) == 1:
|
||||
return 0
|
||||
print("There are multiple matching containers running:")
|
||||
for j, c in enumerate(choices):
|
||||
print("[" + str(j+1) + "]\t" + c)
|
||||
inp = input("select [1]: ")
|
||||
if inp == "":
|
||||
i = 0
|
||||
else:
|
||||
i = int(inp) - 1
|
||||
assert(0 <= i < len(choices))
|
||||
return i
|
||||
|
||||
#if __name__ == "__main__":
|
||||
def parse_args():
|
||||
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(prog=prog)
|
||||
parser.add_argument('--version',
|
||||
action='version',
|
||||
version=version)
|
||||
parser.add_argument('-i', '--image',
|
||||
dest='image',
|
||||
help="base image to be used",
|
||||
default="") #.completer = ChoicesCompleter(tuple(images))
|
||||
parser.add_argument('-n', '--name',
|
||||
dest='name',
|
||||
help="container name",
|
||||
default="") #.completer = ChoicesCompleter(tuple(containers))
|
||||
parser.add_argument('-t', '--temporary',
|
||||
dest='temp',
|
||||
action='store_true',
|
||||
help="execute in temporary container",
|
||||
default=False)
|
||||
parser.add_argument('-c', '--command',
|
||||
dest='cmd',
|
||||
help="pass command to bash in container",
|
||||
default="")
|
||||
parser.add_argument('--home',
|
||||
dest='home',
|
||||
help="user home directory",
|
||||
default=ini['homedir'])
|
||||
#argcomplete.autocomplete(parser) #TODO make autocompletion work
|
||||
args = parser.parse_args()
|
||||
|
||||
args.suffix = ini['suffix']
|
||||
args.greeting = ini['greeting']
|
||||
args.ini = ini
|
||||
return args
|
||||
|
||||
|
||||
|
||||
|
||||
# load ini
|
||||
cfg = ConfigParser({"USER": user, "HOSTNAME": hostname}, interpolation=ExtendedInterpolation())
|
||||
cfg.read(config_file, encoding="utf-8")
|
||||
|
||||
if os.getenv("USER") and user != os.getenv('USER') and user in cfg["ADMIN"]["names"].splitlines():
|
||||
user = os.getenv('USER')
|
||||
|
||||
# reread config
|
||||
cfg = ConfigParser({"USER": user, "HOSTNAME": hostname}, interpolation=ExtendedInterpolation())
|
||||
cfg.read(config_file, encoding="utf-8")
|
||||
|
||||
|
||||
admin_cmd = "admin"
|
||||
admin_shell = "/bin/bash"
|
||||
if cfg.has_section("ADMIN") and "command" in cfg["ADMIN"]:
|
||||
admin_cmd = cfg["ADMIN"]["command"]
|
||||
if "admin_shell" in cfg["ADMIN"]:
|
||||
admin_shell = cfg["ADMIN"]["admin_shell"]
|
||||
ini = cfg[user] if cfg.has_section(user) else cfg['DEFAULT']
|
||||
|
||||
#if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
|
||||
if args.cmd == admin_cmd:
|
||||
print("Trying to login into host: "+user)
|
||||
if not sys.stdout.isatty():
|
||||
print()
|
||||
print("admin mode is only possible using pseudo tty-allocation.")
|
||||
print("Try login using:")
|
||||
print("ssh -t ...")
|
||||
sys.exit(0)
|
||||
os.system("sudo -u "+user+" sudo "+admin_shell)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if cfg.has_section("ADMIN") and "maintenance" in cfg["ADMIN"] and cfg["ADMIN"]["maintenance"] == "on" and (not "maintenance_scp" in cfg["ADMIN"] or cfg["ADMIN"]["maintenance_scp"] != "on"):
|
||||
if "maintenance_text" in cfg["ADMIN"]:
|
||||
print(cfg["ADMIN"]["maintenance_text"])
|
||||
else:
|
||||
print("This Maschine is in Maintanence Mode.")
|
||||
sys.exit(0)
|
||||
|
||||
is_scp_cmd = False
|
||||
if args.cmd:
|
||||
if os.path.basename(args.cmd).startswith(("scp","rsync --server","sftp-server","ls","*")):
|
||||
is_scp_cmd = True
|
||||
if args.cmd == "envir":
|
||||
print(os.environ)
|
||||
name_passed = (args.name != "")
|
||||
image_passed = (args.image != "")
|
||||
|
||||
if not is_scp_cmd and cfg.has_section("ADMIN") and "maintenance" in cfg["ADMIN"] and cfg["ADMIN"]["maintenance"] == "on":
|
||||
if "maintenance_text" in cfg["ADMIN"]:
|
||||
print(cfg["ADMIN"]["maintenance_text"])
|
||||
else:
|
||||
print("This Maschine is in Maintanence Mode. However, you can copy files with scp, rsync, sftp or list files with ls without connecting to the maschine.")
|
||||
sys.exit(0)
|
||||
|
||||
if args.temp:
|
||||
if not image_passed:
|
||||
args.image = args.ini['image']
|
||||
args.image_base, args.image_tag = image_split(args.image)
|
||||
args.image = args.image_base + ':' + args.image_tag
|
||||
args.name = strip(args.image) + '_tmp' + random_string(4)
|
||||
else:
|
||||
if name_passed:
|
||||
args.name = strip(args.name, args.suffix)
|
||||
|
||||
filtered_con = containers(image_filter=args.image, container_filter=args.name)
|
||||
|
||||
if len(filtered_con) > 0:
|
||||
con_names = [c['Names'][0][1:] for c in filtered_con]
|
||||
i = selection_menu(con_names)
|
||||
args.name = strip(con_names[i], args.suffix)
|
||||
else:
|
||||
if not image_passed:
|
||||
args.image = args.ini['image']
|
||||
args.image_base, args.image_tag = image_split(args.image)
|
||||
args.image = args.image_base + ':' + args.image_tag
|
||||
|
||||
if not name_passed:
|
||||
args.name = strip(args.image)
|
||||
|
||||
if len(containers(container_filter=args.name)) != 0:
|
||||
print("WARNING: container name already exists (ignoring --image)")
|
||||
|
||||
args.full_name = args.name + args.suffix
|
||||
|
||||
initing = False
|
||||
if len(containers(container_filter=args.name)) == 0:
|
||||
volumes = []
|
||||
if "volumes" in args.ini:
|
||||
volumes = volumes + args.ini["volumes"].split(",")
|
||||
volumes = [v.split(":") for v in volumes]
|
||||
binds = {v[0].strip():{"bind":v[1].strip(),"mode":v[2].strip()} for v in volumes}
|
||||
volumes = [v[1] for v in volumes]
|
||||
|
||||
host_config = cli.create_host_config(
|
||||
binds=binds,
|
||||
restart_policy={'Name' : 'unless-stopped'})
|
||||
|
||||
#cli.pull(args.image)
|
||||
userpwd = getpwnam(user)
|
||||
cli.create_container(args.image,
|
||||
stdin_open=True,
|
||||
tty=True,
|
||||
name=args.full_name,
|
||||
hostname=args.name,
|
||||
labels={'group': prog, 'user': user},
|
||||
volumes=volumes,
|
||||
working_dir=args.home,
|
||||
environment={
|
||||
"HOST_USER_ID": userpwd.pw_uid,
|
||||
"HOST_USER_GID": userpwd.pw_gid,
|
||||
"HOST_USER_NAME": user
|
||||
},
|
||||
host_config=host_config
|
||||
)
|
||||
initing=True
|
||||
|
||||
cli.start(args.full_name)
|
||||
if initing:
|
||||
print("")
|
||||
print("Initializing...")
|
||||
#os.popen('docker exec '+args.full_name + ' /bin/bash -c "if [ -e /init-user ]; then /init-user; else echo \"No Initialization skript found for container\"; fi; echo Initialization finished."').read().split(":")[-1]
|
||||
init_cmd = 'docker exec '+args.full_name + ' /bin/bash -c "if [ -e /init-user ]; then /init-user; else echo \\\"Script...\\\"; fi; echo Initialization finished."'
|
||||
print(os.popen(init_cmd).read())
|
||||
#print("Please login again.")
|
||||
#sys.exit(0)
|
||||
if len(args.cmd) == 0:
|
||||
try:
|
||||
print(args.greeting.replace("```",""))
|
||||
except UnicodeEncodeError:
|
||||
print(hostname)
|
||||
user_bash = os.popen('docker exec -u root '+args.full_name + ' getent passwd '+user+'').read().split(":")[-1]
|
||||
if user_bash == "":
|
||||
user_bash = "/bin/bash"
|
||||
cmd = args.cmd if args.cmd else user_bash
|
||||
#custom
|
||||
#user_bash = "/bin/sh"
|
||||
#cmd = user_bash
|
||||
cmd = "/bin/bash -c \"" + cmd + "\""
|
||||
|
||||
#custom
|
||||
#os.system('docker exec -u '+user+' '+ args.full_name + ' ' + 'useradd -s /bin/bash user')
|
||||
|
||||
# a tty needs -it, scp needs -i
|
||||
docker_arg = "-i" if not sys.stdout.isatty() or is_scp_cmd else "-it"
|
||||
os.system('docker exec -u '+user+" " + docker_arg +' '+ args.full_name + ' ' + cmd+"")
|
||||
|
||||
if args.temp:
|
||||
cli.remove_container(args.full_name, v=True, force=True)
|
||||
|
||||
cli.close()
|
9
lcpubsh/image_template/Dockerfile
Normal file
9
lcpubsh/image_template/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
# Original by https://github.com/sleeepyjack/dockersh
|
||||
# Modified by georg@lysergic.dev
|
||||
# Note! This is a skeleton, it is being altered by the spawn process.
|
||||
FROM lc-archlinux-userbase-v2:sh0
|
||||
|
||||
COPY user-mapping.sh /
|
||||
RUN chmod u+x /user-mapping.sh
|
||||
|
||||
ENTRYPOINT ["/user-mapping.sh"]
|
21
lcpubsh/image_template/user-mapping.sh
Normal file
21
lcpubsh/image_template/user-mapping.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Original by https://github.com/sleeepyjack/dockersh
|
||||
# Modified by georg@lysergic.dev
|
||||
if [ -z "${HOST_USER_NAME}" -o -z "${HOST_USER_ID}" -o -z "${HOST_USER_GID}" ]; then
|
||||
echo "HOST_USER_NAME, HOST_USER_ID & HOST_USER_GID needs to be set!"; exit 100
|
||||
fi
|
||||
|
||||
useradd \
|
||||
--uid ${HOST_USER_ID} \
|
||||
--gid ${HOST_USER_GID} \
|
||||
--create-home \
|
||||
--shell /bin/bash \
|
||||
${HOST_USER_NAME}
|
||||
groupadd --gid "${HOST_USER_GID}" "${HOST_USER_NAME}"
|
||||
usermod -aG sudo ${HOST_USER_NAME}
|
||||
sleep 5s
|
||||
|
||||
echo ${HOST_USER_NAME}:${HOST_USER_NAME} | chpasswd
|
||||
|
||||
exec su - "${HOST_USER_NAME}"
|
||||
|
Loading…
Reference in New Issue
Block a user