Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using SUID in Alpine Docker Image

I am trying to run some scripts as different users in Alpine Docker image. While logged in as devuser I want run setup.sh as root and app.sh as appuser. Since I have read that you can't use the SUID on script files I have a couple C programs, setup and app, that call the scripts. I can run setup as root but can't run app as appuser.

Here is the content of the directories. Notice that app and setup have the SUID bit set on the programs. I tried setting the SUID on the scripts but that didn't work.

/opt/app $ ls -l
total 24552
-r-sr-xr-x    1 appuser  appgroup     10632 Jun 27 12:59 app
-r--------    1 appuser  appgroup  25101769 Jun 27 12:59 app.jar
-r-xr-xr--    1 appuser  appgroup       327 Jun 27 12:59 app.sh
-r--------    1 appuser  appgroup       316 Jun 27 12:59 application.yml
-r-sr-xr-x    1 root     root         10632 Jun 27 12:59 setup
-r-xr-xr--    1 root     root           152 Jun 27 12:59 setup.sh

I am running as devuser.

/opt/app $ whoami
devuser

I can run setup successfully. It is owned by root and runs as root.

/opt/app $ ./setup
Running As: root:appgroup

I try running app and it does not change to the owner.

/opt/app $ ./app
Running As: devuser:appgroup
Error: Unable to access jarfile app.jar

Here is the source for setup.sh.

/opt/app $ cat setup.sh
#!/bin/ash

echo "Running As: $(whoami):$(id -gn)"

Here is the source for app.sh.

/opt/app $ cat app.sh
#!/bin/ash

echo "Running As: $(whoami):$(id -gn)"

java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar $SPRING_OPTS

Here are the two users.

/opt/app $ id devuser
uid=701(devuser) gid=700(appgroup) groups=700(appgroup),700(appgroup)

/opt/app $ id appuser
uid=700(appuser) gid=700(appgroup) groups=700(appgroup),700(appgroup)

Here is the source for setup.c.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    setuid(0);
    system("./setup.sh");
    return 0;
}

Here is the source for app.c. I had tried setuid(0) too but that did not work.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    setuid(700);
    system("./app.sh");
    return 0;
}

And finally my dirty laundry; the Docker build. I have tried setting up adduser as a system user and a non-system user.

RUN    addgroup -g 700 appgroup \
    && adduser -G appgroup -D -u 700 -S -H -s /bin/sh appuser \
    && adduser -G appgroup -D -u 701 -s /bin/sh devuser

RUN    sh -c 'touch app.jar' \
    && chown appuser:appgroup *.jar  \
    && chown appuser:appgroup *.yml  \
    && chown appuser:appgroup app.sh  \
    && chown appuser:appgroup app \
#    && chmod -R 750 . \
    && chmod u+x,g+x,o-x *.sh \
    && chmod 4555 setup \
    && chmod 4555 app \
    && chmod 400 *.yml \
    && chmod 400 *.jar \
    && chmod -R -w .

USER devuser
# USER appuser

Thanks for any help, Wes.

like image 846
Wes Avatar asked Jun 27 '17 18:06

Wes


1 Answers

If you change setuid() to setreuid() in app.c it will work.

See this answer and comments for reason: https://stackoverflow.com/a/20687988


However, the way you describe is non-standard. It sounds hacky to have SUID binaries that call shell scripts.

Here's a way to do it using the Alpine standard su-exec:

app.sh

#!/bin/sh

echo "Running As: $(whoami):$(id -gn)"

java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar $SPRING_OPTS

setup.sh

#!/bin/sh

echo "Running As: $(whoami):$(id -gn)"

exec su-exec appuser:appgroup ./app.sh

Dockerfile

FROM alpine

WORKDIR /app

RUN apk add --no-cache su-exec

RUN    addgroup -g 700 appgroup \
    && adduser -G appgroup -D -u 700 -S -H -s /bin/sh appuser

COPY * ./

RUN chmod 0755 *.sh

ENTRYPOINT ["./setup.sh"]

Much simpler, and probably much safer as well.

like image 152
aude Avatar answered Oct 16 '22 13:10

aude