diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3eb9d4e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..35d8cd3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,20 @@ +name: Build + +permissions: + contents: read + +on: + push: + branches: + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Run docker build + run: docker buildx build . -t ghcr.io/tweedegolf/debian:latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2363824 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +ARG DEBIAN_VERSION +FROM debian:${DEBIAN_VERSION} + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \ + && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ + wget \ + curl \ + ca-certificates \ + apt-transport-https \ + gnupg \ + dirmngr \ + gosu \ + git \ + dnsutils \ + tmux \ + nano \ + vim \ + lsof \ + unzip \ + libnss-wrapper \ + procps \ + strace \ + zutils \ + openssh-client \ + openssl \ + && rm -rf /var/lib/apt/lists/* + +# Set default timezone +ENV TZ Europe/Amsterdam +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ENV DOCKER 1 + +ENV DYNAMIC_USER_NAME tg +ENV DYNAMIC_GROUP_NAME tg +ENV DYNAMIC_USER_HOME /home/public +ENV DYNAMIC_USER_SHELL /bin/bash +ENV ROOT_SWITCH_USER "" + +# Create a world writable public home folder +RUN mkdir /home/public && chmod 0777 /home/public + +# Create a known hosts file with github / gitlab keys +COPY ssh_known_hosts /etc/ssh/ssh_known_hosts + +# Setup docker secrets to env script +COPY docker-secrets-to-env.sh /usr/local/bin/docker-secrets-to-env + +# Setup docker-entrypoint +RUN mkdir /usr/local/bin/docker-entrypoint.d +RUN mkdir /usr/local/bin/docker-entrypoint-scripts.d +COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint +RUN ln -s /usr/local/bin/docker-entrypoint /usr/local/bin/doen +ENTRYPOINT ["docker-entrypoint"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..28e9412 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2024 Tweede Golf and Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..46977d8 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +set -Eeo pipefail + +if [ "$DOCKER_ENTRYPOINT_DEBUG" = '1' ] || [ "$DOCKER_ENTRYPOINT_DEBUG" = "true" ]; then + set -x +fi + +export USER_ID=$(id -u) +export GROUP_ID=$(id -g) + +# Switch to another user if the ROOT_SWITCH_USER variable is set +if [ "$USER_ID" = '0' ] && [ ! -z "$ROOT_SWITCH_USER" ]; then + exec gosu "$ROOT_SWITCH_USER" "$BASH_SOURCE" "$@" +fi + +# Test and store if this is the initial startup process for the container +test $$ = '1' +export DOCKER_IS_INIT=$? + +# Root always exists, so we skip the libnss wrapper when root +if ! [ "$USER_ID" = '0' ]; then + + # Add wrapper passwd file if the user does not exist + if ! getent passwd "$USER_ID" 2>&1 >/dev/null; then + export NSS_WRAPPER_PASSWD=$(mktemp --tmpdir passwd.XXXXXX) + cat /etc/passwd > "${NSS_WRAPPER_PASSWD}" + echo "${DYNAMIC_USER_NAME}:x:${USER_ID}:${GROUP_ID}:${DYNAMIC_USER_NAME}:${DYNAMIC_USER_HOME}:${DYNAMIC_USER_SHELL}" >> "${NSS_WRAPPER_PASSWD}" + + # Re-export home to make sure it is set for the current session + export HOME="${DYNAMIC_USER_HOME}" + fi + + # Add wrapper group file if the group does not exist + if ! getent group "$GROUP_ID" 2>&1 >/dev/null; then + export NSS_WRAPPER_GROUP=$(mktemp --tmpdir group.XXXXXX) + cat /etc/group > "${NSS_WRAPPER_GROUP}" + echo "${DYNAMIC_GROUP_NAME}:x:${GROUP_ID}:" >> "${NSS_WRAPPER_GROUP}" + fi + + # Preload the libnss_wrapper library when running the command + dpkgArch="$(dpkg --print-architecture)" + case "${dpkgArch##*-}" in + amd64) export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libnss_wrapper.so ;; + arm64) export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libnss_wrapper.so ;; + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; + esac +fi + +eval $(docker-secrets-to-env) + +# Load additional scripts from /usr/local/bin/docker-entrypoint.d +if [ -d /usr/local/bin/docker-entrypoint.d ]; then + find "/usr/local/bin/docker-entrypoint.d/" -executable -follow -type f -print | sort -n | while read -r f; do + "$f" + done +fi + +if [ -d /usr/local/bin/docker-entrypoint-scripts.d ]; then + find "/usr/local/bin/docker-entrypoint-scripts.d/" -name '*.sh' -follow -type f -print | sort -n | while read -r f; do + source "$f" + done +fi + +# Run the command +exec "$@" diff --git a/docker-secrets-to-env.sh b/docker-secrets-to-env.sh new file mode 100755 index 0000000..c01d0c8 --- /dev/null +++ b/docker-secrets-to-env.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +# Setup error handling +set -Eeo pipefail +shopt -s nullglob + +list_all=false +secrets_path="${DOCKER_SECRETS_PATH:-/run/secrets}" +IFS=',' read -r -a listed_secrets <<<${DOCKER_ENV_SECRETS:-} + +# Read all data before any '--', they should be the requested secrets +while [[ $# -gt 0 ]]; do + key="$1" + shift + + case $key in + --all) + list_all=true + ;; + --) + break + ;; + *) + listed_secrets+=("$key") + ;; + esac +done + +# If there are any remaining arguments after the '--' assume it is a runnable command +if [[ "$#" -gt 0 ]]; then + exec_command=true +else + exec_command=false +fi + +# If the listed secrets is empty we load all secrets +if [ "${list_all}" = true ]; then + listed_secrets=() + for file in "${secrets_path}"/*; do + filename="${file#"$secrets_path/"}" + listed_secrets+=("$filename") + done +fi + +# Loop over the requested secret names +for item in "${listed_secrets[@]}"; do + # If a secret has an additional question mark we don't warn about it missing + warn_missing=true + if [ "${item: -1}" = '?' ]; then + warn_missing=false + item="${item%?}" + fi + + # Check if there is a file with the requested name + if [ -f "${secrets_path}/$item" ]; then + # Generate the command + cmd="export ${item}=\"\$(cat '${secrets_path}/$item')\"" + + # Either eval or echo the command + if [ "$exec_command" = true ]; then + eval "$cmd" + else + echo "$cmd" + fi + else + if [ "$warn_missing" = true ]; then + echo "Warning: Secret for $item is not defined in file '$secrets_path/$item'" 1>&2 + fi + fi +done + +# If there is a command to exec, run it +if [ "$exec_command" = true ]; then + exec "$@" +fi