如何在Docker容器开启SSH服务的同时完全禁用其互联网访问?
如何在Docker容器开启SSH服务的同时完全禁用其互联网访问?
一、核心问题:开启SSH+彻底禁用容器外网访问
要实现「能SSH进容器但容器完全无外网」,得分两步走:先构建带SSH服务的镜像,再通过网络配置锁死外网访问。
1. 构建带SSH服务的容器镜像
以Ubuntu为例(也可以用更轻量化的Alpine),先做一个包含openssh-server的基础镜像:
FROM ubuntu:latest # 安装SSH服务并清理缓存 RUN apt-get update && apt-get install -y openssh-server && rm -rf /var/lib/apt/lists/* # 创建SSH启动所需的目录 RUN mkdir -p /var/run/sshd # 修改SSH配置,允许root登录(推荐后续换成密钥认证更安全) RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config # 设置root密码(替换成你自己的安全密码) RUN echo 'root:yourSecurePassword123' | chpasswd # 暴露SSH端口 EXPOSE 22 # 前台启动SSH服务 CMD ["/usr/sbin/sshd", "-D"]
执行构建命令:docker build -t ssh-no-internet .
注意:构建镜像时需要联网下载依赖,但运行容器时会彻底切断外网
2. 运行容器并禁用外网访问
这里有两种可靠方案:
方案A:删除容器默认路由(简单直接)
启动容器时映射SSH端口,赋予容器修改网络的权限,之后删除默认路由切断外网:
# 启动容器,映射主机2222端口到容器22端口,添加网络管理权限 docker run -d -p 2222:22 --name restricted-ssh --cap-add NET_ADMIN ssh-no-internet # 进入容器删除默认路由,彻底阻断外网访问 docker exec restricted-ssh ip route del default
之后你就能通过ssh root@你的主机IP -p 2222登录容器,此时容器执行ping google.com会完全失败,但和主机的通信不受影响。
方案B:主机端用iptables锁死容器外网(更彻底)
如果担心容器内被篡改网络配置,直接在主机层面用iptables阻止容器的外网流量:
# 先正常启动容器 docker run -d -p 2222:22 --name restricted-ssh ssh-no-internet # 获取容器的内网IP CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' restricted-ssh) # 添加iptables规则:允许容器和Docker内网通信,禁止访问外部网络 iptables -A FORWARD -s $CONTAINER_IP ! -d 172.17.0.0/16 -j DROP
172.17.0.0/16是Docker默认桥接网络的网段,如果你用了自定义网络,替换成对应网段即可
二、附加问题:Go服务转发docker exec的终端交互问题
关于你之前用Go服务转发docker exec命令时,nano/vim这类交互式命令无法正常显示的问题,核心是没有分配伪终端(PTY)。
解决思路是在调用Docker API时开启PTY并处理双向流:
- 用Go的Docker SDK创建
ExecConfig时,开启伪终端并配置双向附加:execConfig := types.ExecConfig{ AttachStdin: true, AttachStdout: true, AttachStderr: true, Tty: true, // 关键:开启伪终端支持 Cmd: []string{"nano"}, // 替换为用户输入的命令 } - 调用
Client.ExecAttach获取和容器的连接,再把浏览器的WebSocket(浏览器端实时交互必须用WebSocket)和这个连接的stdin/stdout绑定——把用户的键盘输入传给容器,再把容器的终端输出推回浏览器。
这样就能实现和SSH几乎一致的终端交互体验,支持所有需要终端的命令。
备注:内容来源于stack exchange,提问作者Realman78




