You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署Flask SSH代理转发应用遇公钥权限拒绝问题

问题诊断与解决方案

核心问题

容器内手动启动SSH代理并添加密钥后,终端进程能正常使用代理转发,但Flask应用进程无法获取到SSH代理的环境变量,导致调用SSH命令时找不到代理,触发Permission denied (publickey)错误。

原因分析

  1. 用户环境隔离:Docker Compose指定容器以root用户启动,但Flask应用最终以tester用户运行。手动在终端执行的ssh-agent和ssh-add是在root用户环境下,而Flask进程属于tester用户,两者环境变量不共享。
  2. 环境变量未传递:SSH代理依赖SSH_AUTH_SOCK和SSH_AGENT_PID两个关键环境变量,Flask进程启动时没有继承这些变量,导致SSH命令无法找到代理套接字。
  3. 权限问题:挂载的SSH密钥文件在/root/.ssh目录下,tester用户没有读取权限,即使传递了环境变量,也无法访问密钥或代理套接字。

解决方案

方案1:统一用户环境,自动启动SSH代理

调整容器启动流程,让tester用户自动启动SSH代理并加载密钥,确保Flask进程继承代理环境变量。

1. 修改Dockerfile

FROM python:3.11-slim-bullseye

# 更新/安装必要的库
RUN apt-get -y update && apt-get install -y openssh-client curl sudo && rm -rf /var/lib/apt/lists/*

# 创建tester用户并配置权限
RUN adduser --disabled-password --gecos "" tester
RUN adduser tester sudo
RUN mkdir -p /home/tester/.ssh && chown -R tester:tester /home/tester/.ssh && chmod 700 /home/tester/.ssh

RUN pip3 install poetry

# 创建项目目录并设置权限
WORKDIR /home/tester/config-app
COPY . .
RUN chown -R tester:tester /home/tester/config-app

# 通过poetry安装Python依赖
RUN poetry config virtualenvs.create false
RUN poetry install

USER tester

# 切换到应用目录
WORKDIR /home/tester/config-app/src/config_fetcher

# 编写启动脚本,自动启动SSH代理并启动Flask
COPY start.sh /home/tester/start.sh
RUN chmod +x /home/tester/start.sh

CMD ["/home/tester/start.sh"]

2. 创建启动脚本start.sh

#!/bin/bash

# 启动SSH代理
eval $(ssh-agent -s)

# 添加密钥(如果密钥路径有变化,自行调整)
ssh-add /home/tester/.ssh/id_ed25519

# 启动Flask应用
poetry run flask --app app run --host 0.0.0.0 --port 5000

3. 修改docker-compose.yml

调整volume挂载路径到tester用户的.ssh目录,移除不必要的user: root配置:

version: '3.8'
services:
  config-fetcher:
    image: config-app
    volumes:
      - ~/.ssh/config:/home/tester/.ssh/config:rw
      - ~/.ssh/id_ed25519:/home/tester/.ssh/id_ed25519:rw
      - ~/.ssh/id_ed25519.pub:/home/tester/.ssh/id_ed25519.pub:rw
      - ~/.ssh/known_hosts:/home/tester/.ssh/known_hosts:rw
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - "5000:5000"

方案2:Flask代码中显式指定SSH密钥(无需代理转发)

如果不想依赖SSH代理,可以在SSH命令中直接指定密钥文件,绕过代理:

修改get_config_via_ssh函数中的命令:

def get_config_via_ssh(user, host, tunnel_ip):
    try:
        # 直接指定密钥文件路径,替换为容器内tester用户的密钥路径
        cmd2 = f"ssh -i /home/tester/.ssh/id_ed25519 -A -tt {user}@{host} -tt \"ssh -i /home/tester/.ssh/id_ed25519 root@{tunnel_ip} 'cat /storage/config'\""
        process = subprocess.getoutput(cmd2, encoding='utf-8')
        cleaner = ConfigCleaner()
        return cleaner.clean(process)
    except Exception as e:
        print(e)
        print("[!] Cannot connect to the device SSH Server")
        return {"error": str(e)}  # 不要直接exit,避免Flask进程退出

额外注意事项

  • 确保挂载的密钥文件权限正确:容器内/home/tester/.ssh/id_ed25519权限应为600,可以在启动脚本中添加chmod 600 /home/tester/.ssh/id_ed25519命令调整。
  • 如果远程主机需要验证指纹,提前在known_hosts文件中添加对应主机的指纹,避免SSH交互提示。

内容的提问来源于stack exchange,提问作者Dani Danger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 19:20:35