Skip to content

Commit acfa8c2

Browse files
committed
dev: use su-exec for change of user
1 parent 3ea283e commit acfa8c2

File tree

14 files changed

+286
-51
lines changed

14 files changed

+286
-51
lines changed

.github/workflows/publish_docker_image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
uses: docker/build-push-action@v4
7777
with:
7878
context: .
79-
file: ./Dockerfile
79+
file: ./Containerfile
8080
build-args: |
8181
RUN_AS_USER=${{ env.TORRUST_TRACKER_RUN_AS_USER }}
8282
push: ${{ github.event_name != 'pull_request' }}

Containerfile

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ RUN mkdir -p /app/share/torrust/default/database/; \
2121
touch /app/share/torrust/default/database/tracker.sqlite3.db; \
2222
echo ";" | sqlite3 /app/share/torrust/default/database/tracker.sqlite3.db
2323

24+
COPY ./contrib/dev-tools/su-exec/ /tmp/su-exec/
25+
RUN cc -Wall -Werror -g /tmp/su-exec/su-exec.c -o /tmp/su-exec/su-exec
26+
2427

2528
## Chef Prepare (look at project and see wat we need)
2629
FROM chef AS recipe
@@ -88,7 +91,8 @@ RUN chown -R root:root /app; chmod -R u=rw,go=r,a+X /app; chmod -R a+x /app/bin
8891

8992
## Runtime
9093
FROM gcr.io/distroless/cc:debug as runtime
91-
RUN ["/busybox/cp", "-sp", "/busybox/sh", "/bin/sh"]
94+
RUN ["/busybox/cp", "-sp", "/busybox/sh","/busybox/cat","/busybox/ls","/busybox/env", "/bin/"]
95+
COPY --from=tester --chmod=0555 /tmp/su-exec/su-exec /bin/su-exec
9296

9397
ARG TORRUST_TRACKER_PATH_CONFIG="/etc/torrust/tracker/config.toml"
9498
ARG USER_ID=1000
@@ -107,32 +111,25 @@ EXPOSE ${UDP_PORT}/udp
107111
EXPOSE ${HTTP_PORT}/tcp
108112
EXPOSE ${API_PORT}/tcp
109113

110-
WORKDIR /home/torrust
111-
RUN adduser --disabled-password --uid "${USER_ID}" "torrust"
112-
113-
RUN mkdir -p /var/lib/torrust/tracker; chown -R "${USER_ID}":"${USER_ID}" /var/lib/torrust; chmod -R 2770 /var/lib/torrust
114-
RUN mkdir -p /var/log/torrust/tracker; chown -R "${USER_ID}":"${USER_ID}" /var/log/torrust; chmod -R 2770 /var/log/torrust
115-
RUN mkdir -p /etc/torrust/tracker; chown -R "${USER_ID}":"${USER_ID}" /etc/torrust; chmod -R 2770 /etc/torrust
114+
RUN mkdir -p /var/lib/torrust/tracker /var/log/torrust/tracker /etc/torrust/tracker
116115

117116
ENV ENV=/etc/profile
118-
COPY --chmod=0555 ./share/docker/entry_script_sh /usr/local/bin/entry.sh
117+
COPY --chmod=0555 ./share/container/entry_script_sh /usr/local/bin/entry.sh
119118

120-
RUN echo '[ ! -z "$TERM" -a -r /etc/motd ] && cat /etc/motd' >> /etc/profile
121-
122-
USER "torrust":"torrust"
123119
VOLUME ["/var/lib/torrust/tracker","/var/log/torrust/tracker","/etc/torrust/tracker"]
124-
ENTRYPOINT ["entry.sh"]
120+
121+
ENTRYPOINT ["/usr/local/bin/entry.sh"]
125122

126123
## Torrust-Tracker (debug)
127124
FROM runtime as debug
128125
COPY --from=test_debug /app/ /usr/
129-
COPY --chmod=0644 ./share/docker/motd.debug /etc/motd
126+
COPY --chmod=0644 ./share/container/motd.debug /etc/motd
130127
RUN env
131128
CMD ["sh"]
132129

