Commit
Author: Kevin Schoon [me@kevinschoon.com]
Hash: 19916f7ab260ba31f0eed732bcb6b76f36c60045
Timestamp: Fri, 26 Apr 2024 16:00:03 +0000 (11 months ago)

+192 -8 +/-10 browse
add multiuser container
add multiuser container

This adds a container for production deployments with use with multiple users
in a shared environment. Full design is still a WIP.
1diff --git a/containers/base/Containerfile b/containers/base/Containerfile
2index 6eb4826..cd8dc2c 100644
3--- a/containers/base/Containerfile
4+++ b/containers/base/Containerfile
5 @@ -49,10 +49,8 @@ RUN adduser -D -s /bin/sh -h /home/ayllu ayllu
6 # NOTE: this explicitly ignores CVE 2022-24765 because this is not a multi-user
7 # git environment.
8 RUN \
9- mkdir -p /etc/ayllu && \
10- ayllu config generate > /etc/ayllu/config.yaml && \
11- git config --global --add user.name 'ayllu' && \
12- git config --global --add safe.directory '*' && \
13+ mkdir -p /etc/ayllu /var/lib/ayllu /var/lib/git && \
14+ ayllu config generate > /etc/ayllu/config.toml && \
15 fc-cache -fv # update font cache which is required by plotters.rs
16
17 # default to the non-root ayllu user
18 diff --git a/containers/multiuser/Containerfile b/containers/multiuser/Containerfile
19new file mode 100644
20index 0000000..d9e99c9
21--- /dev/null
22+++ b/containers/multiuser/Containerfile
23 @@ -0,0 +1,12 @@
24+ FROM registry.ayllu-forge.org/projects/ayllu:main
25+
26+ USER root
27+
28+ RUN apk add --no-cache gawk dropbear runit
29+
30+ COPY containers/multiuser/motd.txt /etc/motd
31+ COPY containers/multiuser/service /etc/service
32+ COPY containers/multiuser/welcome.sh /etc/profile.d/
33+ COPY containers/multiuser/run_all.sh /
34+
35+ CMD ["/run_all.sh"]
36 diff --git a/containers/multiuser/README.md b/containers/multiuser/README.md
37new file mode 100644
38index 0000000..8ad93ae
39--- /dev/null
40+++ b/containers/multiuser/README.md
41 @@ -0,0 +1,23 @@
42+ # Multiuser Container
43+
44+ This container has configuration for supporting a multi-user development
45+ environment where users have push access controller by SSH. The container
46+ launches multiple processes which are managed by
47+ [runit](https://smarden.org/runit).
48+
49+ ## Environment Variables
50+
51+ ### AYLLU_AUTHORIZED_KEYS
52+
53+ You can specify any number of authorized keys separated by a `;` which will
54+ automatically be added to the `ayllu` user's `~/.ssh/authorized_keys` file.
55+ If you would like multiple users to have full "administrative" access to all
56+ repositories you may add them here.
57+
58+ ### AYLLU_USER_$NAME
59+
60+ You can also specify any number of authorized keys separated by a `;` and the
61+ container will automatically setup user accounts along with SSH access for each
62+ matching variable. This configuration is useful if you want to isolate users
63+ from one another. Note that you still need to configure collections in your
64+ Ayllu configuration file in order for them to be served.
65 diff --git a/containers/multiuser/motd.txt b/containers/multiuser/motd.txt
66new file mode 100644
67index 0000000..fab8d1d
68--- /dev/null
69+++ b/containers/multiuser/motd.txt
70 @@ -0,0 +1,14 @@
71+
72+ ████ ████
73+ ░░███ ░░███
74+ ██████ █████ ████ ░███ ░███ █████ ████
75+ ░░░░░███ ░░███ ░███ ░███ ░███ ░░███ ░███
76+ ███████ ░███ ░███ ░███ ░███ ░███ ░███
77+ ███░░███ ░███ ░███ ░███ ░███ ░███ ░███
78+ ░░████████ ░░███████ █████ █████ ░░████████
79+ ░░░░░░░░ ░░░░░███ ░░░░░ ░░░░░ ░░░░░░░░
80+ ███ ░███
81+ ░░██████
82+ ░░░░░░
83+
84+ A Hyper Performant & Hackable Code Forge Built on Open Standards.
85 diff --git a/containers/multiuser/run_all.sh b/containers/multiuser/run_all.sh
86new file mode 100755
87index 0000000..0db983d
88--- /dev/null
89+++ b/containers/multiuser/run_all.sh
90 @@ -0,0 +1,61 @@
91+ #!/usr/bin/env sh
92+
93+ # copy all authorized keys specified as AYLLU_AUTHORIZED_KEYS=ecdsa-sha-2 ...::ssh-rsa ...
94+ # to the ~/.ssh/authorized_keys file of the Ayllu user.
95+
96+ AYLLU_HOME="/home/ayllu"
97+ AYLLU_SSH_AUTHORIZED_KEYS_FILE="$AYLLU_HOME/.ssh/authorized_keys"
98+
99+ mkdir -p "$AYLLU_HOME/.ssh"
100+ chown ayllu:ayllu "$AYLLU_HOME/.ssh"
101+ echo /dev/null > "$AYLLU_SSH_AUTHORIZED_KEYS_FILE"
102+ chmod 644 "$AYLLU_SSH_AUTHORIZED_KEYS_FILE"
103+
104+ echo "$AYLLU_AUTHORIZED_KEYS" | while IFS= read -r public_key
105+ do
106+ echo "$public_key" >> "$AYLLU_SSH_AUTHORIZED_KEYS_FILE"
107+ done
108+
109+ # take envs with the format AYLLU_USER_$NAME="ecdsa-sha2 ...::ssh-rsa ..."
110+ # and configure a user within the container setting each SSH public key into
111+ # that user's ~/.ssh/authorized_keys file.
112+
113+ env |grep AYLLU_USER_ | while IFS= read -r env_entry
114+ do
115+ username="$(echo "$env_entry" \
116+ | awk -F= '{split($1, arr, "_"); print tolower(arr[3])}')"
117+
118+ echo "creating user $username"
119+
120+ adduser -h "/home/$username" -D -g "Ayllu Managed User" "$username"
121+ mkdir -p "/home/$username/.ssh"
122+ echo /dev/null > "/home/$username/.ssh/authorized_keys"
123+
124+ env_key=$(echo "$env_entry" | awk -F= '{print $1}' | sed "r/")
125+ replacement=$(printf "s/%s=//" "$env_key")
126+ all_keys="$(echo "$env_entry" | sed "${replacement}")"
127+
128+ echo "$all_keys" | sed 's/::/\n/g' | while IFS= read -r key_entry
129+ do
130+ echo "$key_entry" >> "/home/$username/.ssh/authorized_keys"
131+ done
132+
133+ chown -R "$username:$username" "/home/$username"
134+ chmod 644 "/home/$username/.ssh/authorized_keys"
135+
136+ # add ayllu to all user groups so it can access their repositories
137+ addgroup ayllu "$username"
138+
139+ done
140+
141+ /sbin/runsvdir /etc/service &
142+
143+ RUNIT_PID="$!"
144+
145+ shutdown() {
146+ kill -TERM "$RUNIT_PID"
147+ exit
148+ }
149+
150+ trap 'shutdown' EXIT INT HUP
151+ wait "$RUNIT_PID"
152 diff --git a/containers/multiuser/service/ayllu/finish b/containers/multiuser/service/ayllu/finish
153new file mode 100755
154index 0000000..43c2f3e
155--- /dev/null
156+++ b/containers/multiuser/service/ayllu/finish
157 @@ -0,0 +1,3 @@
158+ #!/bin/sh
159+
160+ sleep 5
161 diff --git a/containers/multiuser/service/ayllu/run b/containers/multiuser/service/ayllu/run
162new file mode 100755
163index 0000000..d642d4c
164--- /dev/null
165+++ b/containers/multiuser/service/ayllu/run
166 @@ -0,0 +1,3 @@
167+ #!/bin/sh
168+
169+ exec su ayllu -c 'ayllu --config /etc/ayllu/config.toml serve'
170 diff --git a/containers/multiuser/service/dropbear/run b/containers/multiuser/service/dropbear/run
171new file mode 100755
172index 0000000..3a10acd
173--- /dev/null
174+++ b/containers/multiuser/service/dropbear/run
175 @@ -0,0 +1,48 @@
176+ #!/bin/sh
177+ set -e
178+ # Dropbear server v2022.83 https://matt.ucc.asn.au/dropbear/dropbear.html
179+ # Usage: dropbear [options]
180+ # -b bannerfile Display the contents of bannerfile before user login
181+ # (default: none)
182+ # -r keyfile Specify hostkeys (repeatable)
183+ # defaults:
184+ # - dss /etc/dropbear/dropbear_dss_host_key
185+ # - rsa /etc/dropbear/dropbear_rsa_host_key
186+ # - ecdsa /etc/dropbear/dropbear_ecdsa_host_key
187+ # - ed25519 /etc/dropbear/dropbear_ed25519_host_key
188+ # -R Create hostkeys as required
189+ # -F Don't fork into background
190+ # -e Pass on server process environment to child process
191+ # -E Log to stderr rather than syslog
192+ # -m Don't display the motd on login
193+ # -w Disallow root logins
194+ # -G Restrict logins to members of specified group
195+ # -s Disable password logins
196+ # -g Disable password logins for root
197+ # -B Allow blank password logins
198+ # -t Enable two-factor authentication (both password and public key required)
199+ # -T Maximum authentication tries (default 10)
200+ # -j Disable local port forwarding
201+ # -k Disable remote port forwarding
202+ # -a Allow connections to forwarded ports from any host
203+ # -c command Force executed command
204+ # -p [address:]port
205+ # Listen on specified tcp port (and optionally address),
206+ # up to 10 can be specified
207+ # (default port is 22 if none specified)
208+ # -P PidFile Create pid file PidFile
209+ # (default /var/run/dropbear.pid)
210+ # -i Start for inetd
211+ # -W <receive_window_buffer> (default 24576, larger may be faster, max 10MB)
212+ # -K <keepalive> (0 is never, default 0, in seconds)
213+ # -I <idle_timeout> (0 is never, default 0, in seconds)
214+ # -z disable QoS
215+ # -V Version
216+
217+ DROPBEAR_FLAGS="-FswERjk"
218+
219+ if [ -n "$DROPBEAR_SSH_PORT" ] ; then
220+ DROPBEAR_FLAGS="$DROPBEAR_FLAGS -p $DROPBEAR_SSH_PORT"
221+ fi
222+
223+ exec dropbear $DROPBEAR_FLAGS
224 diff --git a/containers/multiuser/welcome.sh b/containers/multiuser/welcome.sh
225new file mode 100755
226index 0000000..7bc7c6b
227--- /dev/null
228+++ b/containers/multiuser/welcome.sh
229 @@ -0,0 +1,4 @@
230+ #!/bin/sh
231+
232+ echo
233+ uptime
234 diff --git a/scripts/build_container.sh b/scripts/build_container.sh
235index e5f2be5..cc10c6e 100755
236--- a/scripts/build_container.sh
237+++ b/scripts/build_container.sh
238 @@ -1,15 +1,33 @@
239 #!/bin/sh
240 set -e
241
242- REGISTRY="registry-auth.ayllu-forge.org"
243+ REGISTRY="registry.ayllu-forge.org"
244 IMAGE_NAME="projects/ayllu"
245 COMMIT_ID="$(git rev-parse HEAD)"
246 BRANCH_NAME="$(git branch --show-current)"
247
248+ usage() {
249+ printf "USAGE: build_container.sh PATH\n"
250+ exit 1
251+ }
252+
253+ TARGET_DIR="$1"
254+
255+ [ -z "$TARGET_DIR" ] && usage
256+
257+ FLAVOR="$(basename "$TARGET_DIR")"
258+ if [ "$FLAVOR" = "base" ]; then
259+ DETAILED_TAG="$COMMIT_ID"
260+ FRIENDLY_TAG="$BRANCH_NAME"
261+ else
262+ DETAILED_TAG="$FLAVOR-$COMMIT_ID"
263+ FRIENDLY_TAG="$FLAVOR-$BRANCH_NAME"
264+ fi
265+
266 podman \
267 build --network=host \
268- -t "$REGISTRY/$IMAGE_NAME:$COMMIT_ID" \
269- -f containers/base/Containerfile .
270+ -t "$REGISTRY/$IMAGE_NAME:$DETAILED_TAG" \
271+ -f "$TARGET_DIR/Containerfile" .
272
273 podman tag \
274- "$REGISTRY/$IMAGE_NAME:$COMMIT_ID" "$REGISTRY/$IMAGE_NAME:$BRANCH_NAME"
275+ "$REGISTRY/$IMAGE_NAME:$DETAILED_TAG" "$REGISTRY/$IMAGE_NAME:$FRIENDLY_TAG"