Jenkins运行含Paramiko的Python脚本遇SSH密钥权限问题求解决方案
Got it, let's work through this problem step by step. You're absolutely right to avoid loosening permissions on your id_rsa file—opening it up to all users is a huge security risk, and SSH will actually refuse to use keys with overly permissive settings anyway. Here are three secure, practical solutions:
方案1:让Jenkins以ec2-user身份执行特定脚本
This is the simplest fix if you want to keep using your existing ec2-user key without modifying your script much:
- First, edit the sudoers file to allow the
jenkinsuser to run your specific Python script asec2-userwithout entering a password. Runsudo visudoand add this line at the end:
Note: Always usejenkins ALL=(ec2-user) NOPASSWD: /usr/bin/python3.8 /home/ec2-user/db_refresh.pyvisudoto edit sudoers—it checks for syntax errors to avoid locking yourself out. - Then, update your Jenkins build command to:
sudo -u ec2-user python3.8 /home/ec2-user/db_refresh.py
This restricts the jenkins user to only running that exact script as ec2-user, so you don't grant unnecessary broad permissions.
方案2:为Jenkins用户创建独立的SSH密钥对
This follows the principle of least privilege—each user has their own dedicated SSH key:
- Switch to the
jenkinsuser:sudo su - jenkins - Generate a new RSA key pair (skip the passphrase if you don't want to deal with it in Jenkins, or set one and store it in Jenkins Credentials later):
ssh-keygen -t rsa -b 4096 - Copy the public key (
/var/lib/jenkins/.ssh/id_rsa.pub) to your target database server's~SSH_USERNAME/.ssh/authorized_keysfile (replaceSSH_USERNAMEwith the user you use to connect to the DB server). - Update your Python script's
key_filenamepath to point to Jenkins' private key:sshcon.connect(MYSQL_HOST, username=SSH_USERNAME, key_filename='/var/lib/jenkins/.ssh/id_rsa')
This keeps permissions tight (only jenkins can access its own key) and avoids sharing ec2-user's credentials.
方案3:利用Jenkins凭据管理存储私钥
This is the most CI/CD-friendly approach, as Jenkins handles secure credential storage:
- In Jenkins, go to Manage Jenkins > Manage Credentials and add a new credential:
- Choose the Secret text type, paste the full content of your
ec2-userprivate key into the "Secret" field, and give it a descriptive ID (likessh_db_refresh_key). - Alternatively, use Secret file if you want to upload the key file directly.
- Choose the Secret text type, paste the full content of your
- In your Jenkins job, configure the build to inject this credential as an environment variable (under Build Environment > Inject environment variables to the build process, or use the Credentials Binding plugin to map it to a variable like
SSH_PRIVATE_KEY). - Modify your Python script to use the private key content from the environment variable instead of a file path:
import os from io import StringIO import paramiko sshcon = paramiko.SSHClient() sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # Don't forget this if you haven't already # Load private key from environment variable private_key_content = os.environ.get('SSH_PRIVATE_KEY') if not private_key_content: raise ValueError("SSH_PRIVATE_KEY environment variable not set") private_key = paramiko.RSAKey.from_private_key(StringIO(private_key_content)) sshcon.connect(MYSQL_HOST, username=SSH_USERNAME, pkey=private_key)
Jenkins will securely inject the credential only for the duration of the build, and the temporary content won't linger on the server.
推荐选择
- If you want minimal changes to your script and setup, go with 方案1.
- If you prefer strict permission isolation, 方案2 is the cleanest long-term solution.
- If you're building out a mature CI/CD pipeline, 方案3 aligns with best practices for credential management.
内容的提问来源于stack exchange,提问作者Mohammad Faisal

