Sign inSign up

oorabona/openresty-hardened-basic

By oorabona

•Updated over 5 years ago

OpenResty flavors for Docker

Image
0

1.4K

oorabona/openresty-hardened-basic repository overview

⁠docker-openresty - OpenResty flavors for Docker

Main CI

⁠TL;DR

The following "flavors" are customized builds of OpenResty source code :

⁠Standard (for dev/qa)

flavorbuild statusdocker hub
Basic ("bare") OpenRestyMain CIOpenResty Basic versionOpenResty Basic pulls
OpenResty with HTTP ConnectMain CIOpenResty Connect versionOpenResty Connect pulls
OpenResty with ModSecurityMain CIOpenResty ModSecurity versionOpenResty ModSecurity pulls

⁠"Hardened" (production)

  • Basic ("bare") OpenResty OpenResty Basic versionOpenResty Basic pulls

  • OpenResty with HTTP Connect OpenResty Connect versionOpenResty Connect pulls

  • OpenResty with ModSecurity OpenResty ModSecurity versionOpenResty ModSecurity pulls

All these flavors are built with multi-architecture manifests.

The following platforms are built :

  • linux/amd64
  • linux/arm/v7

But of course others could be added as well, let me know of any interest in adding new platforms.

Releases are tagged with <openresty-version>-<base-os>

For now, only alpine is used as a base OS to build OpenResty on. The latest version is always tagged with latest-<base-os>.

In the event other images are built from a different base image than alpine, the latest tag will always point to latest-alpine.

⁠Table of Contents

⁠Description

OpenResty⁠ is an awesome integration work of Nginx with the power of the scripting language Lua⁠ provides. There is already an official Docker⁠ repository for the containerized packages named docker-openresty⁠.

Kudos go to all the teams who contribute to this work. :+1:

Although you will find some similarities with the former repository, this project is meant to go further with more integrated libraries loaded in.

Indeed NGiNX⁠ has an ecosystem of external libraries and bindings which would be nice to have in OpenResty.

Therefore this repository goal is to properly package these to the world of OpenResty.

⁠Usage

Your habits (should!) remain unchanged :wink:

⁠Running locally

# The latest version for a distribution
$ docker run [options] oorabona/openresty-<FLAVOR>:alpine
# A specific version with its distro
$ docker run [options] oorabona/openresty-<FLAVOR>:1.19.3.2-alpine
# The hardened version
$ docker run [options] oorabona/openresty-hardened-<FLAVOR>:alpine

⁠Using Kubernetes

TODO

Back to TOC⁠

⁠Images

Like the official OpenResty official Docker repository⁠, the underlying base system of choice is the Alpine image, although a Debian Buster is under work.

OpenResty software, and what is directly involved in its compilation (OpenSSL, Luarocks, etc.) are built from their source.

⁠Main differences with the upstream repository

  • At the moment there is no installation of binary packages, given that most of the software do not have repository binaries (partly because it is kind of bleeding edge), it would be eventually less adaptable and quite complex (if even possible) to have it installed by a single apt or apk command.

  • For numerous reasons, the main goal when building these images is to minimize their size. This is not an easy task and at the moment the Alpine based image is by far the smallest image.

  • Therefore there is no -fat version at all. If you need to install additional software, feel free to use these images as base in your FROM directives.

  • Last difference, the PRE / POST evaluated ARGuments, which are later evaluated in RUN commands have been removed. Again if you need something specific, either derive from these images, or use them in a COPY --from for example.

⁠About other packaging out there

  • bunkerized-nginx⁠ has more scripts and is more integrated with auto SSL with Let's Encrypt, and lots of other features and a configuration system of its own.

Again, all of these integrations can be done by deriving from this work. Everything related to configuration handling and such is somewhat one's own recipe, whether Swarm or Kubernetes based, etc. So basically you are more than welcome to derive from these images and build your own system from it!

Feel free to point out other related packages missing from this list !

