Skip to content

Commit c05cb21

Browse files
authored
Merge pull request #8 from WebClub-NITK/docker-container-auth
Docker auth
2 parents a3a663e + b26556e commit c05cb21

File tree

4 files changed

+130
-30
lines changed

4 files changed

+130
-30
lines changed

backend/docker_plugin.py

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,116 @@
1-
from docker import DockerClient
1+
from docker import DockerClient, APIClient
2+
from docker.transport import SSHHTTPAdapter
3+
import secrets
4+
import logging
25
from docker.errors import APIError
36

4-
# TODO: Add better error reporting than print statements
7+
logging.basicConfig(
8+
format="%(asctime)s - %(levelname)s - %(message)s", level=logging.ERROR
9+
)
10+
11+
ALLOWED_CHARACTERS = (
12+
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
13+
)
14+
515

616
class DockerPlugin:
7-
def __init__(self, base_url: str = "unix://var/run/docker.sock"):
8-
self.client = DockerClient(base_url=base_url)
9-
17+
def __init__(self, base_url: str = "unix://var/run/docker.sock", key_file: str = None):
18+
if key_file is None:
19+
self.docker_client = DockerClient(base_url=base_url)
20+
else:
21+
class MySSHHTTPAdapter(SSHHTTPAdapter):
22+
def _connect(self):
23+
if self.ssh_client:
24+
self.ssh_params["key_filename"] = key_file
25+
self.ssh_client.connect(**self.ssh_params)
26+
27+
self.docker_client = DockerClient()
28+
api_client = APIClient(
29+
base_url="ssh://ip:22",
30+
use_ssh_client=True,
31+
version='1.41',
32+
)
33+
ssh_client = MySSHHTTPAdapter(base_url)
34+
api_client.mount("http+docker://ssh", ssh_client)
35+
self.docker_client.api = api_client
36+
1037
def add_image(self, data: bytes):
1138
try:
12-
self.client.images.load(data)
13-
return True
39+
images = self.docker_client.images.load(data)
40+
return images[0].id
1441
except APIError as error:
15-
print(error)
16-
return False
17-
18-
def run_container(self, image: str, port: int):
42+
logging.error(error)
43+
return None
44+
45+
def run_container(self, image: str, port: int, container_name: str = None):
1946
try:
20-
# TODO: Play around with the resources parameter to limit the amount of resources the container can use
21-
container = self.client.containers.run(image, detach=True, auto_remove=True, ports={f"{port}/tcp": None})
22-
return container.id
47+
password = "".join(
48+
secrets.choice(ALLOWED_CHARACTERS) for _ in range(16)
49+
)
50+
51+
resources = {
52+
"cpu_quota": 50000, # 50% of a single core
53+
"cpu_period": 100000, # 100% of a single core
54+
"memory": "512m",
55+
}
56+
57+
if container_name and not container_name.isalnum():
58+
logging.error("Invalid container name.")
59+
return None
60+
61+
container = self.docker_client.containers.run(
62+
image,
63+
detach=True,
64+
auto_remove=True,
65+
tty=True,
66+
name=container_name,
67+
environment={"PASS": password},
68+
ports={f"{port}/tcp": None},
69+
cpu_quota=resources["cpu_quota"],
70+
cpu_period=resources["cpu_period"],
71+
mem_limit=resources["memory"],
72+
)
73+
return container.id, password
2374
except APIError as error:
24-
print(error)
75+
logging.error(error)
2576
return None
26-
77+
2778
def stop_container(self, container_id: str):
2879
try:
29-
container = self.client.containers.get(container_id)
80+
container = self.docker_client.containers.get(container_id)
3081
container.stop()
3182
return True
3283
except APIError as error:
33-
print(error)
84+
logging.error(error)
3485
return False
35-
86+
3687
def restart_container(self, container_id: str):
3788
try:
38-
container = self.client.containers.get(container_id)
89+
container = self.docker_client.containers.get(container_id)
3990
container.restart()
4091
return True
4192
except APIError as error:
42-
print(error)
93+
logging.error(error)
4394
return False
44-
95+
4596
def get_images(self):
46-
return self.client.images.list()
47-
97+
return self.docker_client.images.list()
98+
4899
def get_container_ports(self, container_id: str):
49100
try:
50-
container = self.client.containers.get(container_id)
101+
container = self.docker_client.containers.get(container_id)
51102
if len(container.ports) == 0:
52103
return None
53104
else:
54105
return container.ports
55106
except APIError as error:
56-
print(error)
107+
logging.error(error)
57108
return None
58-
109+
59110
def get_container_logs(self, container_id: str, stream: bool = True):
60111
try:
61-
container = self.client.containers.get(container_id)
112+
container = self.docker_client.containers.get(container_id)
62113
return container.logs(stream=stream)
63114
except APIError as error:
64-
print(error)
65-
115+
logging.error(error)
66116
return None

challenge.Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM alpine:latest
2+
3+
RUN apk add --no-cache openssh-server && \
4+
adduser -D atlas && \
5+
ssh-keygen -A
6+
7+
WORKDIR /home/atlas/
8+
9+
COPY challenge.sh /home/atlas/challenge.sh
10+
RUN chmod +x /home/atlas/challenge.sh
11+
12+
USER atlas
13+
14+
# Do your build here
15+
16+
USER root
17+
18+
CMD [ "/bin/sh", "-c", "/home/atlas/challenge.sh" ]

challenge.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
3+
echo "Starting the application"
4+
echo "atlas:$PASS" | chpasswd
5+
unset PASS
6+
/usr/sbin/sshd -D

cron.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
if [ -z "$1" ]; then
4+
MINUTES=$1
5+
else
6+
MINUTES=$"{DEFAULT_DOCKER_STOP_TIMEOUT:-60}"
7+
fi
8+
9+
10+
CURRENT_TIME=$(date +%s)
11+
12+
docker ps --format '{{.ID}}' | while read -r CONTAINER_ID; do
13+
STARTED_AT=$(docker inspect --format '{{.State.StartedAt}}' "$CONTAINER_ID")
14+
STARTED_TIME=$(date --date="$STARTED_AT" +%s 2>/dev/null)
15+
RUNNING_TIME=$(( (CURRENT_TIME - STARTED_TIME) / 60 ))
16+
17+
# TODO: Add container specific timeout
18+
# CONTAINER_SPECIFIC_VAR_NAME=DOCKER_STOP_TIMEOUT_$CONTAINER_ID
19+
# CONTAINER_SPECIFIC_TIMEOUT=${!CONTAINER_SPECIFIC_VAR_NAME:-$MINUTES}
20+
21+
if [ "$RUNNING_TIME" -gt "$MINUTES" ]; then
22+
CONTAINER_NAME=$(docker inspect --format '{{.Name}}' "$CONTAINER_ID" | sed 's/^\///')
23+
echo "Stopping container $CONTAINER_NAME (ID: $CONTAINER_ID) running for $RUNNING_TIME minutes..."
24+
docker stop "$CONTAINER_ID"
25+
fi
26+
done

0 commit comments

Comments
 (0)