diff --git a/win32/README.md b/win32/README.md new file mode 100644 index 0000000..bf445b6 --- /dev/null +++ b/win32/README.md @@ -0,0 +1,197 @@ +# ModSecurity-nginx Windows build information + +## Contents + +- [References](#references) +- [Prerequisites](#prerequisites) +- [Build](#build) + - [Docker container](#docker-container) +- [Tests](#tests) +- [Miscellaneous](#miscellaneous) + +## References + + * [Building nginx on the Win32 platform with Visual C](https://nginx.org/en/docs/howto_build_on_win32.html) + * [libModSecurity Windows build information](https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md) + * [ModSecurity-nginx - Compilation](https://github.com/owasp-modsecurity/ModSecurity-nginx#compilation) + +## Prerequisites + + * [Build Tools for Visual Studio 2022](https://aka.ms/vs/17/release/vs_buildtools.exe) + * Install *Desktop development with C++* workload, which includes: + * MSVC C++ compiler + * Windows SDK + * CMake + * NOTE: The build steps assume this has been installed in `C:\BuildTools`. + * [MSYS2](https://www.msys2.org/) + * For nginx build on Windows + * NOTE: The build steps assume this has been installed in `C:\msys64`. + * [Conan package manager 2.2.2](https://github.com/conan-io/conan/releases/download/2.2.2/conan-2.2.2-windows-x86_64-installer.exe) + * Required to build libModSecurity v3 on Windows. + * Install and then setup the default Conan profile to use the MSVC C++ compiler: + 1. Open a command-prompt and set the MSVC C++ compiler environment by executing: `C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat` + 2. Execute: `conan profile detect --force` + * [Git for Windows 2.44.0](https://github.com/git-for-windows/git/releases/download/v2.44.0.windows.1/Git-2.44.0-64-bit.exe) + * [Strawberry Perl for Windows](https://strawberryperl.com/) + * nginx build on Windows requires a native Perl build. The one included in MSYS2 triggers the following error: + ``` + This perl implementation doesn't produce Windows like paths (with backward slash directory separators). Please use an implementation that matches your building platform. + ``` + * NOTE: The build steps assume this has been installed in `C:\Strawberry\perl`. + +## Build + + 1. Open a command prompt + 2. Set up MSVC C++ compiler environment by executing: + ```shell + C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat + ``` + 3. From this command prompt, launch a `MSYS2 UCRT64 Shell` (to inherit MSVC C++ compiler environment) + ```shell + c:\msys64\ucrt64.exe + ``` + 4. Checkout nginx source code + ```shell + git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx.git + cd nginx + ``` + 5. Download third-party libraries + ```shell + mkdir objs + mkdir objs/lib + cd objs/lib + + echo Downloading PCRE2 + wget -q -O - https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.39/pcre2-10.39.tar.gz | tar -xzf - + + echo Downloading zlib + wget -q -O - https://www.zlib.net/fossils/zlib-1.3.tar.gz | tar -xzf - + + echo Downloading OpenSSL + wget -q -O - https://www.openssl.org/source/openssl-3.0.13.tar.gz | tar -xzf - + ``` + 6. Checkout and build libModSecurity v3 + * For more information on libModSecurity v3 build options, see [libModSecurity Windows build information](https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md). + ```shell + git clone -c advice.detachedHead=false --depth 1 --branch windows-port https://github.com/eduar-hte/ModSecurity + #git clone -c advice.detachedHead=false --depth 1 https://github.com/owasp-modsecurity/ModSecurity.git + + cd ModSecurity + + git submodule init + git submodule update + + vcbuild.bat + + cd .. + ``` + 7. Checkout ModSecurity-nginx + ```shell + git clone -c advice.detachedHead=false --depth 1 --branch windows-port https://github.com/eduar-hte/ModSecurity-nginx.git + #git clone -c advice.detachedHead=false --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git + + cd ../.. + ``` + 8. Setup environment variables for nginx build + ```shell + # remove (or move) /usr/bin/link conflicting with MSVC link.exe + rm /usr/bin/link + + # nginx build on windows requires a native perl build (see prerequisites) + export PATH=/c/Strawberry/perl/bin:$PATH + # avoid perl 'Setting locale failed.' warnings + export LC_ALL=C + + # provide location of libModsecurity headers & libraries for + # the ModSecurity-nginx module build + export MODSECURITY_INC=objs/lib/ModSecurity/headers + export MODSECURITY_LIB=objs/lib/ModSecurity/build/win32/build/Release + ``` + 9. Configure nginx build + ```shell + auto/configure \ + --with-cc=cl \ + --with-debug \ + --prefix= \ + --conf-path=conf/nginx.conf \ + --pid-path=logs/nginx.pid \ + --http-log-path=logs/access.log \ + --error-log-path=logs/error.log \ + --sbin-path=nginx.exe \ + --http-client-body-temp-path=temp/client_body_temp \ + --http-proxy-temp-path=temp/proxy_temp \ + --http-fastcgi-temp-path=temp/fastcgi_temp \ + --http-scgi-temp-path=temp/scgi_temp \ + --http-uwsgi-temp-path=temp/uwsgi_temp \ + --with-cc-opt=-DFD_SETSIZE=1024 \ + --with-pcre=objs/lib/pcre2-10.39 \ + --with-zlib=objs/lib/zlib-1.3 \ + --with-openssl=objs/lib/openssl-3.0.13 \ + --with-openssl-opt=no-asm \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_auth_request_module \ + --add-module=objs/lib/ModSecurity-nginx + ``` + 10. Build nginx + ```shell + nmake + ``` + +### Docker container + +A `Dockerfile` configuration file is provided in the `docker` subdir that creates a Windows container image which installs the [prerequisites](#prerequisites) and builds libModSecurity v3 and nginx w/ModSecurity-nginx. + +NOTE: Windows containers are supported in Docker Desktop for Windows, using the *Switch to Windows containers...* option on the context menu of the system tray icon. + +To build the docker image, execute the following command (from the `win32\docker` directory): + + * `docker build -t modsecurity_nginx:latest -m 4GB .` + +Once the image is generated, the built binaries are located in the `C:\src\nginx\objs` directory. + +To extract the built binaries from the image, you can execute the following commands: + + * `docker container create --name [container_name] modsecurity_nginx` + * `docker cp [container_name]:C:\src\nginx\objs\nginx.exe .` + * `docker cp [container_name]:C:\src\nginx\objs\libModSecurity.dll .` + +Additionally, the image can be used interactively for additional development work by executing: + + * `docker run -it modsecurity_nginx` + +## Tests + +In order to validate the nginx w/ModSecurity-nginx binary it's recommended that you set up and run ModSecurity-nginx tests following these steps: + + 1. Open a command prompt and go to the directory where `nginx` was built. + 2. Clone nginx-tests + ```shell + git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx-tests.git test + ``` + 3. Copy `libModSecurity.dll` to the directory where `nginx.exe` is located. + ```shell + cd objs + copy objs\lib\ModSecurity\build\win32\Release\build\libModSecurity.dll + ``` + 4. Copy ModSecurity-nginx tests to the nginx tests directory. + ```shell + cd ..\test + copy ..\objs\lib\ModSecurity-nginx\tests\*.* + ``` + 5. Run ModSecurity-nginx tests + ```shell + set TEST_NGINX_BINARY=..\objs\nginx.exe + prove modsecurity*.t + ``` + +NOTES + + * `TEST_NGINX_BINARY` requires path with backslashes. nginx won't work with path with slashes. + * The tests generate nginx configuration and associated files (such as log files) on the temp directory indicated by the `TEMP` environment variable. nginx won't work if the path contains spaces or short path names with the `~` character. You may need to set the `TEMP` environment variable to a path that respects these limitations (such as `C:\TEMP`). + +## Miscellaneous + +The ModSecurity-nginx connector is built as a static nginx module. It looks as if there's currently no support for dynamic modules on nginx for Windows using MSVC. + +It may be possible to cross-compile for Windows using gcc/clang, which may enable building using dynamic modules too. \ No newline at end of file diff --git a/win32/docker/Dockerfile b/win32/docker/Dockerfile new file mode 100644 index 0000000..42ba688 --- /dev/null +++ b/win32/docker/Dockerfile @@ -0,0 +1,161 @@ +# escape=` + +# References +# +# * Building nginx on the Win32 platform with Visual C +# * https://nginx.org/en/docs/howto_build_on_win32.html +# * libModSecurity Windows build information +# * https://github.com/eduar-hte/ModSecurity/blob/windows-port/build/win32/README.md +# * ModSecurity-nginx - Compilation +# * https://github.com/owasp-modsecurity/ModSecurity-nginx#compilation + +ARG FROM_IMAGE=mcr.microsoft.com/windows/servercore:ltsc2022 +FROM ${FROM_IMAGE} + +# reset the shell. +SHELL ["cmd", "/S", "/C"] + +# set up environment to collect install errors. +COPY InstallBuildTools.cmd C:\TEMP\ +ADD https://aka.ms/vscollect.exe C:\TEMP\collect.exe + +# download channel for fixed install. +ARG CHANNEL_URL=https://aka.ms/vs/17/release/channel +ADD ${CHANNEL_URL} C:\TEMP\VisualStudio.chman + +# download and install Build Tools for Visual Studio 2022 for native desktop workload. +ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe +RUN C:\TEMP\InstallBuildTools.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ` + --channelUri C:\TEMP\VisualStudio.chman ` + --installChannelUri C:\TEMP\VisualStudio.chman ` + --add Microsoft.VisualStudio.Workload.VCTools ` + --includeRecommended ` + --installPath C:\BuildTools + +# download & install git +ARG GIT_VERSION=2.44.0 +ARG GIT_BINARY=Git-${GIT_VERSION}-64-bit.exe +ARG GIT_URL=https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/${GIT_BINARY} + +COPY git.inf C:\TEMP\ +ARG INSTALLER=C:\TEMP\${GIT_BINARY} +ADD ${GIT_URL} ${INSTALLER} +RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES /NOCANCEL ` + /NORESTART /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF=git.inf + +# download & setup conan (for libModSecurity build) +ARG CONAN_VERSION=2.2.2 +ARG CONAN_BINARY=conan-${CONAN_VERSION}-windows-x86_64-installer.exe +ARG CONAN_URL=https://github.com/conan-io/conan/releases/download/${CONAN_VERSION}/${CONAN_BINARY} + +ARG INSTALLER=C:\TEMP\${CONAN_BINARY} +ADD ${CONAN_URL} ${INSTALLER} +RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES + +# setup conan profile +RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && conan profile detect --force + +# download & setup Strawberry Perl (nginx requires a native Windows perl version to build) +ARG PERL_VERSION=5.38.2.2 +ARG PERL_BINARY=strawberry-perl-${PERL_VERSION}-64bit.msi +ARG PERL_URL=https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_53822_64bit/${PERL_BINARY} + +ARG INSTALLER=C:\TEMP\${PERL_BINARY} +ADD ${PERL_URL} ${INSTALLER} +RUN msiexec /i %INSTALLER% /quiet /qn /norestart + +# msys2 (to build nginx) +# +# References +# +# * Using MSYS2 in CI +# * https://www.msys2.org/docs/ci/ + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ` + Invoke-WebRequest -UseBasicParsing -uri "https://github.com/msys2/msys2-installer/releases/download/nightly-x86_64/msys2-base-x86_64-latest.sfx.exe" -OutFile msys2.exe; ` + .\msys2.exe -y -oC:\; ` + Remove-Item msys2.exe ; ` + function msys() { C:\msys64\usr\bin\bash.exe @('-lc') + @Args; } ` + msys ' '; ` + msys 'pacman --noconfirm -Syuu'; ` + msys 'pacman --noconfirm -Syuu'; ` + msys 'pacman --noconfirm -Scc'; + +# revert back to the default shell (cmd.exe) +SHELL ["cmd", "/S", "/C"] + +# create src dir +ARG SRC_DIR=C:\src + +WORKDIR C:\ +RUN cmd.exe /C md %SRC_DIR% + +WORKDIR ${SRC_DIR} + +# nginx +# + +RUN git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx.git + +ARG NGINX_DIR=${SRC_DIR}\nginx +WORKDIR ${NGINX_DIR} + +# nginx/tests +RUN git clone -c advice.detachedHead=false --depth 1 https://github.com/nginx/nginx-tests.git test + +ARG NGINX_LIBS_DIR=${NGINX_DIR}\objs\lib + +# libModSecurity +# + +WORKDIR ${NGINX_LIBS_DIR} + +ARG MOD_SECURITY_TAG=windows-port +RUN git clone -c advice.detachedHead=false --depth 1 --branch %MOD_SECURITY_TAG% https://github.com/eduar-hte/ModSecurity.git + +ARG MOD_SECURITY_DIR=${NGINX_LIBS_DIR}\ModSecurity +WORKDIR ${MOD_SECURITY_DIR} + +# fetch submodules (bindings/python, others/libinjection, test/test-cases/secrules-language-tests) +RUN git submodule init +RUN git submodule update + +# build +RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && vcbuild.bat + +RUN cmd.exe /C copy build\win32\build\Release\libModSecurity.dll ..\.. + +# ModSecurity-nginx +# + +WORKDIR ${NGINX_LIBS_DIR} + +ARG MOD_SECURITY_NGINX_TAG=windows-port +RUN git clone -c advice.detachedHead=false --depth 1 --branch %MOD_SECURITY_NGINX_TAG% https://github.com/eduar-hte/ModSecurity-nginx.git + +RUN cmd.exe /C copy ModSecurity-nginx\tests\*.* ..\..\test + +# nginx w/ModSecurity-nginx +# + +WORKDIR ${NGINX_DIR} + +COPY build-nginx.sh ${NGINX_DIR} +COPY build-nginx-bootstrap.bat ${NGINX_DIR} + +RUN cmd.exe /C build-nginx-bootstrap.bat + +# execute ModSecurity-nginx tests +WORKDIR ${NGINX_DIR}\test + +RUN set TEST_NGINX_BINARY=..\objs\nginx.exe && prove modsecurity*.t + +# setup container's entrypoint +# + +WORKDIR ${NGINX_DIR} + +# Use developer command prompt and start PowerShell if no other command specified. +ENTRYPOINT ["C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"] diff --git a/win32/docker/InstallBuildTools.cmd b/win32/docker/InstallBuildTools.cmd new file mode 100644 index 0000000..a0c07c7 --- /dev/null +++ b/win32/docker/InstallBuildTools.cmd @@ -0,0 +1,17 @@ +@rem Copyright (C) Microsoft Corporation. All rights reserved. +@rem Licensed under the MIT license. See LICENSE.txt in the project root for license information. + +@if not defined _echo echo off +setlocal enabledelayedexpansion + +call %* +if "%ERRORLEVEL%"=="3010" ( + exit /b 0 +) else ( + if not "%ERRORLEVEL%"=="0" ( + set ERR=%ERRORLEVEL% + call C:\TEMP\collect.exe -zip:C:\vslogs.zip + + exit /b !ERR! + ) +) diff --git a/win32/docker/build-nginx-bootstrap.bat b/win32/docker/build-nginx-bootstrap.bat new file mode 100644 index 0000000..259c7d3 --- /dev/null +++ b/win32/docker/build-nginx-bootstrap.bat @@ -0,0 +1,6 @@ +@echo off +rem Bootstrap to setup MSVC compiler environment and inherit it into bash +call "C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat" +set MSYSTEM=UCRT64 +set MSYS2_PATH_TYPE=inherit +C:\msys64\usr\bin\bash.exe -lc 'cd /c/src/nginx ; ./build-nginx.sh' diff --git a/win32/docker/build-nginx.sh b/win32/docker/build-nginx.sh new file mode 100644 index 0000000..88b97f3 --- /dev/null +++ b/win32/docker/build-nginx.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +cd objs/lib + +echo Downloading PCRE2 +wget -q -O - https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.39/pcre2-10.39.tar.gz | tar -xzf - + +echo Downloading zlib +wget -q -O - https://www.zlib.net/fossils/zlib-1.3.tar.gz | tar -xzf - + +echo Downloading OpenSSL +wget -q -O - https://www.openssl.org/source/openssl-3.0.13.tar.gz | tar -xzf - + +cd ../.. + +# remove /usr/bin/link conflicting with MSVC link.exe +rm /usr/bin/link + +# nginx build on windows requires a native perl build +export PATH=/c/Strawberry/perl/bin:$PATH +# avoid perl 'Setting locale failed.' warnings +export LC_ALL=C + +export MODSECURITY_INC=objs/lib/ModSecurity/headers +export MODSECURITY_LIB=objs/lib/ModSecurity/build/win32/build/Release + +auto/configure \ + --with-cc=cl \ + --with-debug \ + --prefix= \ + --conf-path=conf/nginx.conf \ + --pid-path=logs/nginx.pid \ + --http-log-path=logs/access.log \ + --error-log-path=logs/error.log \ + --sbin-path=nginx.exe \ + --http-client-body-temp-path=temp/client_body_temp \ + --http-proxy-temp-path=temp/proxy_temp \ + --http-fastcgi-temp-path=temp/fastcgi_temp \ + --http-scgi-temp-path=temp/scgi_temp \ + --http-uwsgi-temp-path=temp/uwsgi_temp \ + --with-cc-opt=-DFD_SETSIZE=1024 \ + --with-pcre=objs/lib/pcre2-10.39 \ + --with-zlib=objs/lib/zlib-1.3 \ + --with-openssl=objs/lib/openssl-3.0.13 \ + --with-openssl-opt=no-asm \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_auth_request_module \ + --add-module=objs/lib/ModSecurity-nginx + +nmake diff --git a/win32/docker/git.inf b/win32/docker/git.inf new file mode 100644 index 0000000..49781dd --- /dev/null +++ b/win32/docker/git.inf @@ -0,0 +1,20 @@ +[Setup] +Lang=default +Dir=C:\Program Files\Git +Group=Git +NoIcons=0 +SetupType=default +Components=ext,ext\shellhere,ext\guihere,gitlfs,assoc,autoupdate +Tasks= +EditorOption=VIM +CustomEditorPath= +PathOption=Cmd +SSHOption=OpenSSH +TortoiseOption=false +CURLOption=WinSSL +CRLFOption=LFOnly +BashTerminalOption=ConHost +PerformanceTweaksFSCache=Enabled +UseCredentialManager=Enabled +EnableSymlinks=Disabled +EnableBuiltinInteractiveAdd=Disabled \ No newline at end of file