⁠Technical stuff

  • By convention, symlinks are created to point /usr/local/openresty/nginx/logs/access.log and error.log to /dev/stdout and /dev/stderr respectively, so that Docker logging works correctly. If you change the log paths in your nginx.conf, you should symlink those paths as well.

  • The pid is by default pointing to /usr/local/openresty/nginx/logs/nginx.pid, although it is not used since these images run openresty binary straight away. For more details, please refer to Docker ENTRYPOINT & CMD⁠

  • The SIGQUIT signal will be sent to nginx to stop this container, to give it an opportunity to stop gracefully (i.e, finish processing active connections). The Docker default is SIGTERM, which immediately terminates active connections. Note that if your configuration listens on UNIX domain sockets, this means that you'll need to manually remove the socket file upon shutdown, due to nginx bug #753⁠.

  • A single Dockerfile handles the build of all flavors for a specific distribution. This is done thanks to multistage Dockerfile which appeared around 18.x version of Docker. Please use a recent version if you want to build these images.

  • These images are built for multi architecture. At the moment only linux/amd64 and linux/arm/v7 (i.e. Raspberry Pi) architectures are built. Other architectures could also be built (as long as QEMU supports) if requested.

  • Building is parallelized as much as possible. The RESTY_J ARGument is set to 4 CPU by default, but of course this is computed automagically from the nproc program called by the build⁠ script.

For details on how to build these images, please go to Building from source⁠

Back to TOC⁠

⁠Software Installed

⁠Runtime Packages

The following packages are added to the base Alpine image:

  • git
  • build-base
  • gd
  • geoip
  • libgcc
  • libxslt
  • zlib
  • curl
  • yajl
  • libintl
  • make
  • musl
  • outils-md5
  • perl
  • unzip
  • libmaxminddb

libmaxminddb is installed in all flavors because it is the most widespread GeoIP library out there. According to some comparison articles (for reference here⁠ and here⁠) there is not a single point of truth about that. Feel free to submit issues / PR if you want other GeoIP providers being enlisted.

⁠OpenResty / NGinx additional libraries

In all flavors, a common set of opinionated libraries are automatically built, whether as dynamic modules or as static modules:

Module nameDescription Dynamic module Static module
http_addition_modulepart of base source:heavy_check_mark:
http_auth_request_modulepart of base source:heavy_check_mark:
http_dav_modulepart of base source:heavy_check_mark:
http_flv_modulepart of base source:heavy_check_mark:
http_geoip_modulepart of base source:heavy_check_mark:
http_gunzip_modulepart of base source:heavy_check_mark:
http_gzip_static_modulepart of base source:heavy_check_mark:
http_image_filter_modulepart of base source:heavy_check_mark:
http_mp4_modulepart of base source:heavy_check_mark:
http_random_index_modulepart of base source:heavy_check_mark:
http_realip_modulepart of base source:heavy_check_mark:
http_secure_link_modulepart of base source:heavy_check_mark:
http_slice_modulepart of base source:heavy_check_mark:
http_ssl_modulepart of base source:heavy_check_mark:
http_stub_status_modulepart of base source:heavy_check_mark:
http_sub_modulepart of base source:heavy_check_mark:
http_v2_modulepart of base source:heavy_check_mark:
http_xslt_modulepart of base source:heavy_check_mark:
mail_ssl_modulepart of base source:heavy_check_mark:
stream_ssl_modulepart of base source:heavy_check_mark:
stream_realip_modulepart of base source:heavy_check_mark:
ngx_brotli⁠Implements Google Brotli compression scheme:heavy_check_mark:
ngx_http_geoip2_module⁠Implements v2 of MaxMind GeoIP:heavy_check_mark:

⁠Possible future additions :

Back to TOC⁠

⁠Nginx Config Files

By default no change is made to the original OpenResty configuration files. They lie in their former directory (namely /usr/local/openresty/nginx/conf).

Only for Production hardened versions⁠ would the basic configuration be replaced with an opinionated set of configuration files.

Eventually you can either bind-mount the volume with :

docker run -v /my/custom/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf oorabona/openresty-${flavor}:latest-alpine

Or completely replace the whole directory :

docker run -v /my/custom/nginx/conf:/usr/local/openresty/nginx/conf oorabona/openresty-${flavor}:latest-alpine

Of course you can also derive from these images to tweak the configuration.

FROM oorabona/openresty-modsecurity:latest-alpine

COPY /my/conf/for/modsecurity /to/place/here
...

If you are running on an SELinux host (e.g. CentOS), you may need to append :Z to your volume bind-mount argument⁠:

E.g:

docker run -v /my/custom/nginx/conf:/usr/local/openresty/nginx/conf:Z oorabona/openresty-${flavor}:latest-alpine

Back to TOC⁠

⁠Production Hardened Versions

You can have a look at these configuration files here⁠ and adjust them to fit your needs.

Production images replace the default nginx.conf and all references to NGiNX configuration files are relative to the base directory.

Base directory is by default /usr/local/openresty/nginx/conf but can be changed in the production vars⁠ file.

You then just need to change only enabled sites :

docker run -v /my/custom/sites/enabled/:/usr/local/openresty/nginx/conf/sites-enabled oorabona/openresty-${flavor}:latest-alpine

Temporary directories such as client_body_temp_path are stored in /var/run/openresty/. You may consider mounting that volume, rather than writing to a container-local directory.

Hardened versions are built on the latest image version

⁠What is different in these versions ?

Mostly a stable, state-of-the-art (if not, please submit issue/PR) configuration files to use as a base for your projects.

Of course not every single configuration will be implemented here, only fundamental (i.e. mandatory) setup, amongst which:

  • Typical configuration for each flavor
  • SSL/HSTS/CSP/etc.
  • Security best practices for nginx
  • Security best practices for Docker

Back to TOC⁠

⁠OPM

Starting at version 1.11.2.2, OpenResty for Linux includes a package manager called opm⁠, which can be found at /usr/local/openresty/bin/opm.

This package is installed in every distribution (OS) and is meant to provide a ground for derived images to integrate extra packages. Feel free to use it and then remove if needed to both size and security reasons.

For that, multi stage Dockerfiles will help.

RUN /usr/local/openresty/bin/opm install <package>

Back to TOC⁠

⁠LuaRocks

Similarly LuaRocks⁠ is installed in every distribution (OS) and has a broader package repository than OPM⁠.

Its binary can be found in /usr/local/bin/luarocks.

For instance you could, in a multi stage Dockerfile have this line :

RUN /usr/local/bin/luarocks install <rock>

Back to TOC⁠

⁠Image Labels

These LABELs are set in each image built. Most of them are common with the official OpenResty Docker repository. Some of them have been removed.

Label NameDescription
maintainerMaintainer of the image
resty_flavorbuildarg RESTY_FLAVOR
resty_add_package_builddepsbuildarg RESTY_ADD_PACKAGE_BUILDDEPS
resty_add_package_rundepsbuildarg RESTY_ADD_PACKAGE_RUNDEPS
resty_config_depsbuildarg _RESTY_CONFIG_DEPS (internal)
resty_config_optionsbuildarg RESTY_CONFIG_OPTIONS
resty_config_options_morebuildarg RESTY_CONFIG_OPTIONS_MORE
resty_image_baseName of the base image to build from, buildarg RESTY_IMAGE_BASE
resty_image_tagTag of the base image to build from, buildarg RESTY_IMAGE_TAG
resty_luajit_optionsbuildarg RESTY_LUAJIT_OPTIONS
resty_luarocks_versionbuildarg RESTY_LUAROCKS_VERSION
resty_openssl_versionbuildarg RESTY_OPENSSL_VERSION
resty_openssl_patch_versionbuildarg RESTY_OPENSSL_PATCH_VERSION
resty_openssl_url_basebuildarg RESTY_OPENSSL_URL_BASE
resty_pcre_versionbuildarg RESTY_PCRE_VERSION
resty_versionbuildarg RESTY_VERSION

Back to TOC⁠

⁠Docker ENTRYPOINT & CMD

The -g "daemon off;" directive is used in the Dockerfile CMD to keep the Nginx daemon running after container creation. If this directive is added to the nginx.conf, then the docker run should explicitly invoke openresty:

docker run [options] oorabona/openresty-<FLAVOR>:alpine openresty

Invoke another CMD, for example the resty utility, like so:

docker run [options] oorabona/openresty-<FLAVOR>:alpine resty [script.lua]

Since this is way easier to operate and there is no need to wrap commands around a script, no ENTRYPOINT is needed.

Back to TOC⁠

⁠Building from source

If you want to build yourself these OpenResty flavors, you just need to git clone this repository and use the build script at its root.

git clone https://github.com/oorabona/docker-openresty.git
cd docker-openresty
./build

It comes with little help on its own :

$ ./build
build <OSes> [flavors] [version] [platforms]

OSes, flavors and platforms must be separated by commas.
If you want to specify version and/or platforms and you want to build all flavors, use 'all'.
If not specified, default version is 'latest'.
If not specified, all flavors for a specific OS are built.
If not specified, linux/arm/v7 and linux/amd64 are built, 'all' is accepted.

So you can build either all flavors for a specific base OS or a specific version of a specific flavor on a specific platform with the same build tool :wink:

NOTES

  • Flavors are derived from the number of shell scripts present in the directory of the base OS. The default is to build all of them.
  • The default value for version is latest. In which case both the version number and latest tag will be pushed.
  • As for now, platforms are only linux/arm/v7 (Raspberry Pi) and linux/amd64. Other may come in the future but since this is cross compiling, it takes way more time.
# Builds on Alpine Linux, all flavors, latest version, default platforms
$ ./build alpine
# Builds on Alpine Linux, ModSecurity only, latest version, Linux AMD64 only
$ ./build alpine modsecurity latest linux/amd64
# Builds on Alpine Linux, all flavors, on 1.19.3.1 version, default platforms
$ ./build alpine all 1.19.3.1
# Builds on Alpine Linux, all flavors, latest version, all platforms (supported by QEMU)
$ ./build alpine all latest all

⁠Building hardened versions

If you want to build the hardened images, use the environment variable HARDENED and set it to 1 :

# Enable hardened image build
$ export HARDENED=1
# Builds on hardened Alpine Linux, all flavors, latest version, default platforms
$ ./build alpine
# Builds on hardened Alpine Linux, ModSecurity only, latest version, Linux AMD64 only
$ ./build alpine modsecurity latest linux/amd64
# Builds on hardened Alpine Linux, all flavors, on 1.19.3.1 version, default platforms
$ ./build alpine all 1.19.3.1
# Builds on hardened Alpine Linux, all flavors, latest version, all platforms (supported by QEMU)
$ ./build alpine all latest all

Back to TOC⁠

⁠Continuous Integration

At the moment, the following pipelines are set up :

To do :

  • Automatic build on new version upstream

Back to TOC⁠

⁠Continuous Deployment

TODO

Back to TOC⁠

⁠Feedback & Bug Reports

You're very welcome to report bugs and give feedback as GitHub Issues:

https://github.com/oorabona/docker-openresty/issues⁠

Back to TOC⁠

⁠Other Documentation

Back to TOC⁠

This work is licensed under MIT license⁠.

Part of it has been inspired by the work done by Evan Wies in this repository⁠.

Kudos go to the team of great people at OpenResty.

Back to TOC⁠

Tag summary

Content type

Image

Digest

Size

81.8 MB

Last updated

over 5 years ago

docker pull oorabona/openresty-hardened-basic