diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d9d655..98d806f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,4 +71,44 @@ jobs: env: DISTRO: ${{matrix.os}} + build-podman: + runs-on: ubuntu-24.04 + env: + DISTRO: ubuntu:noble + steps: + - uses: actions/checkout@v6 + + - name: Show OS information + run: cat /etc/os-release 2>/dev/null || \ + echo /etc/os-release not available + + - name: Install build dependencies + run: sudo --preserve-env bash .github/workflows/install-dependencies + + - name: Build tang + run: | + mkdir -p build && cd build + export ninja=$(command -v ninja) + [ -z "${ninja}" ] && export ninja=$(command -v ninja-build) + meson setup .. || cat meson-logs/meson-log.txt >&2 + ${ninja} + export podman=$(command -v podman) + [ -n "${podman}" ] && ${podman} build -t tangd .. + + - name: Run tests + run: | + cd build + if ! meson test ; then + cat meson-logs/testlog.txt >&2 + exit -1 + fi + + - name: Show full test logs + run: | + if [ -r build/meson-logs/testlog.txt ]; then + cat build/meson-logs/testlog.txt >&2 + else + echo "No test log available" >&2 + fi + # vim:set ts=2 sw=2 et: diff --git a/.github/workflows/install-dependencies b/.github/workflows/install-dependencies index c8729ac..822a947 100755 --- a/.github/workflows/install-dependencies +++ b/.github/workflows/install-dependencies @@ -6,7 +6,7 @@ ubuntu:focal) apt clean apt update apt -y install gcc pkg-config libjose-dev jose libhttp-parser-dev \ - systemd gcovr curl socat iproute2 asciidoc git python3-pip ninja-build + systemd gcovr curl socat iproute2 asciidoc git python3-pip ninja-build apt remove -y meson pip3 install --upgrade meson ;; @@ -16,7 +16,7 @@ debian:*|ubuntu:*) apt clean apt update apt -y install gcc meson pkg-config libjose-dev jose libhttp-parser-dev \ - systemd gcovr curl socat iproute2 asciidoc git + systemd gcovr curl socat iproute2 asciidoc git podman ;; *fedora:*) @@ -24,7 +24,7 @@ debian:*|ubuntu:*) dnf -y clean all dnf -y --setopt=deltarpm=0 update dnf -y install gcc meson pkgconfig libjose-devel jose llhttp-devel \ - systemd gcovr curl socat iproute asciidoc git + systemd gcovr curl socat iproute asciidoc git podman ;; centos:7) @@ -33,7 +33,7 @@ centos:7) yum install -y yum-utils epel-release yum config-manager -y --set-enabled PowerTools \ || yum config-manager -y --set-enabled powertools || : - yum -y install meson socat iproute asciidoc git + yum -y install meson socat iproute asciidoc git podman yum-builddep -y tang ;; @@ -43,7 +43,7 @@ centos:7) dnf install -y dnf-plugins-core epel-release dnf config-manager -y --set-enabled powertools \ || dnf config-manager -y --set-enabled crb || : - dnf -y install meson socat iproute git + dnf -y install meson socat iproute git podman dnf builddep -y tang --allowerasing --skip-broken --nobest ;; esac diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..c3cf0d9 --- /dev/null +++ b/Containerfile @@ -0,0 +1,17 @@ +FROM quay.io/fedora/fedora:latest AS build +RUN dnf -y --setopt=deltarpm=0 update && \ + dnf -y install gcc pkgconfig meson libjose-devel jose llhttp-devel +RUN mkdir -p /build/in /build/out +COPY . /build/in/ +WORKDIR /build/out +RUN meson setup ../in && ninja-build + +FROM quay.io/fedora/fedora:latest AS runtime +RUN dnf -y install jose llhttp +COPY src/tang-show-keys /bin/ +COPY --from=build /build/out/src/tangd /build/out/src/tangd-rotate-keys /build/out/src/tangd-keygen /bin/ + +VOLUME [ "/jwkdir" ] +EXPOSE 9090 + +CMD [ "/bin/tangd", "-l", "-p", "9090", "/jwkdir" ] \ No newline at end of file diff --git a/README.md b/README.md index 0106a69..545ef8b 100644 --- a/README.md +++ b/README.md @@ -124,14 +124,22 @@ and start the server: # service tangd enable # service tangd start -#### Docker Container +#### Docker/Podman Container -Tang is also available as a [Docker -Container](https://gitlab.com/AdrianKoshka/tang-docker-container/). +Tang can also be built as a Docker or Podman image using the included +Containerfile. -Care should be taken to ensure that, when deploying in a container cluster, -that the Tang keys are not stored on the same physical medium that you wish to -protect. +When deploying in a container cluster, care should be taken to ensure that the +Tang keys are not stored on the same physical medium that you wish to protect. + +By default, this container starts in listen mode on port 9090 of all addresses +within the container, with the key directory set to the container's `/jwkdir`. +This path should be bound to a key storage location on the container host. + +Note that socket activation is **not supported** for Tang Podman containers, as +Tang uses inetd-style socket activation (`Accept=yes`) rather than systemd-style +socket activation (`Accept=no`), and Podman quadlets do not support inetd-style +socket activation due to containers/podman#22874 (among other reasons). ### Building and Installing from Source diff --git a/tests/adv b/tests/adv index 416dc6e..c21c42e 100755 --- a/tests/adv +++ b/tests/adv @@ -75,7 +75,9 @@ adv_second_phase () { test "$(tang-show-keys $PORT $ENDPOINT)" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i $TMP/db/sig.jwk)" # Check that new keys will be created if none exist. - rm -rf "${TMP}/db" && mkdir -p "${TMP}/db" + # Use find to delete the contents here because deleting the directory + # breaks the container-volume link in Podman tests, which is a problem. + find "${TMP}/db" -mindepth 1 -depth -delete fetch "${ENDPOINT}"/adv # Now let's make sure the new keys were named using our default thumbprint diff --git a/tests/adv-podman b/tests/adv-podman new file mode 100644 index 0000000..51ec789 --- /dev/null +++ b/tests/adv-podman @@ -0,0 +1,30 @@ +#!/bin/sh -ex +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2026 Marissa Lyndon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. adv + +sanity_check_podman + +adv_startup + +export PORT=$(random_port) +export CONTAINER=$(start_podman_server "${PORT}") +wait_for_port "${PORT}" + +adv_second_phase diff --git a/tests/adv-podman-endpoint b/tests/adv-podman-endpoint new file mode 100644 index 0000000..f15b95d --- /dev/null +++ b/tests/adv-podman-endpoint @@ -0,0 +1,30 @@ +#!/bin/sh -ex +# +# Copyright (c) 2026 Marissa Lyndon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. adv + +sanity_check_podman + +adv_startup + +export PORT=$(random_port) +export ENDPOINT="/api/dee-hms" +export CONTAINER=$(start_podman_server_endpoint "${PORT}" "${ENDPOINT}") +wait_for_port "${PORT}" + +adv_second_phase diff --git a/tests/adv-socat b/tests/adv-socat index 02c9037..3349a50 100755 --- a/tests/adv-socat +++ b/tests/adv-socat @@ -20,7 +20,7 @@ . adv -sanity_check +sanity_check_socat adv_startup diff --git a/tests/adv-socat-endpoint b/tests/adv-socat-endpoint index c4deb88..aa7f3e2 100644 --- a/tests/adv-socat-endpoint +++ b/tests/adv-socat-endpoint @@ -19,7 +19,7 @@ . adv -sanity_check +sanity_check_socat adv_startup diff --git a/tests/helpers b/tests/helpers index ebce966..c707352 100755 --- a/tests/helpers +++ b/tests/helpers @@ -83,11 +83,22 @@ start_standalone_server_endpoint() { ${VALGRIND} tangd -p ${1} -l ${TMP}/db -e ${2} & } +start_podman_server() { + "${PODMAN}" run -d -p "${1}":9090 -v "${TMP}"/db:/jwkdir localhost/tangd +} + +start_podman_server_endpoint() { + "${PODMAN}" run -d -p "${1}":9090 -v "${TMP}"/db:/jwkdir localhost/tangd /bin/tangd -p 9090 -l -e "${2}" /jwkdir +} + on_exit() { if [ "${PID}" ]; then kill "${PID}" || true wait "${PID}" || true fi + if [ -n "${PODMAN}" ] && [ -n "${CONTAINER}" ]; then + "${PODMAN}" stop --time 1 "${CONTAINER}" + fi [ -d "${TMP}" ] && rm -rf "${TMP}" } @@ -114,11 +125,18 @@ validate_exc() { --use deriveKey 2>/dev/null } -sanity_check() { +sanity_check_socat() { # Skip test if socat is not available. [ -n "${SOCAT}" ] || exit 77 } +sanity_check_podman() { + # Skip test if podman is not available or the image does not exist. + if [ -z "${PODMAN}" ] || ! podman image exists localhost/tangd; then + exit 77 + fi +} + die() { echo "${1}" >&2 exit 1 diff --git a/tests/meson.build b/tests/meson.build index e2e9924..0a898f0 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -23,6 +23,11 @@ socat = find_program( required: false ) +podman = find_program( + 'podman', + required: false +) + env = environment() env.prepend('PATH', join_paths(meson.source_root(), 'src'), @@ -40,10 +45,18 @@ if socat.found() env.set('SOCAT', socat.path()) endif +if podman.found() + env.set('PODMAN', podman.path()) +endif + +test('adv-podman', find_program('adv-podman'), env: env, timeout: 360) +test('adv-podman-endpoint', find_program('adv-podman-endpoint'), env: env, timeout: 360) test('adv-standalone', find_program('adv-standalone'), env: env, timeout: 360) test('adv-standalone-endpoint', find_program('adv-standalone-endpoint'), env: env, timeout: 360) test('adv-socat', find_program('adv-socat'), env: env, timeout: 360) test('adv-socat-endpoint', find_program('adv-socat-endpoint'), env: env, timeout: 360) +test('rec-podman', find_program('rec-podman'), env: env, timeout: 360) +test('rec-podman-endpoint', find_program('rec-podman-endpoint'), env: env, timeout: 360) test('rec-standalone', find_program('rec-standalone'), env: env, timeout: 360) test('rec-standalone-endpoint', find_program('rec-standalone-endpoint'), env: env, timeout: 360) test('rec-socat', find_program('rec-socat'), env: env, timeout: 360) diff --git a/tests/rec-podman b/tests/rec-podman new file mode 100755 index 0000000..f41ac75 --- /dev/null +++ b/tests/rec-podman @@ -0,0 +1,30 @@ +#!/bin/sh -ex +# vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: +# +# Copyright (c) 2026 Marissa Lyndon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. rec + +sanity_check_podman + +rec_startup + +export PORT=$(random_port) +export CONTAINER=$(start_podman_server "${PORT}") +wait_for_port "${PORT}" + +rec_second_phase diff --git a/tests/rec-podman-endpoint b/tests/rec-podman-endpoint new file mode 100755 index 0000000..73e8e4b --- /dev/null +++ b/tests/rec-podman-endpoint @@ -0,0 +1,30 @@ +#!/bin/sh -ex +# +# Copyright (c) 2026 Marissa Lyndon +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. rec + +sanity_check_podman + +rec_startup + +export PORT=$(random_port) +export ENDPOINT="api/dee-hms" +export CONTAINER=$(start_podman_server_endpoint "${PORT}" "${ENDPOINT}") +wait_for_port "${PORT}" + +rec_second_phase_endpoint diff --git a/tests/rec-socat b/tests/rec-socat index 2b1483d..4ffc05f 100755 --- a/tests/rec-socat +++ b/tests/rec-socat @@ -20,7 +20,7 @@ . rec -sanity_check +sanity_check_socat rec_startup diff --git a/tests/rec-socat-endpoint b/tests/rec-socat-endpoint index f62d919..d2273ff 100644 --- a/tests/rec-socat-endpoint +++ b/tests/rec-socat-endpoint @@ -19,7 +19,7 @@ . rec -sanity_check +sanity_check_socat rec_startup diff --git a/tests/rec-standalone b/tests/rec-standalone index 0538f12..609d975 100755 --- a/tests/rec-standalone +++ b/tests/rec-standalone @@ -20,8 +20,6 @@ . rec -sanity_check - rec_startup # Start the server diff --git a/tests/rec-standalone-endpoint b/tests/rec-standalone-endpoint index 2e7e1b8..67eb88b 100755 --- a/tests/rec-standalone-endpoint +++ b/tests/rec-standalone-endpoint @@ -19,8 +19,6 @@ . rec -sanity_check - rec_startup # Start the server