【问题标题】:create jenkins ssh username with private key credential via rest xml api通过rest xml api创建带有私钥凭据的jenkins ssh用户名
【发布时间】:2022-05-12 18:18:50
【问题描述】:

基本上,我正在尝试通过 Rest API 在 jenkins 上创建凭据。使用下面的xml数据:

<?xml version='1.0' encoding='UTF-8'?>
<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
    <scope>GLOBAL</scope>
    <id>jenkins-github-ssh</id>
    <description>jenkins-github-ssh</description>
    <username>username</username>
    <directEntryPrivateKeySource>
        <privateKey>-----BEGIN OPENSSH PRIVATE KEY-----
*****************************************
-----END OPENSSH PRIVATE KEY-----</privateKey>
    </directEntryPrivateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>

在调用 REST 发布请求后,我可以看到 credential。但是当我将此凭证用于 GitHub 存储库时,Jenkins 说:

无法连接到存储库:命令“git ls-remote -h -- git@github.com:***.git HEAD”返回状态码 128: 标准输出: 标准错误:加载密钥“/tmp/ssh3978703187838467164.key”:格式无效 git@github.com:权限被拒绝(公钥)。 致命:无法从远程存储库读取。

但是,如果我使用上面相同的私钥手动更新由 rest api 创建的凭据。有用。发布时不知何故钥匙坏了。你们有什么想法给我指出解决方案吗?

Jenkins 2.198 和 SSH 凭证插件 1.17.3

谢谢

【问题讨论】:

标签: jenkins ssh credentials


【解决方案1】:

在通过 Python 脚本将私有 SSH 密钥推送到 Jenkins 时,我遇到了完全相同的问题。我正在使用 Requests 库在 Jenkins 服务器上的任意凭据存储中创建和更新 SSH 密钥凭据集。

一般问题是您的 XML 结构部分错误。标签

<directEntryPrivateKeySource>

必须替换为

<privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">

获取基本的 XML 结构

按照以下步骤,您可以自己从 Jenkins 服务器获取正确的 XML 结构:

  1. 手动创建 SSH 密钥凭据项。在下面的示例中,密钥的 id 是 test-sshkey。让我们将它放在位于文件夹“API-Test”的凭证存储中,该文件夹是“Playground”的子文件夹,即 Playground/API-Test
  2. 当您在 Jenkins UI 中单击新创建的凭据项时,其 URL 应如下所示:

    https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/test-sshkey/

  3. /config.xml 添加到上面的 URL 中,使其看起来像这样:

    https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/test-sshkey/config.xml

第 3 步中 URL 返回的 XML 结构几乎具有我们在使用 Credentials API 时所需的结构,但部分不完整:

<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey plugin="ssh-credentials@1.18.1">
  <id>test-sshkey</id>
  <description>DELETE AFTER USE</description>
  <username>test</username>
  <privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
    <privateKey>
      <secret-redacted/>
    </privateKey>
  </privateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>

使用凭据 API

添加标签 &lt;scope&gt;&lt;passphrase&gt; 以获得可以 POST 到 Credentials API 的有效 XML 脚手架:

<com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
    <scope>GLOBAL</scope>
    <id>CREDENTIAL_ID</id>
    <description>MY_DESCRIPTION</description>
    <username>A_USERNAME</username>
    <passphrase>OPTIONAL_KEY_PASSWORD</passphrase>
    <privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
        <privateKey>YOUR_PRIVATE_SSH_KEY_GOES_HERE</privateKey>
    </privateKeySource>
</com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>

警告:如果提交的 XML 结构错误,凭据插件的 REST API 仍会接受它并返回误导性 HTTP 状态代码 200!

现在我们可以使用这个 XML 结构将其发布到 API 端点,以便通过 cURL 或类似工具创建或更新。我们假设所有操作都在文件夹“Playground/API-Test”的凭证存储中执行。

以下 Python 代码示例完全“简化”以专注于一般方法:

