435 lines
12 KiB
Docker
435 lines
12 KiB
Docker
ARG PYTHONTAG=3.12.11-slim-trixie
|
|
FROM docker.io/python:${PYTHONTAG} AS base-upstream
|
|
|
|
FROM base-upstream AS base-intermediate
|
|
SHELL [ "/bin/sh", "-ec" ]
|
|
|
|
COPY /scripts/* /usr/local/sbin/
|
|
COPY /extra-scripts/* /usr/local/sbin/
|
|
|
|
## PATH: remove /sbin and /bin (/usr is merged)
|
|
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \
|
|
TMPDIR=/tmp \
|
|
LANG=C.UTF-8 \
|
|
LC_ALL=C.UTF-8 \
|
|
TERM=linux \
|
|
TZ=Etc/UTC \
|
|
MALLOC_ARENA_MAX=2 \
|
|
PYTHONUNBUFFERED=1 \
|
|
PYTHONDONTWRITEBYTECODE=1
|
|
|
|
COPY /apt/sources.debian /etc/apt/sources.list.d/debian.sources
|
|
|
|
## prevent services from auto-starting, part 1
|
|
RUN s='/usr/sbin/policy-rc.d' ; b='/usr/bin/policy-rc.d' ; \
|
|
rm -f "$s" "$b" ; \
|
|
echo '#!/bin/sh' > "$b" ; \
|
|
echo 'exit 101' >> "$b" ; \
|
|
chmod 0755 "$b" ; \
|
|
ln -s "$b" "$s"
|
|
|
|
RUN divert_true() { divert-rm.sh "$1" ; ln -sv /bin/true "$1" ; } ; \
|
|
## prevent services from auto-starting, part 2
|
|
divert_true /sbin/start-stop-daemon ; \
|
|
## always report that we're in chroot
|
|
divert_true /usr/bin/ischroot ; \
|
|
## hide systemd helpers
|
|
divert_true /usr/bin/deb-systemd-helper ; \
|
|
divert_true /usr/bin/deb-systemd-invoke
|
|
|
|
RUN apt-env.sh apt-get update ; \
|
|
apt-remove.sh \
|
|
ca-certificates \
|
|
e2fsprogs \
|
|
; \
|
|
apt-env.sh apt-get upgrade -y ; \
|
|
apt-install.sh \
|
|
apt-utils \
|
|
brotli \
|
|
cron \
|
|
curl \
|
|
file \
|
|
gettext-base \
|
|
gnupg \
|
|
iproute2 \
|
|
iputils-ping \
|
|
jdupes \
|
|
jq \
|
|
less \
|
|
libcap2-bin \
|
|
libnss-wrapper \
|
|
logrotate \
|
|
lsof \
|
|
ncurses-base \
|
|
netbase \
|
|
netcat-openbsd \
|
|
openssl \
|
|
procps \
|
|
psmisc \
|
|
systemd-standalone-sysusers \
|
|
tzdata \
|
|
vim \
|
|
xxd \
|
|
xz-utils \
|
|
zstd \
|
|
; \
|
|
apt-clean.sh ; \
|
|
## remove broken symlinks
|
|
find /etc/ -xdev -follow -type l -ls -delete
|
|
|
|
## perl-base: hardlink->symlink
|
|
RUN set +e ; \
|
|
d=/usr/bin ; \
|
|
ls -li "$d/perl" ; \
|
|
find "$d/" -xdev -samefile "$d/perl" 2>/dev/null \
|
|
| grep -Fxv -e "$d/perl" \
|
|
| while read -r p ; do \
|
|
[ -n "$p" ] || continue ; \
|
|
[ -e "$p" ] || continue ; \
|
|
ls -li "$p" ; \
|
|
rm -fv "$p" ; \
|
|
ln -fsv perl "$p" ; \
|
|
ls -li "$p" ; \
|
|
echo ; \
|
|
done
|
|
|
|
## remove unwanted binaries
|
|
RUN set -f ; \
|
|
for i in \
|
|
addpart \
|
|
apt-ftparchive \
|
|
agetty \
|
|
badblocks \
|
|
blkdiscard \
|
|
blkid \
|
|
blkzone \
|
|
blockdev \
|
|
bsd-write \
|
|
chage \
|
|
chcpu \
|
|
chfn \
|
|
chgpasswd \
|
|
chmem \
|
|
chpasswd \
|
|
chsh \
|
|
cpgr \
|
|
cppw \
|
|
crontab \
|
|
ctrlaltdel \
|
|
debugfs \
|
|
delpart \
|
|
dmesg \
|
|
dumpe2fs \
|
|
e2freefrag \
|
|
e2fsck \
|
|
e2image \
|
|
e2label \
|
|
e2mmpstatus \
|
|
e2scrub \
|
|
'e2scrub*' \
|
|
e2undo \
|
|
e4crypt \
|
|
e4defrag \
|
|
expiry \
|
|
faillock \
|
|
fdformat \
|
|
fincore \
|
|
findfs \
|
|
fsck \
|
|
'fsck.*' \
|
|
fsfreeze \
|
|
fstrim \
|
|
getty \
|
|
gpasswd \
|
|
groupmems \
|
|
grpck \
|
|
grpconv \
|
|
grpunconv \
|
|
hwclock \
|
|
isosize \
|
|
last \
|
|
lastb \
|
|
ldattach \
|
|
losetup \
|
|
lsblk \
|
|
lsirq \
|
|
lslogins \
|
|
mcookie \
|
|
mesg \
|
|
mke2fs \
|
|
mkfs \
|
|
'mkfs.*' \
|
|
mkhomedir_helper \
|
|
mklost+found \
|
|
mkswap \
|
|
mount \
|
|
newgrp \
|
|
newusers \
|
|
pam-auth-update \
|
|
pam_getenv \
|
|
pam_namespace_helper \
|
|
pam_timestamp_check \
|
|
partx \
|
|
pivot_root \
|
|
pwck \
|
|
pwconv \
|
|
pwhistory_helper \
|
|
pwunconv \
|
|
raw \
|
|
readprofile \
|
|
resize2fs \
|
|
resizepart \
|
|
rtcwake \
|
|
sg \
|
|
shadowconfig \
|
|
sulogin \
|
|
swaplabel \
|
|
swapoff \
|
|
swapon \
|
|
switch_root \
|
|
tune2fs \
|
|
umount \
|
|
unix_chkpwd \
|
|
unix_update \
|
|
utmpdump \
|
|
vigr \
|
|
vipw \
|
|
wall \
|
|
wdctl \
|
|
wipefs \
|
|
write \
|
|
'write.*' \
|
|
zramctl \
|
|
; do \
|
|
## try dpkg-divert first
|
|
for d in /usr/sbin /usr/bin ; do \
|
|
find "$d/" ! -type d -wholename "$d/$i" ; \
|
|
done \
|
|
| while read -r p ; do \
|
|
[ -n "$p" ] || continue ; \
|
|
[ -e "$p" ] || continue ; \
|
|
dpkg-search.sh "$p" || continue ; \
|
|
done \
|
|
| sed -E '/^diversion by/d' \
|
|
| sort -uV \
|
|
| while read -r pkg path ; do \
|
|
[ -n "${pkg}" ] || continue ; \
|
|
[ -e "${path}" ] || continue ; \
|
|
divert-rm.sh "${path}" ; \
|
|
done ; \
|
|
## remove if still exists
|
|
for d in /usr/sbin /usr/bin ; do \
|
|
find "$d/" ! -type d -wholename "$d/$i" ; \
|
|
done \
|
|
| while read -r p ; do \
|
|
[ -n "$p" ] || continue ; \
|
|
[ -e "$p" ] || continue ; \
|
|
rm -fv "$p" ; \
|
|
done ; \
|
|
done ; \
|
|
## remove broken symlinks
|
|
find /bin/ /sbin/ -xdev -follow -type l -ls -delete
|
|
|
|
## remove excessive privileges from binaries: setuid/setgid
|
|
RUN find / -xdev -type f -perm /7000 \
|
|
| sort -V \
|
|
| while read -r p ; do \
|
|
[ -n "$p" ] || continue ; \
|
|
## clear setuid/setgid bit
|
|
m=$(env stat -c '0%a' "$p") ; \
|
|
m=$(printf '0%o\n' $((m & 00777)) ) ; \
|
|
## try to lookup in dpkg database
|
|
n=$(set +e ; dpkg-search.sh "$p" | sed -E '/^diversion by/d' | cut -d ' ' -f2-) ; \
|
|
ls -l "$p" ; \
|
|
if [ "$p" = "$n" ] ; then \
|
|
o=$(env stat -c '%U' "$n") ; \
|
|
g=$(env stat -c '%G' "$n") ; \
|
|
dpkg-statoverride --force --update --add "$o" "$g" "$m" "$n" ; \
|
|
else \
|
|
env printf 'unable to find in dpkg database: %q\n' "$n" ; \
|
|
chmod "$m" "$p" ; \
|
|
fi ; \
|
|
ls -l "$p" ; \
|
|
done
|
|
|
|
## remove excessive privileges from binaries: setcap
|
|
RUN find / -xdev -type f -executable -exec getcap {} + \
|
|
| sort -V \
|
|
| while read -r path caps ; do \
|
|
[ -n "${path}" ] || continue ; \
|
|
if [ "${path}" = /usr/bin/ping ] ; then continue ; fi ; \
|
|
getcap -v "${path}" ; \
|
|
setcap -r "${path}" "${caps}" 2>/dev/null || : ; \
|
|
getcap -v "${path}" ; \
|
|
done
|
|
|
|
## "docker.io/python"-specific cleanup
|
|
RUN env -C /root rm -f .bash_history .python_history .wget-hsts
|
|
|
|
## ---
|
|
|
|
FROM base-intermediate AS certs
|
|
SHELL [ "/bin/sh", "-ec" ]
|
|
|
|
## "2025.08.03"
|
|
ENV CERTIFI_COMMIT=a97d9ad8f87c382378dddc0b0b33b9770932404e
|
|
|
|
# 'https://raw.githubusercontent.com/certifi/python-certifi'
|
|
ARG CERTIFI_BASE_URI='https://github.com/certifi/python-certifi/raw'
|
|
|
|
ARG CERTIFI_URI="${CERTIFI_BASE_URI}/${CERTIFI_COMMIT}/certifi/cacert.pem"
|
|
ADD "${CERTIFI_URI}" /tmp/certifi.crt
|
|
|
|
RUN apt-install.sh ca-certificates ; \
|
|
apt-clean.sh ; \
|
|
ca_file='/etc/ssl/certs/ca-certificates.crt' ; \
|
|
ls -l "${ca_file}" ; \
|
|
## process certifi
|
|
certifi-extras.sh /tmp/certifi.crt ; \
|
|
openssl-cert-auto-pem.sh "${ca_file}" "${ca_file}.new" "${ca_file}.fp" ; \
|
|
mv -f "${ca_file}.new" "${ca_file}" ; \
|
|
chmod 0444 "${ca_file}" "${ca_file}.fp" ; \
|
|
ls -l "${ca_file}" "${ca_file}.fp"
|
|
|
|
## ---
|
|
|
|
FROM base-intermediate AS apt-gpg
|
|
SHELL [ "/bin/sh", "-ec" ]
|
|
|
|
COPY --from=certs /etc/ssl/certs/ca-certificates.* /etc/ssl/certs/
|
|
|
|
ADD https://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc /tmp/pgdg.gpg.bin
|
|
ADD https://packagecloud.io/citusdata/community/gpgkey /tmp/citus.gpg.bin
|
|
|
|
## process GPG keyrings
|
|
RUN pkg='gnupg' ; \
|
|
apt-install.sh ${pkg} ; \
|
|
gpg-export.sh /tmp/pgdg.gpg.bin /etc/apt/keyrings/pgdg.gpg.asc ; \
|
|
gpg-export.sh /tmp/citus.gpg.bin /etc/apt/keyrings/citus.gpg.asc ; \
|
|
apt-remove.sh ${pkg}
|
|
|
|
COPY /apt/sources.pgdg /etc/apt/sources.list.d/pgdg.sources
|
|
## TODO: disabled until citus packages are ready for Debian 13
|
|
# COPY /apt/sources.citus /etc/apt/sources.list.d/citus.sources
|
|
|
|
## verify sources!
|
|
RUN apt-env.sh apt-get update ; \
|
|
apt-clean.sh
|
|
|
|
## ---
|
|
|
|
FROM base-intermediate AS tools
|
|
SHELL [ "/bin/sh", "-ec" ]
|
|
|
|
## current HEAD: "main: don't use secure_getenv", December 14, 2024
|
|
ENV CATATONIT_COMMIT=56579adbb42c0c7ad94fc12d844b38fc5b37b3ce
|
|
|
|
# ARG CATATONIT_BASE_URI='https://codeload.github.com/openSUSE/catatonit/tar.gz'
|
|
# ARG CATATONIT_URI="${CATATONIT_BASE_URI}/${CATATONIT_COMMIT}"
|
|
|
|
ARG CATATONIT_BASE_URI='https://github.com/openSUSE/catatonit/archive'
|
|
ARG CATATONIT_URI="${CATATONIT_BASE_URI}/${CATATONIT_COMMIT}.tar.gz"
|
|
|
|
# hadolint ignore=DL3020
|
|
ADD "${CATATONIT_URI}" /tmp/catatonit.tar.gz
|
|
|
|
RUN pkg='build-essential debhelper musl-dev autoconf autoconf-archive' ; \
|
|
apt-install.sh ${pkg} ; \
|
|
DEB_HOST_GNU_TYPE=$(dpkg-architecture -q DEB_HOST_GNU_TYPE) ; \
|
|
export HOSTCC="${DEB_HOST_GNU_TYPE}-gcc" ; \
|
|
DEB_TARGET_GNU_TYPE=$(dpkg-architecture -q DEB_TARGET_GNU_TYPE) ; \
|
|
DEB_TARGET_MUSL_TYPE=$(printf '%s' "${DEB_TARGET_GNU_TYPE}" | sed -E 's/-gnu$/-musl/') ; \
|
|
CFLAGS_LTO="-flto=2 -fuse-linker-plugin -ffat-lto-objects -flto-partition=none" ; \
|
|
CFLAGS_COMMON="-O2 -g -pipe -fPIE -fstack-protector-strong -fstack-clash-protection -fcf-protection" ; \
|
|
CPPFLAGS="-Wall -Wextra -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2" ; \
|
|
## build catatonit
|
|
d=/tmp/catatonit ; \
|
|
rm -rf "$d" ; \
|
|
mkdir -p "$d" ; \
|
|
( \
|
|
cd "$d" ; \
|
|
tar --strip-components=1 -xf /tmp/catatonit.tar.gz ; \
|
|
commit_abbrev=$(printf '%s' "${CATATONIT_COMMIT}" | cut -c1-8) ; \
|
|
sed -i "s/+dev/+git.${commit_abbrev}/" configure.ac ; \
|
|
export CC="${DEB_TARGET_MUSL_TYPE}-gcc" ; \
|
|
export CFLAGS="${CFLAGS_LTO} ${CFLAGS_COMMON} ${CPPFLAGS}" ; \
|
|
export LDFLAGS="-static-pie -Wl,-z,relro -Wl,-z,now" ; \
|
|
autoreconf -fiv ; \
|
|
./configure ; \
|
|
make -j1 ; \
|
|
ls -l catatonit ; \
|
|
# "${DEB_TARGET_GNU_TYPE}-strip" --strip-debug --strip-unneeded catatonit ; \
|
|
strip --strip-debug --strip-unneeded catatonit ; \
|
|
ls -l catatonit ; \
|
|
cp catatonit /usr/local/bin/ ; \
|
|
) ; \
|
|
## cleanup
|
|
rm -rf "$d" ; \
|
|
apt-remove.sh ${pkg} ; \
|
|
apt-clean.sh
|
|
|
|
## ---
|
|
|
|
FROM base-intermediate AS base
|
|
SHELL [ "/bin/sh", "-ec" ]
|
|
|
|
COPY /Dockerfile.base /usr/local/share/
|
|
|
|
COPY --from=certs /etc/ssl/certs/ca-certificates.* /etc/ssl/certs/
|
|
COPY --from=apt-gpg /etc/apt/keyrings/ /etc/apt/keyrings/
|
|
COPY --from=tools /usr/local/bin/catatonit /usr/local/bin/
|
|
|
|
RUN python-rm-cache.sh /usr/local
|
|
|
|
RUN pip-env.sh pip list --format freeze \
|
|
| grep -F '==' | awk -F= '{print $1}' \
|
|
| xargs -r pip-env.sh pip install -U ; \
|
|
python-rm-cache.sh /usr/local
|
|
|
|
RUN libpython="${PYTHON_SITE_PACKAGES%/*}" ; \
|
|
rm -rfv \
|
|
/usr/local/bin/idle* \
|
|
/usr/local/bin/pydoc* \
|
|
"${libpython}/ensurepip/_bundled" \
|
|
"${libpython}/idlelib" \
|
|
"${libpython}/pydoc.py" \
|
|
"${libpython}/pydoc_data" \
|
|
"${libpython}/tkinter" \
|
|
"${libpython}/turtle.py" \
|
|
"${libpython}/turtledemo" \
|
|
; \
|
|
find "${PYTHON_SITE_PACKAGES}/" -iname '*.exe' -ls -delete
|
|
|
|
## adjust pip/certifi
|
|
RUN certifi_pem="${PYTHON_SITE_PACKAGES}/pip/_vendor/certifi/cacert.pem" ; \
|
|
[ -d "${certifi_pem%/*}" ] || exit 0 ; \
|
|
rm -f "${certifi_pem}" ; \
|
|
ln -sv /etc/ssl/certs/ca-certificates.crt "${certifi_pem}"
|
|
|
|
## set up locales!
|
|
RUN _lang=en_US.UTF8 ; \
|
|
{ \
|
|
echo "locales locales/default_environment_locale select ${LANG}" ; \
|
|
echo "locales locales/locales_to_be_generated multiselect ${LANG} UTF-8" ; \
|
|
} | debconf-set-selections ; \
|
|
f=/etc/dpkg/dpkg.cfg.d/docker ; \
|
|
if [ -f "$f" ] ; then \
|
|
sed -Ei '/\/usr\/share\/locale/d' "$f" ; \
|
|
fi ; \
|
|
echo "LANG=${_lang}" > /etc/default/locale ; \
|
|
apt-install.sh locales ; apt-clean.sh ; \
|
|
grep -Fixq "${_lang} UTF-8" /etc/locale.gen || { \
|
|
echo "${_lang} UTF-8" >> /etc/locale.gen ; \
|
|
locale-gen ; \
|
|
} ; \
|
|
locale -a | grep -Fixq "${_lang}"
|
|
ENV LANG=en_US.UTF8
|
|
|
|
RUN find /usr/local/sbin/ ! -type d -ls -delete ; \
|
|
find /run/ -mindepth 1 -ls -delete || : ; \
|
|
install -d -m 01777 /run/lock ; \
|
|
jdupes -1LSpr /usr/
|
|
|
|
ENTRYPOINT [ ]
|
|
CMD [ "bash" ]
|