- CI pipeline & Dockerfile hardening: env var rename, extended logging, POSIX shell, privilege drop #5

Merged
GuillaumeHemmen merged 5 commits from 4-script-is-not-found into master 2025-05-19 11:31:46 +00:00
3 changed files with 58 additions and 50 deletions

View file

@ -34,11 +34,14 @@ LABEL \
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Copy artefacts & make the wrapper executable # Copy artefacts & make the wrapper executable
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
COPY build.sh /usr/local/bin/build.sh COPY --chmod=0755 build.sh /bin/build.sh
COPY LICENSE /LICENSE COPY LICENSE /LICENSE
RUN chmod +x /usr/local/bin/build.sh RUN chmod +x /bin/build.sh
# Drop root privileges (UID 1000 exists in the base image)
USER 0
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Runtime entrypoint # Runtime entrypoint
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
ENTRYPOINT ["/usr/local/bin/build.sh"] ENTRYPOINT ["/bin/build.sh"]

View file

@ -47,15 +47,15 @@ jobs:
env: env:
# --- mandatory -------------------------------------------------------- # --- mandatory --------------------------------------------------------
KANIKO_CONTEXT: git://git.van-hemmen.com/actions/kaniko.git KANIKO_CONTEXT: git://git.van-hemmen.com/actions/kaniko.git
GITHUB_REF_NAME: ${{ github.ref_name }} GIT_REF_NAME: ${{ github.ref_name }}
GIT_USERNAME: ${{ secrets.GIT_USERNAME }} GIT_USERNAME: ${{ secrets.docker_username }}
GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }} GIT_PASSWORD: ${{ secrets.access_token }}
# --- optional (only needed when you plan to push) --------------------- # --- optional (only needed when you plan to push) ---------------------
REGISTRY_HOST: ghcr.io REGISTRY_HOST: ghcr.io
REGISTRY_USER: ${{ secrets.REGISTRY_USER }} REGISTRY_USER: ${{ secrets.docker_username }}
REGISTRY_PASS: ${{ secrets.REGISTRY_PASS }} REGISTRY_PASS: ${{ secrets.access_token }}
KANIKO_DESTINATION: ghcr.io/myorg/myapp:${{ github.sha }} KANIKO_DESTINATION: git.van-hemmen.com/myorg/myapp:${GITHUB_SHA}
# --- fine-tuning ------------------------------------------------------ # --- fine-tuning ------------------------------------------------------
KANIKO_DOCKERFILE: ./Dockerfile KANIKO_DOCKERFILE: ./Dockerfile
@ -68,7 +68,7 @@ jobs:
| Variable | Required | Purpose | Example value | | Variable | Required | Purpose | Example value |
|----------|----------|---------|----------------------------------------------------------------| |----------|----------|---------|----------------------------------------------------------------|
| `KANIKO_CONTEXT` | **Yes** | Build context (`git://`). | `git://git.van-hemmen.com/actions/kaniko.git` | | `KANIKO_CONTEXT` | **Yes** | Build context (`git://`). | `git://git.van-hemmen.com/actions/kaniko.git` |
| `GITHUB_REF_NAME` | **Yes** | Branch or tag that is being built. | `${{ github.ref_name }}` | | `GIT_REF_NAME` | **Yes** | Branch or tag that is being built. | `${{ github.ref_name }}` |
| `GIT_USERNAME` | **Yes** | Username with access to `KANIKO_CONTEXT` when it is private. | `${{ secrets.GIT_USERNAME }}` | | `GIT_USERNAME` | **Yes** | Username with access to `KANIKO_CONTEXT` when it is private. | `${{ secrets.GIT_USERNAME }}` |
| `GIT_PASSWORD` | **Yes** | Token/password paired with `GIT_USERNAME`. | `${{ secrets.GIT_PASSWORD }}` | | `GIT_PASSWORD` | **Yes** | Token/password paired with `GIT_USERNAME`. | `${{ secrets.GIT_PASSWORD }}` |
| `REGISTRY_HOST` | No (default `git.van-hemmen.com`) | Target registry hostname. | `ghcr.io` | | `REGISTRY_HOST` | No (default `git.van-hemmen.com`) | Target registry hostname. | `ghcr.io` |

View file

