summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2020-01-14 11:31:11 -0800
committerGitHub <noreply@github.com>2020-01-14 11:31:11 -0800
commit7d1579e8e140ead2a5fda8af2f6fc4a638ed7646 (patch)
treec77f5ffd09f72b10c39f7ade9f60df139db041ff
parent6ecd3150bb62c19bbf6f2f549883d70b401601b3 (diff)
parent10c547871db8221d95bc779f37000ee92da890d6 (diff)
downloadchef-7d1579e8e140ead2a5fda8af2f6fc4a638ed7646.tar.gz
Merge pull request #9187 from julienhuon/master
x509_certificate : Add the capability to automatically renew a certificate
-rw-r--r--lib/chef/mixin/openssl_helper.rb21
-rw-r--r--lib/chef/resource/openssl_x509_certificate.rb53
-rw-r--r--spec/unit/mixin/openssl_helper_spec.rb42
3 files changed, 95 insertions, 21 deletions
diff --git a/lib/chef/mixin/openssl_helper.rb b/lib/chef/mixin/openssl_helper.rb
index 5a4bd6077a..a9201d8637 100644
--- a/lib/chef/mixin/openssl_helper.rb
+++ b/lib/chef/mixin/openssl_helper.rb
@@ -401,6 +401,27 @@ class Chef
crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new)
crl
end
+
+ # Return true if a certificate need to be renewed (or doesn't exist) according to the number
+ # of days before expiration given
+ # @param [string] cert_file path of the cert file or cert content
+ # @param [integer] renew_before_expiry number of days before expiration
+ # @return [true, false]
+ def cert_need_renewall?(cert_file, renew_before_expiry)
+ resp = true
+ cert_content = ::File.exist?(cert_file) ? File.read(cert_file) : cert_file
+ begin
+ cert = OpenSSL::X509::Certificate.new cert_content
+ rescue ::OpenSSL::X509::CertificateError
+ return resp
+ end
+
+ unless cert.not_after <= Time.now + 3600 * 24 * renew_before_expiry
+ resp = false
+ end
+
+ resp
+ end
end
end
end
diff --git a/lib/chef/resource/openssl_x509_certificate.rb b/lib/chef/resource/openssl_x509_certificate.rb
index 20cf998239..a501fbdaac 100644
--- a/lib/chef/resource/openssl_x509_certificate.rb
+++ b/lib/chef/resource/openssl_x509_certificate.rb
@@ -109,30 +109,41 @@ class Chef
property :ca_key_pass, String,
description: "The passphrase for CA private key's passphrase."
+ property :renew_before_expiry, Integer,
+ description: "The number of days before the expiry. The certificate will be automaticaly renewed when the value is reached.",
+ introduced: "15.7"
+
action :create do
description "Generate a certificate"
- unless ::File.exist? new_resource.path
- converge_by("Create #{@new_resource}") do
- file new_resource.path do
- action :create_if_missing
- owner new_resource.owner unless new_resource.owner.nil?
- group new_resource.group unless new_resource.group.nil?
- mode new_resource.mode unless new_resource.mode.nil?
- sensitive true
- content cert.to_pem
- end
-
- if new_resource.csr_file.nil?
- file new_resource.key_file do
- action :create_if_missing
- owner new_resource.owner unless new_resource.owner.nil?
- group new_resource.group unless new_resource.group.nil?
- mode new_resource.mode unless new_resource.mode.nil?
- sensitive true
- content key.to_pem
- end
- end
+ file new_resource.path do
+ action :create_if_missing
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode unless new_resource.mode.nil?
+ sensitive true
+ content cert.to_pem
+ end
+
+ if !new_resource.renew_before_expiry.nil? && cert_need_renewall?(new_resource.path, new_resource.renew_before_expiry)
+ file new_resource.path do
+ action :create
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode unless new_resource.mode.nil?
+ sensitive true
+ content cert.to_pem
+ end
+ end
+
+ if new_resource.csr_file.nil?
+ file new_resource.key_file do
+ action :create_if_missing
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode unless new_resource.mode.nil?
+ sensitive true
+ content key.to_pem
end
end
end
diff --git a/spec/unit/mixin/openssl_helper_spec.rb b/spec/unit/mixin/openssl_helper_spec.rb
index a6a6fb0e71..5155d66a22 100644
--- a/spec/unit/mixin/openssl_helper_spec.rb
+++ b/spec/unit/mixin/openssl_helper_spec.rb
@@ -854,4 +854,46 @@ describe Chef::Mixin::OpenSSLHelper do
end
end
end
+
+ describe "#cert_need_renewall?" do
+ require "tempfile"
+
+ before(:each) do
+ @certfile = Tempfile.new("certfile")
+ end
+
+ context "When the cert file doesnt not exist" do
+ it "returns true" do
+ expect(instance.cert_need_renewall?("/tmp/bad_filename", 3650)).to be_truthy
+ end
+ end
+
+ context "When the cert file does exist, but does not contain a valid Certificate" do
+ it "returns true" do
+ @certfile.write("I_am_not_a_cert_I_am_a_free_man")
+ @certfile.close
+ expect(instance.cert_need_renewall?(@certfile.path, 3650)).to be_truthy
+ end
+ end
+
+ context "When the cert file does exist, and does not contain a soon to expire certficitate" do
+ it "returns false" do
+ @certfile.write("-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIVAPCkjE+wlZ1PgXwgvFgXKzhSpUkvMA0GCSqGSIb3DQEB\nCwUAMA0xCzAJBgNVBAMMAkNBMB4XDTE5MTIyNTEyNTY1NVoXDTI5MTIyMjEyNTY1\nNVowDTELMAkGA1UEAwwCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQC9bDWs5akf85UEMj8kry4DYNuAnaL4GnMs6XukQtp3dso+FgbKprgVogyepnet\nE+GlQq32u/n4y8K228kB6NoCn+c/yP+4QlKUBt0xSzQbSUuAE/5xZoKi/kH1ZsQ/\nuKXN/tIHagApEUGn5zqc8WBvWPliRAqiklwj8WtSw1WRa5eCdaVtln3wKuvPnYR5\n/V4YBHyHNhtlfXJBMtEaXm1rRzJGun+FdcrsCfcIFXp8lWobF+EVP8fRwqFTEtT6\nRXv6RT8sHy53a0KNTm8qnbacfr1MofgUuhzLjOrbIVvXpnRLeOkv8XW5rSH+zgsC\nZFK3bJ3j6UVbFQV4jXwlAWVrAgMBAAGjgY4wgYswDgYDVR0PAQH/BAQDAgGmMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK4S2PNu6bpjxkJxedNaxfCrwtD4MEkG\nA1UdIwRCMECAFK4S2PNu6bpjxkJxedNaxfCrwtD4oRGkDzANMQswCQYDVQQDDAJD\nQYIVAPCkjE+wlZ1PgXwgvFgXKzhSpUkvMA0GCSqGSIb3DQEBCwUAA4IBAQBGk+u3\n9N3PLWNOwYrqK7fD4yceWnz4UsV9uN1IU5PQTgYBaGyAZvU+VJluZZeDj7QjwbUW\ngISclvW/pSWpUVW3O0sfAM97u+5UMYHz4W5Bgq8CtdOKHgdZHKhzBePhmou11zO0\nZ6uQ7bkh0/REqKO7TFKaMMnakEhFXoDrS1EiB4W69KVXyrBVzVm5LK7uvOAQAeMp\nnEk3Oz+5pmKjSCf1cEd2jzAgDbaVrIvxICPgXAlNrKukmRW/0UHqDDVBfF7PioD2\nptlQFxWIkih6s/clwhsBFBwV1yyCirYfjhzmKPPLZUmx10okudLzaKrRbkPxrzbC\nmKEZoV+Nz2CNrGm5\n-----END CERTIFICATE-----\n")
+ @certfile.close
+ expect(instance.cert_need_renewall?(@certfile.path, 5)).to be_falsey
+ end
+ end
+
+ context "When the cert file does exist, and does contain a soon to expire certficitate" do
+ it "returns true" do
+ @certfile.write("-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIVAPCkjE+wlZ1PgXwgvFgXKzhSpUkvMA0GCSqGSIb3DQEB\nCwUAMA0xCzAJBgNVBAMMAkNBMB4XDTE5MTIyNTEyNTY1NVoXDTI5MTIyMjEyNTY1\nNVowDTELMAkGA1UEAwwCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQC9bDWs5akf85UEMj8kry4DYNuAnaL4GnMs6XukQtp3dso+FgbKprgVogyepnet\nE+GlQq32u/n4y8K228kB6NoCn+c/yP+4QlKUBt0xSzQbSUuAE/5xZoKi/kH1ZsQ/\nuKXN/tIHagApEUGn5zqc8WBvWPliRAqiklwj8WtSw1WRa5eCdaVtln3wKuvPnYR5\n/V4YBHyHNhtlfXJBMtEaXm1rRzJGun+FdcrsCfcIFXp8lWobF+EVP8fRwqFTEtT6\nRXv6RT8sHy53a0KNTm8qnbacfr1MofgUuhzLjOrbIVvXpnRLeOkv8XW5rSH+zgsC\nZFK3bJ3j6UVbFQV4jXwlAWVrAgMBAAGjgY4wgYswDgYDVR0PAQH/BAQDAgGmMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK4S2PNu6bpjxkJxedNaxfCrwtD4MEkG\nA1UdIwRCMECAFK4S2PNu6bpjxkJxedNaxfCrwtD4oRGkDzANMQswCQYDVQQDDAJD\nQYIVAPCkjE+wlZ1PgXwgvFgXKzhSpUkvMA0GCSqGSIb3DQEBCwUAA4IBAQBGk+u3\n9N3PLWNOwYrqK7fD4yceWnz4UsV9uN1IU5PQTgYBaGyAZvU+VJluZZeDj7QjwbUW\ngISclvW/pSWpUVW3O0sfAM97u+5UMYHz4W5Bgq8CtdOKHgdZHKhzBePhmou11zO0\nZ6uQ7bkh0/REqKO7TFKaMMnakEhFXoDrS1EiB4W69KVXyrBVzVm5LK7uvOAQAeMp\nnEk3Oz+5pmKjSCf1cEd2jzAgDbaVrIvxICPgXAlNrKukmRW/0UHqDDVBfF7PioD2\nptlQFxWIkih6s/clwhsBFBwV1yyCirYfjhzmKPPLZUmx10okudLzaKrRbkPxrzbC\nmKEZoV+Nz2CNrGm5\n-----END CERTIFICATE-----\n")
+ @certfile.close
+ expect(instance.cert_need_renewall?(@certfile.path, 3650)).to be_truthy
+ end
+ end
+
+ after(:each) do
+ @certfile.unlink
+ end
+ end
end