My app has a Flask backend and an Angular/Electron frontend. The app runs locally on Mac Catalina. Flask, Celery and Redis are in separate docker containers, while the frontend is outside Docker. The Flask container is listening on port 0.0.0.0:5078. I've set CORS policy to allow messages from "127.0.0.1:4200" only, sent by the frontend. There's no need for internet connections. The backend containers will be launched by the frontend by emulating a terminal command. I'll install the app remotely on non-technical users' Catalina MacBooks.
Question: According to Docker might be exposing ports to the world, Beware of exposing ports in Docker and Docker not blocked by macOS firewall, this use of 0.0.0.0:5078 is a security threat. How can I resolve this threat, eg by block ing any external connections to this port?
Here's some python 3.8 code
# 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)
Here's the 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"]
and the 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: {}
Tried: The Docker-based solutions I've found use Linux iptables, eg Disallow egress from Docker containers on Docker for Mac and the above references. So I've added these to the 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
Without the middle three lines, I got an error that DOCKER-USER couldn't be found; with them, that I must run as a root. I've tried a privileged mode and app_cap
, but as I'm new to Docker, I haven't got this to work.
I've also looked into defining a rule in Mac's PF firewall to block external connections to the port in question. However, this is not ideal for people who'll be using my app. A similar situation is with installing the paid-for "Little Snitch" app.
Before going this route, could there be a code or Docker-based solution? (Or perhaps there is an appropriate command for launching the backend?)