def addCredentialSetSshPrivateKey(self, credentialDataObj):
    """
    Adds a credential set with a private SSH key to a credential store
    credentialDataObj: An instance of a simple DTO
    """
    jenkinsRequestUrl = "https://ci-yoda-new.codemanufaktur.com/job/Playground/job/API-Test/credentials/store/folder/domain/_/createCredentials"
    authentication = ("jenkins_admin_user", "API-TOKEN_FOR_THE_USER")

    completeSamlData = """
    <com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
        <scope>GLOBAL</scope>
        <id>{0}</id>
        <description>{1}</description>
        <username>{2}</username>
        <passphrase>{3}</passphrase>
        <privateKeySource class="com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource">
            <privateKey>{4}</privateKey>
        </privateKeySource>
    </com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey>
    """.format(credentialDataObj.id(), credentialDataObj.description(), credentialDataObj.username(), credentialDataObj.key_passphrase(), credentialDataObj.private_ssh_key())

    # When using CSRF protection in Jenkins a API crumb must be included in the actual REST call.
    # The following method requests the Jenkins Crumb Issuer for a API crumb and returns a JSON object like this:
    # {'_class': 'hudson.security.csrf.DefaultCrumbIssuer', 'crumb': 'a5d36ef09e063322169888f0b81341fe13b4109482a7936bc08c6f9a01badd39', 'crumbRequestField': 'Jenkins-Crumb'}
    jsonCrumb = self._requestApiCrumb()

    # The actual REST call with headers, XML payload and all other bells and whistles.
    remoteSession = requests.Session()
    return remoteSession.post(jenkinsRequestUrl, auth = authentication, headers = {"content-type":"application/xml", jsonCrumb['crumbRequestField']:jsonCrumb['crumb']}, data = completeSamlData)

用于创建 SSH 凭证项的 REST 端点https://JENKINS_HOSTNAME/job/Playground/job/API-Test/credentials/store/folder/domain/_/createCredentials

用于更新 SSH 凭证项的 REST 端点https://ci-yoda-new.codemanufaktur.com/job/Playground/job/API-Test/credentials/store/folder/domain/_/credential/credential_ci-yoda-new-project-apex_privatekey/config.xml

显然在后一种情况下,您只需更新现有凭据项的 config.xml 文件。

另请参阅凭据插件的user guideREST API 部分,特别是用于构建正确的 REST URL。如需使用 Python 请求 Jenkins crumb issuer,请参阅this StackOverflow answer

解决方案测试:

  • 詹金斯 2.214
  • 凭据插件 2.3.1
  • SSH 凭据插件 1.18.1

【讨论】:

    【解决方案2】:

    对于遇到完全相同问题的人;

    我尝试将其作为文件上传、使用 API 上传、使用 jenkins CLI 等。我尝试的一切都失败了。同样的问题也在这里发布;

    https://issues.jenkins.io/browse/JENKINS-60714

    所以最终起作用的步骤解释如下;

    1. 将 Jenkins 配置安装和配置为代码插件。

    2. 上传您的配置类似于下面的 yaml 文件。

    您可能还想将私钥内容定义为 Jenkins 实例中的环境变量,并将其用作“${private_key}”,而不是显式粘贴。

    jenkins:
      systemMessage: "Example of configuring credentials in Jenkins"
    
    credentials:
      system:
        domainCredentials:
        - credentials:
          - basicSSHUserPrivateKey:
              description: "kro"
              id: "kro"
              scope: GLOBAL
              username: "kro"
              privateKeySource:
                directEntry:
                  privateKey: |
                    -----BEGIN RSA PRIVATE KEY-----
                    MIIG5AIBAAKCAYEAvuiaIDs+ydzR7Xxo5Owvv+G9/arbqN0YwhaGQQlicJjM4ZvI
                  ..........YOUR KEY.............
                    53Zg4QmSb1XGKUTXxIeGd27OIvgkwAn7K/cjQsU9t802iYV3tisnfA==
                    -----END RSA PRIVATE KEY-----
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 2017-03-01
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多