133130
## Torrust-Tracker (release) (default)
134131
FROM runtime as release
135132
COPY --from=test /app/ /usr/
136-
COPY --chmod=0644 ./share/docker/motd.release /etc/motd
133+
COPY --chmod=0644 ./share/container/motd.release /etc/motd
137134
# HEALTHCHECK CMD ["/usr/bin/wget", "--no-verbose", "--tries=1", "--spider", "localhost:${API_PORT}/version"]
138135
CMD ["/usr/bin/torrust-tracker"]

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ git clone https://github.com/torrust/torrust-tracker.git \
4545
&& mkdir -p ./storage/ssl_certificates
4646
```
4747

48-
And then run `cargo run` twice. The first time to generate the `tracker.toml` file and the second time to run the tracker with the default configuration.
48+
The tracker gets it's default configuration from the [share/default/config](./share/default/config/) folder: either [´tracker.sqlite3.development.toml´](./share/default/config/tracker.sqlite3.development.toml), the [local default](./src/bootstrap/config.rs#L18); or [tracker.sqlite3.distribution.toml´](./share/default/config/tracker.sqlite3.distribution.toml), the [container default](./share/container/entry_script_s#L10).
4949

50-
After running the tracker these services will be available:
50+
To specify a different configuration file, supply it's path on an environmental variable: [`TORRUST_TRACKER_PATH_CONFIG`](./src/bootstrap/config.rs#L15), or simply supply your entire configuration on the environmental variable itself: [`TORRUST_TRACKER_CONFIG`](./src/bootstrap/config.rs#L11).
51+
52+
You can also supply the api administration token via an environmental variable: [`ENV_VAR_API_ADMIN_TOKEN`](./src/bootstrap/config.rs#L12).
53+
54+
After running the tracker these services will be available (as defined in the default configuration):
5155

5256
* UDP tracker: `udp://127.0.0.1:6969/announce`.
5357
* HTTP tracker: `http://127.0.0.1:6969/announce`.

cSpell.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"libsqlite",
5959
"libtorrent",
6060
"libz",
61+
"LOGNAME",
6162
"Lphant",
6263
"metainfo",
6364
"middlewares",
@@ -95,6 +96,7 @@
9596
"Seedable",
9697
"Shareaza",
9798
"sharktorrent",
99+
"SHLVL",
98100
"socketaddr",
99101
"sqllite",
100102
"subsec",
@@ -114,6 +116,7 @@
114116
"uroot",
115117
"Vagaa",
116118
"Vuze",
119+
"Werror",
117120
"whitespaces",
118121
"XBTT",
119122
"Xeon",
@@ -123,6 +126,7 @@
123126
"yyyyyyyyyyyyyyyyyyyyd"
124127
],
125128
"enableFiletypes": [
126-
"dockerfile"
129+
"dockerfile",
130+
"shellscript"
127131
]
128132
}

contrib/dev-tools/containers/README.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,39 @@
88
```s
99
$ tree storage/
1010
storage/
11-
├── database
12-
│   └── data.db
13-
└── ssl_certificates
14-
├── localhost.crt
15-
└── localhost.key
11+
├── lib
12+
│ ├── database
13+
│ │   └── sqlite3.db <=[auto populated]
14+
│ └── ssl_certificates
15+
│ ├── localhost.crt <=[user supplied]
16+
│ └── localhost.key <=[user supplied]
17+
├── log * (future use)
18+
└── etc
19+
└── config.toml <=[auto populated]
1620
```
17-
21+
*
1822
> NOTE: you only need the `ssl_certificates` directory and certificates in case you have enabled SSL for the one HTTP tracker or the API.
1923
2024
## Demo environment
2125

22-
You can run a single command to setup the tracker with the default
26+
It is simple to setup the tracker with the default
2327
configuration and run it using the pre-built public docker image:
2428

29+
(in new a new directory)
30+
2531
```s
26-
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/torrust/torrust-tracker/v3.0.0-alpha.3/bin/install-demo.sh | bash
27-
export TORRUST_TRACKER_USER_UID=1000 \
28-
&& docker run -it \
29-
--user="$TORRUST_TRACKER_USER_UID" \
32+
mkdir -p ./storage/lib/ ./storage/log/ ./storage/etc/
33+
34+
docker run -it \
35+
--env USER_ID:$(id -u)
3036
--publish 6969:6969/udp \
3137
--publish 7070:7070/tcp \
3238
--publish 1212:1212/tcp \
33-
--volume "$(pwd)/storage":"/app/storage" \
34-
--volume "$(pwd)/tracker.toml":"/app/tracker.toml":ro \
35-
torrust/tracker:3.0.0-alpha.3
39+
--volume ./storage/lib:/var/lib/torrust/tracker \
40+
--volume ./storage/log:/var/log/torrust/tracker \
41+
--volume ./storage/etc:/etc/torrust/tracker \
42+
torrust/tracker:3.0.0-beta.0
43+
3644
```
3745

3846
This is intended to be used to run a quick demo of the application.

contrib/dev-tools/containers/docker-run-local-image.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#!/bin/bash
22

3-
TORRUST_TRACKER_CONFIG=$(cat tracker.toml)
4-
53
docker run -it \
64
--user="$(whoami)" \
75
--publish 6969:6969/udp \

contrib/dev-tools/su-exec/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 ncopa
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

