安全配置
安全性是 Jenkins 生产环境部署的关键考量。Jenkins 存储着源代码访问凭证、部署密钥、云平台凭证等敏感信息,一旦被入侵可能导致严重的安全事故。本章将详细介绍 Jenkins 的安全配置,包括认证、授权、凭据管理和安全最佳实践。
安全架构概述
Jenkins 的安全体系由两个核心概念构成:认证(Authentication)和授权(Authorization)。
认证(Security Realm):解决"你是谁"的问题,验证用户身份。认证系统决定了用户如何登录 Jenkins,支持本地用户数据库、LDAP、GitHub OAuth 等多种方式。
授权(Authorization):解决"你能做什么"的问题,控制用户权限。授权系统决定了已认证用户可以访问哪些资源、执行哪些操作。
认证配置
Jenkins 本地用户数据库
这是默认的认证方式,Jenkins 维护自己的用户数据库。适合小型团队或独立使用的场景。
配置步骤:
- 导航到 Manage Jenkins → Security
- 在 Security Realm 部分选择 Jenkins' own user database
- 可选择是否允许用户注册
用户管理:
Manage Jenkins → Users → Create User
用户信息存储在 JENKINS_HOME/users/ 目录下,每个用户有一个独立的配置目录。
LDAP 集成
企业环境通常使用 LDAP(Lightweight Directory Access Protocol)进行统一的用户管理。Jenkins 可以与 LDAP 服务器集成,实现单点登录。
安装插件:LDAP Plugin
配置步骤:
- 导航到 Manage Jenkins → Security
- 在 Security Realm 部分选择 LDAP
- 配置 LDAP 连接参数:
Server: ldap://ldap.example.com:389
# 或使用 SSL
Server: ldaps://ldap.example.com:636
root DN: dc=example,dc=com
User Search Base: ou=users
User Search Filter: uid={0}
Group Search Base: ou=groups
Group Search Filter: cn={0}
Manager DN: cn=admin,dc=example,dc=com
Manager Password: ********
配置示例:
Server: ldap://ldap.company.com:389
root DN: dc=company,dc=com
User Search Base: ou=People,dc=company,dc=com
User Search Filter: (uid={0})
Group Search Base: ou=Groups,dc=company,dc=com
Group Search Filter: (cn={0})
Group Membership: Search for LDAP groups containing user
Group membership filter: (member={0})
Active Directory 集成
对于使用 Microsoft Active Directory 的企业,可以使用 AD 插件进行集成。
安装插件:Active Directory Plugin
配置步骤:
Domain Name: company.com
Domain Controller: dc1.company.com
Site: Default-First-Site-Name
Bind DN: cn=jenkins,ou=ServiceAccounts,dc=company,dc=com
Bind Password: ********
OAuth 集成
支持 GitHub、GitLab、Google 等 OAuth 提供商进行认证。
GitHub OAuth 配置:
- 安装 GitHub OAuth Plugin
- 在 GitHub 创建 OAuth App,获取 Client ID 和 Client Secret
- 在 Jenkins 配置:
GitHub Web URI: https://github.com
GitHub API URI: https://api.github.com
Client ID: your-client-id
Client Secret: your-client-secret
OAuth Scope: read:org,user:email
SAML 集成
对于使用 SAML 2.0 的企业单点登录系统(如 Okta、Azure AD),可以使用 SAML 插件。
安装插件:SAML Plugin
配置步骤:
IdP Metadata URL: https://idp.example.com/metadata
SP Entity ID: https://jenkins.example.com
授权配置
授权策略决定了用户可以执行哪些操作。选择合适的授权策略对安全至关重要。
安全矩阵(Matrix-based security)
安全矩阵提供细粒度的权限控制,推荐用于生产环境。
配置步骤:
- 导航到 Manage Jenkins → Security
- 在 Authorization 部分选择 Matrix-based security
- 添加用户/组,分配权限
权限类型:
| 权限类别 | 权限名称 | 说明 |
|---|---|---|
| Overall | Administer | 完全管理权限 |
| Overall | Read | 查看 Jenkins 首页 |
| Overall | RunScripts | 执行 Groovy 脚本(Script Console) |
| Credentials | Create | 创建凭据 |
| Credentials | Update | 更新凭据 |
| Credentials | Delete | 删除凭据 |
| Job | Build | 触发构建 |
| Job | Cancel | 取消构建 |
| Job | Configure | 配置任务 |
| Job | Create | 创建任务 |
| Job | Delete | 删除任务 |
| Job | Read | 查看任务 |
| View | Configure | 配置视图 |
| View | Create | 创建视图 |
| View | Delete | 删除视图 |
推荐配置示例:
匿名用户:Overall Read(仅查看首页,无法登录)
authenticated(所有已登录用户):
- Overall Read
- Job Read
- Job Build
developers 组:
- Overall Read
- Job Read, Build, Cancel
- View Read
admins 组:
- Overall Administer
- 所有权限
项目级矩阵授权
项目级矩阵授权是对全局矩阵的补充,允许在项目级别配置权限。
配置步骤:
- 在全局安全配置中选择 Project-based Matrix Authorization Strategy
- 在项目配置页面配置项目级权限
示例场景:允许 frontend-team 组只能访问前端相关的项目,backend-team 组只能访问后端相关的项目。
角色策略插件
Role-based Authorization Strategy 插件提供更灵活的角色管理机制。
安装插件:Role-based Authorization Strategy
配置步骤:
- 选择 Role-Based Strategy 授权策略
- 导航到 Manage Jenkins → Manage and Assign Roles
- 创建角色并分配权限
角色类型:
- Global Roles:全局角色,应用于整个 Jenkins
- Project Roles:项目角色,使用正则匹配项目名称
- Slave Roles:节点角色,控制 Agent 访问权限
配置示例:
Global Roles:
- admin: 所有权限
- developer: Job Read, Build, Cancel, Workspace
- viewer: Job Read, View Read
Project Roles:
- frontend-.*: 匹配所有 frontend- 开头的项目
- backend-.*: 匹配所有 backend- 开头的项目
- deploy-.*: 匹配所有 deploy- 开头的项目
Assign Roles:
- alice: admin
- bob: developer, frontend-.*
- charlie: developer, backend-.*
凭据管理
凭据(Credentials)是 Jenkins 存储敏感信息的机制,包括密码、SSH 密钥、API Token 等。正确管理凭据是 Jenkins 安全的关键。
凭据类型
| 类型 | 用途 | 示例 |
|---|---|---|
| Username with password | 用户名密码对 | Git 仓库凭证 |
| SSH Username with private key | SSH 密钥认证 | Git SSH、服务器登录 |
| Secret file | 敏感文件 | 配置文件、证书文件 |
| Secret text | 文本形式的密钥 | API Token、密码 |
| Certificate | PKCS#12 证书 | 客户端证书 |
凭据范围
System:仅 Jenkins 系统内部使用,Pipeline 无法直接访问。适合存储 Jenkins 系统本身需要的凭据,如 LDAP 绑定密码。
Global:全局可用,所有 Pipeline 都可以访问。这是最常用的范围。
Folder:仅在特定文件夹内可用,实现凭据的隔离。适合多团队共享 Jenkins 实例的场景。
创建凭据
通过 Web 界面创建:
- 导航到 Manage Jenkins → Credentials → System → Global credentials
- 点击 Add Credentials
- 选择类型并填写信息
在 Pipeline 中使用凭据
pipeline {
agent any
environment {
// 引用凭据
GIT_CREDS = credentials('github-credentials')
// 使用后自动解压为 USER 和 PSW 两个变量
// GIT_CREDS_USR: 用户名
// GIT_CREDS_PSW: 密码
}
stages {
stage('Checkout') {
steps {
// 使用凭据检出代码
git credentialsId: 'github-credentials',
url: 'https://github.com/example/repo.git'
}
}
stage('Deploy') {
steps {
// 使用 withCredentials 包装器
withCredentials([
usernamePassword(
credentialsId: 'server-credentials',
usernameVariable: 'SERVER_USER',
passwordVariable: 'SERVER_PASS'
),
sshUserPrivateKey(
credentialsId: 'ssh-key',
keyFileVariable: 'SSH_KEY_FILE',
usernameVariable: 'SSH_USER'
),
string(
credentialsId: 'api-token',
variable: 'API_TOKEN'
)
]) {
sh '''
ssh -i $SSH_KEY_FILE $SSH_USER@server "deploy.sh"
curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com
'''
}
}
}
}
}
SSH Agent 使用
使用 sshagent 步骤进行 SSH 密钥认证:
stage('Deploy') {
steps {
sshagent(['ssh-deploy-key']) {
sh '''
ssh -o StrictHostKeyChecking=no user@server << EOF
cd /opt/app
git pull
docker-compose up -d --build
EOF
'''
}
}
}
凭据安全最佳实践
最小权限原则:为凭据分配最小必要的权限。例如,部署用的 Git 凭据只需要读取权限,不需要写入权限。
定期轮换:定期更换密码和密钥,避免长期使用同一凭据。
使用文件夹隔离:为不同团队或项目创建独立的文件夹,凭据存储在对应的文件夹中,实现权限隔离。
审计凭据使用:定期检查凭据的使用情况,删除不再使用的凭据。
避免在日志中泄露:
// 错误做法 - 密码可能出现在日志中
echo "Password: ${env.PASSWORD}"
// 正确做法 - 使用 mask-passwords 插件
wrap([$class: 'MaskPasswordsBuildWrapper']) {
echo "Deploying..."
sh './deploy.sh'
}
控制器隔离与 Agent→Controller 访问控制
为什么不在内置节点上执行构建?
Jenkins 开箱即用时会将构建运行在内置节点(Built-in Node)上,这是为了方便快速上手,但在生产环境中强烈不建议这样做。
构建过程通常由以下几类人员控制,他们的信任程度往往低于 Jenkins 管理员:
- 拥有 Job/Configure 权限的 Jenkins 用户
- 构建脚本作者(
pom.xml、Makefile等) - 代码作者(例如在构建过程中执行的测试代码)
这些人员都对构建期间执行的命令有一定程度的控制权。如果在内置节点上运行构建,构建过程与 Jenkins 控制器进程拥有相同的文件系统访问权限,存在以下风险:
- 恶意构建脚本可以访问 Jenkins 主目录中的敏感配置
- 可能读取或修改凭据存储
- 可能篡改 Jenkins 核心配置
- 构建错误可能导致控制器崩溃
配置控制器隔离
禁用内置节点的构建执行:
- 导航到 Manage Jenkins → Nodes and Clouds
- 选择 Built-In Node
- 点击 Configure
- 将执行器数量设置为 0
- 保存配置
这样配置后,所有构建都必须在 Agent 上执行,实现控制器与构建环境的隔离。
替代方案:如果没有额外的机器运行 Agent,可以在同一台机器上以不同的操作系统用户运行 Agent 进程。这种情况下,需要确保:
- Agent 进程没有对 Jenkins 主目录的文件系统访问权限(读写都应禁止)
- Agent 进程不能使用 Jenkins 控制器用户的权限
Agent→Controller 访问控制
Jenkins 控制器和 Agent 可以看作是一个分布式系统,执行跨越多个进程和机器。这种架构允许 Agent 向控制器进程请求信息,例如文件内容,甚至可以让控制器在 Agent 请求时执行某些命令。
这意味着,即使不使用内置节点进行构建,被恶意用户接管的 Agent 进程仍然可能获取数据或在 Jenkins 控制器上执行命令。为了防止这种情况,Jenkins 提供了 Agent→Controller 访问控制 系统。
访问控制状态:
- 从 Jenkins 2.326 开始,该系统始终启用,无法禁用
- 在 Jenkins 2.325 及更早版本中,默认启用,但可以在 Web UI 中禁用(不推荐)
强烈建议不要禁用 Agent→Controller 访问控制系统。
访问控制的工作原理
当 Agent→Controller 访问控制启用时,Agent 进程发出的请求会受到限制:
- Agent 只能访问有限的控制器功能
- 敏感操作会被阻止
- 文件系统访问受到严格控制
这确保了即使 Agent 被攻陷,攻击者也无法轻易获取控制器上的敏感数据或执行任意命令。
安全配置最佳实践
网络安全
HTTPS 配置
强烈建议为 Jenkins 启用 HTTPS,加密传输敏感数据。
使用反向代理(推荐):
Nginx 配置示例:
server {
listen 443 ssl http2;
server_name jenkins.example.com;
ssl_certificate /etc/nginx/ssl/jenkins.crt;
ssl_certificate_key /etc/nginx/ssl/jenkins.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
listen 80;
server_name jenkins.example.com;
return 301 https://$server_name$request_uri;
}
Jenkins 配置:
Manage Jenkins → System → Jenkins URL
设置为: https://jenkins.example.com/
防火墙配置
限制 Jenkins 的网络访问:
# 仅允许特定 IP 访问 Jenkins Web
sudo ufw allow from 10.0.0.0/8 to any port 8080
# 仅允许 Agent 连接端口
sudo ufw allow from 10.0.0.0/8 to any port 50000
CSRF 保护
Jenkins 默认启用 CSRF 保护,防止跨站请求伪造攻击。
验证 CSRF 保护已启用:
Manage Jenkins → Security → CSRF Protection
确保已勾选 Enable CSRF Protection
API 调用时处理 CSRF:
# 获取 CSRF Token
CRUMB=$(curl -s 'http://jenkins.example.com/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)' -u user:token)
# 使用 Token 调用 API
curl -X POST -H "$CRUMB" http://jenkins.example.com/job/myjob/build -u user:token
禁用不必要的功能
禁用 CLI:
// 在 Jenkins 配置中禁用 CLI
jenkins.model.Jenkins.instance.getDescriptor("jenkins.CLI").setEnabled(false)
禁用旧版协议:
Manage Jenkins → System → Agent protocols
仅保留:
- JNLP4-connect
- Ping
审计与监控
审计日志
安装 Audit Trail Plugin 记录用户操作:
Loggers: Local File Logger
Log file: /var/log/jenkins/audit.log
Log file size: 100MB
Log files count: 10
审计日志内容示例:
2024-01-15 10:30:45 INFO alice created job 'frontend-app'
2024-01-15 10:31:22 INFO bob started build 'backend-api #42'
2024-01-15 10:45:33 INFO alice updated credentials 'github-deploy-key'
2024-01-15 11:00:00 INFO admin updated security configuration
登录失败监控
安装 Login Trial Plugin 监控登录尝试:
Manage Jenkins → Security → Login Trial
配置:
- Maximum trials: 5
- Block duration: 300 seconds
安全扫描
定期使用安全扫描工具检查 Jenkins:
# 使用 jenkins-security-scan
docker run --rm -v $(pwd):/app \
jenkinsciinfra/jenkins-security-scan \
--jenkinsfile /app/Jenkinsfile
安全最佳实践清单
初始安装后
- 修改默认管理员密码
- 禁用匿名用户访问
- 配置安全的授权策略
- 启用 CSRF 保护
认证与授权
- 使用企业级认证(LDAP/OAuth)
- 实施最小权限原则
- 定期审计用户权限
- 禁用不再使用的账户
凭据管理
- 所有敏感信息存储在凭据中
- 使用文件夹隔离凭据
- 定期轮换密钥和密码
- 审计凭据使用情况
网络安全
- 启用 HTTPS
- 配置防火墙规则
- 使用反向代理
- 限制 Agent 连接来源
系统维护
- 定期更新 Jenkins 和插件
- 监控安全公告
- 启用审计日志
- 配置备份策略
Agent 安全
- 控制器不执行构建任务
- Agent 使用专用账户
- 限制 Agent 网络访问
- 定期更新 Agent 环境
常见安全问题
问题 1:忘记管理员密码
解决方案:
- 停止 Jenkins 服务
- 编辑
config.xml,禁用安全:
<useSecurity>false</useSecurity>
- 重启 Jenkins,修改密码
- 重新启用安全配置
或者使用 Script Console(需要管理员权限):
import jenkins.model.*
import hudson.security.*
def instance = Jenkins.getInstance()
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount("admin", "new-password")
instance.setSecurityRealm(hudsonRealm)
instance.save()
问题 2:权限配置错误被锁定
解决方案:
修改 config.xml,重置授权配置:
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
问题 3:凭据泄露
解决方案:
- 立即轮换泄露的凭据
- 检查审计日志,确认泄露范围
- 评估是否需要撤销所有相关 Token
- 加强凭据管理流程
小结
Jenkins 安全配置是多层次的系统工程:
- 认证:选择合适的认证方式,与企业身份系统集成
- 授权:实施最小权限原则,使用矩阵或角色策略
- 凭据管理:安全存储敏感信息,定期轮换
- 网络安全:启用 HTTPS,配置防火墙
- 审计监控:记录操作日志,及时发现异常
下一步
- 分布式构建 - Agent 安全配置
- 多分支 Pipeline - 多分支项目的权限控制
- 共享库 - 共享库的安全考量