Skip to content

Commit

Permalink
feat(docker): adding an hardened docker image version of arskcript/ni…
Browse files Browse the repository at this point in the history
…ghtly to be able to run untrusted user input
  • Loading branch information
SuperFola committed May 19, 2024
1 parent 6a4c644 commit 67b7313
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 21 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
!.gitmodules
!CMakeLists.txt
!Installer.iss.in
!harden_docker.sh
11 changes: 11 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,14 @@ jobs:
# tag with the git commit SHA
tag_with_sha: true
tags: latest

- name: Build and push harden Docker image
uses: docker/[email protected]
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: arkscript/harden
dockerfile: harden.dockerfile
# tag with the git commit SHA
tag_with_sha: true
tags: latest
17 changes: 11 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FROM alpine:3.17 AS permissions-giver
FROM alpine:3.19 AS permissions-giver

WORKDIR /out

FROM alpine:3.17 AS submodule-initializor
FROM alpine:3.19 AS submodule-initializor

# Install git
RUN apk --no-cache add git
Expand All @@ -12,12 +12,13 @@ COPY .git .git
COPY lib lib
COPY .gitmodules .

RUN git rev-parse --short=8 HEAD > /rev
# Get submodules and remove unneccesary files
RUN git submodule update --init --recursive \
&& rm -rf `find . -type d -name ".git"` \
&& rm .gitmodules

FROM alpine:3.17 AS builder
FROM alpine:3.19 AS builder

# Install cmake
RUN apk --no-cache add cmake clang clang-dev make gcc g++ libc-dev linux-headers
Expand All @@ -29,18 +30,21 @@ COPY Installer.iss.in .
COPY CMakeLists.txt .
COPY cmake cmake
COPY --from=submodule-initializor /out .
RUN cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DARK_BUILD_EXE=On \
COPY --from=submodule-initializor /rev .
RUN cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DARK_BUILD_EXE=On -DARK_COMMIT="$(cat rev)" \
&& cmake --build build --target arkscript -- -j $(nproc)

FROM alpine:3.17 AS organizer
FROM alpine:3.19 AS organizer

# Files needed to run Ark
WORKDIR /out/ark
COPY --from=builder build build
COPY --from=builder include include
COPY --from=builder lib lib

FROM alpine:3.17 AS runner
FROM alpine:3.19 AS runner

# Install cmake
RUN apk --no-cache add cmake
Expand All @@ -49,5 +53,6 @@ RUN apk --no-cache add cmake
COPY --from=organizer /out/ark .
RUN cmake --install build --config Release
ENV LD_LIBRARY_PATH=/usr/local/lib64
ENV ARKSCRIPT_PATH=/usr/local/lib/Ark

ENTRYPOINT [ "arkscript" ]
65 changes: 65 additions & 0 deletions harden.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
FROM alpine:3.19 AS permissions-giver

WORKDIR /out

FROM alpine:3.19 AS submodule-initializor

# Install git
RUN apk --no-cache add git

WORKDIR /out
COPY .git .git
COPY lib lib
COPY .gitmodules .

RUN git rev-parse --short=8 HEAD > /rev
# Get submodules and remove unneccesary files
RUN git submodule update --init --recursive \
&& rm -rf `find . -type d -name ".git"` \
&& rm .gitmodules

FROM alpine:3.19 AS builder

# Install cmake
RUN apk --no-cache add cmake clang clang-dev make gcc g++ libc-dev linux-headers

# Build
COPY include include
COPY src src
COPY Installer.iss.in .
COPY CMakeLists.txt .
COPY cmake cmake
COPY --from=submodule-initializor /out .
COPY --from=submodule-initializor /rev .
RUN cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DARK_BUILD_EXE=On -DARK_ENABLE_SYSTEM=Off -DARK_COMMIT="$(cat rev)" \
&& cmake --build build --target arkscript -- -j $(nproc)

FROM alpine:3.19 AS organizer

# Files needed to run Ark
WORKDIR /out/ark
COPY --from=builder build build
COPY --from=builder include include
COPY --from=builder lib lib

FROM alpine:3.19 AS runner

# Install cmake
RUN apk --no-cache add cmake
RUN apk add --update duo_unix

# Install Ark
COPY --from=organizer /out/ark .
RUN cmake --install build --config Release
ENV LD_LIBRARY_PATH=/usr/local/lib64
ENV ARKSCRIPT_PATH=/usr/local/lib/Ark

COPY harden_docker.sh /usr/sbin/harden.sh
RUN chmod u+x /usr/sbin/harden.sh
RUN /usr/sbin/harden.sh

USER user
WORKDIR /home/user
ENTRYPOINT [ "arkscript" ]
140 changes: 140 additions & 0 deletions harden_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/bin/sh
set -x
set -e
#
# Docker build calls this script to harden the image during build.
#
# NOTE: To build on CircleCI, you must take care to keep the `find`
# command out of the /proc filesystem to avoid errors like:
#
# find: /proc/tty/driver: Permission denied
# lxc-start: The container failed to start.
# lxc-start: Additional information can be obtained by \
# setting the --logfile and --logpriority options.

adduser -D -s /bin/sh -u 1000 user
sed -i -r 's/^user:!:/user:x:/' /etc/shadow

# Avoid error `Only root may specify -c or -f` when using
# ForceCommand with `-f` option at non-root ssh login.
# https://www.duosecurity.com/docs/duounix-faq#can-i-use-login_duo-to-protect-non-root-shared-accounts,-or-can-i-do-an-install-without-root-privileges?
if [[ -f /usr/sbin/login_duo ]]; then
chmod u-s /usr/sbin/login_duo
fi