contrib/dev-tools/su-exec/Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
CFLAGS ?= -Wall -Werror -g
3+
LDFLAGS ?=
4+
5+
PROG := su-exec
6+
SRCS := $(PROG).c
7+
8+
all: $(PROG)
9+
10+
$(PROG): $(SRCS)
11+
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
12+
13+
$(PROG)-static: $(SRCS)
14+
$(CC) $(CFLAGS) -o $@ $^ -static $(LDFLAGS)
15+
16+
clean:
17+
rm -f $(PROG) $(PROG)-static
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# su-exec
2+
switch user and group id, setgroups and exec
3+
4+
## Purpose
5+
6+
This is a simple tool that will simply execute a program with different
7+
privileges. The program will be executed directly and not run as a child,
8+
like su and sudo does, which avoids TTY and signal issues (see below).
9+
10+
Notice that su-exec depends on being run by the root user, non-root
11+
users do not have permission to change uid/gid.
12+
13+
## Usage
14+
15+
```shell
16+
su-exec user-spec command [ arguments... ]
17+
```
18+
19+
`user-spec` is either a user name (e.g. `nobody`) or user name and group
20+
name separated with colon (e.g. `nobody:ftp`). Numeric uid/gid values
21+
can be used instead of names. Example:
22+
23+
```shell
24+
$ su-exec apache:1000 /usr/sbin/httpd -f /opt/www/httpd.conf
25+
```
26+
27+
## TTY & parent/child handling
28+
29+
Notice how `su` will make `ps` be a child of a shell while `su-exec`
30+
just executes `ps` directly.
31+
32+
```shell
33+
$ docker run -it --rm alpine:edge su postgres -c 'ps aux'
34+
PID USER TIME COMMAND
35+
1 postgres 0:00 ash -c ps aux
36+
12 postgres 0:00 ps aux
37+
$ docker run -it --rm -v $PWD/su-exec:/sbin/su-exec:ro alpine:edge su-exec postgres ps aux
38+
PID USER TIME COMMAND
39+
1 postgres 0:00 ps aux
40+
```
41+
42+
## Why reinvent gosu?
43+
44+
This does more or less exactly the same thing as [gosu](https://github.com/tianon/gosu)
45+
but it is only 10kb instead of 1.8MB.
46+
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* set user and group id and exec */
2+
3+
#include <sys/types.h>
4+
5+
#include <err.h>
6+
#include <errno.h>
7+
#include <grp.h>
8+
#include <pwd.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <unistd.h>
13+
14+
static char *argv0;
15+
16+
static void usage(int exitcode)
17+
{
18+
printf("Usage: %s user-spec command [args]\n", argv0);
19+
exit(exitcode);
20+
}
21+
22+
int main(int argc, char *argv[])
23+
{
24+
char *user, *group, **cmdargv;
25+
char *end;
26+
27+
uid_t uid = getuid();
28+
gid_t gid = getgid();
29+
30+
argv0 = argv[0];
31+
if (argc < 3)
32+
usage(0);
33+
34+
user = argv[1];
35+
group = strchr(user, ':');
36+
if (group)
37+
*group++ = '\0';
38+
39+
cmdargv = &argv[2];
40+
41+
struct passwd *pw = NULL;
42+
if (user[0] != '\0') {
43+
uid_t nuid = strtol(user, &end, 10);
44+
if (*end == '\0')
45+
uid = nuid;
46+
else {
47+
pw = getpwnam(user);
48+
if (pw == NULL)
49+
err(1, "getpwnam(%s)", user);
50+
}
51+
}
52+
if (pw == NULL) {
53+
pw = getpwuid(uid);
54+
}
55+
if (pw != NULL) {
56+
uid = pw->pw_uid;
57+
gid = pw->pw_gid;
58+
}
59+
60+
setenv("HOME", pw != NULL ? pw->pw_dir : "/", 1);
61+
62+
if (group && group[0] != '\0') {
63+
/* group was specified, ignore grouplist for setgroups later */
64+
pw = NULL;
65+
66+
gid_t ngid = strtol(group, &end, 10);
67+
if (*end == '\0')
68+
gid = ngid;
69+
else {
70+
struct group *gr = getgrnam(group);
71+
if (gr == NULL)
72+
err(1, "getgrnam(%s)", group);
73+
gid = gr->gr_gid;
74+
}
75+
}
76+
77+
if (pw == NULL) {
78+
if (setgroups(1, &gid) < 0)
79+
err(1, "setgroups(%i)", gid);
80+
} else {
81+
int ngroups = 0;
82+
gid_t *glist = NULL;
83+
84+
while (1) {
85+
int r = getgrouplist(pw->pw_name, gid, glist, &ngroups);
86+
87+
if (r >= 0) {
88+
if (setgroups(ngroups, glist) < 0)
89+
err(1, "setgroups");
90+
break;
91+
}
92+
93+
glist = realloc(glist, ngroups * sizeof(gid_t));
94+
if (glist == NULL)
95+
err(1, "malloc");
96+
}
97+
}
98+
99+
if (setgid(gid) < 0)
100+
err(1, "setgid(%i)", gid);
101+
102+
if (setuid(uid) < 0)
103+
err(1, "setuid(%i)", uid);
104+
105+
execvp(cmdargv[0], cmdargv);
106+
err(1, "%s", cmdargv[0]);
107+
108+
return 1;
109+
}

0 commit comments

Comments
 (0)