Docker部署FastAPI时如何限制仅同网络serviceA容器可访问serviceB
问题原因
你对TrustedHostMiddleware的作用存在误解,这是配置不生效的核心原因:
TrustedHostMiddleware的校验对象是HTTP请求头中的Host字段,该字段标识的是请求要访问的目标主机地址,而非请求的来源地址。你从serviceA向serviceB发请求时,Host字段值为serviceB的服务名/IP,所以你配置允许的Host为serviceA相关值时,所有请求都会命中拦截规则。- 你的配置写法存在错误:
Host字段本身不携带http://这类协议前缀,哪怕是按该中间件的正确用法,填写带协议的地址也属于无效配置。
解决方案
推荐优先选择Docker网络层面的控制方案,无需修改业务代码,安全性更高:
方案1:Docker网络隔离(推荐)
利用Docker的bridge网络实现访问限制,公网完全无法触达serviceB,仅同网络内的serviceA可访问:
- 先创建专属内部网络:
docker network create --driver bridge internal-only
- 启动容器时,仅给serviceA配置公网端口映射,serviceB不配置任何端口映射,两个服务都接入上述内部网络即可。
如果使用docker-compose部署,参考配置如下:
version: '3.8' services: serviceA: build: ./serviceA ports: - "8000:8000" # 仅serviceA暴露公网端口 networks: - internal-net serviceB: build: ./serviceB # 不配置ports字段,公网无访问入口 networks: - internal-net networks: internal-net: driver: bridge
方案2:代码层来源校验
如果确实需要将serviceB暴露到公网,仅允许serviceA的请求访问,可以自定义中间件校验请求来源IP:
from fastapi import FastAPI, Request, HTTPException import socket # 预解析serviceA的容器IP列表,Docker内部网络中serviceA的IP变更时可以定时刷新该列表 ALLOWED_CLIENT_IPS = set(socket.gethostbyname_ex('serviceA')[2]) async def check_origin_middleware(request: Request, call_next): client_ip = request.client.host if client_ip not in ALLOWED_CLIENT_IPS: raise HTTPException(status_code=403, detail="Forbidden") return await call_next(request) def get_application(): app = FastAPI(title=server_config.PROJECT_NAME, version=server_config.VERSION) # 移除原来的TrustedHostMiddleware配置,替换为自定义的来源校验中间件 app.middleware("http")(check_origin_middleware) return app app = get_application()
如果serviceA有固定公网出口IP,也可以直接将ALLOWED_CLIENT_IPS配置为固定的公网IP值。
内容的提问来源于stack exchange,提问作者Pepo。
相关产品推荐
相关产品推荐

