Ansible jenkins_plugin 模块 returns "HTTP Error 403: No valid crumb was included in the request"

Ansible jenkins_plugin module returns "HTTP Error 403: No valid crumb was included in the request"

我正在使用 Ansible (v 2.8) 作为 Packer 模板背后的配置器来为 Jenkins 主节点构建 AMI。对于以前的版本,剧本成功通过。但是,从 Jenkins 版本 2.176.3 开始,jenkins_plugin 模块一直在抛出:

HTTP Error 403: No valid crumb was included in the request

我已取回面包屑并将其注册到一个变量中。我尝试使用 http_agent 字段将其传递给 jenkins_plugin,但这不起作用。我尝试使用 attributes,但这也无济于事。除非我遗漏了一些非常基本的东西,否则我已经束手无策了。

- name:               Get Jenkins Crumb
  uri:
    force_basic_auth: yes
    url_username:     ****
    url_password:     ****
    url:              http://localhost:8080/crumbIssuer/api/json
    return_content:   yes
  register:           jenkins_crumb
  until:              jenkins_crumb.content.find('Please wait while Jenkins is getting ready') == -1
  retries:            10
  delay:              5

- name:               Install plugin
  jenkins_plugin:
    name:             "{{ item }}"
    version:          latest
    force_basic_auth: yes
    url_username:     ****
    url_password:     ****
    http_agent:       "Jenkins-Crumb:{{ jenkins_crumb.json.crumb }}"
  with_items:         "{{ jenkins_plugins }}"

我期待已安装的插件和愉快构建的 AMI。我得到的是 "HTTP Error 403: No valid crumb was included in the request" 并且 Packer 构建失败。

看起来 2.176 LTS release 中的 crumb 发布者发生了变化,强制将初始令牌生成调用的 Web 会话 ID 与使用所述 crumb 的后续调用中的 crumb 一起包含在内。

CSRF tokens (crumbs) are now only valid for the web session they were created in to limit the impact of attackers obtaining them. Scripts that obtain a crumb using the /crumbIssuer/api URL will now fail to perform actions protected from CSRF unless the scripts retain the web session ID in subsequent requests.

除了建议您暂时禁用 CSRF 之外,同一文档还建议您只能禁用新功能,而不是整个 CSRF,这应该允许您的 packer/ansible 像以前一样完成照原样做了。

To disable this improvement you can set the system property hudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID to true.

编辑:

/etc/default/jenkins 中添加以下行清除了我自己的剧本中的 CSRF 问题(Ansible 2.8.4、Ubuntu 18.04、OpenJDK 11.0.4)

JAVA_ARGS="$JAVA_ARGS -Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true"

在工具维护者赶上 API 变化之前,这可能是一个足够好的拐杖。

我也遇到了这个问题,并给出了需要在会话中完成的工作的指针,我为 ansible 打开了一个 PR:

https://github.com/ansible/ansible/issues/61672 https://github.com/ansible/ansible/issues/61673

这是一个小改动,应该可以为您的本地安装打补丁。

更新:补丁已在 Ansbile 中应用 v2.8.9 and v2.9.1 如果您有旧版本,请务必升级 ansible。

我最终应用的解决方案是使用 a handy piece of Groovy 禁用 CSRF,然后在播放结束时重新启用它。

感谢大家的帮助和建议。

这正是@runningEagle 提到的原因。您需要将初始会话 cookie 值与面包屑一起传播到所有后续请求。

需要新的 Ansible 代码修改:

...

# Requesting the crumb
uri:
  url: "<crumb_URL>"
register: response

...

# Actual action request
uri:
  url: "<action_URL>"
  headers: '{ ... , "Cookie": "{{ response.set_cookie }}", ... }'

...

已尝试根据 /etc/default/jenkins(大多数 Linux)和 /etc/sysconfig/jenkins (RHEL) 的文档设置以下内容:

hudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID to true

因此添加:

JAVA_ARGS="-Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true

但无济于事。使用@Yuri answer 为我修复了它。见下文:

和之前一样要求面包屑。 面包屑:

- uri:
    url: "http://localhost:8080/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)"
    return_content: yes
  register: crumb

操作请求:

    uri:
      method: POST
      url: "http://localhost:8080/credentials/store/system/domain/_/createCredentials"
      headers:
        Jenkins-Crumb: "{{ crumb.content.split(':')[1] }}"
        Cookie: "{{ crumb.set_cookie }}"
      body: |
        json={
          "": "0",
          "credentials": {
            "scope": "GLOBAL",
            "id": "identification",
            "username": "manu",
            "password": "bar",
            "description": "linda",
            "$class": "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
          }
        }
      status_code: 302

分辨率:

  • 安装名为 Strict Crumb Issue 的插件

  • 转到管理 Jenkins -> 配置全局安全 -> CSRF 保护。

  • Select 严格的碎屑发行者。

  • 单击“高级”。

  • 取消选中“检查会话 ID”框。

  • 保存。