From 26c1079392d94b183afa562451dfd5720f7df7e4 Mon Sep 17 00:00:00 2001 From: Martin Korbel Date: Wed, 20 Nov 2024 10:37:49 +0100 Subject: [PATCH] Add docker build for fido2-tests --- ...ild-powerauth-fido2-tests-docker-image.yml | 73 ++++++++ .../deploy/conf/fido2-demo.xml | 18 ++ .../conf/logback/fido2-demo-logback.xml | 13 ++ .../deploy/docker-entrypoint.sh | 6 + .../deploy/nginx/html/favicon.ico | Bin 0 -> 1150 bytes powerauth-fido2-tests/deploy/nginx/nginx.conf | 134 ++++++++++++++ .../docker-powerauth-fido2-tests/Dockerfile | 167 ++++++++++++++++++ 7 files changed, 411 insertions(+) create mode 100644 .github/workflows/build-powerauth-fido2-tests-docker-image.yml create mode 100644 powerauth-fido2-tests/deploy/conf/fido2-demo.xml create mode 100644 powerauth-fido2-tests/deploy/conf/logback/fido2-demo-logback.xml create mode 100755 powerauth-fido2-tests/deploy/docker-entrypoint.sh create mode 100644 powerauth-fido2-tests/deploy/nginx/html/favicon.ico create mode 100644 powerauth-fido2-tests/deploy/nginx/nginx.conf create mode 100644 powerauth-fido2-tests/docker-powerauth-fido2-tests/Dockerfile diff --git a/.github/workflows/build-powerauth-fido2-tests-docker-image.yml b/.github/workflows/build-powerauth-fido2-tests-docker-image.yml new file mode 100644 index 00000000..ff0bb57e --- /dev/null +++ b/.github/workflows/build-powerauth-fido2-tests-docker-image.yml @@ -0,0 +1,73 @@ + +name: Build and push docker image of Powerauth Fido2 Demo to Docker registry + +on: + workflow_dispatch: + pull_request: + branches: + - 'develop' + - 'main' + - 'releases/*' + paths: + - 'powerauth-fido2-tests/**' + push: + branches: + - 'develop' + paths: + - 'powerauth-fido2-tests/**' + +jobs: + build: + runs-on: 'ubuntu-latest' + environment: docker-publish + env: + # these are global secrets - for readonly access to artifactory + INTERNAL_USERNAME: ${{ secrets.JFROG_USERNAME }} + INTERNAL_PASSWORD: ${{ secrets.JFROG_PASSWORD }} + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: powerauth-fido2-tests + - uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + server-id: jfrog-central + server-username: INTERNAL_USERNAME + server-password: INTERNAL_PASSWORD + - name: Get version + run: | + cd powerauth-fido2-tests + REVISION=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + echo "REVISION=$REVISION" >> $GITHUB_ENV + - name: Build war + run: | + cd powerauth-fido2-tests + mvn -U -DuseInternalRepo=true --no-transfer-progress package + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + install: true + - name: Log in to Azure registry + if: ${{ github.actor != 'dependabot[bot]' && (github.event_name == 'workflow_dispatch' || github.event_name == 'push') }} + uses: docker/login-action@v3 + with: + registry: https://powerauth.azurecr.io/ + username: ${{ vars.ACR_USERNAME }} + password: ${{ secrets.ACR_PASSWORD }} + - name: Build and push container image to Azure registry + uses: docker/build-push-action@v6 + with: + push: ${{ github.actor != 'dependabot[bot]' && (github.event_name == 'workflow_dispatch' || github.event_name == 'push') }} + platforms: linux/amd64,linux/arm64 + tags: powerauth.azurecr.io/powerauth-fido2-tests:${{ github.sha }} + file: ./powerauth-fido2-tests/docker-powerauth-fido2-tests/Dockerfile + context: ./powerauth-fido2-tests + cache-from: type=gha + cache-to: type=gha,mode=max + - if: ${{ github.actor != 'dependabot[bot]' && (github.event_name == 'workflow_dispatch' || github.event_name == 'push') }} + run: | + echo '### 🚀 Published images' >> $GITHUB_STEP_SUMMARY + echo 'powerauth.azurecr.io/powerauth-fido2-tests:${{ github.sha }}' >> $GITHUB_STEP_SUMMARY diff --git a/powerauth-fido2-tests/deploy/conf/fido2-demo.xml b/powerauth-fido2-tests/deploy/conf/fido2-demo.xml new file mode 100644 index 00000000..023f7d87 --- /dev/null +++ b/powerauth-fido2-tests/deploy/conf/fido2-demo.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/powerauth-fido2-tests/deploy/conf/logback/fido2-demo-logback.xml b/powerauth-fido2-tests/deploy/conf/logback/fido2-demo-logback.xml new file mode 100644 index 00000000..15edf478 --- /dev/null +++ b/powerauth-fido2-tests/deploy/conf/logback/fido2-demo-logback.xml @@ -0,0 +1,13 @@ + + + + + true + {"appname":"fido2-demo"} + + + + + + + diff --git a/powerauth-fido2-tests/deploy/docker-entrypoint.sh b/powerauth-fido2-tests/deploy/docker-entrypoint.sh new file mode 100755 index 00000000..ef9d318d --- /dev/null +++ b/powerauth-fido2-tests/deploy/docker-entrypoint.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +nginx + +catalina.sh run diff --git a/powerauth-fido2-tests/deploy/nginx/html/favicon.ico b/powerauth-fido2-tests/deploy/nginx/html/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..48f40e65fb14edc19dfff29fa0349cd010162d41 GIT binary patch literal 1150 zcmdr|yNbd<6rE^H6(u&YOSTE@AE=Fw&k)i?Lb6~T6cj=5D@3$Y&`t{lixf$%Uy}U7 zapo=w!mi8imQJ|2Gw0mbxr|Bt(=^8aZ|p;6OlOR}bK?+4K5_0Cm~9D6xaRTb@a zo2*j=XT zqtOVmEMv3TV7uL-SS%t40^(}5+S554$HC=tfu?B`ljVz^l}ZKY^BMhq|7reewZeEj z&iTb+f#q_UzlXyi*6TGSNy@QIPpMR*J=wOMbDd5H-EKF3_j)}Xk4Gqql4DuE(74;} zFc=J|zR+JN6v)I~^z?ln`~9Bwk>x%5$z*~!j^Vm4Ow*(uBG0lcc%FwSiZGo{zx2*( d7>0pnvq}4V)F|etR;$E`m@NK9JeTqRa|bmvS84zN literal 0 HcmV?d00001 diff --git a/powerauth-fido2-tests/deploy/nginx/nginx.conf b/powerauth-fido2-tests/deploy/nginx/nginx.conf new file mode 100644 index 00000000..c568584a --- /dev/null +++ b/powerauth-fido2-tests/deploy/nginx/nginx.conf @@ -0,0 +1,134 @@ +worker_processes 2; +pid /tmp/nginx.pid; + +events { + + use epoll; + accept_mutex on; + worker_connections 512; + +} + +http { + + client_body_temp_path /tmp/client_temp; + proxy_temp_path /tmp/proxy_temp_path; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + + server_tokens off; + + tcp_nodelay on; + tcp_nopush on; + + # Logging + + # Excludes logging for requests with HTTP status codes 2xx (Success) and 3xx (Redirection) + map $status $loggable { + ~^[23] 0; + default 1; + } + + log_format custom_format 'measure#nginx.service=$request_time content_type=$content_type ' + 'content_length=$content_length request_length=$request_length request_time=$request_time ' + 'status=$status'; + access_log '/dev/stdout' custom_format if=$loggable; + error_log '/dev/stderr'; + + include mime.types; + default_type application/json; + sendfile on; + + # Defines a timeout for reading client request body, period between two successive read operations (default 60s) + client_body_timeout 10s; + + # Allows FastCGI server responses with codes greater than or equal to 300 to be passed to a client + fastcgi_intercept_errors on; + + # Defines a timeout for establishing a connection with a proxied server (default 60s) + proxy_connect_timeout 10s; + + # Defines a timeout for reading a response from the proxied server (default 60s) + proxy_read_timeout 29s; + + # Server name must be without underscores + upstream demo { + server localhost:8080 fail_timeout=0; + } + + server { + listen 8000; + #listen [::]:80 default_server ipv6only=on; + + # error pages rewriting + location @401_json { + default_type application/json; + return 200 '{"status":"ERROR","responseObject":{"code":"HTTP_401","message":"Unauthorized"}}'; + } + + location @403_json { + default_type application/json; + return 200 '{"status":"ERROR","responseObject":{"code":"HTTP_403","message":"Forbidden"}}'; + } + + error_page 404 @404_json; + + location @404_json { + default_type application/json; + return 404 '{"status":"ERROR","responseObject":{"code":"HTTP_404","message":"Not Found"}}'; + } + + error_page 500 502 503 504 @500_json; + location @500_json { + default_type application/json; + return 200 '{"status":"ERROR","responseObject":{"code":"ERROR_GENERIC","message":"Unknown Error"}}'; + } + + # Sets a $real_scheme variable whose value is the scheme passed by the load + # balancer in X-Forwarded-Proto, or to X-AppService-Proto in case of Azure + # cloud deployment. + set $real_scheme "http"; + if ($http_x_forwarded_proto = "https") { # Generic proxy + set $real_scheme "https"; + } + if ($http_x_appservice_proto = "https") { # Azure proxy + set $real_scheme "https"; + } + + add_header Permissions-Policy "publickey-credentials-get=*; publickey-credentials-create=*"; + + # global proxy configuration + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $real_scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_cookie_flags ~ secure samesite=none; + + proxy_intercept_errors on; + proxy_pass_request_headers on; + + location ~ ^(/health|/fido2-demo) { + error_page 401 @401_json; + + error_page 403 @403_json; + + rewrite ^/health$ /fido2-demo/actuator/health break; + rewrite ^/fido2-demo$ $real_scheme://$http_host/fido2-demo/ permanent; + + proxy_pass http://demo; + } + + location = /favicon.ico { + alias /etc/nginx/html/favicon.ico; + } + + location = / { + return 301 $real_scheme://$http_host/fido2-demo/; + } + + + } + +} diff --git a/powerauth-fido2-tests/docker-powerauth-fido2-tests/Dockerfile b/powerauth-fido2-tests/docker-powerauth-fido2-tests/Dockerfile new file mode 100644 index 00000000..32ad2524 --- /dev/null +++ b/powerauth-fido2-tests/docker-powerauth-fido2-tests/Dockerfile @@ -0,0 +1,167 @@ +FROM ibm-semeru-runtimes:open-21.0.5_11-jre + +# Prepare environment variables +ENV JAVA_HOME=/opt/java/openjdk \ + NGINX_VERSION=1.25.4 \ + NJS_VERSION=0.8.3 \ + PKG_RELEASE=1~jammy \ + TOMCAT_HOME=/usr/local/tomcat \ + TOMCAT_MAJOR=10 \ + TOMCAT_VERSION=10.1.25 \ + TOMCAT_ARCHIVE_SHA512=d7498e23e54425d728ed3481579dccc4fe3d720a4b6d491ce9a04f9d19647b60a398b76dbfec63a32f7ee98195b97231d34b6f850283f38a1acb9908d3015565 \ + LOGBACK_CONF=/opt/logback/conf \ + TZ=UTC + +ENV PATH=$PATH:$TOMCAT_HOME/bin + +# Init +RUN apt-get -y update \ + && apt-get -y upgrade \ + && apt-get -y install bash curl wget postgresql-client cron rsyslog + +# Install tomcat +RUN curl -jkSL -o /tmp/apache-tomcat.tar.gz http://archive.apache.org/dist/tomcat/tomcat-${TOMCAT_MAJOR}/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz \ + && [ "$TOMCAT_ARCHIVE_SHA512 /tmp/apache-tomcat.tar.gz" = "$(sha512sum /tmp/apache-tomcat.tar.gz)" ] \ + && gunzip /tmp/apache-tomcat.tar.gz \ + && tar -C /opt -xf /tmp/apache-tomcat.tar \ + && ln -s /opt/apache-tomcat-$TOMCAT_VERSION $TOMCAT_HOME + +# Install nginx - source: https://github.com/nginxinc/docker-nginx/blob/master/mainline/debian/Dockerfile +RUN set -x \ + && apt-get update \ + && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates \ + && \ + NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \ + found=''; \ + for server in \ + hkp://keyserver.ubuntu.com:80 \ + pgp.mit.edu \ + ; do \ + echo "Fetching GPG key $NGINX_GPGKEY from $server"; \ + apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \ + done; \ + test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \ + apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \ + && dpkgArch="$(dpkg --print-architecture)" \ + && nginxPackages=" \ + nginx=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} \ + nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE} \ + " \ + && case "$dpkgArch" in \ + amd64|arm64) \ +# arches officialy built by upstream + echo "deb https://nginx.org/packages/mainline/ubuntu jammy nginx" >> /etc/apt/sources.list.d/nginx.list \ + && apt-get update \ + ;; \ + *) \ +# we're on an architecture upstream doesn't officially build for +# let's build binaries from the published source packages + echo "deb-src https://nginx.org/packages/mainline/ubuntu jammy nginx" >> /etc/apt/sources.list.d/nginx.list \ + \ +# new directory for storing sources and .deb files + && tempDir="$(mktemp -d)" \ + && chmod 777 "$tempDir" \ +# (777 to ensure APT's "_apt" user can access it too) + \ +# save list of currently-installed packages so build dependencies can be cleanly removed later + && savedAptMark="$(apt-mark showmanual)" \ + \ +# build .deb files from upstream's source packages (which are verified by apt-get) + && apt-get update \ + && apt-get build-dep -y $nginxPackages \ + && ( \ + cd "$tempDir" \ + && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" \ + apt-get source --compile $nginxPackages \ + ) \ +# we don't remove APT lists here because they get re-downloaded and removed later + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies +# (which is done after we install the built packages so we don't have to redownload any overlapping dependencies) + && apt-mark showmanual | xargs apt-mark auto > /dev/null \ + && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } \ + \ +# create a temporary local APT repo to install from (so that dependency resolution can be handled by APT, as it should be) + && ls -lAFh "$tempDir" \ + && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) \ + && grep '^Package: ' "$tempDir/Packages" \ + && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list \ +# work around the following APT issue by using "Acquire::GzipIndexes=false" (overriding "/etc/apt/apt.conf.d/docker-gzip-indexes") +# Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) +# ... +# E: Failed to fetch store:/var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages Could not open file /var/lib/apt/lists/partial/_tmp_tmp.ODWljpQfkE_._Packages - open (13: Permission denied) + && apt-get -o Acquire::GzipIndexes=false update \ + ;; \ + esac \ + \ + && apt-get install --no-install-recommends --no-install-suggests -y \ + $nginxPackages \ + gettext-base \ + curl \ + && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ + \ +# if we have leftovers from building, let's purge them (including extra, unnecessary build deps) + && if [ -n "$tempDir" ]; then \ + apt-get purge -y --auto-remove \ + && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; \ + fi \ +# forward request and error logs to docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ +# create a docker-entrypoint.d directory + && mkdir /docker-entrypoint.d + +# Copy nginx configuration and files +COPY deploy/nginx/ /etc/nginx/ + +# Clear root context +RUN rm -rf $TOMCAT_HOME/webapps/* + +# Optimize tomcat startup +# allow parallel start of app modules, auto-detection based on number of available cores +RUN sed -i -e 's///g' $TOMCAT_HOME/conf/context.xml \ + && echo 'org.apache.catalina.startup.TldConfig.jarsToSkip=*.jar' >> $TOMCAT_HOME/conf/catalina.properties \ +# remove context configuration scanning + && sed -i -e 's/tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\\/tomcat.util.scan.StandardJarScanFilter.jarsToSkip=*,\\/g' $TOMCAT_HOME/conf/catalina.properties + +# Add valve for proxy with SSL termination +RUN sed -i -e 's/<\/Host>/<\/Host>/' $TOMCAT_HOME/conf/server.xml + +# Avoid having JSESSIONID in URI +RUN sed -i -e 's||\n COOKIE|' $TOMCAT_HOME/conf/web.xml + +# Deploy and run applications +COPY deploy/conf/fido2-demo.xml \ + $TOMCAT_HOME/conf/Catalina/localhost/ + +COPY target/powerauth-fido2-tests*.war $TOMCAT_HOME/webapps/fido2-demo.war + +COPY deploy/conf/logback/* $LOGBACK_CONF/ + +RUN set -x \ +# Uninstall packages which are no longer needed and clean apt caches + && apt-get -y remove wget curl gettext-base \ + && apt-get -y purge --auto-remove \ + && rm -rf /tmp/* /var/cache/apt/* + + +# Docker configuration +EXPOSE 8000 +STOPSIGNAL SIGQUIT + +# Add PowerAuth User +RUN groupadd -r powerauth \ + && useradd -r -g powerauth -s /sbin/nologin powerauth \ + && chown -R powerauth:powerauth $TOMCAT_HOME \ + && chown -R powerauth:powerauth /opt/apache-tomcat-$TOMCAT_VERSION +USER powerauth + +# Define entry point +COPY deploy/docker-entrypoint.sh / +ENTRYPOINT ["/docker-entrypoint.sh"]