简体   繁体   English

Chef:启用Jenkins安全性会导致插件安装失败

[英]Chef: Enabling Jenkins security causes plugin installation to fail

I am currently using Chef to deploy a Jenkins instance on a managed node. 我目前正在使用Chef在受管节点上部署Jenkins实例。 I am using the following public supermarket cookbook: https://supermarket.chef.io/cookbooks/jenkins . 我正在使用以下公共超市食谱: https : //supermarket.chef.io/cookbooks/jenkins

I am using the following code in my recipe file to enable authentication: 我在我的配方文件中使用以下代码来启用身份验证:

jenkins_script 'activate global security' do
  command <<-EOH.gsub(/^ {4}/, '')
      import jenkins.model.*
      import hudson.security.*
      def instance = Jenkins.getInstance()

      def hudsonRealm = new HudsonPrivateSecurityRealm(false)
      hudsonRealm.createAccount("Administrator","Password")
      instance.setSecurityRealm(hudsonRealm)
      instance.save()

      def strategy = new GlobalMatrixAuthorizationStrategy()
        strategy.add(Jenkins.ADMINISTER, "Administrator")
        instance.setAuthorizationStrategy(strategy)

      instance.save()
  EOH
 end

This works great to setup security on the instance the first time the recipe is run on the managed node. 第一次在受管节点上运行配方时,这对于在实例上设置安全性非常有用。 It creates an administrator user with administrator permissions on the Jenkins server. 它在Jenkins服务器上创建具有管理员权限的管理员用户。 In addition to enabling security on the Jenkins instance, plugins are also installed using this recipe. 除了在Jenkins实例上启用安全性之外,还使用此配方安装插件。

Once security has been enabled, installation of plugins which do not yet exist (but are specified to be installed), fail: 启用安全性后,尚不存在(但已指定要安装)的插件的安装将失败:

ERROR: anonymous is missing the Overall/Read permission

I assume this is an error related to the newly created administrator account, and Chef attempting to install the plugins using the anonymous user as opposed to the administrator user. 我认为这是与新创建的管理员帐户有关的错误,Chef尝试使用匿名用户(而不是管理员用户)安装插件。 Is there anything that should be set in my recipe file in order to work around this permissions issue? 为了解决此权限问题,应在我的配方文件中进行任何设置吗?

The goal here is that in the event a plugin is upgraded to an undesired version or uninstalled completely, running the recipe will reinstall / rollback any plugin changes. 目的是在将插件升级到不需要的版本或完全卸载的情况下,运行配方将重新安装/回滚任何插件更改。 Currently this does not appear to be possible if I also have security enabled on the Jenkins instance. 如果我在Jenkins实例上也启用了安全性,那么目前看来这是不可能的。

EDIT It should also be noted that currently each time I need to repair plugins in this way, I have to disable security then run the entire recipe (plugin installation + security enable). 编辑还应该指出的是,当前每次我需要以这种方式修复插件时,都必须禁用安全性,然后运行整个配方(插件安装+安全性启用)。

Thanks for any help! 谢谢你的帮助!

The jenkins_plugin resource doesn't appear to expose any authentication options so you'll probably need to build your own resource. jenkins_plugin资源似乎没有公开任何身份验证选项,因此您可能需要构建自己的资源。 If you dive in to the code you'll see that the underlying executor layer in the cookbook does support auth (and a whole bunch of other stuff) so it might be easy to do in a copy-fork (and send us a patch) of just that resource. 如果深入研究代码,您会发现菜谱中的底层执行程序层确实支持auth(以及其他很多东西),因此在复制叉中很容易做到(并向我们发送补丁)只是那个资源。

We ran into this because we had previously been defining :jenkins_username and :jenkins_password , but those only work with the remoting protocol which is being deprecated in favor of the REST API being accessed via SSH or HTTPS and in newer releases defaults to DISABLED. 我们之所以:jenkins_username是因为我们之前已经定义了:jenkins_username:jenkins_password ,但是它们仅适用于remoting协议,而remoting协议不建议使用,而希望通过SSH或HTTPS访问REST API,并且在较新的版本中默认为DISABLED。

