mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-28 17:49:08 +02:00
[proxy] Add a release-wired UBI image variant (#7464)
Add a UBI-based reverse-proxy image for the internal Red Hat certification requirement, without changing the existing image or deployment defaults. Includes non-root execution, licensing and image metadata, plus an AMD64 GoReleaser entry with separate UBI tags. Preflight and TLS/overlay checks passed. An intermittent shutdown exit error remains deferred; this stays draft pending maintainer testing.
This commit is contained in:
@@ -194,6 +194,14 @@ jobs:
|
||||
- name: Fill the RPM ISA provide version
|
||||
# nfpm cannot emit rpmbuild's ISA provide and GoReleaser cannot template it.
|
||||
run: bash release_files/rpm-provides.sh
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '22'
|
||||
- name: Install proxy web dependencies for license collection
|
||||
# proxy/collect-licenses.sh reads the UI's license terms from node_modules.
|
||||
working-directory: proxy/web
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 #v4.1.0
|
||||
- name: Set up Docker Buildx
|
||||
@@ -301,10 +309,12 @@ jobs:
|
||||
tag_and_push() {
|
||||
local src="$1" img_name tag dst variant=""
|
||||
img_name="${src%%:*}"
|
||||
# Client variants share a repository, so keep their tag suffixes.
|
||||
# Variants share a repository with their default image, so keep
|
||||
# their tag suffixes. Order matters: the first matching pattern wins.
|
||||
case "$src" in
|
||||
*-rootless-ubi-amd64) variant="-rootless-ubi" ;;
|
||||
*-rootless-amd64) variant="-rootless" ;;
|
||||
*-ubi-amd64) variant="-ubi" ;;
|
||||
esac
|
||||
for tag in $(resolve_tags); do
|
||||
dst="${img_name}:${tag}${variant}"
|
||||
|
||||
@@ -533,6 +533,41 @@ dockers_v2:
|
||||
"org.opencontainers.image.revision": "{{.FullCommit}}"
|
||||
"org.opencontainers.image.source": "{{.GitURL}}"
|
||||
"maintainer": "dev@netbird.io"
|
||||
- id: proxy-ubi
|
||||
disable: "{{ .Env.SKIP_DOCKER_PUSH }}"
|
||||
ids:
|
||||
- netbird-proxy
|
||||
images:
|
||||
- netbirdio/reverse-proxy
|
||||
- ghcr.io/netbirdio/reverse-proxy
|
||||
tags:
|
||||
- "{{ .Version }}-ubi"
|
||||
- "{{ if eq .Env.SKIP_PUBLISH \"false\" }}ubi-latest{{ end }}"
|
||||
dockerfile: proxy/Dockerfile.ubi
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
build_args:
|
||||
VERSION: "{{ .Version }}"
|
||||
RELEASE: "{{ .Timestamp }}"
|
||||
hooks:
|
||||
pre:
|
||||
- cmd: 'sh proxy/collect-licenses.sh "{{ .ContextDir }}/licenses" amd64 arm64'
|
||||
env:
|
||||
- GOOS=linux
|
||||
- CGO_ENABLED=0
|
||||
labels:
|
||||
"org.opencontainers.image.created": "{{.Date}}"
|
||||
"org.opencontainers.image.version": "{{.Version}}"
|
||||
"org.opencontainers.image.revision": "{{.FullCommit}}"
|
||||
"org.opencontainers.image.source": "{{.GitURL}}"
|
||||
annotations:
|
||||
"org.opencontainers.image.created": "{{.Date}}"
|
||||
"org.opencontainers.image.title": "{{.ProjectName}}"
|
||||
"org.opencontainers.image.version": "{{.Version}}"
|
||||
"org.opencontainers.image.revision": "{{.FullCommit}}"
|
||||
"org.opencontainers.image.source": "{{.GitURL}}"
|
||||
"maintainer": "dev@netbird.io"
|
||||
|
||||
brews:
|
||||
- ids:
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
FROM registry.access.redhat.com/ubi9/ubi-minimal@sha256:7fbeae18dc9476399f565e68255f602a3374ea8614ba3d14843565131a13ff93
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG VERSION=dev
|
||||
ARG RELEASE=1
|
||||
|
||||
LABEL name="netbird-reverse-proxy" \
|
||||
maintainer="NetBird <dev@netbird.io>" \
|
||||
vendor="NetBird GmbH" \
|
||||
version="${VERSION}" \
|
||||
release="${RELEASE}" \
|
||||
summary="NetBird Reverse Proxy" \
|
||||
description="NetBird Reverse Proxy provides an identity-aware entrypoint to services in NetBird networks."
|
||||
|
||||
COPY --chmod=0555 ${TARGETPLATFORM}/netbird-proxy /go/bin/netbird-proxy
|
||||
COPY licenses/ /licenses/
|
||||
# Only the writable directories share the root group for arbitrary non-root UIDs.
|
||||
# Runtime-created private keys retain the application's restrictive file modes.
|
||||
RUN mkdir -p /var/lib/netbird /certs && \
|
||||
chown 1000:0 /var/lib/netbird /certs && \
|
||||
chmod 0770 /var/lib/netbird /certs && \
|
||||
chmod -R a+rX /licenses
|
||||
|
||||
USER 1000:0
|
||||
ENV HOME=/var/lib/netbird
|
||||
ENV NB_PROXY_ADDRESS=":8443"
|
||||
# Unprivileged ports: runtimes such as OpenShift and Podman keep the kernel
|
||||
# default that reserves ports below 1024 for root. 8080 is the health probe.
|
||||
ENV NB_PROXY_ACME_ADDRESS=":8081"
|
||||
EXPOSE 8443
|
||||
STOPSIGNAL SIGTERM
|
||||
ENTRYPOINT ["/go/bin/netbird-proxy"]
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
printf '%s\n' "usage: $0 OUTPUT_DIRECTORY GOARCH..." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)
|
||||
output_name=$(basename "$1")
|
||||
if [ -z "$output_name" ] || [ "$output_name" = . ] || [ "$output_name" = .. ] || [ "$output_name" = / ]; then
|
||||
printf '%s\n' "OUTPUT_DIRECTORY must name a directory" >&2
|
||||
exit 2
|
||||
fi
|
||||
output_parent=$(CDPATH= cd -- "$(dirname "$1")" && pwd)
|
||||
output="$output_parent/$output_name"
|
||||
shift
|
||||
modules=$(mktemp "${TMPDIR:-/tmp}/netbird-proxy-licenses.modules.XXXXXX")
|
||||
sorted_modules=$(mktemp "${TMPDIR:-/tmp}/netbird-proxy-licenses.sorted.XXXXXX")
|
||||
|
||||
if [ -e "$output" ] || [ -L "$output" ]; then
|
||||
printf 'output directory already exists: %s\n' "$output" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Assemble beside the target and rename on success, so a failed run leaves
|
||||
# nothing behind that would block the next attempt.
|
||||
staging=$(mktemp -d "$output_parent/.$output_name.XXXXXX")
|
||||
trap 'rm -f "$modules" "$sorted_modules"; rm -rf "$staging"' EXIT HUP INT TERM
|
||||
mkdir "$staging/third_party"
|
||||
|
||||
cp "$repo_root/proxy/LICENSE" "$staging/AGPL-3.0.txt"
|
||||
cp "$repo_root/LICENSE" "$staging/BSD-3-Clause.txt"
|
||||
node "$repo_root/proxy/web/scripts/third-party-licenses.mjs" >"$staging/Web-THIRD-PARTY-LICENSES"
|
||||
|
||||
cd "$repo_root"
|
||||
for arch in "$@"; do
|
||||
GOOS=${GOOS:-linux} GOARCH="$arch" CGO_ENABLED=${CGO_ENABLED:-0} \
|
||||
go list -deps -f '{{with .Module}}{{if .Replace}}{{.Replace.Path}}{{"\t"}}{{.Replace.Version}}{{"\t"}}{{.Replace.Dir}}{{else}}{{.Path}}{{"\t"}}{{.Version}}{{"\t"}}{{.Dir}}{{end}}{{end}}' ./proxy/cmd/proxy >>"$modules"
|
||||
done
|
||||
LC_ALL=C sort -u "$modules" >"$sorted_modules"
|
||||
|
||||
goroot=$(go env GOROOT)
|
||||
for term in LICENSE PATENTS; do
|
||||
if [ ! -f "$goroot/$term" ]; then
|
||||
printf 'missing Go standard-library term: %s\n' "$goroot/$term" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp "$goroot/$term" "$staging/Go-$term"
|
||||
done
|
||||
|
||||
while IFS=' ' read -r module version module_dir; do
|
||||
[ -n "$module" ] || continue
|
||||
[ "$module" = "github.com/netbirdio/netbird" ] && continue
|
||||
|
||||
if [ -z "$version" ] || [ ! -d "$module_dir" ]; then
|
||||
printf 'cannot collect terms for module %s at version %s\n' "$module" "$version" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
destination="$staging/third_party/$module/$version"
|
||||
mkdir -p "$destination"
|
||||
printf 'module: %s\nversion: %s\n' "$module" "$version" >"$destination/MODULE"
|
||||
|
||||
found=false
|
||||
for term in \
|
||||
"$module_dir"/LICENSE* "$module_dir"/License* "$module_dir"/license* \
|
||||
"$module_dir"/LICENCE* "$module_dir"/Licence* "$module_dir"/licence* \
|
||||
"$module_dir"/COPYING* "$module_dir"/Copying* "$module_dir"/copying* \
|
||||
"$module_dir"/NOTICE* "$module_dir"/Notice* "$module_dir"/notice* \
|
||||
"$module_dir"/PATENTS* "$module_dir"/Patents* "$module_dir"/patents*; do
|
||||
[ -f "$term" ] || continue
|
||||
cp "$term" "$destination/"
|
||||
found=true
|
||||
done
|
||||
|
||||
if [ "$found" = false ]; then
|
||||
printf 'no root license terms found for module %s at %s\n' "$module" "$module_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
done <"$sorted_modules"
|
||||
|
||||
mv "$staging" "$output"
|
||||
@@ -0,0 +1,68 @@
|
||||
// Prints the third-party terms for the prebuilt UI in dist/ to stdout.
|
||||
// Package versions come from package-lock.json and the license texts from an
|
||||
// installed node_modules (run `npm ci --ignore-scripts` first).
|
||||
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const webDir = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
// Build tools whose own code is emitted into dist: tailwindcss generates the
|
||||
// preflight and utility CSS, vite injects its modulepreload polyfill.
|
||||
const bundledTooling = new Set(["node_modules/tailwindcss", "node_modules/vite"]);
|
||||
|
||||
// Inter ships as a font file rather than a package, so its OFL lives beside it.
|
||||
const staticTerms = [
|
||||
{
|
||||
title: "Inter 4.001 (git-66647c0bb), SIL Open Font License 1.1",
|
||||
file: "src/assets/fonts/OFL.txt",
|
||||
},
|
||||
];
|
||||
|
||||
const termPattern = /^(licen[cs]e|copying|notice|patents)/i;
|
||||
|
||||
function fail(message) {
|
||||
process.stderr.write(`${message}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function shippedPackages(lock) {
|
||||
return Object.entries(lock.packages)
|
||||
.filter(([path, meta]) => path !== "" && (!meta.dev || bundledTooling.has(path)))
|
||||
.sort(([a], [b]) => Number(a > b) - Number(a < b));
|
||||
}
|
||||
|
||||
function packageSection(path, meta) {
|
||||
const dir = join(webDir, path);
|
||||
const manifest = join(dir, "package.json");
|
||||
if (!existsSync(manifest)) {
|
||||
fail(`${path} is not installed; run npm ci --ignore-scripts in proxy/web`);
|
||||
}
|
||||
const installed = JSON.parse(readFileSync(manifest, "utf8"));
|
||||
if (installed.version !== meta.version) {
|
||||
fail(`${path} is ${installed.version}, package-lock.json pins ${meta.version}`);
|
||||
}
|
||||
|
||||
const terms = readdirSync(dir).filter((name) => termPattern.test(name)).sort();
|
||||
if (terms.length === 0) {
|
||||
fail(`no license terms found for ${path}`);
|
||||
}
|
||||
|
||||
const name = path.slice(path.lastIndexOf("node_modules/") + "node_modules/".length);
|
||||
return terms
|
||||
.map((term) => `=== ${name} ${meta.version} (${term}) ===\n\n${readFileSync(join(dir, term), "utf8")}`)
|
||||
.join("\n\n");
|
||||
}
|
||||
|
||||
const lock = JSON.parse(readFileSync(join(webDir, "package-lock.json"), "utf8"));
|
||||
const sections = shippedPackages(lock).map(([path, meta]) => packageSection(path, meta));
|
||||
for (const { title, file } of staticTerms) {
|
||||
sections.push(`=== ${title} ===\n\n${readFileSync(join(webDir, file), "utf8")}`);
|
||||
}
|
||||
|
||||
process.stdout.write(
|
||||
"Third-party terms for the prebuilt authentication UI in proxy/web/dist.\n" +
|
||||
"Generated from proxy/web/package-lock.json at release time.\n\n\n" +
|
||||
sections.join("\n\n\n") +
|
||||
"\n",
|
||||
);
|
||||
@@ -0,0 +1,92 @@
|
||||
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION AND CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Reference in New Issue
Block a user