Как я могу защитить свое Dockerized приложение Django + PostgreSQL в рабочей среде на VPS с помощью Nginx?

Я использую Django и PostgreSQL для своего веб-проекта, который я контейнеризировал с помощью Docker. Я запускаю его на VPS и обслуживаю с помощью Nginx (работающего вне Docker).

Я обеспокоен безопасностью своей базы данных PostgreSQL и хочу убедиться, что она должным образом заблокирована. В частности, я хочу понять рекомендации по защите базы данных в следующих случаях:

  • Контейнеры Docker работают в автономном режиме
  • Служба PostgreSQL находится внутри Docker
  • Nginx действует как веб-точка входа с хоста

Мои вопросы:

  1. Как я могу гарантировать, что мой контейнер PostgreSQL не будет доступен в общедоступном Интернете?
  2. Какие улучшения безопасности, специфичные для Docker и PostgreSQL, я могу применить?
  3. Следует ли мне внести какие-либо изменения в следующий файл Dockerfile или docker-compose-prod.yml?

Мой текущий файл Dockerfile

FROM python:3.x.x

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=x
ENV PYTHONUNBUFFERED=x

WORKDIR /src

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# Install Poetry
RUN curl -sSL https://install.python-poetry.org | python3 - && \
    export PATH="/root/.local/bin:$PATH"

# Add this line to make sure Poetry is in the PATH for subsequent commands
ENV PATH="/root/.local/bin:$PATH"

COPY pyproject.toml poetry.lock* ./

# # Install dependencies
RUN poetry config virtualenvs.create false \
    && poetry install --no-interaction --no-ansi


# Copy the rest of the code
COPY . .

Мой текущий файл docker-compose-prod.yml

services:
  web:
    restart: always
    build:
      context: .
    command: bash -c "demo command"
    ports:
      - "8002:8002"
    volumes:
      - .:/src
      - other-demo-volumes....
    depends_on:
      - db
    environment:
      - demo environment

  db:
    restart: always
    image: postgres:16.2
    volumes:
      - app-pg-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB_HOST=${POSTGRES_HOST}
      - POSTGRES_PORT=${DB_PORT}

volumes:
  app-pg-data:
  other-demo-volumes....

  1. Улучшена четкость и сфокусированность. Добавлен соответствующий код для проверки
  2. Устранены проблемы с безопасностью PostgreSQL в Docker на VPS

Как я могу гарантировать, что мой контейнер PostgreSQL не будет доступен в общедоступном Интернете?

Если у него нет функции Compose ports:, он недоступен по сети. (Для полноты картины, network_mode: host также сделает его доступным по сети, но, как правило, вам следует избегать этой опции.)

Какие улучшения безопасности, специфичные для Docker и PostgreSQL, я могу применить?

Убедитесь, что ваш контейнер не имеет доступа к файловой системе хоста; удалите volumes: из файла Compose, который (для чтения и записи) монтирует содержимое хоста в контейнер. Соответственно, обычно вам следует убедиться, что содержимое вашего изображения принадлежит пользователю root и недоступно для записи во всем мире, а затем запускается от имени пользователя, не являющегося пользователем root. Это предотвратит случайную перезапись кода приложения или статических ресурсов.

FROM python:3.x.x

# Create the non-root user.
#
# This is independent of the application content, so you save a minor bit of time
# during rebuilds doing it first.  The syntax is different for Alpine-based images
# (but Python should almost always use a Debian/Ubuntu base).  The user ID does not
# need to match anything else in particular and you shouldn't need to manually
# specify it.
#
# Do NOT chown files to this user.
RUN adduser --system appuser

# Do all the other setup as before, still as root.
ENV ...
COPY ...
RUN pip install ...

# Switch to the non-root user only at the end, when you're otherwise specifying
# what the default runtime behavior is.
USER appuser
CMD ["demo", "command"]

Следует ли мне внести какие-либо изменения в следующий файл Dockerfile или docker-compose-prod.yml?

Рассмотрите возможность использования многоступенчатой сборки, чтобы избежать сохранения очень тяжелого набора инструментов C из пакета build-essential в конечном образе.

Предпочтительнее указывать значение по умолчанию CMD в файле Docker, а не переопределять значение command: в файле Compose. Предпочитайте sh -c вместо bash -c и избегайте синтаксиса, специфичного для bash; для простых команд, которые не используют несколько команд, замену окружения или другие функции оболочки, полностью пропустите оболочку.

Не монтируйте содержимое в контейнер, который скрывает содержимое изображения. Таргетинг на монтирование /src скрывает почти все, что есть в образе, и это означает, что вы запускаете все, что есть на целевой машине, а не то, что вы тестировали в своей среде CI.

По возможности, также избегайте монтирования чего-либо еще в контейнер вашего приложения. Обычно это означает, что все данные хранятся в базе данных или в каком-либо доступном по сети хранилище. Если у вас есть тома для "обмена файлами" между контейнером приложения и обратным прокси-сервером, имейте в виду, что это не особенно надежный подход, и, в частности, вы не увидите обновлений своего статического содержимого, если обновите изображение. Контейнеры с отслеживанием состояния сложнее запускать в таких средах, как Kubernetes, где хранилище файловой системы должно быть доступно по сети и где у вас часто будет запущено несколько копий вашего контейнера.

Вернуться на верх