Puppet 4.10中的自定义函数仅返回哈希中的第一个数组项

时间:2018-08-08 10:25:10

标签: ruby puppet

Puppet中的一个自定义函数,该函数从数据库读取SSL证书,并将其结果作为哈希数组返回。此功能用于使我们的代理服务器上的SSL证书保持最新。

在创建代理虚拟主机时,我们将读取SSL证书以确定该虚拟主机应在哪些主机上处于活动状态。为此,我们从证书中检索“主题备用名称”并将其解析为一个数组。

以下代码提取SAN:

def subject_alt_names
  san = @x509.extensions.find { |e| e.oid == 'subjectAltName' }
  san.value.split(',').map { |name| name.strip.sub!('DNS:', '') }
end

@x509变量包含OpenSSL::X509::Certificate.new的实例,而subject_alt_names产生证书中期望的名称数组。

到目前为止一切顺利!

现在,当收集所有证书时,我们会根据从数据库中检索到的结果创建一个哈希数组。

代码类似于:

Puppet::Functions.create_function(:'certificates') do
  dispatch :up do
  end

  def up
    # Omitted DB calls

    mappings.map { |mapping|
      certificate = Certificate.new(
        OpenSSL::X509::Certificate.new(mapping['certificate']),
        OpenSSL::PKey::RSA.new(mapping['private_key']),
        mapping['intermediates']
      )

      {
        'common_name' => certificate.common_name,
        'domains' => certificate.subject_alt_names,
        'private_key' => certificate.private_key,
        'certificate' => certificate.x509,
        'intermediates' => certificate.chain
      }
    }
  end
end

在Puppet中调用函数时,哈希中的domains数组仅包含一个条目(“ domain.tld”),而不是两个条目(“ domain.tld”和“ www.domain.tld”)。数据库中的大多数SSL证书都包含两个SAN名称。

一个非常简单的测试函数会产生我们期望的结果:

Puppet::Functions.create_function(:'certificates_test') do
  dispatch :up do
  end

  def up
    test = "DNS:domain.tld, DNS:www.domain.tld, DNS: www2.domain.tld"

    domains = test.split(',').map { |name| name.strip.sub!('DNS:', '') }

    {
      'domains' => domains
    }
  end
end

输出:

{
    "domains" => ["domain.tld", "www.domain.tld"]
}

在Puppet中执行代码时,仅返回“域”数组中的第一个条目。该功能在Puppet中的调用方式如下:

certificates().each |$certificate| {
    $domains = $certificate['domains']

    # Omitted defining of hosts based on $certificate
}

在CentOS上的Puppet 4.10.12(服务器2.8.1)上运行。

facter rubysitedir rubyversion的输出:

rubysitedir => /opt/puppetlabs/puppet/lib/ruby/site_ruby/2.1.0
rubyversion => 2.1.9

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

通过更新证书类的“ subject_alt_names”方法解决了此问题。我认为Puppet有时会使开发扩展变得困难,因为自定义函数是使用JRuby执行的(这有所不同)。在这种情况下,我使用的OpenSSL扩展并不会以一个字符串返回所有SAN名称,而是将其拆分并使其成为一个哈希数组。

以下代码与JRuby和Ruby的OpenSSL扩展一起使用(其中x509参数是OpenSSL::X509::Certificate的实例):

def subject_alt_names x509
  names = []

  x509.extensions.each do |e|
    next if e.oid != 'subjectAltName'

    names << e.value.split(',').map { |name|
      name.strip.sub!('DNS:', '')
    }
  end

  names
end

感谢所有评论!这真的帮助我弄清楚了:)