diff --git a/README.md b/README.md index 95b57084..34a77d88 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ utilizing *fleet* and *etcd*. * **mysql-galera-demo**: This demo uses NGINX Plus as a TCP load balancer for a MySQL Galera cluster consisting of two mysqld servers. It does round-robin load balancing between the 2 mysqld servers and also does active health checks using an xinetd script running on port 9200 inside each mysqld container. -* **nginx-agent-docker**: This demo helps building a docker image to deploy NGINX Plus and NGINX Agent for NGINX Management Suite, with optional support for NGINX App Protect WAF and NGINX Developer Portal for API Connectivity Manager +* **nginx-docker-builder**: This demo helps building a docker image to deploy NGINX Plus (privileged and unprivileged), NGINX App Protect WAF and NGINX Agent for NGINX Instance Manager and NGINX One Console * **nginx-hello**: NGINX running as webserver in a docker container that serves a simple page containing the container's hostname, IP address and port diff --git a/nginx-agent-docker/README.md b/nginx-agent-docker/README.md deleted file mode 100644 index e04243f5..00000000 --- a/nginx-agent-docker/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# NGINX Plus and NGINX Agent - Docker image builder - -## Description - -This repository can be used to build a docker image with NGINX (Plus or Opensource) and NGINX Instance Manager Agent (https://docs.nginx.com/nginx-instance-manager/). - -## Tested releases - -This repository has been tested with: NGINX agent for: - -- NGINX Plus R29+ -- NGINX Opensource 1.24.0+ -- NGINX Agent 2.14+ -- NGINX Instance Manager 2.15+ -- NGINX App Protect WAF 4.100.1+ -- NGINX One Cloud Console - -## Prerequisites - -- Linux host running Docker to build the image -- NGINX Plus license -- One of - - [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager/) - - [NGINX One Cloud Console](https://docs.nginx.com/nginx-one/) -- Openshift/Kubernetes cluster - -## Building the docker image - -The install script can be used to build the Docker image: - -``` -NGINX Opensource/Plus & NGINX Agent Docker image builder - - This tool builds a Docker image to run NGINX Opensource/Plus and NGINX Agent - - === Usage: - - ./scripts/build.sh [options] - - === Options: - - -h - This help - -t [target image] - The Docker image to be created - -C [file.crt] - Certificate to pull packages from the official NGINX repository - -K [file.key] - Key to pull packages from the official NGINX repository - -n [URL] - NGINX Instance Manager / NGINX SaaS console URL to fetch the agent - -w - Add NGINX App Protect WAF (requires NGINX Plus) - -O - Use NGINX Opensource instead of NGINX Plus - - === Examples: - - NGINX Plus and NGINX Agent image: - ./scripts/build.sh -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-with-agent:latest -n https://nim.f5.ff.lan - - NGINX Plus, NGINX App Protect WAF and NGINX Agent image: - ./scripts/build.sh -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-with-agent:latest-nap -w -n https://nim.f5.ff.lan - - NGINX Opensource and NGINX Agent image: - ./scripts/build.sh -O -t registry.ff.lan:31005/nginx-oss-with-agent:latest -n https://nim.f5.ff.lan -``` - -1. Clone this repository -2. For NGINX Plus only: get your license certificate and key to fetch NGINX Management Suite packages from NGINX repository -3. [Install](https://docs.nginx.com/nginx-management-suite/) and start NGINX Management Suite / NGINX Instance Manager. Skip this step if using the NGINX SaaS console -4. Build the Docker image using `./scripts/build.sh` - -the build script will push the image to your private registry once build is complete. - -### Running the docker image on Kubernetes - -1. Edit `manifests/1.nginx-nim.yaml` and specify the correct image by modifying the `image:` line, and set the following environment variables. Default values for `NIM_HOST` and `NIM_GRPC_PORT` can be used if NGINX Instance Manager is deployed using https://github.com/nginxinc/NGINX-Demos/tree/master/nginx-nms-docker - - `NIM_HOST` - NGINX Instance Manager hostname/IP address - - `NIM_GRPC_PORT` - NGINX Instance Manager gRPC port - - `NIM_TOKEN` - NGINX One Cloud Console authentication token - - `NIM_INSTANCEGROUP` - instance group for the NGINX instance - - `NIM_TAGS` - comma separated list of tags for the NGINX instance - - `NIM_ADVANCED_METRICS` - set to `"true"` to enable advanced metrics collection - NGINX Plus only - - `NAP_WAF` - set to `"true"` to enable NGINX App Protect WAF (docker image built using `-w`) - NGINX Plus only - - `NAP_WAF_PRECOMPILED_POLICIES` - set to `"true"` to enable NGINX App Protect WAF precompiled policies (docker image built using `-w`) - NGINX Plus only - - `AGENT_LOGLEVEL` - NGINX Agent loglevel, optional. If not specified defaults to `info` - -2. Start and stop using - -``` -$ ./scripts/nginxWithAgentStart.sh start -$ ./scripts/nginxWithAgentStart.sh stop -``` - -3. After startup NGINX instances will register to NGINX Instance Manager / NGINX SaaS console and will be displayed on the "instances" dashboard - -### Running the docker image on Docker - -1. Start using - -``` -docker run --rm --name nginx -p [PORT_TO_EXPOSE] \ - -e "NIM_HOST=" \ - -e "NIM_GRPC_PORT=" \ - -e "NIM_TOKEN=" \ - -e "NIM_INSTANCEGROUP=" \ - -e "NIM_TAGS=" \ - -e "NIM_ADVANCED_METRICS=[true|false]" \ - -e "NAP_WAF=[true|false]" \ - -e "NAP_WAF_PRECOMPILED_POLICIES=[true|false]" \ - -e "AGENT_LOGLEVEL=[panic|fatal|error|info|debug|trace]" \ - -``` - -2. After startup NGINX Plus instances will register to NGINX Instance Manager and will be displayed on the "instances" dashboard diff --git a/nginx-agent-docker/container/start.sh b/nginx-agent-docker/container/start.sh deleted file mode 100755 index e6a9f288..00000000 --- a/nginx-agent-docker/container/start.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -nginx -sleep 2 - -# NGINX Agent version detection, change in behaviour in v2.24.0+ -AGENT_VERSION=`nginx-agent -v|awk '{print $3}'` -AGENT_VERSION_MAJOR=`echo $AGENT_VERSION | awk -F\. '{print $1}' | sed 's/v//'` -AGENT_VERSION_MINOR=`echo $AGENT_VERSION | awk -F\. '{print $2}'` - -echo "=> NGINX Agent version $AGENT_VERSION" - -PARM="" - -yq -i ' - .server.host=strenv(NIM_HOST) | - .server.grpcPort=strenv(NIM_GRPC_PORT) - ' /etc/nginx-agent/nginx-agent.conf - -if [[ ! -z "$NIM_INSTANCEGROUP" ]]; then - PARM="${PARM} --instance-group $NIM_INSTANCEGROUP" -fi - -if [[ ! -z "$NIM_TAGS" ]]; then - PARM="${PARM} --tags $NIM_TAGS" -fi - -if [[ ! -z "$NIM_TOKEN" ]]; then - yq -i ' - .server.token=strenv(NIM_TOKEN) - ' /etc/nginx-agent/nginx-agent.conf -fi - -if [[ ! -z "$AGENT_LOGLEVEL" ]]; then - yq -i ' - .log.level=strenv(AGENT_LOGLEVEL) - ' /etc/nginx-agent/nginx-agent.conf -fi - -if [[ "$NIM_ADVANCED_METRICS" == "true" ]]; then - yq -i ' - .advanced_metrics.socket_path="/var/run/nginx-agent/advanced-metrics.sock" | - .advanced_metrics.aggregation_period="1s" | - .advanced_metrics.publishing_period="3s" | - .advanced_metrics.table_sizes_limits.staging_table_max_size=1000 | - .advanced_metrics.table_sizes_limits.staging_table_threshold=1000 | - .advanced_metrics.table_sizes_limits.priority_table_max_size=1000 | - .advanced_metrics.table_sizes_limits.priority_table_threshold= 1000 | - .extensions += ["advanced-metrics"] - ' /etc/nginx-agent/nginx-agent.conf -fi - -if [[ "$NAP_WAF" == "true" ]]; then - export FQDN=127.0.0.1 - - yq -i ' - .nap_monitoring.collector_buffer_size=50000 | - .nap_monitoring.processor_buffer_size=50000 | - .nap_monitoring.syslog_ip=strenv(FQDN) | - .nap_monitoring.syslog_port=514 | - .extensions += ["nginx-app-protect","nap-monitoring"] - ' /etc/nginx-agent/nginx-agent.conf - - su - nginx -s /bin/bash -c "/opt/app_protect/bin/bd_agent &" - su - nginx -s /bin/bash -c "/usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 471859200 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config &" - - while ([ ! -e /opt/app_protect/pipe/app_protect_plugin_socket ] || [ ! -e /opt/app_protect/pipe/ts_agent_pipe ]) - do - sleep 1 - done - - chown nginx:nginx /opt/app_protect/pipe/* - -if [[ "$NAP_WAF_PRECOMPILED_POLICIES" == "true" ]]; then - yq -i ' - .nginx_app_protect.precompiled_publication=true - ' /etc/nginx-agent/nginx-agent.conf -fi - -fi - -sg nginx-agent "/usr/bin/nginx-agent $PARM" diff --git a/nginx-agent-docker/manifests/1.nginx-with-agent.yaml b/nginx-agent-docker/manifests/1.nginx-with-agent.yaml deleted file mode 100644 index 8a60e240..00000000 --- a/nginx-agent-docker/manifests/1.nginx-with-agent.yaml +++ /dev/null @@ -1,95 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-nim - namespace: nim-test - labels: - app: nginx-nim -spec: - selector: - matchLabels: - app: nginx-nim - replicas: 2 - template: - metadata: - labels: - app: nginx-nim - spec: - containers: - - name: nginx-nim - image: your.registry.tld/nginx-with-nim2-agent:tag - imagePullPolicy: Always - ports: - - name: http - containerPort: 80 - env: - - name: NIM_HOST - # NGINX Instance Manager hostname or IP address - value: "nginx-nim2.nginx-nim2" - - name: NIM_GRPC_PORT - value: "443" - - name: NIM_TOKEN - value: "XYZ" - - name: NIM_INSTANCEGROUP - value: "lab" - - name: NIM_TAGS - value: "preprod,devops" - - # Optional to enable advanced metrics collection - set to "true" to enable - - name: NIM_ADVANCED_METRICS - value: "true" - - # Optional to set NGINX Agent loglevel - default is "info" - #- name: AGENT_LOGLEVEL - # value: "info" - - # Optional if NGINX App Protect WAF is available in the docker image - set to "true" to enable - #- name: NAP_WAF - # value: "true" - #- name: NAP_WAF_PRECOMPILED_POLICIES - # value: "true" - ---- -apiVersion: v1 -kind: Service -metadata: - name: nginx-nim - namespace: nim-test - labels: - app: nginx-nim -spec: - ports: - - name: http - port: 80 - - name: api - port: 8080 - selector: - app: nginx-nim - type: ClusterIP - ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: nginx-nim - namespace: nim-test - annotations: - nginx.org/proxy-connect-timeout: "30s" - nginx.org/proxy-read-timeout: "20s" - nginx.org/client-max-body-size: "4m" - nginx.com/health-checks: "true" - labels: - app: nginx-nim -spec: - ingressClassName: nginx - rules: - - host: nim-test-nim.f5.ff.lan - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: nginx-nim - port: - number: 80 diff --git a/nginx-agent-docker/scripts/nginxWithAgentStart.sh b/nginx-agent-docker/scripts/nginxWithAgentStart.sh deleted file mode 100755 index 78a80186..00000000 --- a/nginx-agent-docker/scripts/nginxWithAgentStart.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -NAMESPACE=nim-test - -case $1 in - 'start') - kubectl create namespace $NAMESPACE - - pushd manifests/ - kubectl apply -n $NAMESPACE -f . - popd - ;; - 'stop') - kubectl delete namespace $NAMESPACE - ;; - *) - echo "$0 [start|stop]" - exit - ;; -esac diff --git a/nginx-agent-docker/Dockerfile.oss b/nginx-docker-builder/Dockerfile.oss similarity index 55% rename from nginx-agent-docker/Dockerfile.oss rename to nginx-docker-builder/Dockerfile.oss index 743b1820..5fb02e7f 100644 --- a/nginx-agent-docker/Dockerfile.oss +++ b/nginx-docker-builder/Dockerfile.oss @@ -1,6 +1,7 @@ FROM nginx:stable-bullseye-perl ARG NMS_URL +ARG NGINX_AGENT=false # Initial packages setup RUN apt-get -y update \ @@ -15,10 +16,13 @@ RUN apt-get -y update \ && groupadd -g 1001 nginx-agent \ && usermod root -G nginx-agent \ && usermod nginx -G nginx-agent \ -# NGINX Instance Manager agent installation - && if [ `curl -o /dev/null -sk -w "%{http_code}\n" $NMS_URL/install/nginx-agent` = 200 ] ; then \ - bash -c 'export DATA_PLANE_KEY="placeholder" && curl -k $NMS_URL/install/nginx-agent | sh' && echo "NGINX Agent installed"; else \ - bash -c 'export DATA_PLANE_KEY="placeholder" && curl -k $NMS_URL/nginx-agent/install | sh || :' && echo "NGINX Agent installed"; fi +# NGINX Agent + && if [ "$NGINX_AGENT" = "true" ] ; then \ + apt-get -y install curl gnupg2 ca-certificates lsb-release debian-archive-keyring \ + && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://packages.nginx.org/nginx-agent/debian/ `lsb_release -cs` agent" > /etc/apt/sources.list.d/nginx-agent.list \ + && apt-get -y update \ + && apt-get -y install nginx-agent; fi # Startup script COPY ./container/start.sh /deployment/ diff --git a/nginx-agent-docker/Dockerfile.plus b/nginx-docker-builder/Dockerfile.plus similarity index 79% rename from nginx-agent-docker/Dockerfile.plus rename to nginx-docker-builder/Dockerfile.plus index 558e9b6e..3da82d41 100644 --- a/nginx-agent-docker/Dockerfile.plus +++ b/nginx-docker-builder/Dockerfile.plus @@ -1,7 +1,7 @@ FROM debian:bullseye-slim -ARG NMS_URL ARG NAP_WAF=false +ARG NGINX_AGENT=false # Initial packages setup RUN apt-get -y update \ @@ -12,7 +12,7 @@ RUN apt-get -y update \ && wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq \ && chmod +x /usr/bin/yq -# Use certificate and key from kubernetes secret +# Use certificate and key from secret RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ set -x \ @@ -32,14 +32,12 @@ RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 # Forward request logs to Docker log collector && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ -# User and group - && groupadd -g 1001 nginx-agent \ - && usermod root -G nginx-agent \ - && usermod nginx -G nginx-agent \ -# NGINX Instance Manager agent installation - && if [ `curl -o /dev/null -sk -w "%{http_code}\n" $NMS_URL/install/nginx-agent` = 200 ] ; then \ - bash -c 'export DATA_PLANE_KEY="placeholder" && curl -k $NMS_URL/install/nginx-agent | sh' && echo "NGINX Agent installed"; else \ - bash -c 'export DATA_PLANE_KEY="placeholder" && curl -k $NMS_URL/nginx-agent/install | sh || :' && echo "NGINX Agent installed"; fi +# NGINX Agent + && if [ "$NGINX_AGENT" = "true" ] ; then \ + curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://packages.nginx.org/nginx-agent/debian/ `lsb_release -cs` agent" > /etc/apt/sources.list.d/nginx-agent.list \ + && apt-get -y update \ + && apt-get -y install nginx-agent; fi # Startup script COPY ./container/start.sh /deployment/ diff --git a/nginx-docker-builder/Dockerfile.plus.unprivileged b/nginx-docker-builder/Dockerfile.plus.unprivileged new file mode 100644 index 00000000..b323d4c3 --- /dev/null +++ b/nginx-docker-builder/Dockerfile.plus.unprivileged @@ -0,0 +1,73 @@ +FROM debian:bullseye-slim + +ARG NAP_WAF=false +ARG NGINX_AGENT=false + +ARG UID=101 +ARG GID=101 + +# Initial packages setup +RUN apt-get -y update \ + && apt-get -y install apt-transport-https lsb-release ca-certificates wget gnupg2 curl debian-archive-keyring iproute2 \ + && mkdir -p /deployment /etc/ssl/nginx /etc/nms \ + && addgroup --system --gid $GID nginx \ + && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid $UID nginx \ + && wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq \ + && chmod +x /usr/bin/yq + +# Use certificate and key from secret +RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + set -x \ +# Install prerequisite packages: + && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg \ + && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/plus/debian `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \ + && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ + && apt-get -y update \ + && apt-get -y install nginx-plus nginx-plus-module-njs nginx-plus-module-prometheus \ +# Optional NGINX App Protect WAF + && if [ "$NAP_WAF" = "true" ] ; then \ + wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | gpg --dearmor > /usr/share/keyrings/app-protect-security-updates.gpg \ + && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/app-protect/debian `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-app-protect.list \ + && printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] https://pkgs.nginx.com/app-protect-security-updates/debian `lsb_release -cs` nginx-plus\n" >> /etc/apt/sources.list.d/nginx-app-protect.list \ + && apt-get -y update \ + && apt-get -y install app-protect app-protect-attack-signatures; fi \ +# Forward request logs to Docker log collector + && ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log \ +# NGINX Agent + && if [ "$NGINX_AGENT" = "true" ] ; then \ + curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://packages.nginx.org/nginx-agent/debian/ `lsb_release -cs` agent" > /etc/apt/sources.list.d/nginx-agent.list \ + && apt-get -y update \ + && apt-get -y install nginx-agent; fi + +# implement changes required to run NGINX as an unprivileged user +RUN rm /etc/nginx/conf.d/default.conf \ + && sed -i '/user nginx;/d' /etc/nginx/nginx.conf \ + && sed -i 's,/var/run/nginx.pid,/tmp/nginx.pid,' /etc/nginx/nginx.conf \ + && sed -i "/^http {/a \ proxy_temp_path /tmp/proxy_temp;\n client_body_temp_path /tmp/client_temp;\n fastcgi_temp_path /tmp/fastcgi_temp;\n uwsgi_temp_path /tmp/uwsgi_temp;\n scgi_temp_path /tmp/scgi_temp;\n" /etc/nginx/nginx.conf \ +# nginx user must own the cache and etc directory to write cache and tweak the nginx config + && chown -R $UID:0 /var/cache/nginx \ + && chmod -R g+w /var/cache/nginx \ + && chown -R $UID:0 /etc/nginx \ + && chmod -R g+w /etc/nginx \ + && chown -R $UID:0 /usr/lib/nginx/modules \ + && chmod -R g+w /usr/lib/nginx/modules \ + && chown -R $UID:0 /etc/nms \ + && chmod -R g+w /etc/nms \ + && chown -R $UID:0 /etc/nginx-agent \ + && chmod -R g+w /etc/nginx-agent \ + && chown -R $UID:0 /var/lib/nginx-agent \ + && chmod -R g+w /var/lib/nginx-agent + +# Startup script +COPY ./container/start.sh /deployment/ +RUN chmod +x /deployment/start.sh && touch /.dockerenv + +EXPOSE 80 +STOPSIGNAL SIGTERM + +USER $UID + +CMD ["/deployment/start.sh"] diff --git a/nginx-docker-builder/README.md b/nginx-docker-builder/README.md new file mode 100644 index 00000000..490ec50f --- /dev/null +++ b/nginx-docker-builder/README.md @@ -0,0 +1,110 @@ +# NGINX Docker image builder + +## Description + +This repository can be used to build a docker image that includes: + +- [NGINX Plus](https://docs.nginx.com/nginx) in privileged or unprivileged/non-root mode +- [NGINX Open Source](https://nginx.org/) +- [NGINX App Protect WAF](https://docs.nginx.com/nginx-app-protect-waf) +- [NGINX Agent](https://docs.nginx.com/nginx-agent) + +## Tested releases + +This repository has been tested with: + +- [NGINX Plus](https://docs.nginx.com/nginx) R29+ +- [NGINX Open Source](https://nginx.org) 1.24.0+ +- [NGINX Agent](https://docs.nginx.com/nginx-agent) 2.14+ +- [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager) 2.15+ +- [NGINX App Protect WAF](https://docs.nginx.com/nginx-app-protect-waf) 4.100.1+ +- [NGINX One Console](https://docs.nginx.com/nginx-app-protect-waf) + +## Prerequisites + +- Linux host running Docker to build the image +- NGINX Plus license +- Access to either control plane: + - [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager/) + - [NGINX One Cloud Console](https://docs.nginx.com/nginx-one/) +- Docker/Docker-compose or Openshift/Kubernetes cluster + +## Building the docker image + +The `./scripts/build.sh` install script can be used to build the Docker image: + +``` +NGINX Docker Image builder + + This tool builds a Docker image to run NGINX Plus/Open Source, NGINX App Protect WAF and NGINX Agent + + === Usage: + + ./scripts/build.sh [options] + + === Options: + + -h - This help + -t [target image] - The Docker image to be created + -C [file.crt] - Certificate to pull packages from the official NGINX repository + -K [file.key] - Key to pull packages from the official NGINX repository + -w - Add NGINX App Protect WAF (requires NGINX Plus) + -O - Use NGINX Open Source instead of NGINX Plus + -u - Build unprivileged image (only for NGINX Plus) + -a - Add NGINX Agent + + === Examples: + + NGINX Plus and NGINX Agent image: + ./scripts/build.sh -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-agent-root -a + + NGINX Plus, NGINX App Protect WAF and NGINX Agent image: + ./scripts/build.sh -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-nap-agent-root -w -a + + NGINX Plus, NGINX App Protect WAF and NGINX Agent unprivileged image: + ./scripts/build.sh -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-nap-agent-nonroot -w -u -a + + NGINX Opensource and NGINX Agent image: + ./scripts/build.sh -O -t registry.ff.lan:31005/nginx-docker:oss-root -a +``` + +1. Clone this repository +2. For NGINX Plus only: get your license certificate and key +3. Build the Docker image using `./scripts/build.sh` + +### Running the docker image on Kubernetes + +1. Edit `manifests/1.nginx-nim.yaml` and specify the correct image by modifying the `image:` line, and set the following environment variables + - `NGINX_LICENSE` - NGINX R33+ JWT license token + - `NGINX_AGENT_SERVER_HOST` - NGINX Instance Manager / NGINX One Console hostname/IP address + - `NGINX_AGENT_SERVER_GRPCPORT` - NGINX Instance Manager / NGINX One Console gRPC port + - `NGINX_AGENT_SERVER_TOKEN` - NGINX Instance Manager / NGINX One Console authentication token + - `NGINX_AGENT_INSTANCE_GROUP` - instance group (NGINX Instance Manager) / config sync group (NGINX One Console) for the NGINX instance + - `NGINX_AGENT_TAGS` - comma separated list of tags for the NGINX instance + - `NAP_WAF` - set to `"true"` to enable NGINX App Protect WAF (docker image built using `-w`) - NGINX Plus only + - `NAP_WAF_PRECOMPILED_POLICIES` - set to `"true"` to enable NGINX App Protect WAF precompiled policies (docker image built using `-w`) - NGINX Plus only + - `NGINX_AGENT_LOG_LEVEL` - NGINX Agent loglevel, optional. If not specified defaults to `info` + +2. Deploy on Kubernetes using the example manifest `manifest/nginx-manifest.yaml` + +3. After startup the NGINX instance will register to NGINX Instance Manager / NGINX One console and will be displayed on the "instances" dashboard if the NGINX Agent has been build into the docker image + +### Running the docker image on Docker + +1. Start using + +``` +docker run --rm --name nginx -p [PORT_TO_EXPOSE] \ + -e "NGINX_LICENSE=" \ + -e "NGINX_AGENT_SERVER_HOST=" \ + -e "NGINX_AGENT_SERVER_GRPCPORT=" \ + -e "NGINX_AGENT_SERVER_TOKEN=" \ + -e "NGINX_AGENT_INSTANCE_GROUP=" \ + -e "NGINX_AGENT_TAGS=" \ + -e "NAP_WAF=[true|false]" \ + -e "NAP_WAF_PRECOMPILED_POLICIES=[true|false]" \ + -e "NGINX_AGENT_LOG_LEVEL=[panic|fatal|error|info|debug|trace]" \ + +``` + +2. After startup the NGINX instance will register to NGINX Instance Manager / NGINX One Console and will be displayed on the "instances" dashboard if the NGINX Agent has been build into the docker image diff --git a/nginx-docker-builder/container/start.sh b/nginx-docker-builder/container/start.sh new file mode 100755 index 00000000..fea5351d --- /dev/null +++ b/nginx-docker-builder/container/start.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +if [[ `whoami` == "nginx" ]]; then + IS_UNPRIVILEGED="true" +else + IS_UNPRIVILEGED= +fi + +if [[ ! -z "$NGINX_LICENSE" ]]; then + echo ${NGINX_LICENSE} > /etc/nginx/license.jwt +fi + +nginx +sleep 2 + +if [[ "$NGINX_AGENT_ENABLED" == "true" ]]; then + + # NGINX Agent version detection, change in behaviour in v2.24.0+ + AGENT_VERSION=`nginx-agent -v|awk '{print $3}'` + AGENT_VERSION_MAJOR=`echo $AGENT_VERSION | awk -F\. '{print $1}' | sed 's/v//'` + AGENT_VERSION_MINOR=`echo $AGENT_VERSION | awk -F\. '{print $2}'` + + echo "=> NGINX Agent version $AGENT_VERSION" + + PARM="" + + yq -i ' + .server.host=strenv(NGINX_AGENT_SERVER_HOST) | + .server.grpcPort=strenv(NGINX_AGENT_SERVER_GRPCPORT) | + .tls.enable=true | + .tls.skip_verify=true | + .tls.cert="" | + .tls.key="" + ' /etc/nginx-agent/nginx-agent.conf + + if [[ ! -z "$NGINX_AGENT_INSTANCE_GROUP" ]]; then + PARM="${PARM} --instance-group $NGINX_AGENT_INSTANCE_GROUP" + fi + + if [[ ! -z "$NGINX_AGENT_TAGS" ]]; then + PARM="${PARM} --tags $NGINX_AGENT_TAGS" + fi + + if [[ ! -z "$NGINX_AGENT_SERVER_TOKEN" ]]; then + yq -i ' + .server.token=strenv(NGINX_AGENT_SERVER_TOKEN) + ' /etc/nginx-agent/nginx-agent.conf + fi + + if [[ ! -z "$NGINX_AGENT_LOG_LEVEL" ]]; then + yq -i ' + .log.level=strenv(NGINX_AGENT_LOG_LEVEL) + ' /etc/nginx-agent/nginx-agent.conf + fi +fi + +if [[ "$NAP_WAF" == "true" ]]; then + export FQDN=127.0.0.1 + + yq -i ' + .nap_monitoring.collector_buffer_size=50000 | + .nap_monitoring.processor_buffer_size=50000 | + .nap_monitoring.syslog_ip=strenv(FQDN) | + .nap_monitoring.syslog_port=514 | + .extensions += ["nginx-app-protect","nap-monitoring"] + ' /etc/nginx-agent/nginx-agent.conf + + if [[ "$IS_UNPRIVILEGED" ]]; then + /opt/app_protect/bin/bd_agent & + /usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 471859200 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config & + else + su - nginx -s /bin/bash -c "/opt/app_protect/bin/bd_agent &" + su - nginx -s /bin/bash -c "/usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 471859200 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config &" + fi + + while ([ ! -e /opt/app_protect/pipe/app_protect_plugin_socket ] || [ ! -e /opt/app_protect/pipe/ts_agent_pipe ]) + do + sleep 1 + done + + chown nginx:nginx /opt/app_protect/pipe/* + +if [[ "$NAP_WAF_PRECOMPILED_POLICIES" == "true" ]]; then + yq -i ' + .nginx_app_protect.precompiled_publication=true + ' /etc/nginx-agent/nginx-agent.conf +fi + +fi + +if [[ "$NGINX_AGENT_ENABLED" == "true" ]]; then + if [[ "$IS_UNPRIVILEGED" ]]; then + /usr/bin/nginx-agent $PARM + else + sg nginx-agent "/usr/bin/nginx-agent $PARM" + fi +else + while [ true ]; do sleep 3600; done +fi diff --git a/nginx-docker-builder/manifests/nginx-manifest.yaml b/nginx-docker-builder/manifests/nginx-manifest.yaml new file mode 100644 index 00000000..75785a34 --- /dev/null +++ b/nginx-docker-builder/manifests/nginx-manifest.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: YOUR_REGISTRY/NGINX_DOCKER_IMAGE_NAME:TAG + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + env: + # NGINX Plus R33+ JWT license token - it is recommended to store this in a Kubernetes secret + - name: NGINX_LICENSE + value: "NGINX_JWT_LICENSE_TOKEN" + + # NGINX Agent Configuration + - name: NGINX_AGENT_ENABLED + value: "true" + - name: NGINX_AGENT_SERVER_HOST + # NGINX Instance Manager / NGINX One Console hostname or IP address + value: "NGINX_CONTROL_PLANE_SERVER" + - name: NGINX_AGENT_SERVER_GRPCPORT + # NGINX Instance Manager / NGINX One Console gRPC port + value: "443" + # Optional parameters + - name: NGINX_AGENT_SERVER_TOKEN + # NGINX Instance Manager / NGINX One Console authentication token + value: "XYZ" + - name: NGINX_AGENT_INSTANCE_GROUP + # The Instance Group (NGINX Instance Manager) / Config Sync Group (NGINX One Console) + value: "lab" + - name: NGINX_AGENT_TAGS + # Comma-separated list of tags for the NGINX instance + value: "preprod,devops" + - name: NGINX_AGENT_LOG_LEVEL + # NGINX Agent loglevel - default is "info" + value: "info" + + # Optional if NGINX App Protect WAF is available in the docker image - set to "true" to enable + #- name: NAP_WAF + # value: "true" + #- name: NAP_WAF_PRECOMPILED_POLICIES + # value: "true" + +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + labels: + app: nginx +spec: + ports: + - name: http + port: 80 + - name: api + port: 8080 + selector: + app: nginx + type: ClusterIP + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: nginx + annotations: + nginx.org/proxy-connect-timeout: "30s" + nginx.org/proxy-read-timeout: "20s" + nginx.org/client-max-body-size: "4m" + nginx.com/health-checks: "true" + labels: + app: nginx +spec: + ingressClassName: nginx + rules: + - host: nginx.yourdomain.tld + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx + port: + number: 80 diff --git a/nginx-agent-docker/scripts/build.sh b/nginx-docker-builder/scripts/build.sh similarity index 55% rename from nginx-agent-docker/scripts/build.sh rename to nginx-docker-builder/scripts/build.sh index 9c7807e4..bc109e13 100755 --- a/nginx-agent-docker/scripts/build.sh +++ b/nginx-docker-builder/scripts/build.sh @@ -2,8 +2,8 @@ # https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-docker/#docker_plus -BANNER="NGINX Opensource/Plus & NGINX Agent Docker image builder\n\n -This tool builds a Docker image to run NGINX Opensource/Plus and NGINX Agent\n\n +BANNER="NGINX Docker Image builder\n\n +This tool builds a Docker image to run NGINX Plus/Open Source, NGINX App Protect WAF and NGINX Agent\n\n === Usage:\n\n $0 [options]\n\n === Options:\n\n @@ -11,18 +11,24 @@ $0 [options]\n\n -t [target image]\t- The Docker image to be created\n -C [file.crt]\t\t- Certificate to pull packages from the official NGINX repository\n -K [file.key]\t\t- Key to pull packages from the official NGINX repository\n --n [URL]\t\t- NGINX Instance Manager / NGINX SaaS console URL to fetch the agent\n -w\t\t\t- Add NGINX App Protect WAF (requires NGINX Plus)\n --O\t\t\t- Use NGINX Opensource instead of NGINX Plus\n\n +-O\t\t\t- Use NGINX Open Source instead of NGINX Plus\n +-u\t\t\t- Build unprivileged image (only for NGINX Plus)\n +-a\t\t\t- Add NGINX Agent\n\n === Examples:\n\n NGINX Plus and NGINX Agent image:\n - $0 -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-with-agent:latest -n https://nim.f5.ff.lan\n\n + $0 -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-agent-root -a\n\n + NGINX Plus, NGINX App Protect WAF and NGINX Agent image:\n - $0 -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-with-agent:latest-nap -w -n https://nim.f5.ff.lan\n\n + $0 -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-nap-agent-root -w -a\n\n + +NGINX Plus, NGINX App Protect WAF and NGINX Agent unprivileged image:\n + $0 -C nginx-repo.crt -K nginx-repo.key -t registry.ff.lan:31005/nginx-docker:plus-nap-agent-nonroot -w -u -a\n\n + NGINX Opensource and NGINX Agent image:\n - $0 -O -t registry.ff.lan:31005/nginx-oss-with-agent:latest -n https://nim.f5.ff.lan\n" + $0 -O -t registry.ff.lan:31005/nginx-docker:oss-root -a\n" -while getopts 'ht:C:K:a:n:wO' OPTION +while getopts 'ht:C:K:awOu' OPTION do case "$OPTION" in h) @@ -38,8 +44,8 @@ do K) NGINX_KEY=$OPTARG ;; - n) - NMSURL=$OPTARG + a) + NGINX_AGENT=true ;; w) NAP_WAF=true @@ -47,6 +53,9 @@ do O) NGINX_OSS=true ;; + u) + UNPRIVILEGED=true + ;; esac done @@ -62,12 +71,6 @@ then exit fi -if [ -z "${NMSURL}" ] -then - echo "NGINX Instance Manager / NGINX SaaS console URL is required" - exit -fi - if ([ -z "${NGINX_OSS}" ] && ([ -z "${NGINX_CERT}" ] || [ -z "${NGINX_KEY}" ]) ) then echo "NGINX certificate and key are required for automated installation" @@ -76,20 +79,36 @@ fi echo "=> Target docker image is $IMAGENAME" +if [ "${NGINX_AGENT}" ] +then + echo "=> Building with NGINX Agent" +fi + if ([ ! -z "${NAP_WAF}" ] && [ -z "${NGINX_OSS}" ]) then -echo "=> Building with NGINX App Protect WAF support" + echo "=> Building with NGINX App Protect WAF" fi if [ -z "${NGINX_OSS}" ] then - DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile.plus \ + if [ -z "${UNPRIVILEGED}" ] + then + DOCKERFILE_NAME=Dockerfile.plus + echo "=> Building with NGINX Plus" + else + DOCKERFILE_NAME=Dockerfile.plus.unprivileged + echo "=> Building with NGINX Plus unprivileged" + fi + + DOCKER_BUILDKIT=1 docker build --no-cache -f $DOCKERFILE_NAME \ --secret id=nginx-key,src=$NGINX_KEY --secret id=nginx-crt,src=$NGINX_CERT \ - --build-arg NMS_URL=$NMSURL --build-arg NAP_WAF=$NAP_WAF -t $IMAGENAME . + --build-arg NAP_WAF=$NAP_WAF --build-arg NGINX_AGENT=$NGINX_AGENT \ + -t $IMAGENAME . else + echo "=> Building with NGINX Open Source" DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile.oss \ - --build-arg NMS_URL=$NMSURL -t $IMAGENAME . + --build-arg NGINX_AGENT=$NGINX_AGENT \ + -t $IMAGENAME . fi echo "=> Build complete for $IMAGENAME" -docker push $IMAGENAME