Browse Source

Feature/harden container security following OWASP best practices (#3614)

* Harden container security

* Update changelog
pull/3632/head
Nuno 2 months ago
committed by GitHub
parent
commit
e0068c4d5d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      CHANGELOG.md
  2. 8
      Dockerfile
  3. 7
      docker/docker-compose.build.yml
  4. 5
      docker/docker-compose.dev.yml
  5. 29
      docker/docker-compose.yml

6
CHANGELOG.md

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Hardened container security by switching to a non-root user, setting the filesystem to read-only, and dropping unnecessary capabilities
## 2.100.0 - 2024-08-03
### Added

8
Dockerfile

@ -11,7 +11,7 @@ COPY ./package.json package.json
COPY ./package-lock.json package-lock.json
COPY ./prisma/schema.prisma prisma/schema.prisma
RUN apt update && apt install -y \
RUN apt-get update && apt-get install -y --no-install-suggests \
g++ \
git \
make \
@ -50,16 +50,18 @@ RUN npm run database:generate-typings
# Image to run, copy everything needed from builder
FROM node:20-slim
LABEL org.opencontainers.image.source="https://github.com/ghostfolio/ghostfolio"
ENV NODE_ENV=production
RUN apt update && apt install -y \
RUN apt-get update && apt-get install -y --no-install-suggests \
curl \
openssl \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /ghostfolio/dist/apps /ghostfolio/apps
COPY ./docker/entrypoint.sh /ghostfolio/entrypoint.sh
RUN chown -R node:node /ghostfolio
WORKDIR /ghostfolio/apps/api
EXPOSE ${PORT:-3333}
USER node
CMD [ "/ghostfolio/entrypoint.sh" ]

7
docker/docker-compose.build.yml

@ -6,7 +6,6 @@ services:
- ../.env
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer
NODE_ENV: production
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD}
ports:
@ -21,8 +20,9 @@ services:
interval: 10s
timeout: 5s
retries: 5
postgres:
image: postgres:15
image: docker.io/library/postgres:15
env_file:
- ../.env
healthcheck:
@ -32,8 +32,9 @@ services:
retries: 5
volumes:
- postgres:/var/lib/postgresql/data
redis:
image: redis:alpine
image: docker.io/library/redis:alpine
env_file:
- ../.env
command: ['redis-server', '--requirepass', $REDIS_PASSWORD]

5
docker/docker-compose.dev.yml

@ -1,6 +1,6 @@
services:
postgres:
image: postgres:15
image: docker.io/library/postgres:15
container_name: postgres
restart: unless-stopped
env_file:
@ -9,8 +9,9 @@ services:
- ${POSTGRES_PORT:-5432}:5432
volumes:
- postgres:/var/lib/postgresql/data
redis:
image: redis:alpine
image: docker.io/library/redis:alpine
container_name: redis
restart: unless-stopped
env_file:

29
docker/docker-compose.yml

@ -1,12 +1,16 @@
services:
ghostfolio:
image: ghostfolio/ghostfolio:latest
image: docker.io/ghostfolio/ghostfolio:latest
init: true
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
env_file:
- ../.env
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?connect_timeout=300&sslmode=prefer
NODE_ENV: production
REDIS_HOST: redis
REDIS_PASSWORD: ${REDIS_PASSWORD}
ports:
@ -21,8 +25,19 @@ services:
interval: 10s
timeout: 5s
retries: 5
postgres:
image: postgres:15
image: docker.io/library/postgres:15
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_READ_SEARCH
- FOWNER
- SETGID
- SETUID
security_opt:
- no-new-privileges:true
env_file:
- ../.env
healthcheck:
@ -32,8 +47,14 @@ services:
retries: 5
volumes:
- postgres:/var/lib/postgresql/data
redis:
image: redis:alpine
image: docker.io/library/redis:alpine
user: '999:1000'
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
env_file:
- ../.env
command: ['redis-server', '--requirepass', $REDIS_PASSWORD]

Loading…
Cancel
Save