跳到主要内容

安全配置

安全性是 Jenkins 生产环境部署的关键考量。Jenkins 存储着源代码访问凭证、部署密钥、云平台凭证等敏感信息,一旦被入侵可能导致严重的安全事故。本章将详细介绍 Jenkins 的安全配置,包括认证、授权、凭据管理和安全最佳实践。

安全架构概述

Jenkins 的安全体系由两个核心概念构成:认证(Authentication)和授权(Authorization)。

认证(Security Realm):解决"你是谁"的问题,验证用户身份。认证系统决定了用户如何登录 Jenkins,支持本地用户数据库、LDAP、GitHub OAuth 等多种方式。

授权(Authorization):解决"你能做什么"的问题,控制用户权限。授权系统决定了已认证用户可以访问哪些资源、执行哪些操作。

认证配置

Jenkins 本地用户数据库

这是默认的认证方式,Jenkins 维护自己的用户数据库。适合小型团队或独立使用的场景。

配置步骤

  1. 导航到 Manage Jenkins → Security
  2. Security Realm 部分选择 Jenkins' own user database
  3. 可选择是否允许用户注册

用户管理

Manage Jenkins → Users → Create User

用户信息存储在 JENKINS_HOME/users/ 目录下,每个用户有一个独立的配置目录。

LDAP 集成

企业环境通常使用 LDAP(Lightweight Directory Access Protocol)进行统一的用户管理。Jenkins 可以与 LDAP 服务器集成,实现单点登录。

安装插件:LDAP Plugin

配置步骤

  1. 导航到 Manage Jenkins → Security
  2. Security Realm 部分选择 LDAP
  3. 配置 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 配置

  1. 安装 GitHub OAuth Plugin
  2. 在 GitHub 创建 OAuth App,获取 Client ID 和 Client Secret
  3. 在 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)

安全矩阵提供细粒度的权限控制,推荐用于生产环境。

配置步骤

  1. 导航到 Manage Jenkins → Security
  2. Authorization 部分选择 Matrix-based security
  3. 添加用户/组,分配权限

权限类型

权限类别权限名称说明
OverallAdminister完全管理权限
OverallRead查看 Jenkins 首页
OverallRunScripts执行 Groovy 脚本(Script Console)
CredentialsCreate创建凭据
CredentialsUpdate更新凭据
CredentialsDelete删除凭据
JobBuild触发构建
JobCancel取消构建
JobConfigure配置任务
JobCreate创建任务
JobDelete删除任务
JobRead查看任务
ViewConfigure配置视图
ViewCreate创建视图
ViewDelete删除视图

推荐配置示例

匿名用户:Overall Read(仅查看首页,无法登录)
authenticated(所有已登录用户):
- Overall Read
- Job Read
- Job Build

developers 组:
- Overall Read
- Job Read, Build, Cancel
- View Read

admins 组:
- Overall Administer
- 所有权限

项目级矩阵授权

项目级矩阵授权是对全局矩阵的补充,允许在项目级别配置权限。

配置步骤

  1. 在全局安全配置中选择 Project-based Matrix Authorization Strategy
  2. 在项目配置页面配置项目级权限

示例场景:允许 frontend-team 组只能访问前端相关的项目,backend-team 组只能访问后端相关的项目。

角色策略插件

Role-based Authorization Strategy 插件提供更灵活的角色管理机制。

安装插件:Role-based Authorization Strategy

配置步骤

  1. 选择 Role-Based Strategy 授权策略
  2. 导航到 Manage Jenkins → Manage and Assign Roles
  3. 创建角色并分配权限

角色类型

  • 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 keySSH 密钥认证Git SSH、服务器登录
Secret file敏感文件配置文件、证书文件
Secret text文本形式的密钥API Token、密码
CertificatePKCS#12 证书客户端证书

凭据范围

System:仅 Jenkins 系统内部使用,Pipeline 无法直接访问。适合存储 Jenkins 系统本身需要的凭据,如 LDAP 绑定密码。

Global:全局可用,所有 Pipeline 都可以访问。这是最常用的范围。

Folder:仅在特定文件夹内可用,实现凭据的隔离。适合多团队共享 Jenkins 实例的场景。

创建凭据

通过 Web 界面创建:

  1. 导航到 Manage Jenkins → Credentials → System → Global credentials
  2. 点击 Add Credentials
  3. 选择类型并填写信息

在 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.xmlMakefile 等)
  • 代码作者(例如在构建过程中执行的测试代码)

这些人员都对构建期间执行的命令有一定程度的控制权。如果在内置节点上运行构建,构建过程与 Jenkins 控制器进程拥有相同的文件系统访问权限,存在以下风险:

  • 恶意构建脚本可以访问 Jenkins 主目录中的敏感配置
  • 可能读取或修改凭据存储
  • 可能篡改 Jenkins 核心配置
  • 构建错误可能导致控制器崩溃

配置控制器隔离

禁用内置节点的构建执行

  1. 导航到 Manage Jenkins → Nodes and Clouds
  2. 选择 Built-In Node
  3. 点击 Configure
  4. 将执行器数量设置为 0
  5. 保存配置

这样配置后,所有构建都必须在 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:忘记管理员密码

解决方案

  1. 停止 Jenkins 服务
  2. 编辑 config.xml,禁用安全:
<useSecurity>false</useSecurity>
  1. 重启 Jenkins,修改密码
  2. 重新启用安全配置

或者使用 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:凭据泄露

解决方案

  1. 立即轮换泄露的凭据
  2. 检查审计日志,确认泄露范围
  3. 评估是否需要撤销所有相关 Token
  4. 加强凭据管理流程

小结

Jenkins 安全配置是多层次的系统工程:

  • 认证:选择合适的认证方式,与企业身份系统集成
  • 授权:实施最小权限原则,使用矩阵或角色策略
  • 凭据管理:安全存储敏感信息,定期轮换
  • 网络安全:启用 HTTPS,配置防火墙
  • 审计监控:记录操作日志,及时发现异常

下一步