@ -1,28 +1,17 @@
#!/usr/bin/env bash #!/bin/sh
set -euo pipefail # BusyBox/dash-friendly: no “pipefail”, no “[[ … ]]”, no “+=”
set -eu # BusyBox ash does not support “pipefail”
############################################################################### ###############################################################################
# Mandatory variables abort if not provided # Mandatory variables abort if not provided
############################################################################### ###############################################################################
if [[ -z "${KANIKO_CONTEXT:-}" ]]; then for var in KANIKO_CONTEXT GIT_REF_NAME GIT_USERNAME GIT_PASSWORD; do
echo "Error: KANIKO_CONTEXT environment variable is required but not set." >&2 eval [ -z \"\${$var:-}\" ] && {
exit 1 echo "Error: $var environment variable is required but not set." >&2
fi exit 1
}
if [[ -z "${GITHUB_REF_NAME:-}" ]]; then done
echo "Error: GITHUB_REF_NAME environment variable is required but not set." >&2
exit 1
fi
if [[ -z "${GIT_USERNAME:-}" ]]; then
echo "Error: GIT_USERNAME environment variable is required but not set." >&2
exit 1
fi
if [[ -z "${GIT_PASSWORD:-}" ]]; then
echo "Error: GIT_PASSWORD environment variable is required but not set." >&2
exit 1
fi
############################################################################### ###############################################################################
# Optional / defaulted variables # Optional / defaulted variables
@ -39,7 +28,7 @@ KANIKO_DOCKERFILE="${KANIKO_DOCKERFILE:-./Dockerfile}"
# Handle registry authentication (only if credentials are present) # Handle registry authentication (only if credentials are present)
############################################################################### ###############################################################################
AUTH_ENABLED=false AUTH_ENABLED=false
if [[ -n "${REGISTRY_USER}" && -n "${REGISTRY_PASS}" ]]; then if [ -n "${REGISTRY_USER}" ] && [ -n "${REGISTRY_PASS}" ]; then
echo "Registry credentials supplied configuring authentication for ${REGISTRY_HOST}" echo "Registry credentials supplied configuring authentication for ${REGISTRY_HOST}"
mkdir -p /kaniko/.docker mkdir -p /kaniko/.docker
cat > /kaniko/.docker/config.json <<EOF cat > /kaniko/.docker/config.json <<EOF
@ -62,35 +51,51 @@ fi
############################################################################### ###############################################################################
DEST_FLAGS="" DEST_FLAGS=""
# Push is only possible if we have BOTH credentials and at least one destination if $AUTH_ENABLED && [ -n "${KANIKO_DESTINATION## }" ]; then
if $AUTH_ENABLED && [[ -n "${KANIKO_DESTINATION// }" ]]; then
echo "Building list of --destination flags" echo "Building list of --destination flags"
OLD_IFS="$IFS"; IFS=',' old_ifs="$IFS"; IFS=','
for raw in $KANIKO_DESTINATION; do for raw in $KANIKO_DESTINATION; do
raw="$(echo "$raw" | xargs)" # trim whitespace raw=$(echo "$raw" | xargs) # trim
expanded="$(eval echo "$raw")" # expand variables expanded=$(eval echo "$raw") # env-var expansion if any
[[ -n "$expanded" ]] && DEST_FLAGS+=" --destination=${expanded}" [ -n "$expanded" ] && DEST_FLAGS="$DEST_FLAGS --destination=$expanded"
done done
IFS="$old_ifs"
IFS="$OLD_IFS"
echo "Image(s) will be pushed to the registry." echo "Image(s) will be pushed to the registry."
else else
DEST_FLAGS="--no-push" DEST_FLAGS="--no-push"
if ! $AUTH_ENABLED; then $AUTH_ENABLED || echo "Registry credentials are missing image(s) will not be pushed."
echo "Image(s) will NOT be pushed because registry credentials are missing." [ -n "${KANIKO_DESTINATION## }" ] || echo "KANIKO_DESTINATION not provided using --no-push."
elif [[ -z "${KANIKO_DESTINATION// }" ]]; then
echo "KANIKO_DESTINATION not provided image(s) will be built with --no-push."
fi
fi fi
echo "Kaniko will be called with: ${DEST_FLAGS}" echo "Kaniko will be called with:${DEST_FLAGS}"
###############################################################################
# resume what will be done
###############################################################################
echo "Environment Variables:"
echo "KANIKO_CONTEXT=${KANIKO_CONTEXT}"
echo "GIT_REF_NAME=${GIT_REF_NAME}"
echo "GIT_USERNAME=${GIT_USERNAME}"
echo "GIT_PASSWORD=$(echo "${GIT_PASSWORD}" | sed 's/\(^..\).*\(..$\)/\1...\2/')"
echo "REGISTRY_HOST=${REGISTRY_HOST}"
echo "REGISTRY_USER=${REGISTRY_USER}"
[ -n "${REGISTRY_PASS}" ] && echo "REGISTRY_PASS=$(echo "${REGISTRY_PASS}" | sed 's/\(^..\).*\(..$\)/\1...\2/')"
echo "KANIKO_DESTINATION=${KANIKO_DESTINATION}"
echo "KANIKO_VERBOSITY=${KANIKO_VERBOSITY}"
echo "KANIKO_DOCKERFILE=${KANIKO_DOCKERFILE}"
echo ""
if [ "${DEST_FLAGS}" = "--no-push" ]; then
echo "Action: Build only (no push)"
else
echo "Action: Build and push"
fi
echo ""
############################################################################### ###############################################################################
# Invoke Kaniko # Invoke Kaniko
############################################################################### ###############################################################################
/kaniko/executor \ exec /kaniko/executor \
--verbosity="${KANIKO_VERBOSITY}" \ --verbosity="${KANIKO_VERBOSITY}" \
--context="${KANIKO_CONTEXT}#${GITHUB_REF_NAME}" \ --context="${KANIKO_CONTEXT}#${GIT_REF_NAME}" \
--dockerfile="${KANIKO_DOCKERFILE}" \ --dockerfile="${KANIKO_DOCKERFILE}" \
${DEST_FLAGS} $DEST_FLAGS