如何在Django管理命令中设置环境变量并实现凭证内存缓存
解决方案
核心思路是通过shell包装函数承接Python进程输出的凭证设置指令,直接在当前父shell中生效,全程不会将敏感信息写入磁盘,shell退出时环境变量自动销毁,完全满足需求。
步骤1:修改Django管理命令逻辑
调整命令输出逻辑:所有业务提示输出到标准错误流(stderr),仅将需要父shell执行的export凭证语句输出到标准输出流(stdout),避免输出混杂。
import os from subprocess import run, PIPE, Popen from getpass import getpass import sys from django.core.management.base import BaseCommand SUDO_ENV_KEY = 'SUDO_PASSWORD' GIT_ENV_KEY = 'GIT_PASSWORD' class Command(BaseCommand): def handle(self, **options): export_cmds = [] # ----获取SUDO权限---- if not (sudo_pass := os.environ.get(SUDO_ENV_KEY)): sudo_pass = getpass(f"请输入sudo密码: ", stream=sys.stderr) export_cmds.append(f"export {SUDO_ENV_KEY}='{sudo_pass}'") # 通过STDIN传递密码,避免bash历史泄露 command = ['echo', '正在获取sudo权限...'] p = Popen(['sudo', '-S'] + command, stdin=PIPE, stderr=PIPE, universal_newlines=True) # 业务输出打到stderr,不影响标准输出的指令解析 print(p.communicate(sudo_pass + '\n')[1], file=sys.stderr) # ----获取GIT权限---- if os.environ.get(GIT_ENV_KEY) != "True": print('正在添加GIT SSH部署密钥...', file=sys.stderr) run(['ssh-add', f'/home/username/.ssh/github'], check=True, stderr=sys.stderr, stdout=sys.stderr) export_cmds.append(f"export {GIT_ENV_KEY}='True'") # 输出所有需要父shell执行的export命令 if export_cmds: print(';'.join(export_cmds))
提示:如果用户密码可能包含单引号、特殊符号,可以在Python侧将敏感值做base64编码后再拼接进export语句,shell侧自动解码,避免转义异常。
步骤2:添加shell包装函数
在你常用的shell配置文件(/.bashrc、/.zshrc等)中添加以下包装函数,替换为你实际的Django项目路径:
function run-deploy { # 进入Django项目根目录,请调整为你的实际路径 cd /path/to/your/django/project # 执行Django命令,将stdout输出的export语句直接在当前shell执行 eval "$(python manage.py $@)" }
修改配置后执行source ~/.bashrc(zsh用户执行source ~/.zshrc)使其生效。
使用方式
后续直接运行包装命令即可:
run-deploy 你的命令名
- 首次运行会提示输入密码,输入后凭证会被export到当前shell的环境变量中
- 后续在同一个shell窗口再次运行命令,会直接读取环境变量中的凭证,无需重复输入
- 关闭当前shell窗口后,环境变量自动销毁,不会残留任何敏感信息
额外优化建议
- SSH密钥添加操作实际上是依托
ssh-agent实现的,只要ssh-agent进程不退出,添加的密钥默认会缓存400秒,无需自己额外标记状态,可以按需删除GIT_ENV_KEY相关逻辑 - 如果需要限制密码缓存时长,可以在shell包装函数中添加定时unset环境变量的逻辑,进一步提升安全性
内容的提问来源于stack exchange,提问作者run_the_race
相关产品推荐
相关产品推荐

