Beta version, working PoC

This commit is contained in:
Adrian Amaglio 2021-02-15 13:51:48 +01:00
parent e122d5a452
commit 182e8b9a94
9 changed files with 46 additions and 39 deletions

View File

@ -0,0 +1 @@
production_eleves

View File

@ -4,7 +4,7 @@ FROM python:3
RUN apt update && apt install -y gcc nginx openssh-server RUN apt update && apt install -y gcc nginx openssh-server
RUN pip3 install uwsgi RUN pip3 install uwsgi
WORKDIR /usr/share/app WORKDIR /app
RUN addgroup eleve RUN addgroup eleve

View File

@ -1,28 +1,41 @@
# Python, web and SSH sandbox # 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? # How to use it?
## Install docker ## Install docker
CF the interweb TODO CF the interweb TODO
## Run it ## 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). (Logs will flow in your terminal, CTRL+C will stop the process).
## Initialize it ## 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. 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. 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 ## Use it
You can now ssh into your localhost (and others computer on the same network can ssh into your host). 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. Usernames and passwords are the one provided in the password file.
Students home directories are then listed in the `production_eleves` directory. 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 # 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 ## Build the docker image
``` ```
docker build . -t adrianamaglio/pythonsandbox docker build . -t adrianamaglio/pythonsandbox
@ -32,36 +45,27 @@ or pull it
TODO: send image to hub TODO: send image to hub
``` ```
## Run the docker image ## Volumes
``` - `/app/modules` is where python scripts will be executed on some URL calls.
docker run -it --network host --name pythonsandbox pythonsandbox - `/app/config` is the location of the user, password and init files.
```
Or if you want to save student work outside of the container: ## Environment variables
``` None used, do watever you want
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
```
# How does it works? # How does it works?
## A python script ## A python script
It run with uwsgi (CF dockerfile CMD line) and load python modules files according to URL. 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`. For instance, when you HTTP-get `/test/my_function` the function `my_function` is executed from the file `test.py`.
Default behavior: ###Default behavior:
- if `test` is a directory, we will try to load default function `index` from file `test/my_function.py` - 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 `test/my_function` is a directory, we will try to load default function `index` from file `test/my_function/main.py`
If you dont like this default behavior, just dont 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). GET arguments (the ones in URL), are passed as function parameter (only if the parameters name matches the arguments name).
## SSH server ## SSH server
Allow student to connect via SSH or SFTP to add python files and play with bash. Allow student to connect via SSH or SFTP to add python files and play with bash.
## A docker image ## NGINX HTTP server
To bundle everything in one place. For more flexibility with HTTP
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.

View File

@ -3,6 +3,6 @@ services:
app: app:
build: . build: .
volumes: volumes:
- ./data:/usr/share/app/data - ./config:/app/config
- ./production_eleves:/usr/share/app/python_app/modules - ./production_eleves:/app/python_app/modules
network_mode: "host" network_mode: "host"

View File

@ -1,16 +1,14 @@
#!/bin/sh #!/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" separator="=" # Must be ascii for cut
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="="
forbidden_chars=". /" forbidden_chars=". /"
# Check we got users # Check we got user list
if [ ! -f "$USERS_LIST" ] && [ ! -f "$PASSWD_LIST" ] ; then if [ ! -f "$USERS_LIST" ] && [ ! -f "$PASSWD_LIST" ] ; then
echo "Les fichiers des utilisateurs ou des passwords nont pas étés trouvées." echo "Les fichiers des utilisateurs ou des passwords nont pas étés trouvées."
exit 1 exit 1
@ -35,7 +33,7 @@ if [ ! -f $PASSWD_LIST ] ; then
done done
fi fi
# Create users # Create users, home dirs, change passwords and home owners
for line in $(cat $PASSWD_LIST) ; do for line in $(cat $PASSWD_LIST) ; do
name="$(echo "$line" | cut -d "$separator" -f 1)" name="$(echo "$line" | cut -d "$separator" -f 1)"
pass="$(echo "$line" | cut -d "$separator" -f 2)" pass="$(echo "$line" | cut -d "$separator" -f 2)"
@ -47,7 +45,10 @@ for line in $(cat $PASSWD_LIST) ; do
chown "$name":eleve "$home" chown "$name":eleve "$home"
done 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" echo "\nFin de la préparation des utilisateurs.\n"
@ -63,7 +64,7 @@ fi
nginx -c '/etc/nginx/nginx.conf' nginx -c '/etc/nginx/nginx.conf'
# SSH server # SSH server
/usr/sbin/sshd /usr/sbin/sshd -E /dev/stderr
# Start watever the container should be doing # Start watever the container should be doing
/bin/sh -c "$*" /bin/sh -c "$*"

View File

@ -45,6 +45,7 @@ def application(env, start_response):
# Import the function # Import the function
try: try:
m = importlib.import_module(module_path) m = importlib.import_module(module_path)
importlib.reload(m)
except ModuleNotFoundError: except ModuleNotFoundError:
#print('Le fichier {} na pas été trouvé. {}'.format(module_path, str(path_elements))) #print('Le fichier {} na pas été trouvé. {}'.format(module_path, str(path_elements)))
return htmlresp(404, 'Le fichier <em>{}</em> na pas été trouvé.'.format(path), start_response) return htmlresp(404, 'Le fichier <em>{}</em> na pas été trouvé.'.format(path), start_response)