diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d13e2ac..bee162b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -168,6 +168,84 @@ jobs: if-no-files-found: error retention-days: 1 + docker-distroless: + name: Build and publish Distroless Docker images + runs-on: ubuntu-latest + needs: [test] + strategy: + fail-fast: true + matrix: + platform: + - linux/amd64 + - linux/arm64 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }}-distroless + tags: | + type=semver,pattern={{version}},prefix=v + type=semver,pattern={{major}}.{{minor}},prefix=v + type=ref,event=branch + type=ref,event=pr + flavor: | + latest=auto + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Supported Architectures + run: docker buildx ls + + - name: Build and publish distroless image + id: docker_build + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile-distroless.ci + platforms: ${{ matrix.platform }} + outputs: type=image,name=${{ env.REGISTRY_IMAGE }}-distroless,push-by-digest=true,name-canonical=true,push=${{ (github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') && 'true' || 'false' }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} + REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + cache-from: type=gha + cache-to: type=gha,mode=max + provenance: false + + - name: Export image digest for Distroless + id: digest-prep-distroless + run: | + mkdir -p /tmp/digests-distroless + digest="${{ steps.docker_build.outputs.digest }}" + echo "manifest-hash=${digest#sha256:}" >> "$GITHUB_OUTPUT" + touch "/tmp/digests-distroless/${digest#sha256:}" + + - name: Upload image digest for Distroless + uses: actions/upload-artifact@v4 + with: + name: docker-distroless-digests-${{ steps.digest-prep-distroless.outputs.manifest-hash }} + path: /tmp/digests-distroless/* + if-no-files-found: error + retention-days: 1 + docker-merge: name: Publish Docker multi-arch manifest if: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request' }} @@ -213,3 +291,49 @@ jobs: - name: Inspect image run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} + + docker-merge-distroless: + name: Publish Distroless Docker multi-arch manifest + if: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: [docker-distroless, test] + steps: + - name: Download image digests for Distroless + uses: actions/download-artifact@v4 + with: + path: /tmp/digests-distroless + pattern: docker-distroless-digests-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Distroless + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }}-distroless + tags: | + type=semver,pattern={{version}},prefix=v + type=semver,pattern={{major}}.{{minor}},prefix=v + type=ref,event=branch + type=ref,event=pr + flavor: | + latest=auto + + - name: Create manifest list and push for Distroless + working-directory: /tmp/digests-distroless + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}-distroless@sha256:%s ' *) + + - name: Inspect Distroless image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}-distroless:${{ steps.meta.outputs.version }} diff --git a/Dockerfile-distroless.ci b/Dockerfile-distroless.ci new file mode 100644 index 0000000..6b93e90 --- /dev/null +++ b/Dockerfile-distroless.ci @@ -0,0 +1,39 @@ +# build app +FROM --platform=$BUILDPLATFORM golang:1.22-alpine3.19 AS app-builder +#RUN apk add --no-cache git tzdata + +ENV SERVICE=omegabrr + +WORKDIR /src + +# Cache Go modules +COPY go.mod go.sum ./ +RUN go mod download + +COPY . ./ + +ARG VERSION=main +ARG REVISION=main +ARG BUILDTIME +ARG TARGETOS TARGETARCH TARGETVARIANT + +RUN --network=none --mount=target=. \ +export GOOS=$TARGETOS; \ +export GOARCH=$TARGETARCH; \ +echo $GOARCH $GOOS; \ +go build -ldflags "-s -w -X github.com/autobrr/omegabrr/internal/buildinfo.Version=${VERSION} -X github.com/autobrr/omegabrr/internal/buildinfo.Commit=${REVISION} -X github.com/autobrr/omegabrr/internal/buildinfo.Date=${BUILDTIME}" -o /out/bin/omegabrr cmd/omegabrr/main.go + +# build runner +FROM gcr.io/distroless/static-debian12:nonroot + +LABEL org.opencontainers.image.source="https://github.com/autobrr/omegabrr" +LABEL org.opencontainers.image.licenses="MIT" +LABEL org.opencontainers.image.base.name="gcr.io/distroless/static-debian12:nonroot" + +COPY --from=app-builder /out/bin/omegabrr /usr/local/bin/ + +WORKDIR /config + +EXPOSE 7441 + +ENTRYPOINT ["omegabrr", "run", "--config", "/config/config.yaml"] \ No newline at end of file diff --git a/README.md b/README.md index 631efd6..a955d85 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,16 @@ Omegabrr transforms items monitored by arrs or lists into autobrr filters. Useful for automating your filters for monitored media or racing criteria. +## Table of Contents +- [Config](#config) + - [Tags](#tags) + - [Lists](#lists) +- [Commands](#commands) +- [Service](#service) + - [Docker Compose](#docker-compose) + - [Distroless alternative](#distroless-docker-images) + - [Systemd Setup](#systemd) + ## Config You can set multiple filters per arr. Find the filter ID by going into the webui and get the ID from the url like `http://localhost:7474/filters/10` where `10` is the filter ID. @@ -273,6 +283,12 @@ Check the `docker-compose.yml` example. If you have custom networks then make sure to add those, so it can communicate with autobrr, sonarr and radarr. +### Distroless Docker Images + +For users who prioritize container security, we offer alternative Docker images built on [Distroless](https://github.com/GoogleContainerTools/distroless). Specifically the `distroless/static-debian12:nonroot` base image. + +Distroless images do not contain a package manager or shell, thereby reducing the potential attack surface and making them a more secure option. These stripped-back images contain only the application and its runtime dependencies. + ### Systemd On Linux-based systems it is recommended to run omegabrr as a systemd service. diff --git a/docker-compose.yml b/docker-compose.yml index d4d825b..841dfbc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,7 @@ services: omegabrr: container_name: omegabrr image: ghcr.io/autobrr/omegabrr:latest + #image: ghcr.io/autobrr/omegabrr-distroless:latest ports: - "7441:7441" user: 1000:1000