18.9.5 权限与凭据安全最佳实践
权限与凭据是 Jenkins 安全基线,实践应覆盖授权模型、凭据全生命周期与审计三条主线,并配合系统与网络加固,确保“最小权限 + 最小暴露 + 可审计”。
原理草图:权限与凭据流转
1) 授权模型与配置示例#
推荐启用 Matrix 或 Role-Based Strategy,禁止匿名访问与过度授权,并将权限隔离到 Folder/Job 级别。
安装与启用 Role Strategy 插件(示例)
# 在插件管理中安装: Role-based Authorization Strategy
# 也可通过脚本化方式(Jenkins Script Console)自动安装
# 进入: Manage Jenkins -> Script Console
def instance = Jenkins.getInstance()
def pm = instance.getPluginManager()
def uc = instance.getUpdateCenter()
def plugin = pm.getPlugin("role-strategy")
if (plugin == null) {
uc.getPlugin("role-strategy").deploy()
println("role-strategy plugin deploying...")
} else {
println("role-strategy already installed")
}
配置角色与权限(Groovy 示例)
// Script Console: 创建全局/项目角色并绑定用户
import com.michelin.cio.hudson.plugins.rolestrategy.*
import hudson.security.*
def strategy = new RoleBasedAuthorizationStrategy()
Jenkins.instance.setAuthorizationStrategy(strategy)
def adminRole = new Role("admin", ".*")
adminRole.add(Permission.fromId("hudson.model.Hudson.Administer"))
def devRole = new Role("dev", "project-.*")
devRole.add(Permission.fromId("hudson.model.Item.Read"))
devRole.add(Permission.fromId("hudson.model.Item.Build"))
devRole.add(Permission.fromId("hudson.model.Item.Workspace"))
def readRole = new Role("read", ".*")
readRole.add(Permission.fromId("hudson.model.Item.Read"))
strategy.addRole(RoleBasedAuthorizationStrategy.GLOBAL, adminRole)
strategy.addRole(RoleBasedAuthorizationStrategy.PROJECT, devRole)
strategy.addRole(RoleBasedAuthorizationStrategy.PROJECT, readRole)
strategy.assignRole(RoleBasedAuthorizationStrategy.GLOBAL, adminRole, "admin")
strategy.assignRole(RoleBasedAuthorizationStrategy.PROJECT, devRole, "dev_user")
strategy.assignRole(RoleBasedAuthorizationStrategy.PROJECT, readRole, "auditor")
Jenkins.instance.save()
println("Roles configured.")
排错要点
- 若用户无法访问某 Job,检查 Job 名匹配正则 与 Folder 继承。
- Permission.fromId 不存在时报错,确认 Jenkins 核心版本与插件版本兼容。
2) 凭据安全:存储、绑定与掩码#
统一进入 Credentials Store,避免脚本/日志明文。按 System/Folder/Job 作用域分层。
添加 SSH Key 凭据(示例)
// Script Console: 添加全局 SSH 凭据
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.jenkins.plugins.sshcredentials.impl.*
def store = Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
def key = new BasicSSHUserPrivateKey(
CredentialsScope.GLOBAL,
"git-ssh",
"git",
new BasicSSHUserPrivateKey.UsersPrivateKeySource(),
null,
"git ssh key"
)
store.addCredentials(Domain.global(), key)
println("SSH credential added.")
Pipeline 中使用凭据(含掩码)
pipeline {
agent any
stages {
stage('Checkout') {
steps {
sshagent (credentials: ['git-ssh']) {
sh 'git clone git@github.com:org/repo.git'
}
}
}
stage('Publish') {
steps {
withCredentials([usernamePassword(
credentialsId: 'registry-cred',
usernameVariable: 'REG_USER',
passwordVariable: 'REG_PASS'
)]) {
sh '''
echo "Logging in registry..."
echo "$REG_PASS" | docker login -u "$REG_USER" --password-stdin registry.example.com
'''
}
}
}
}
}
排错要点
- “Credentials not found” 多因作用域不匹配(Folder vs Global)。
- 日志中出现明文,检查是否使用 withCredentials/sshagent,并确保未 echo 密文。
3) 系统与网络加固示例#
禁止以 root 运行 & HTTPS 反代
# systemd 服务用户最小化
sudo sed -i 's/^User=.*/User=jenkins/' /etc/systemd/system/jenkins.service
sudo systemctl daemon-reload && sudo systemctl restart jenkins
# Nginx 反代 + HTTPS 安全头 (片段)
cat >/etc/nginx/conf.d/jenkins.conf <<'EOF'
server {
listen 443 ssl;
server_name jenkins.example.com;
ssl_certificate /etc/ssl/certs/jenkins.crt;
ssl_certificate_key /etc/ssl/private/jenkins.key;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'self'";
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}
EOF
nginx -t && systemctl reload nginx
4) 审计与告警示例#
开启安全日志(Jenkins 系统日志)
// Script Console: 添加安全相关日志记录器
import java.util.logging.*
def logger = Logger.getLogger("hudson.security")
logger.setLevel(Level.FINE)
println("Security logger set to FINE")
告警思路(Prometheus/日志平台)
- 关键事件:异常登录、权限提升、凭据频繁读取。
- 规则示例:同一用户 5 分钟内多次失败登录告警。
5) 典型故障与修复清单#
- 无法登录/权限丢失:检查
config.xml中authorizationStrategy与securityRealm是否被覆盖。 - 凭据消失:检查
credentials.xml是否损坏,必要时从备份恢复并重启。 - 节点绕过权限:限制 Agent 标签与执行权限,禁止不可信节点执行敏感任务。
修复示例:回滚安全配置
# 备份后替换 config.xml
cp /var/lib/jenkins/config.xml /var/lib/jenkins/config.xml.bak
cp /var/lib/jenkins/backup/config.xml /var/lib/jenkins/config.xml
chown jenkins:jenkins /var/lib/jenkins/config.xml
systemctl restart jenkins
6) 练习题(可操作)#
- 创建
dev角色,仅允许构建project-*的 Job,验证auditor只读访问。 - 在 Folder 级别创建凭据并在 Pipeline 中使用,确认日志无明文。
- 将 Jenkins 置于 Nginx 反代 HTTPS 下,访问
https://jenkins.example.com验证安全头。