diff --git a/REFERENCE.md b/REFERENCE.md
index 0632859..fa4a9b7 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -369,6 +369,7 @@ The following parameters are available in the `openssl::certificate::x509` defin
* [`encrypted`](#-openssl--certificate--x509--encrypted)
* [`ca`](#-openssl--certificate--x509--ca)
* [`cakey`](#-openssl--certificate--x509--cakey)
+* [`cakey_password`](#-openssl--certificate--x509--cakey_password)
##### `ensure`
@@ -648,6 +649,14 @@ provided.
Default value: `undef`
+##### `cakey_password`
+
+Data type: `Optional[Variant[Sensitive[String[1]], String[1]]]`
+
+Optional password that has encrypted the CA key.
+
+Default value: `undef`
+
### `openssl::config`
Generates an openssl.conf file using defaults
@@ -1312,6 +1321,7 @@ The following parameters are available in the `x509_cert` type.
* [`authentication`](#-x509_cert--authentication)
* [`ca`](#-x509_cert--ca)
* [`cakey`](#-x509_cert--cakey)
+* [`cakey_password`](#-x509_cert--cakey_password)
* [`csr`](#-x509_cert--csr)
* [`days`](#-x509_cert--days)
* [`force`](#-x509_cert--force)
@@ -1338,6 +1348,10 @@ The optional ca certificate filepath
The optional ca private key filepath
+##### `cakey_password`
+
+The optional CA key password
+
##### `csr`
The optional certificate signing request path
diff --git a/lib/puppet/provider/x509_cert/openssl.rb b/lib/puppet/provider/x509_cert/openssl.rb
index e5262a7..997d7da 100644
--- a/lib/puppet/provider/x509_cert/openssl.rb
+++ b/lib/puppet/provider/x509_cert/openssl.rb
@@ -99,7 +99,10 @@ def create
'-out', resource[:path]
]
end
- options << ['-passin', "pass:#{resource[:password]}"] if resource[:password]
+
+ password = resource[:cakey_password] || resource[:password]
+
+ options << ['-passin', "pass:#{password}"] if password
options << ['-extensions', 'v3_req'] if resource[:req_ext] != :false
openssl options
end
diff --git a/lib/puppet/type/x509_cert.rb b/lib/puppet/type/x509_cert.rb
index be58061..68ea9b1 100644
--- a/lib/puppet/type/x509_cert.rb
+++ b/lib/puppet/type/x509_cert.rb
@@ -78,6 +78,10 @@
desc 'The optional ca private key filepath'
end
+ newparam(:cakey_password) do
+ desc 'The optional CA key password'
+ end
+
autorequire(:file) do
self[:template]
end
diff --git a/manifests/certificate/x509.pp b/manifests/certificate/x509.pp
index 2aae7c4..3d8a1f1 100644
--- a/manifests/certificate/x509.pp
+++ b/manifests/certificate/x509.pp
@@ -93,6 +93,8 @@
# @param cakey
# Path to CA private key for signing. Undef mean no CAkey will be
# provided.
+# @param cakey_password
+# Optional password that has encrypted the CA key.
#
# @example basic usage
#
@@ -147,6 +149,7 @@
Boolean $encrypted = true,
Optional[Stdlib::Absolutepath] $ca = undef,
Optional[Stdlib::Absolutepath] $cakey = undef,
+ Optional[Variant[Sensitive[String[1]], String[1]]] $cakey_password = undef,
) {
unless $country or $organization or $unit or $state or $commonname {
fail('At least one of $country, $organization, $unit, $state or $commonname is required.')
@@ -179,15 +182,16 @@
encrypted => $encrypted,
}
~> x509_cert { $crt:
- ensure => $ensure,
- template => $cnf,
- csr => $csr,
- days => $days,
- password => $password,
- req_ext => !empty($altnames) or !empty($extkeyusage),
- force => $force,
- ca => $ca,
- cakey => $cakey,
+ ensure => $ensure,
+ template => $cnf,
+ csr => $csr,
+ days => $days,
+ password => $password,
+ req_ext => !empty($altnames) or !empty($extkeyusage),
+ force => $force,
+ ca => $ca,
+ cakey => $cakey,
+ cakey_password => $cakey_password,
}
# Set owner of all files
diff --git a/metadata.json b/metadata.json
index 50a472f..a8afb9a 100644
--- a/metadata.json
+++ b/metadata.json
@@ -36,6 +36,20 @@
"9"
]
},
+ {
+ "operatingsystem": "OracleLinux",
+ "operatingsystemrelease": [
+ "8",
+ "9"
+ ]
+ },
+ {
+ "operatingsystem": "Rocky",
+ "operatingsystemrelease": [
+ "8",
+ "9"
+ ]
+ },
{
"operatingsystem": "AlmaLinux",
"operatingsystemrelease": [
diff --git a/spec/defines/openssl_certificate_x509_spec.rb b/spec/defines/openssl_certificate_x509_spec.rb
index c3b42d3..e5fe21b 100644
--- a/spec/defines/openssl_certificate_x509_spec.rb
+++ b/spec/defines/openssl_certificate_x509_spec.rb
@@ -604,4 +604,111 @@
)
}
end
+
+ context 'when passing CA properties' do
+ let(:params) do
+ {
+ country: 'com',
+ organization: 'bar',
+ commonname: 'baz',
+ state: 'FR',
+ locality: 'here',
+ unit: 'braz',
+ altnames: ['a.com', 'b.com', 'c.com'],
+ extkeyusage: %w[serverAuth clientAuth],
+ email: 'contact@foo.com',
+ days: 4567,
+ key_size: 4096,
+ owner: 'www-data',
+ ca: '/etc/pki/ca.crt',
+ cakey: '/etc/pki/ca.key',
+ cakey_password: '5r$}^',
+ force: false,
+ base_dir: '/tmp/foobar',
+ }
+ end
+
+ it {
+ is_expected.to contain_file('/tmp/foobar/foo.cnf').with(
+ ensure: 'present',
+ owner: 'www-data'
+ ).with_content(
+ %r{countryName\s+=\s+com}
+ ).with_content(
+ %r{stateOrProvinceName\s+=\s+FR}
+ ).with_content(
+ %r{localityName\s+=\s+here}
+ ).with_content(
+ %r{organizationName\s+=\s+bar}
+ ).with_content(
+ %r{organizationalUnitName\s+=\s+braz}
+ ).with_content(
+ %r{commonName\s+=\s+baz}
+ ).with_content(
+ %r{emailAddress\s+=\s+contact@foo\.com}
+ ).with_content(
+ %r{extendedKeyUsage\s+=\s+serverAuth,\s+clientAuth}
+ ).with_content(
+ %r{subjectAltName\s+=\s+@alt_names}
+ ).with_content(
+ %r{DNS\.0\s+=\s+a\.com}
+ ).with_content(
+ %r{DNS\.1\s+=\s+b\.com}
+ ).with_content(
+ %r{DNS\.2\s+=\s+c\.com}
+ )
+ }
+
+ it {
+ is_expected.to contain_ssl_pkey('/tmp/foobar/foo.key').with(
+ ensure: 'present',
+ password: nil,
+ size: 4096
+ )
+ }
+
+ it {
+ is_expected.to contain_x509_cert('/tmp/foobar/foo.crt').with(
+ ensure: 'present',
+ template: '/tmp/foobar/foo.cnf',
+ csr: '/tmp/foobar/foo.csr',
+ days: 4567,
+ ca: '/etc/pki/ca.crt',
+ cakey: '/etc/pki/ca.key',
+ cakey_password: '5r$}^',
+ force: false
+ )
+ }
+
+ it {
+ is_expected.to contain_x509_request('/tmp/foobar/foo.csr').with(
+ ensure: 'present',
+ template: '/tmp/foobar/foo.cnf',
+ private_key: '/tmp/foobar/foo.key',
+ password: nil,
+ force: false
+ )
+ }
+
+ it {
+ is_expected.to contain_file('/tmp/foobar/foo.key').with(
+ ensure: 'present',
+ owner: 'www-data'
+ )
+ }
+
+ it {
+ is_expected.to contain_file('/tmp/foobar/foo.crt').with(
+ ensure: 'present',
+ owner: 'www-data'
+ )
+ }
+
+ it {
+ is_expected.to contain_file('/tmp/foobar/foo.csr').with(
+ ensure: 'present',
+ owner: 'www-data'
+ )
+ }
+ end
end
diff --git a/spec/unit/puppet/provider/x509_cert/openssl_spec.rb b/spec/unit/puppet/provider/x509_cert/openssl_spec.rb
index 88b42de..8a11059 100644
--- a/spec/unit/puppet/provider/x509_cert/openssl_spec.rb
+++ b/spec/unit/puppet/provider/x509_cert/openssl_spec.rb
@@ -79,6 +79,29 @@
end
end
+ context 'when using a CA for signing with a password' do
+ it 'creates a certificate with the proper options' do
+ resource[:csr] = '/tmp/foo.csr'
+ resource[:ca] = '/tmp/foo-ca.crt'
+ resource[:cakey] = '/tmp/foo-ca.key'
+ resource[:cakey_password] = '5i;6%'
+ expect(provider_class).to receive(:openssl).with([
+ 'x509',
+ '-req',
+ '-days', 3650,
+ '-in', '/tmp/foo.csr',
+ '-out', '/tmp/foo.crt',
+ ['-extfile', '/tmp/foo.cnf'],
+ ['-CAcreateserial'],
+ ['-CA', '/tmp/foo-ca.crt'],
+ ['-CAkey', '/tmp/foo-ca.key'],
+ ['-passin', 'pass:5i;6%'],
+ ['-extensions', 'v3_req']
+ ])
+ resource.provider.create
+ end
+ end
+
context 'when forcing key' do
it 'exists? should return true if certificate exists and is synced' do
resource[:force] = true