diff --git a/test-python-ssh/.dockerignore b/test-python-ssh/.dockerignore new file mode 100644 index 0000000..3a81348 --- /dev/null +++ b/test-python-ssh/.dockerignore @@ -0,0 +1 @@ +production_eleves diff --git a/test-python-ssh/Dockerfile b/test-python-ssh/Dockerfile index 86a961b..86ba3d7 100644 --- a/test-python-ssh/Dockerfile +++ b/test-python-ssh/Dockerfile @@ -4,7 +4,7 @@ FROM python:3 RUN apt update && apt install -y gcc nginx openssh-server RUN pip3 install uwsgi -WORKDIR /usr/share/app +WORKDIR /app RUN addgroup eleve diff --git a/test-python-ssh/Readme.md b/test-python-ssh/Readme.md index da129ec..d0b0708 100644 --- a/test-python-ssh/Readme.md +++ b/test-python-ssh/Readme.md @@ -1,28 +1,41 @@ # Python, web and SSH sandbox -**For educational purpose only! None of this software is industry grade quality.** +**For educational purpose only! None of this software is tested, optimized nor secured. It is actually unsecure on purpose** +This is a very experimental tool, **it may be working**. Any suggestion or PR is welcome. # How to use it? ## Install docker CF the interweb TODO ## Run it +While in this file directory, open a terminal and run: ``` -docker run --name pythonsandbox --rm --network-mode host -v ./production_eleves:/app/python_app/modules -v ./data:/app/data adrianamaglio/pythonsandbox +docker run -it --name pythonsandbox --rm --network host -v "$(pwd)"/production_eleves:/app/python_app/modules -v "$(pwd)"/config:/app/config adrianamaglio/pythonsandbox ``` (Logs will flow in your terminal, CTRL+C will stop the process). ## Initialize it -The directory `data` must contain a `users.txt` containing one username per line, or a `passwords.txt` file, containing `username=password` lines. +The directory `config` must contain a `users.txt` containing one username per line, or a `passwords.txt` file, containing `username=password` lines. If you do not provide a password file, it will be generated from user file. The password file is the database from which users/passwords are created in the system. -Additionnaly, you can add a file named `./data/init.sh` which will be executed (as root) before starting the servers. It is usefull for debuging or customisation purposes! +APermitRootLogindditionnaly, you can add a file named `./config/init.sh` which will be executed (as root) before starting the servers. It is usefull for debuging and customisation purposes! ## Use it You can now ssh into your localhost (and others computer on the same network can ssh into your host). Usernames and passwords are the one provided in the password file. Students home directories are then listed in the `production_eleves` directory. +## Debug it +You can open a shell in the container anytime by running this command on the docker host: +``` +docker exec -it pythonsandbox bash +``` + # The docker image +To bundle everything in one place. +This docker image is not a pretty one, we should split those services into several containers. +But that would be harder to run, so forget that. +Also, as this is poorly tested, the docker system make sure the environment is stable. + ## Build the docker image ``` docker build . -t adrianamaglio/pythonsandbox @@ -32,36 +45,27 @@ or pull it TODO: send image to hub ``` -## Run the docker image -``` -docker run -it --network host --name pythonsandbox pythonsandbox -``` -Or if you want to save student work outside of the container: -``` -docker run -it --network host --name pythonsandbox -v "$(pwd)"/app/modules:/usr/share/app/modules pythonsandbox -``` -And with user list file -``` -docker run -it --network host --name pythonsandbox -v "$(pwd)"/app/modules:/usr/share/app/modules -v "$(pwd)"/app/users.txt:/usr/share/app/users.txt pythonsandbox -``` +## Volumes +- `/app/modules` is where python scripts will be executed on some URL calls. +- `/app/config` is the location of the user, password and init files. + +## Environment variables +None used, do watever you want # How does it works? ## A python script It run with uwsgi (CF dockerfile CMD line) and load python modules files according to URL. -For instance, when you get `/test/my_function` the function `my_function` is executed from the file `test.py`. -Default behavior: +For instance, when you HTTP-get `/test/my_function` the function `my_function` is executed from the file `test.py`. +###Default behavior: - if `test` is a directory, we will try to load default function `index` from file `test/my_function.py` - if `test/my_function` is a directory, we will try to load default function `index` from file `test/my_function/main.py` +If you don’t like this default behavior, just don’t use main and index names. +### Arguments GET arguments (the ones in URL), are passed as function parameter (only if the parameters name matches the arguments name). ## SSH server Allow student to connect via SSH or SFTP to add python files and play with bash. -## A docker image -To bundle everything in one place. -This docker image is not a pretty one, we should split those services into several containers. -But that would be harder to run, so forget that. -Also, as this is poorly tested, the docker system make sure the environment is stable. - - +## NGINX HTTP server +For more flexibility with HTTP diff --git a/test-python-ssh/data/init.sh b/test-python-ssh/config/init.sh similarity index 100% rename from test-python-ssh/data/init.sh rename to test-python-ssh/config/init.sh diff --git a/test-python-ssh/data/passwords.txt b/test-python-ssh/config/passwords.txt similarity index 100% rename from test-python-ssh/data/passwords.txt rename to test-python-ssh/config/passwords.txt diff --git a/test-python-ssh/data/users.txt b/test-python-ssh/config/users.txt similarity index 100% rename from test-python-ssh/data/users.txt rename to test-python-ssh/config/users.txt diff --git a/test-python-ssh/docker-compose.yml b/test-python-ssh/docker-compose.yml index 9d4c272..387c317 100644 --- a/test-python-ssh/docker-compose.yml +++ b/test-python-ssh/docker-compose.yml @@ -3,6 +3,6 @@ services: app: build: . volumes: - - ./data:/usr/share/app/data - - ./production_eleves:/usr/share/app/python_app/modules + - ./config:/app/config + - ./production_eleves:/app/python_app/modules network_mode: "host" diff --git a/test-python-ssh/entrypoint.sh b/test-python-ssh/entrypoint.sh index b533600..06043c2 100755 --- a/test-python-ssh/entrypoint.sh +++ b/test-python-ssh/entrypoint.sh @@ -1,16 +1,14 @@ #!/bin/sh +HOME_BASE="/app/python_app/modules" +USERS_LIST="/app/config/users.txt" +PASSWD_LIST="/app/config/passwords.txt" +CUSTOM_SCRIPT="/app/config/init.sh" -HOME_BASE="/usr/share/app/python_app/modules" -USERS_LIST="/usr/share/app/data/users.txt" -PASSWD_LIST="/usr/share/app/data/passwords.txt" -CUSTOM_SCRIPT="/usr/share/app/data/init.sh" - -# Must be ascii for cut -separator="=" +separator="=" # Must be ascii for cut forbidden_chars=". /" -# Check we got users +# Check we got user list if [ ! -f "$USERS_LIST" ] && [ ! -f "$PASSWD_LIST" ] ; then echo "Les fichiers des utilisateurs ou des passwords n’ont pas étés trouvées." exit 1 @@ -35,7 +33,7 @@ if [ ! -f $PASSWD_LIST ] ; then done fi -# Create users +# Create users, home dirs, change passwords and home owners for line in $(cat $PASSWD_LIST) ; do name="$(echo "$line" | cut -d "$separator" -f 1)" pass="$(echo "$line" | cut -d "$separator" -f 2)" @@ -47,7 +45,10 @@ for line in $(cat $PASSWD_LIST) ; do chown "$name":eleve "$home" done -echo "PermitRootLogin yes" >> /etc/ssh/sshd_config +# Allow SSH as root +if [ -z "$(grep '^PermitRootLogin yes' /etc/ssh/sshd_config)" ] ; then + echo "PermitRootLogin yes" >> /etc/ssh/sshd_config +fi echo "\nFin de la préparation des utilisateurs.\n" @@ -63,7 +64,7 @@ fi nginx -c '/etc/nginx/nginx.conf' # SSH server -/usr/sbin/sshd +/usr/sbin/sshd -E /dev/stderr # Start watever the container should be doing /bin/sh -c "$*" diff --git a/test-python-ssh/python_app/main.py b/test-python-ssh/python_app/main.py index 1a60e92..1080b3d 100644 --- a/test-python-ssh/python_app/main.py +++ b/test-python-ssh/python_app/main.py @@ -45,6 +45,7 @@ def application(env, start_response): # Import the function try: m = importlib.import_module(module_path) + importlib.reload(m) except ModuleNotFoundError: #print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(path_elements))) return htmlresp(404, 'Le fichier {} n’a pas été trouvé.'.format(path), start_response)