Beta version, working PoC
This commit is contained in:
parent
e122d5a452
commit
182e8b9a94
1
test-python-ssh/.dockerignore
Normal file
1
test-python-ssh/.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
production_eleves
|
@ -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
|
||||||
|
|
||||||
|
@ -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 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).
|
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.
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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 n’ont pas étés trouvées."
|
echo "Les fichiers des utilisateurs ou des passwords n’ont 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 "$*"
|
||||||
|
@ -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 {} n’a pas été trouvé. {}'.format(module_path, str(path_elements)))
|
#print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(path_elements)))
|
||||||
return htmlresp(404, 'Le fichier <em>{}</em> n’a pas été trouvé.'.format(path), start_response)
|
return htmlresp(404, 'Le fichier <em>{}</em> n’a pas été trouvé.'.format(path), start_response)
|
||||||
|
Loading…
Reference in New Issue
Block a user