# /etc/duo/login_duo.conf must be readable only by user 'user'.
if [[ -f /etc/duo/login_duo.conf ]]; then
chown user:user /etc/duo/login_duo.conf
chmod 0400 /etc/duo/login_duo.conf
fi

# Ensure strict ownership and perms.
if [[ -f /usr/bin/github_pubkeys ]]; then
chown root:root /usr/bin/github_pubkeys
chmod 0555 /usr/bin/github_pubkeys
fi

# Be informative after successful login.
echo -e "\n\nHardened App container image built on $(date)." > /etc/motd

# Improve strength of diffie-hellman-group-exchange-sha256 (Custom DH with SHA2).
# See https://stribika.github.io/2015/01/04/secure-secure-shell.html
#
# Columns in the moduli file are:
# Time Type Tests Tries Size Generator Modulus
#
# This file is provided by the openssh package on Fedora.
moduli=/etc/ssh/moduli
if [[ -f ${moduli} ]]; then
cp ${moduli} ${moduli}.orig
awk '$5 >= 2000' ${moduli}.orig > ${moduli}
rm -f ${moduli}.orig
fi

# Remove existing crontabs, if any.
rm -fr /var/spool/cron
rm -fr /etc/crontabs
rm -fr /etc/periodic

# Remove all but a handful of admin commands.
find /sbin /usr/sbin ! -type d \
-a ! -name login_duo \
-a ! -name nologin \
-a ! -name setup-proxy \
-a ! -name sshd \
-a ! -name start.sh \
-delete

# Remove world-writable permissions.
# This breaks apps that need to write to /tmp,
# such as ssh-agent.
find / -xdev -type d -perm +0002 -exec chmod o-w {} +
find / -xdev -type f -perm +0002 -exec chmod o-w {} +

# Remove unnecessary user accounts.
sed -i -r '/^(user|root|sshd)/!d' /etc/group
sed -i -r '/^(user|root|sshd)/!d' /etc/passwd

# Remove interactive login shell for everybody but user.
sed -i -r '/^user:/! s#^(.*):[^:]*$#\1:/sbin/nologin#' /etc/passwd

sysdirs="
/bin
/etc
/lib
/sbin
/usr
"

# Remove apk configs.
find $sysdirs -xdev -regex '.*apk.*' -exec rm -fr {} +

# Remove crufty...
# /etc/shadow-
# /etc/passwd-
# /etc/group-
find $sysdirs -xdev -type f -regex '.*-$' -exec rm -f {} +

# Ensure system dirs are owned by root and not writable by anybody else.
find $sysdirs -xdev -type d \
-exec chown root:root {} \; \
-exec chmod 0755 {} \;

# Remove all suid files.
find $sysdirs -xdev -type f -a -perm +4000 -delete

# Remove other programs that could be dangerous.
find $sysdirs -xdev \( \
-name hexdump -o \
-name chgrp -o \
-name chmod -o \
-name chown -o \
-name ln -o \
-name od -o \
-name strings -o \
-name su \
\) -delete

# Remove init scripts since we do not use them.
rm -fr /etc/init.d
rm -fr /lib/rc
rm -fr /etc/conf.d
rm -fr /etc/inittab
rm -fr /etc/runlevels
rm -fr /etc/rc.conf

# Remove kernel tunables since we do not need them.
rm -fr /etc/sysctl*
rm -fr /etc/modprobe.d
rm -fr /etc/modules
rm -fr /etc/mdev.conf
rm -fr /etc/acpi

# Remove root homedir since we do not need it.
rm -fr /root

# Remove fstab since we do not need it.
rm -f /etc/fstab

# Remove broken symlinks (because we removed the targets above).
find $sysdirs -xdev -type l -exec test ! -e {} \; -delete
31 changes: 16 additions & 15 deletions include/utf8.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,42 @@ namespace utf8
namespace details
{
// clang-format off
constexpr char no = static_cast<char>(-1);
constexpr std::array<char, 128> ASCIIHexToInt =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no,
no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no,
no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, no, no, no, no, no, no,
no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no,
no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no,
no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no,
no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no,
};
// clang-format on
}

inline Utf8Type utf8type(const char* input, int32_t* out = nullptr)
{
int32_t codepoint = 0;
int32_t codepoint_ = 0;
int shift = 0;

for (const char* s = input; *s != 0; ++s)
{
codepoint = ((codepoint << shift) | details::ASCIIHexToInt[*s]);
codepoint_ = ((codepoint_ << shift) | details::ASCIIHexToInt[*s]);
shift = 4;
}

if (out != nullptr)
*out = codepoint;
*out = codepoint_;

if (codepoint >= 0x0000 && codepoint <= 0x007f)
if (codepoint_ >= 0x0000 && codepoint_ <= 0x007f)
return Utf8Type::Ascii;
else if (codepoint > 0x007f && codepoint <= 0x07ff)
else if (codepoint_ > 0x007f && codepoint_ <= 0x07ff)
return Utf8Type::LatinExtra;
else if (codepoint > 0x07ff && codepoint <= 0xffff)
else if (codepoint_ > 0x07ff && codepoint_ <= 0xffff)
return Utf8Type::BasicMultiLingual;
else if (codepoint > 0xffff && codepoint <= 0x10ffff)
else if (codepoint_ > 0xffff && codepoint_ <= 0x10ffff)
return Utf8Type::OthersPlanesUnicode;

return Utf8Type::OutRange;
Expand Down

0 comments on commit 67b7313

Please sign in to comment.