From 6a0d85a82aa105becd90245a3cf7a1d60ea86700 Mon Sep 17 00:00:00 2001 From: pentago <876756+pentago@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:39:45 +0200 Subject: [PATCH] Added code Signed-off-by: pentago <876756+pentago@users.noreply.github.com> --- .markdownlint.json | 4 +++ .yamllint | 5 ++++ Dockerfile | 32 ++++++++++++++++++++++ README.md | 18 ++++++++++++ tests/compose.yaml | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 .markdownlint.json create mode 100644 .yamllint create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 tests/compose.yaml diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..928d5d2 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "default": true, + "MD013": false, // Disable line length rule +} \ No newline at end of file diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..f8ed731 --- /dev/null +++ b/.yamllint @@ -0,0 +1,5 @@ +extends: default + +rules: + document-start: disable + line-length: disable \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..276c7f9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# https://github.com/traefik/traefik/releases +ARG TRAEFIK_VERSION=v3.1.1 + +# https://hub.docker.com/_/alpine +ARG ALPINE_VERSION=3.20.2 + +# Official image +FROM traefik:$TRAEFIK_VERSION AS source + +# Rootless customization +FROM alpine:$ALPINE_VERSION AS build +COPY --from=source /usr/local/bin/traefik / + +# Modification to allow running rootless while listening on low ports +# RUN apk --no-cache add libcap +# RUN setcap cap_net_bind_service=+ep /traefik + +# Final minimal image +FROM scratch + +LABEL org.opencontainers.image.source="https://github.com/pentago/traefik-rootless" +LABEL org.opencontainers.image.licenses="MIT" +LABEL org.opencontainers.image.base.name="scratch" + +COPY --from=source /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=source /usr/share/zoneinfo /usr/share/ +COPY --from=build /traefik / + +USER 1000:1000 +EXPOSE 8080 8443 +VOLUME ["/tmp"] +ENTRYPOINT ["/traefik"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a5122c --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Unprivileged Traefik Container Image + +[![Main CI](https://github.com/pentago/traefik-rootless/actions/workflows/main.yaml/badge.svg)](https://github.com/pentago/traefik-rootless/actions/workflows/main.yaml) + +To be able to run this critical component as unprivileged and secure as possible, it needs to be built as a custom image. + +Approach here is to fetch the official image binary, and copy over the binary to a `scratch` based image with bare minimum of additions (*root certificates and zoneinfo* files from official image), running as unprivileged user (`1000:1000`) by default, all making it smaller and more secure. + +Considering official image simplicity, this unprivileged image can be used across at least entire 3.x branch lifetime, hopefully even longer. + +## Features + +* Official, untouched binary +* Rootless +* Listens on high ports +* Bare-bones scratch image +* Multiple architectures +* Free diff --git a/tests/compose.yaml b/tests/compose.yaml new file mode 100644 index 0000000..a1e5237 --- /dev/null +++ b/tests/compose.yaml @@ -0,0 +1,68 @@ +services: + + socket_proxy: + container_name: socket_proxy + hostname: socket_proxy + image: lscr.io/linuxserver/socket-proxy:latest + environment: + VERSION: 1 + CONTAINERS: 1 + EVENTS: 1 + ALLOW_START: 0 + ALLOW_STOP: 0 + ALLOW_RESTARTS: 0 + AUTH: 0 + BUILD: 0 + COMMIT: 0 + CONFIGS: 0 + DISABLE_IPV6: 0 + DISTRIBUTION: 0 + EXEC: 0 + IMAGES: 0 + INFO: 0 + NETWORKS: 0 + NODES: 0 + PING: 0 + POST: 0 + PLUGINS: 0 + SECRETS: 0 + SERVICES: 0 + SESSION: 0 + SWARM: 0 + SYSTEM: 0 + TASKS: 0 + VOLUMES: 0 + expose: + - 2375 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + read_only: true + tmpfs: + - /run + + traefik: + container_name: traefik + hostname: traefik + image: TRAEFIK_ROOTLES_IMAGE:latest + command: + - --log.level=DEBUG + - --api.insecure=true + - --providers.docker=true + - --providers.docker.endpoint=tcp://socket_proxy:2375 + - --providers.docker.exposedbydefault=false + - --entryPoints.web.address=:80 + ports: + - "8080:80" + depends_on: + - socket_proxy + + whoami: + container_name: whoami + hostname: whoami + image: traefik/whoami:latest + depends_on: + - traefik + labels: + - traefik.enable=true + - traefik.http.routers.whoami.rule=Host(`localhost`) && PathPrefix(`/whoami`) + - traefik.http.routers.whoami.entrypoints=web