diff --git a/Dockerfile.nginx-alpine b/Dockerfile.nginx-alpine index fd50cb9e472..d6b13d729f2 100644 --- a/Dockerfile.nginx-alpine +++ b/Dockerfile.nginx-alpine @@ -64,18 +64,23 @@ COPY dojo/ ./dojo/ RUN env DD_SECRET_KEY='.' DD_DJANGO_DEBUG_TOOLBAR_ENABLED=True python3 manage.py collectstatic --noinput --verbosity=2 && true FROM nginx:1.29.1-alpine3.22@sha256:42a516af16b852e33b7682d5ef8acbd5d13fe08fecadc7ed98605ba5e3b26ab8 -ARG uid=1001 -ARG appuser=defectdojo +ARG uid=101 +ARG gid=101 COPY --from=collectstatic /app/static/ /usr/share/nginx/html/static/ COPY wsgi_params nginx/nginx.conf nginx/nginx_TLS.conf /etc/nginx/ COPY docker/entrypoint-nginx.sh / RUN \ apk add --no-cache openssl && \ chmod -R g=u /var/cache/nginx && \ + chown -R ${uid}:${gid} /var/cache/nginx && \ mkdir /var/run/defectdojo && \ chmod -R g=u /var/run/defectdojo && \ + chown -R ${uid}:${gid} /var/run/defectdojo && \ + chmod -R g=u /run/defectdojo && \ + chown -R ${uid}:${gid} /run/defectdojo && \ mkdir -p /etc/nginx/ssl && \ chmod -R g=u /etc/nginx && \ + chown -R ${uid}:${gid} /etc/nginx && \ true ENV \ DD_UWSGI_PASS="uwsgi_server" \ @@ -86,6 +91,6 @@ ENV \ NGINX_METRICS_ENABLED="false" \ METRICS_HTTP_AUTH_USER="" \ METRICS_HTTP_AUTH_PASSWORD="" -USER ${uid} +USER ${uid}:${gid} EXPOSE 8080 ENTRYPOINT ["/entrypoint-nginx.sh"] diff --git a/docker-compose.override.https.yml b/docker-compose.override.https.yml index abe06b4812d..156b4ca5d8c 100644 --- a/docker-compose.override.https.yml +++ b/docker-compose.override.https.yml @@ -4,6 +4,8 @@ services: environment: USE_TLS: 'true' GENERATE_TLS_CERTIFICATE: 'true' + tmpfs: + - /etc/nginx/ssl:uid=101,gid=101 ports: - target: 8443 published: ${DD_TLS_PORT:-8443} diff --git a/docker-compose.yml b/docker-compose.yml index e5238fa6b8b..70e6814a0e8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,8 +19,12 @@ services: NGINX_METRICS_ENABLED: "${NGINX_METRICS_ENABLED:-false}" DD_UWSGI_HOST: "${DD_UWSGI_HOST:-uwsgi}" DD_UWSGI_PORT: "${DD_UWSGI_PORT:-3031}" + read_only: true volumes: - defectdojo_media:/usr/share/nginx/html/media + tmpfs: + - /run/defectdojo:uid=101,gid=101 + - /var/cache/nginx:uid=101,gid=101 ports: - target: 8080 published: ${DD_PORT:-8080} diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 7dfd0153e86..0181f3cccb5 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -19,4 +19,6 @@ dependencies: condition: redis.enabled annotations: artifacthub.io/prerelease: "true" - artifacthub.io/changes: "" + artifacthub.io/changes: | + - kind: changed + description: Hardening of Nginx container diff --git a/helm/defectdojo/README.md b/helm/defectdojo/README.md index fac1345d8c2..0285e14d344 100644 --- a/helm/defectdojo/README.md +++ b/helm/defectdojo/README.md @@ -611,7 +611,12 @@ A Helm chart for Kubernetes to install DefectDojo | django.mediaPersistentVolume.persistentVolumeClaim.size | string | `"5Gi"` | | | django.mediaPersistentVolume.persistentVolumeClaim.storageClassName | string | `""` | | | django.mediaPersistentVolume.type | string | `"emptyDir"` | | -| django.nginx.containerSecurityContext.runAsUser | int | `1001` | | +| django.nginx.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | | +| django.nginx.containerSecurityContext.capabilities.drop[0] | string | `"ALL"` | | +| django.nginx.containerSecurityContext.readOnlyRootFilesystem | bool | `true` | | +| django.nginx.containerSecurityContext.runAsGroup | int | `101` | | +| django.nginx.containerSecurityContext.runAsNonRoot | bool | `true` | | +| django.nginx.containerSecurityContext.runAsUser | int | `101` | | | django.nginx.extraEnv | list | `[]` | | | django.nginx.extraVolumeMounts | list | `[]` | | | django.nginx.resources.limits.cpu | string | `"2000m"` | | diff --git a/helm/defectdojo/templates/django-deployment.yaml b/helm/defectdojo/templates/django-deployment.yaml index 16738a91b41..817bc3ed46e 100644 --- a/helm/defectdojo/templates/django-deployment.yaml +++ b/helm/defectdojo/templates/django-deployment.yaml @@ -76,6 +76,8 @@ spec: volumes: - name: run emptyDir: {} + - name: nginx-cache + emptyDir: {} {{- if .Values.localsettingspy }} - name: localsettingspy configMap: @@ -296,6 +298,8 @@ spec: volumeMounts: - name: run mountPath: /run/defectdojo + - name: nginx-cache + mountPath: /var/cache/nginx {{- with .Values.django.extraVolumeMounts }} {{- . | toYaml | nindent 8 }} {{- end }} diff --git a/helm/defectdojo/values.schema.json b/helm/defectdojo/values.schema.json index 74e14508d13..9d130da29de 100644 --- a/helm/defectdojo/values.schema.json +++ b/helm/defectdojo/values.schema.json @@ -399,6 +399,29 @@ "containerSecurityContext": { "type": "object", "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, "runAsUser": { "type": "integer" } diff --git a/helm/defectdojo/values.yaml b/helm/defectdojo/values.yaml index bba288d5dbf..3098508694a 100644 --- a/helm/defectdojo/values.yaml +++ b/helm/defectdojo/values.yaml @@ -286,8 +286,14 @@ django: nginx: # Container security context for the nginx containers. containerSecurityContext: - # nginx dockerfile sets USER=1001 - runAsUser: 1001 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 101 + runAsGroup: 101 # To extra environment variables to the nginx container, you can use extraEnv. For example: # extraEnv: # - name: FOO