【问题标题】:Securing a localhost port for a Flask/Celery app running locally on 0.0.0.0 in Docker on MacOS保护本地运行的 Flask/Celery 应用程序的 localhost 端口,该应用程序在 MacOS 上的 Docker 中的 0.0.0.0 上本地运行
【发布时间】:2020-12-21 19:56:13
【问题描述】:

我的应用有一个 Flask 后端和一个 Angular/Electron 前端。该应用程序在 Mac Catalina 上本地运行。 Flask、Celery 和 Redis 位于单独的 docker 容器中,而前端位于 Docker 之外。 Flask 容器正在侦听端口 0.0.0.0:5078。我已将 CORS 策略设置为仅允许来自“127.0.0.1:4200”的消息由前端发送。无需互联网连接。后端容器将由前端通过模拟终端命令来启动。我将在非技术用户的 Catalina MacBook 上远程安装该应用程序。

问题: 根据Docker might be exposing ports to the worldBeware of exposing ports in DockerDocker not blocked by macOS firewall,0.0.0.0:5078 的这种使用是一种安全威胁。我怎样才能解决这个威胁,例如通过阻止任何外部连接到这个端口?

这是一些 python 3.8 代码

# imports: waitress, flask_cors, blueprint
cors = CORS(blueprint, resources={r"/*": {"origins":["http://127.0.0.1:4200"]}})
if __name__ == "__main__":
      serve(flask_app, host= '0.0.0.0', port=5078, threads=8)

这是 Dockerfile:

FROM python:3.8.3-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
ENV BUILD_DEPS="build-essential" \
    APP_DEPS="curl libpq-dev"

RUN apt-get update \
  && apt-get install -y ${BUILD_DEPS} ${APP_DEPS} --no-install-recommends \
  && pip install --default-timeout=10000 -r requirements.txt

ARG FLASK_ENV="development"
ENV FLASK_ENV="${FLASK_ENV}" \
    FLASK_APP="back5x.api.app" \
    PYTHONUNBUFFERED="true"\
    FLASK_DEBUG=1
COPY  . .

RUN ["chmod", "+x", "/app/docker-entrypoint.sh"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
EXPOSE 5078
CMD ["python", "main.py"]

还有 docker-compose:

version: "3.8"
services:
  redis:
 #    ...

  web:
    build:
      context: "."
      args:
        - "FLASK_ENV=development"
    depends_on:
      - "redis"
      - "worker"
    env_file:
      - ".env"
    environment:
      FLASK_DEBUG: 1
      FLASK_APP: back5x.api.app.py
    healthcheck:
      test: "${DOCKER_HEALTHCHECK_TEST:-curl localhost:5078/healthy}"
        ...
    ports:
      - "5078:5078"
    restart: "unless-stopped"
    volumes:
       - ".:/app"

  worker: #celery worker
    ...
volumes:
  redis: {}

试过了: 我发现的基于 Docker 的解决方案使用 Linux iptables,例如 Disallow egress from Docker containers on Docker for Mac 和上述参考资料。所以我将这些添加到 Dockerfile 中:

RUN apt-get install -y iptables  --no-install-recommends   #after pip install
RUN iptables -N DOCKER-USER   #after COPY . .
RUN iptables -I FORWARD -j DOCKER-USER
RUN iptables -A DOCKER-USER -j RETURN
RUN iptables -I DOCKER-USER -i eth0 ! -s 0.0.0.0 -j DROP

没有中间三行,我得到一个错误,找不到DOCKER-USER;与他们一起,我必须以 root 身份运行。我已经尝试过特权模式和app_cap,但由于我是 Docker 新手,所以我还没有让它工作。

我还研究了在 Mac 的 PF 防火墙中定义一条规则,以阻止与相关端口的外部连接。但是,这对于将使用我的应用程序的人来说并不理想。类似的情况是安装付费的“小飞贼”应用程序。

在走这条路之前,是否有代码或基于 Docker 的解决方案? (或者也许有一个合适的命令来启动后端?)

【问题讨论】:

  • 您应该能够设置ports: ['127.0.0.1:5078:5078'] 和类似的设置 Docker 不对外发布端口。 iptables 无法在 MacOS 主机或 Dockerfile 上运行。 (你能用原生 Javascript 重写“后端”部分,并拥有一个独立的非 Docker Electron 应用程序吗?)
  • @DavidMaze 在后端有很多 python 统计/数字运算的东西,所以在 JS 中很难做到。 AFAIK Electron/GUI 不适合放入 docker。但是设置 ports: ['127.0.0.1:5078:5078'] 会解决问题吗?即,仍然从 Electron 收到消息但没有互联网连接? – 薛定谔科德
  • 使用 127.0.0.1:5078 将只允许 Mac 上运行的进程进行连接。链接的出口问题解决了另一个问题,即来自容器的出站流量。

标签: macos docker security flask docker-compose


【解决方案1】:

一个可行的解决方案基于 David Maze 和 Matt 的 cmets 以及此 question。这些是步骤:

  1. 打开 Docker for MacPreferencesDocker Engine。在 json 配置文件中添加 "ip": "127.0.0.1"
  2. docker-compose 中,将 ports 设置为 "127.0.0.1:5078:5078" 以获取 web 服务。
  3. 保持Dockerfile和python代码不变:即flask主机还是0.0.0.0

当我检查时,来自 Electron 的 localhost 4201 的消息通过了。此外,运行 netstat -anvp tcp | awk 'NR<3 || /LISTEN/ 表明不安全端口0.0.0.0.5078 不再暴露于外部。 `

【讨论】:

    猜你喜欢
    • 2019-05-24
    • 2021-08-31
    • 2018-08-31
    • 2011-06-17
    • 2019-11-20
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    相关资源
    最近更新 更多