We ended up combining the logic from @StephenKing's cookbook and the information from chef-cookbooks/jenkins and this GitHub issue comment on that repo to get our plugin installation working after enabling authentication via Active Directory on our instances (we used SSH). 我们最终结合了@StephenKing食谱中的逻辑, chef-cookbooks / jenkins中的信息以及此GitHub在该存储库上发表的评论,以使我们的实例在通过Active Directory启用身份验证后才能安装插件(我们使用SSH)。

We basically pulled the example from https://github.com/TYPO3-cookbooks/jenkins-chefci/blob/e1b82e679074e96de5d6e668b0f10549c48b58d1/recipes/_jenkins_chef_user.rb and removed the portion that automatically generated the key if it didn't exist (our instances stick around and need to be mostly deterministic) and replaced the File.read with a lookup in our encrypted databag (or functional equivalent). 我们基本上从https://github.com/TYPO3-cookbooks/jenkins-chefci/blob/e1b82e679074e96de5d6e668b0f10549c48b58d1/recipes/_jenkins_chef_user.rb中删除了该示例,并删除了如果密钥不存在会自动生成密钥的部分(我们的实例会坚持下去) ,并且基本上需要确定性),并在我们的加密数据包(或功能等效的文件)中用查找替换File.read。

recipes/authentication.rb 食谱/ authentication.rb

require 'aws-sdk'
require 'net/ssh'
require 'openssl'

ssm = Aws::SSM::Client.new(region: 'us-west-2')

unless node.run_state[:jenkins_private_key]

  key_contents = ssm.get_parameter(name: node['jenkins_wrapper']['secrets']['chefjenkins']['id_rsa']['path'], with_decryption: true).parameter.value
  key_path = node['jenkins_wrapper']['secrets']['chefjenkins']['id_rsa']['path']


  key = OpenSSL::PKey::RSA.new key_contents
  # We use `log` here so we can assert the correct path was queried without exposing or hardcoding the secret in our tests
  log 'Successfully read existing private key from ' + key_path

  public_key = [key.ssh_type, [key.to_blob].pack('m0'), 'auto-generated key'].join(' ')

  # Create the Chef Jenkins user with the public key
  jenkins_user 'chefjenkins' do
    id 'chefjenkins' # This also matches up with an Active Directory user
    full_name 'Chef Client'
    public_keys [public_key]
  end

  # Set the private key on the Jenkins executor
  node.run_state[:jenkins_private_key] = key.to_pem

end

# This was our previous implementation that stopped working recently
# jenkins_password = ssm.get_parameter(name: node['jenkins_wrapper']['secrets']['chefjenkins']['path'], with_decryption: true).parameter.value
# node.run_state[:jenkins_username] = 'chefjenkins' # ~FC001
# node.run_state[:jenkins_password] = jenkins_password # ~FC001

recipes/enable_jenkins_sshd.rb 食谱/ enable_jenkins_sshd.rb

port = node['jenkins']['ssh']['port']
jenkins_script 'configure_sshd_access' do
  command <<-EOH.gsub(/^ {4}/, '')
    import jenkins.model.*
    def instance = Jenkins.getInstance()
    def sshd = instance.getDescriptor("org.jenkinsci.main.modules.sshd.SSHD")
    def currentPort = sshd.getActualPort()
    def expectedPort = #{port}

    if (currentPort != expectedPort) {
      sshd.setPort(expectedPort)
    }
    EOH
  not_if "grep #{port} /var/lib/jenkins/org.jenkinsci.main.modules.sshd.SSHD.xml"
  notifies :execute, 'jenkins_command[safe-restart]', :immediately
end

attributes/default.rb 属性/ default.rb

# Enable/disable SSHd.
# If the port is 0, Jenkins will serve SSHd on a random port
# If the port is > 0, Jenkins will serve SSHd on that port specifically
# If the port is is -1 turns off SSHd.
default['jenkins']['ssh']['port'] = 8222

# This happens to be our lookup path in AWS SSM, but
# this could be a local file on Jenkins or in databag or wherever
default['jenkins_wrapper']['secrets']['chefjenkins']['id_rsa']['path'] = 'jenkins_wrapper.users.chefjenkins.id_rsa'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM