Vendor the external cookbooks

Knife-Zero doesn't include Berkshelf support, so vendoring everything in
the repo is convenient again
This commit is contained in:
Greg Karékinian
2019-10-13 19:17:42 +02:00
parent f4bfe31ac1
commit a32f34b408
1245 changed files with 100630 additions and 0 deletions

View File

@@ -0,0 +1,217 @@
# openssl Cookbook CHANGELOG
This file is used to list changes made in each version of the openssl cookbook.
## 8.5.5 (2018-09-04)
All resources in this cookbook are now built into Chef 14.4+. When Chef 15.4 is released (April 2019) the resources will be removed from this cookbook as all users should be running Chef 14.4 or later at that point.
## 8.5.4 (2018-08-29)
- Add missing email documentation for the request property
- Fix x509_crl to work on non-Linux platforms
- Attribute -> Property in the readme
- revokation -> revocation in the readme
- Update group/owner documentation
- Avoid deprecation warnings on Chef 14.3+
## 8.5.3 (2018-08-15)
- Call ::OpenSSL not OpenSSL to be more defensive in the helpers
## 8.5.2 (2018-08-14)
- Back out mode change in ec_private_key
## 8.5.1 (2018-08-14)
- Add license headers to the resources
- Remove default_action setup from the resources since this is done automatically in custom resources now
- Make sure to use the path name_property when creating the ec public key file
- Make sure we're using openssl and not Chef's Openssl class
- Simplify how we handle user/group properties
## 8.5.0 (2018-08-02)
- Use the system provided owner/group defaults in resources
- Added new openssl_x509_crl resource
- Fix openssl_ec_public_key with documentation & tests
- Few corrections in the documentation
- Fix backward compatibility with chef client 12
## 8.4.0 (2018-07-30)
This release is brought to you by Institut National de l'Audiovisuel, which contributed the following changes:
- openssl_x509 is renamed to openssl_x509_certificate with backwards compatibility for the old name
- openssl_x509_certificate can now generate a signed certificate with a provided CA cert & key
- openssl_x509_certificate now support x509 extensions
- openssl_x509_certificate now support x509 csr
- openssl_x509_certificate now generate a random serial for the certificate
- openssl_x509_certificate expires has now a default value : 365
- country field is now mandatory in x509_request
- the private key file is not rewrited in x509_request if it already exist
## 8.3.0 (2018-07-25)
- Add resource x509_request
## 8.2.0 (2018-07-23)
- Add ec_private_key & ec_public_key resources
## 8.1.2 (2018-02-09)
- Fix typo in resources that caused failures on Windows.
- Properly reference key_cipher in the readme
## 8.1.1 (2018-01-05)
- Add YARD comments to all the helpers
- Move valid ciphers directly into the equal_to check
- Remove the Chefspec matchers since modern ChefSpec does this automatically
- Fix failures on Windows nodes
## 8.1.0 (2017-12-28)
- Adding x509 support for /ST and /L
- Allow passing private key content to rsa_public_key resource via property
- Fix openssl_rsa_public_key converging on every run
- Fix undefied method "cipher" error in openssl_rsa_private_key resource
## 8.0.0 (2017-12-11)
- Added a new openssl_rsa_public_key resource which generates a public key from a private key
- Rename openssl_rsa_key to openssl_rsa_private_key, while still allowing the old name to function. This resource actually generates private keys, but the previous name didn't make that clear
- Added owner, group, and mode properties to all of the resources so you could control who owned the files you generated
- Set the default modes of generated files to 640 instead of 644
- Set the files to generate using node['root_group'] not 'root' for compatibility on other *nix systems such as FreeBSD and macOS
- Added a new property to openssl_rsa_private_key for specifying the cipher to use
- Converted integration tests to InSpec and moved all resources to a single Kitchen suite for quicker testing
- Added a force property to allow overwriting any existing key that may exist
- Fixed upgrade recipe failures on Debian 9
- Added a new path property which allows you to set the path there instead of in the resource's name
- Improved input validation in some of the helpers
- Added a deprecation message in Opscode::OpenSSL::Password helper "secure_password" and removed readme documentation
- Added a warning in the upgrade recipe if we're on an unsupported platform
- Switched the upgrade recipe to a multipackage upgrade to speed up Chef runs
## 7.1.0 (2017-05-30)
- Add supported platforms to the metdata
- Fix amazon support
- Remove class_eval usage and require Chef 12.7+
## 7.0.1 (2017-03-21)
- Fix compatibility with Chef 12.5.1
## 7.0.0 (2017-03-06)
- Converted LWRPs to custom resources, increasing the chef-client dependency to 12.5+. This fixes the bus where each resource notified on every run even if it didn't actually update the files on disk.
- Added testing for Chef 13
- Test with Local Delivery instead of Rake
## 6.1.1 (2017-01-19)
- Resolve deprecation warnings in chefspec
- Use proper ::File class and fix ^2 validation of dhparam key length
- Disable .zero? in cookstyle for now
## 6.1.0 (2017-01-18)
- [#37] Support for Subject Alternative Names on generated self-signed certificates
- rubocop
- Cookstyle fixes
## 6.0.0 (2016-09-08)
- Update the minimum chef release to 12.1
## 5.0.1 (2016-09-01)
- Update docs from node.normal as node.set has been deprecated
- Testing updates
## 5.0.0 (2016-08-27)
- Remove the need for the chef-sugar cookbook
- Remove the default['openssl']['packages'] attribute in the upgrades recipe and instead use the correct openssl packages based on platform
- Remove support for Debian 6 and Ubuntu 10.04 in the upgrade recipe
- Add support for Fedora and Suse in the upgrade recipe
- Prevent errors with unset variable in error raising within the random password helper
- Add cookstyle and resolve all warnings
- Add testing, contributing, and maintainers documentation
- Add integration testing in Travis CI with kitchen-dokken
- Add issues_url, source_url and chef_version metadata
- Update the requirements section of the README
- Update the Chefspecs to avoid errors and run using caching for faster runs
- Add issues and PR templates for Github
## v4.4.0 (2015-08-28)
- NEW: x509 certificates are now signed via SHA-256 instead of SHA-1
- FIX: gen_dhparam error now correctly fails with TypeError instead of ArgumentError if Generator argument isn't an integer
## v4.3.2 (2015-08-01)
- FIX: Updated changelog
## v4.3 (2015-08-01)
- NEW: Add rsa_key lwrp
- FIX: dhparam lwrp now correctly honors the generator parameter
## v4.2 (2015-06-23)
- NEW: Add dhparam lwrp
- FIX: x509 lwrp now updates resource count correctly
## v4.1.2 (2015-06-20)
- Add Serverspec suite
- Removed update suite from .kitchen.yml
- Add explicit license to test cookbook recipes
- Add Whyrun support to x509 LWRP
- Expand Chefspec tests for x509 LWRP to step_into LWRP
- Add helper library
- Update x509 LWRP to verify existing keys, if specified
## v4.1.1 (2015-06-11)
- README.md fixes
## v4.1.0 (2015-06-11)
- Add new random_password Mixin (Thanks, Seth!)
- Rewritten README.md
- Refactor specs
- Clear Rubocop violations
## v4.0.0 (2015-02-19)
- Reverting to Opscode module namespace
## v3.0.2 (2015-12-18)
- Accidently released 2.0.2 as 3.0.2
- Re-namespaced `Opscode::OpenSSL::Password` module as `Chef::OpenSSL::Password`
## v2.0.2 (2014-12-30)
- Call cert.to_pem before recipe DSL
## v2.0.0 (2014-06-11)
- # 1 - **[COOK-847](https://tickets.chef.io/browse/COOK-847)** - Add LWRP for generating self signed certs
- # 4 - **[COOK-4715](https://tickets.chef.io/browse/COOK-4715)** - add upgrade recipe and complete test harness
## v1.1.0
### Improvement
- **[COOK-3222](https://tickets.chef.io/browse/COOK-3222)** - Allow setting length for `secure_password`
## v1.0.2
- Add name attribute to metadata

View File

@@ -0,0 +1,2 @@
Please refer to
https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD

416
cookbooks/openssl/README.md Normal file
View File

@@ -0,0 +1,416 @@
# OpenSSL Cookbook
[![Build Status](https://travis-ci.org/chef-cookbooks/openssl.svg?branch=master)](http://travis-ci.org/chef-cookbooks/openssl) [![Cookbook Version](https://img.shields.io/cookbook/v/openssl.svg)](https://supermarket.chef.io/cookbooks/openssl)
This cookbook provides tools for working with the Ruby OpenSSL library. It includes:
- A library method to generate secure random passwords in recipes, using the Ruby SecureRandom library.
- A resource for generating RSA private keys.
- A resource for generating RSA public keys.
- A resource for generating EC private keys.
- A resource for generating EC public keys.
- A resource for generating x509 certificates.
- A resource for generating x509 requests.
- A resource for generating x509 crl.
- A resource for generating dhparam.pem files.
- An attribute-driven recipe for upgrading OpenSSL packages.
NOTE: All resources in this cookbook are now built-into Chef 14.4 and later so this cookbook is no longer necessary to use those resources. When Chef 15.4 is released (Aug 2019) the resources will be removed from this cookbook as all users should be running Chef 14.4 or later.
## Platforms
- Debian / Ubuntu derivatives
- Fedora
- FreeBSD
- macOS
- openSUSE / SUSE Linux Enterprises
- RHEL/CentOS/Scientific/Amazon/Oracle
- Solaris
## Chef
- Chef 12.7+
## Cookbooks
- none
## Attributes
- `node['openssl']['restart_services']` - An array of service resources that depend on the openssl packages. This array is empty by default, as Chef has no reasonable way to detect which applications or services are compiled against these packages. _Note_ Each service listed in this array should represent a "`service`" resource specified in the recipes of the node's run list.
## Recipes
### upgrade
The upgrade recipe iterates over the list of packages in the `node['openssl']['packages']` attribute, and manages them with the `:upgrade` action. Each package will send a `:restart` notification to service resources named in the `node['openssl']['restart_services']` attribute.
#### Example Usage
In this example, assume the node is running the `stats_collector` daemon, which depends on the openssl library. Imagine that a new openssl vulnerability has been disclosed, and the operating system vendor has released an update to openssl to address this vulnerability. In order to protect the node, an administrator crafts this recipe:
```ruby
node.default['openssl']['restart_services'] = ['stats_collector']
# other recipe code here...
service 'stats_collector' do
action [:enable, :start]
end
include_recipe 'openssl::upgrade'
```
When executed, this recipe will ensure that openssl is upgraded to the latest version, and that the `stats_collector` service is restarted to pick up the latest security fixes released in the openssl package.
## Libraries
There are two mixins packaged with this cookbook.
### random_password (`OpenSSLCookbook::RandomPassword`)
The `RandomPassword` mixin can be used to generate secure random passwords in Chef cookbooks, usually for assignment to a variable or an attribute. `random_password` uses Ruby's SecureRandom library and is customizable.
#### Example Usage
```ruby
Chef::Recipe.send(:include, OpenSSLCookbook::RandomPassword)
node.normal['my_secure_attribute'] = random_password
node.normal_unless['my_secure_attribute'] = random_password
node.normal['my_secure_attribute'] = random_password(length: 50)
node.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64)
node.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64, encoding: 'ASCII')
```
Note that node attributes are widely accessible. Storing unencrypted passwords in node attributes, as in this example, carries risk.
## Resources
### openssl_x509_certificate
This resource generates signed or self-signed, PEM-formatted x509 certificates. If no existing key is specified, the resource will automatically generate a passwordless key with the certificate. If a CA private key and certificate are provided, the certificate will be signed with them.
Note: This resource was renamed from openssl_x509 to openssl_x509_certificate. The legacy name will continue to function, but cookbook code should be updated for the new resource name.
#### Properties
Name | Type | Description
------------------ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`common_name` | String (Optional) | Value for the `CN` certificate field.
`org` | String (Optional) | Value for the `O` certificate field.
`org_unit` | String (Optional) | Value for the `OU` certificate field.
`city` | String (Optional) | Value for the `L` certificate field.
`state` | String (Optional) | Value for the `ST` certificate field.
`country` | String (Optional) | Value for the `C` ssl field.
`email` | String (Optional) | Value for the `email` ssl field.
`expire` | Integer (Optional) | Value representing the number of days from _now_ through which the issued certificate cert will remain valid. The certificate will expire after this period. _Default: 365
`extensions` | Hash (Optional) | Hash of X509 Extensions entries, in format `{ 'keyUsage' => { 'values' => %w( keyEncipherment digitalSignature), 'critical' => true } }` _Default: empty_
`subject_alt_name` | Array (Optional) | Array of _Subject Alternative Name_ entries, in format `DNS:example.com` or `IP:1.2.3.4` _Default: empty_
`key_file` | String (Optional) | The path to a certificate key file on the filesystem. If the `key_file` property is specified, the resource will attempt to source a key from this location. If no key file is found, the resource will generate a new key file at this location. If the `key_file` property is not specified, the resource will generate a key file in the same directory as the generated certificate, with the same name as the generated certificate.
`key_pass` | String (Optional) | The passphrase for an existing key's passphrase
`key_type` | String (Optional) | The desired type of the generated key (rsa or ec). _Default: rsa_
`key_length` | Integer (Optional) | The desired Bit Length of the generated key (if key_type is equal to 'rsa'). _Default: 2048_
`key_curve` | String (Optional) | The desired curve of the generated key (if key_type is equal to 'ec'). Run `openssl ecparam -list_curves` to see available options. _Default: prime256v1_
`csr_file` | String (Optional) | The path to a X509 Certificate Request (CSR) on the filesystem. If the `csr_file` property is specified, the resource will attempt to source a CSR from this location. If no CSR file is found, the resource will generate a Self-Signed Certificate and the certificate fields must be specified (common_name at last).
`ca_cert_file` | String (Optional) | The path to the CA X509 Certificate on the filesystem. If the `ca_cert_file` property is specified, the `ca_key_file` property must also be specified, the certificate will be signed with them.
`ca_key_file` | String (Optional) | The path to the CA private key on the filesystem. If the `ca_key_file` property is specified, the `ca_cert_file' property must also be specified, the certificate will be signed with them.
`ca_key_pass` | String (Optional) | The passphrase for CA private key's passphrase
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource.
#### Example Usage
In this example, an administrator wishes to create a self-signed x509 certificate for use with a web server. In order to create the certificate, the administrator crafts this recipe:
```ruby
openssl_x509 '/etc/httpd/ssl/mycert.pem' do
common_name 'www.f00bar.com'
org 'Foo Bar'
org_unit 'Lab'
country 'US'
end
```
When executed, this recipe will generate a key certificate at `/etc/httpd/ssl/mycert.key`. It will then use that key to generate a new certificate file at `/etc/httpd/ssl/mycert.pem`.
In this example, an administrator wishes to create a x509 certificate signed with a CA certificate and key. In order to create the certificate, the administrator crafts this recipe:
```ruby
openssl_x509_certificate '/etc/ssl_test/my_signed_cert.crt' do
common_name 'www.f00bar.com'
ca_key_file '/etc/ssl_test/my_ca.key'
ca_cert_file '/etc/ssl_test/my_ca.crt'
expire 365
extensions(
'keyUsage' => {
'values' => %w(
keyEncipherment
digitalSignature),
'critical' => true,
},
'extendedKeyUsage' => {
'values' => %w(serverAuth),
'critical' => false,
}
)
subject_alt_name ['IP:127.0.0.1', 'DNS:localhost.localdomain']
end
```
When executed, this recipe will generate a key certificate at `/etc/ssl_test/my_signed_cert.key`. It will then use that key to generate a CSR and signed it with `my_ca.key/my_ca.crt`. A new certificate file at `/etc/ssl_test/my_signed_cert.cert` will be created as a result.
### openssl_x509_request
This resource generates PEM-formatted x509 certificates requests. If no existing key is specified, the resource will automatically generate a passwordless key with the certificate.
#### Properties
Name | Type | Description
--------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`common_name` | String (Required) | Value for the `CN` certificate field.
`org` | String (Optional) | Value for the `O` certificate field.
`org_unit` | String (Optional) | Value for the `OU` certificate field.
`city` | String (Optional) | Value for the `L` certificate field.
`state` | String (Optional) | Value for the `ST` certificate field.
`country` | String (Optional) | Value for the `C` ssl field.
`email` | String (Optional) | Value for the `email` ssl field.
`key_file` | String (Optional) | The path to a certificate key file on the filesystem. If the `key_file` property is specified, the resource will attempt to source a key from this location. If no key file is found, the resource will generate a new key file at this location. If the `key_file` property is not specified, the resource will generate a key file in the same directory as the generated certificate, with the same name as the generated certificate.
`key_pass` | String (Optional) | The passphrase for an existing key's passphrase
`key_type` | String (Optional) | The desired type of the generated key (rsa or ec). _Default: ec_
`key_length` | Integer (Optional) | The desired Bit Length of the generated key (if key_type is equal to 'rsa'). _Default: 2048_
`key_curve` | String (Optional) | The desired curve of the generated key (if key_type is equal to 'ec'). Run `openssl ecparam -list_curves` to see available options. _Default: prime256v1
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource.
#### Example Usage
In this example, an administrator wishes to create a x509 CRL. In order to create the CRL, the administrator crafts this recipe:
```ruby
openssl_x509_request '/etc/ssl_test/my_ec_request.csr' do
common_name 'myecrequest.example.com'
org 'Test Kitchen Example'
org_unit 'Kitchens'
country 'UK'
end
```
When executed, this recipe will generate a key certificate at `/etc/httpd/ssl/my_ec_request.key`. It will then use that key to generate a new csr file at `/etc/ssl_test/my_ec_request.csr`.
### openssl_x509_crl
This resource generates PEM-formatted x509 CRL.
#### Properties
Name | Type | Description
--------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`serial_to_revoke` | String or Integer(Optional) | Serial of the X509 Certificate to revoke
`revocation_reason` | String or Integer(Optional) | [Reason of the revocation]((https://en.wikipedia.org/wiki/Certificate_revocation_list#Reasons_for_revocation)) _Default: 0_
`expire` | Integer (Optional) | Value representing the number of days from _now_ through which the issued CRL will remain valid. The CRL will expire after this period. _Default: 8_
`renewal_threshold` | Integer (Optional) | Number of days before the expiration. It this threshold is reached, the CRL will be renewed _Default: 1_
`ca_cert_file` | String (Required) | The path to the CA X509 Certificate on the filesystem. If the `ca_cert_file` property is specified, the `ca_key_file` property must also be specified, the CRL will be signed with them.
`ca_key_file` | String (Required) | The path to the CA private key on the filesystem. If the `ca_key_file` property is specified, the `ca_cert_file' property must also be specified, the CRL will be signed with them.
`ca_key_pass` | String (Optional) | The passphrase for CA private key's passphrase
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource.
#### Example Usage
In this example, an administrator wishes to create an empty X509 CRL. In order to create the CRL, the administrator crafts this recipe:
```ruby
openssl_x509_crl '/etc/ssl_test/my_ca.crl' do
ca_cert_file '/etc/ssl_test/my_ca.crt'
ca_key_file '/etc/ssl_test/my_ca.key'
end
```
When executed, this recipe will generate a new CRL file at `/etc/ssl_test/my_ca.crl`.
In this example, an administrator wishes to revoke a certificate in an existing X509 CRL.
```ruby
openssl_x509_crl '/etc/ssl_test/my_ca.crl' do
ca_cert_file '/etc/ssl_test/my_ca.crt'
ca_key_file '/etc/ssl_test/my_ca.key'
serial_to_revoke C7BCB6602A2E4251EF4E2827A228CB52BC0CEA2F
end
```
### openssl_dhparam
This resource generates dhparam.pem files. If a valid dhparam.pem file is found at the specified location, no new file will be created. If a file is found at the specified location but it is not a valid dhparam file, it will be overwritten.
#### Properties
Name | Type | Description
------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`key_length` | Integer (Optional) | The desired Bit Length of the generated key. _Default: 2048_
`generator` | Integer (Optional) | The desired Diffie-Hellmann generator. Can be _2_ or _5_.
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0640"_
#### Example Usage
In this example, an administrator wishes to create a dhparam.pem file for use with a web server. In order to create the .pem file, the administrator crafts this recipe:
```ruby
openssl_dhparam '/etc/httpd/ssl/dhparam.pem' do
key_length 2048
generator 2
end
```
When executed, this recipe will generate a dhparam file at `/etc/httpd/ssl/dhparam.pem`.
### openssl_rsa_private_key
This resource generates rsa private key files. If a valid rsa key file can be opened at the specified location, no new file will be created. If the RSA key file cannot be opened, either because it does not exist or because the password to the RSA key file does not match the password in the recipe, it will be overwritten.
Note: This resource was renamed from openssl_rsa_key to openssl_rsa_private_key. The legacy name will continue to function, but cookbook code should be updated for the new resource name.
#### Properties
Name | Type | Description
------------ | ---------------------------- | -----------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`key_length` | Integer (Optional) | The desired Bit Length of the generated key. _Default: 2048_
`key_cipher` | String (Optional) | The designed cipher to use when generating your key. Run `openssl list-cipher-algorithms` to see available options. _Default: des3_
`key_pass` | String (Optional) | The desired passphrase for the key.
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0640"_
`force` | true/false (Optional) | Force creating the key even if the existing key exists. _Default: false_
#### Example Usage
In this example, an administrator wishes to create a new RSA private key file in order to generate other certificates and public keys. In order to create the key file, the administrator crafts this recipe:
```ruby
openssl_rsa_private_key '/etc/httpd/ssl/server.key' do
key_length 2048
end
```
When executed, this recipe will generate a passwordless RSA key file at `/etc/httpd/ssl/server.key`.
### openssl_rsa_public_key
This resource generates rsa public key files given a private key.
#### Properties
Name | Type | Description
--------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`private_key_path` | String (Required unless private_key_content used) | The path to the private key to generate the public key from
`private_key_content` | String (Required unless private_key_path used) | The content of the private key including new lines. Used if you don't want to write a private key to disk and use `private_key_path`.
`private_key_pass` | String (Optional) | The passphrase of the provided private key
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0640"_
**Note**: To use `private_key_content` the private key string must be properly formatted including new lines. The easiest way to get the right string is to run the following from irb (/opt/chefdk/embedded/bin/irb from ChefDK)
```ruby
File.read('/foo/bar/private.pem')
```
#### Example Usage
```ruby
openssl_rsa_public_key '/etc/foo/something.pub' do
priv_key_path '/etc/foo/something.pem'
end
```
### openssl_ec_private_key
This resource generates ec private key files. If a valid ec key file can be opened at the specified location, no new file will be created. If the EC key file cannot be opened, either because it does not exist or because the password to the EC key file does not match the password in the recipe, it will be overwritten.
#### Properties
Name | Type | Description
------------ | ---------------------------- | -----------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`key_curve` | String (Optional) | The desired curve of the generated key. Run `openssl ecparam -list_curves` to see available options. _Default: prime256v1
`key_cipher` | String (Optional) | The designed cipher to use when generating your key. Run `openssl list-cipher-algorithms` to see available options. _Default: des3_
`key_pass` | String (Optional) | The desired passphrase for the key.
`owner` | String (optional) | The owner of all files created by the resource.
`group` | String (optional) | The group of all files created by the resource.
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0640"_
`force` | true/false (Optional) | Force creating the key even if the existing key exists. _Default: false_
#### Example Usage
In this example, an administrator wishes to create a new EC private key file in order to generate other certificates and public keys. In order to create the key file, the administrator crafts this recipe:
```ruby
openssl_ec_private_key '/etc/httpd/ssl/server.key' do
key_curve "prime256v1'
end
```
When executed, this recipe will generate a passwordless EC key file at `/etc/httpd/ssl/server.key`.
### openssl_ec_public_key
This resource generates ec public key files given a private key.
#### Properties
Name | Type | Description
--------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`private_key_path` | String (Required unless private_key_content used) | The path to the private key to generate the public key from
`private_key_content` | String (Required unless private_key_path used) | The content of the private key including new lines. Used if you don't want to write a private key to disk and use `private_key_path`.
`private_key_pass` | String (Optional) | The passphrase of the provided private key
`owner` | String (optional) | The owner of all files created by the resource. _Default: "root"_
`group` | String (optional) | The group of all files created by the resource. _Default: "root or wheel depending on platform"_
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0640"_
**Note**: To use `private_key_content` the private key string must be properly formatted including new lines. The easiest way to get the right string is to run the following from irb (/opt/chefdk/embedded/bin/irb from ChefDK)
```ruby
File.read('/foo/bar/private.pem')
```
#### Example Usage
```ruby
openssl_ec_public_key '/etc/foo/something.pub' do
priv_key_path '/etc/foo/something.pem'
end
```
## Maintainers
This cookbook is maintained by Chef's Community Cookbook Engineering team. Our goal is to improve cookbook quality and to aid the community in contributing to cookbooks. To learn more about our team, process, and design goals see our [team documentation](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/COOKBOOK_TEAM.MD). To learn more about contributing to cookbooks like this see our [contributing documentation](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD), or if you have general questions about this cookbook come chat with us in #cookbok-engineering on the [Chef Community Slack](http://community-slack.chef.io/)
## License
**Copyright:** 2009-2018, Chef Software, Inc.
```
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

View File

@@ -0,0 +1,20 @@
#
# Cookbook:: openssl
# Attributes:: default
#
# Copyright:: 2014-2017, Chef Software, Inc. <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
default['openssl']['restart_services'] = []

View File

@@ -0,0 +1,399 @@
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module OpenSSLCookbook
# Helper functions for the OpenSSL cookbook.
module Helpers
def self.included(_base)
require 'openssl' unless defined?(::OpenSSL)
end
# determine the key filename from the cert filename
# @param [String] cert_filename the path to the certfile
# @return [String] the path to the keyfile
def get_key_filename(cert_filename)
cert_file_path, cert_filename = ::File.split(cert_filename)
cert_filename = ::File.basename(cert_filename, ::File.extname(cert_filename))
cert_file_path + ::File::SEPARATOR + cert_filename + '.key'
end
# is the key length a valid key length
# @param [Integer] number
# @return [Boolean] is length valid
def key_length_valid?(number)
number >= 1024 && (number & (number - 1) == 0)
end
# validate a dhparam file from path
# @param [String] dhparam_pem_path the path to the pem file
# @return [Boolean] is the key valid
def dhparam_pem_valid?(dhparam_pem_path)
# Check if the dhparam.pem file exists
# Verify the dhparam.pem file contains a key
return false unless ::File.exist?(dhparam_pem_path)
dhparam = ::OpenSSL::PKey::DH.new File.read(dhparam_pem_path)
dhparam.params_ok?
end
# given either a key file path or key file content see if it's actually
# a private key
# @param [String] key_file the path to the keyfile or the key contents
# @param [String] key_password optional password to the keyfile
# @return [Boolean] is the key valid?
def priv_key_file_valid?(key_file, key_password = nil)
# if the file exists try to read the content
# if not assume we were passed the key and set the string to the content
key_content = ::File.exist?(key_file) ? File.read(key_file) : key_file
begin
key = ::OpenSSL::PKey.read key_content, key_password
rescue ::OpenSSL::PKey::PKeyError, ArgumentError
return false
end
if key.is_a?(::OpenSSL::PKey::EC)
key.private_key?
else
key.private?
end
end
# given a crl file path see if it's actually a crl
# @param [String] crl_file the path to the crlfile
# @return [Boolean] is the key valid?
def crl_file_valid?(crl_file)
begin
::OpenSSL::X509::CRL.new ::File.read(crl_file)
rescue ::OpenSSL::X509::CRLError, Errno::ENOENT
return false
end
true
end
# check is a serial given is revoked in a crl given
# @param [OpenSSL::X509::CRL] crl X509 CRL to check
# @param [String, Integer] serial X509 Certificate Serial Number
# @return [true, false]
def serial_revoked?(crl, serial)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(::OpenSSL::X509::CRL)
raise TypeError, 'serial must be a Ruby String or Integer object' unless serial.is_a?(String) || serial.is_a?(Integer)
serial_to_verify = if serial.is_a?(String)
serial.to_i(16)
else
serial
end
status = false
crl.revoked.each do |revoked|
status = true if revoked.serial == serial_to_verify
end
status
end
# generate a dhparam file
# @param [String] key_length the length of the key
# @param [Integer] generator the dhparam generator to use
# @return [OpenSSL::PKey::DH]
def gen_dhparam(key_length, generator)
raise ArgumentError, 'Key length must be a power of 2 greater than or equal to 1024' unless key_length_valid?(key_length)
raise TypeError, 'Generator must be an integer' unless generator.is_a?(Integer)
::OpenSSL::PKey::DH.new(key_length, generator)
end
# generate an RSA private key given key length
# @param [Integer] key_length the key length of the private key
# @return [OpenSSL::PKey::DH]
def gen_rsa_priv_key(key_length)
raise ArgumentError, 'Key length must be a power of 2 greater than or equal to 1024' unless key_length_valid?(key_length)
::OpenSSL::PKey::RSA.new(key_length)
end
# generate pem format of the public key given a private key
# @param [String] priv_key either the contents of the private key or the path to the file
# @param [String] priv_key_password optional password for the private key
# @return [String] pem format of the public key
def gen_rsa_pub_key(priv_key, priv_key_password = nil)
# if the file exists try to read the content
# if not assume we were passed the key and set the string to the content
key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key
key = ::OpenSSL::PKey::RSA.new key_content, priv_key_password
key.public_key.to_pem
end
# generate a pem file given a cipher, key, an optional key_password
# @param [OpenSSL::PKey::RSA] rsa_key the private key object
# @param [String] key_password the password for the private key
# @param [String] key_cipher the cipher to use
# @return [String] pem contents
def encrypt_rsa_key(rsa_key, key_password, key_cipher)
raise TypeError, 'rsa_key must be a Ruby OpenSSL::PKey::RSA object' unless rsa_key.is_a?(::OpenSSL::PKey::RSA)
raise TypeError, 'key_password must be a string' unless key_password.is_a?(String)
raise TypeError, 'key_cipher must be a string' unless key_cipher.is_a?(String)
raise ArgumentError, 'Specified key_cipher is not available on this system' unless ::OpenSSL::Cipher.ciphers.include?(key_cipher)
cipher = ::OpenSSL::Cipher.new(key_cipher)
rsa_key.to_pem(cipher, key_password)
end
# generate an ec private key given curve type
# @param [String] curve the kind of curve to use
# @return [OpenSSL::PKey::DH]
def gen_ec_priv_key(curve)
raise TypeError, 'curve must be a string' unless curve.is_a?(String)
raise ArgumentError, 'Specified curve is not available on this system' unless curve == 'prime256v1' || curve == 'secp384r1' || curve == 'secp521r1'
::OpenSSL::PKey::EC.new(curve).generate_key
end
# generate pem format of the public key given a private key
# @param [String] priv_key either the contents of the private key or the path to the file
# @param [String] priv_key_password optional password for the private key
# @return [String] pem format of the public key
def gen_ec_pub_key(priv_key, priv_key_password = nil)
# if the file exists try to read the content
# if not assume we were passed the key and set the string to the content
key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key
key = ::OpenSSL::PKey::EC.new key_content, priv_key_password
# Get curve type (prime256v1...)
group = ::OpenSSL::PKey::EC::Group.new(key.group.curve_name)
# Get Generator point & public point (priv * generator)
generator = group.generator
pub_point = generator.mul(key.private_key)
key.public_key = pub_point
# Public Key in pem
public_key = ::OpenSSL::PKey::EC.new
public_key.group = group
public_key.public_key = pub_point
public_key.to_pem
end
# generate a pem file given a cipher, key, an optional key_password
# @param [OpenSSL::PKey::EC] ec_key the private key object
# @param [String] key_password the password for the private key
# @param [String] key_cipher the cipher to use
# @return [String] pem contents
def encrypt_ec_key(ec_key, key_password, key_cipher)
raise TypeError, 'ec_key must be a Ruby OpenSSL::PKey::EC object' unless ec_key.is_a?(::OpenSSL::PKey::EC)
raise TypeError, 'key_password must be a string' unless key_password.is_a?(String)
raise TypeError, 'key_cipher must be a string' unless key_cipher.is_a?(String)
raise ArgumentError, 'Specified key_cipher is not available on this system' unless ::OpenSSL::Cipher.ciphers.include?(key_cipher)
cipher = ::OpenSSL::Cipher.new(key_cipher)
ec_key.to_pem(cipher, key_password)
end
# generate a csr pem file given a subject and a private key
# @param [OpenSSL::X509::Name] subject the x509 subject object
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] key the private key object
# @return [OpenSSL::X509::Request]
def gen_x509_request(subject, key)
raise TypeError, 'subject must be a Ruby OpenSSL::X509::Name object' unless subject.is_a?(::OpenSSL::X509::Name)
raise TypeError, 'key must be a Ruby OpenSSL::PKey::EC or a Ruby OpenSSL::PKey::RSA object' unless key.is_a?(::OpenSSL::PKey::EC) || key.is_a?(::OpenSSL::PKey::RSA)
request = ::OpenSSL::X509::Request.new
request.version = 0
request.subject = subject
request.public_key = key
# Chef 12 backward compatibility
::OpenSSL::PKey::EC.send(:alias_method, :private?, :private_key?)
request.sign(key, ::OpenSSL::Digest::SHA256.new)
request
end
# generate an array of X509 Extensions given a hash of extensions
# @param [Hash] extensions hash of extensions
# @return [Array]
def gen_x509_extensions(extensions)
raise TypeError, 'extensions must be a Ruby Hash object' unless extensions.is_a?(Hash)
exts = []
extensions.each do |ext_name, ext_prop|
raise TypeError, "#{ext_name} must contain a Ruby Hash" unless ext_prop.is_a?(Hash)
raise ArgumentError, "keys in #{ext_name} must be 'values' and 'critical'" unless ext_prop.key?('values') && ext_prop.key?('critical')
raise TypeError, "the key 'values' must contain a Ruby Arrays" unless ext_prop['values'].is_a?(Array)
raise TypeError, "the key 'critical' must be a Ruby Boolean true/false" unless ext_prop['critical'].is_a?(TrueClass) || ext_prop['critical'].is_a?(FalseClass)
exts << ::OpenSSL::X509::ExtensionFactory.new.create_extension(ext_name, ext_prop['values'].join(','), ext_prop['critical'])
end
exts
end
# generate a random Serial
# @return [Integer]
def gen_serial
::OpenSSL::BN.generate_prime(160)
end
# generate a Certificate given a X509 request
# @param [OpenSSL::X509::Request] request X509 Certificate Request
# @param [Array] extension Array of X509 Certificate Extension
# @param [Hash] info issuer & validity
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] key private key to sign with
# @return [OpenSSL::X509::Certificate]
def gen_x509_cert(request, extension, info, key)
raise TypeError, 'request must be a Ruby OpenSSL::X509::Request' unless request.is_a?(::OpenSSL::X509::Request)
raise TypeError, 'extension must be a Ruby Array' unless extension.is_a?(Array)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise TypeError, 'key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless key.is_a?(::OpenSSL::PKey::EC) || key.is_a?(::OpenSSL::PKey::RSA)
raise ArgumentError, 'info must contain a validity' unless info.key?('validity')
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
cert = ::OpenSSL::X509::Certificate.new
ef = ::OpenSSL::X509::ExtensionFactory.new
cert.serial = gen_serial()
cert.version = 2
cert.subject = request.subject
cert.public_key = request.public_key
cert.not_before = Time.now
cert.not_after = cert.not_before + info['validity'] * 24 * 60 * 60
if info['issuer'].nil?
cert.issuer = request.subject
ef.issuer_certificate = cert
extension << ef.create_extension('basicConstraints', 'CA:TRUE', true)
else
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(::OpenSSL::X509::Certificate)
cert.issuer = info['issuer'].subject
ef.issuer_certificate = info['issuer']
end
ef.subject_certificate = cert
ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE)
cert.extensions = extension
cert.add_extension ef.create_extension('subjectKeyIdentifier', 'hash')
cert.add_extension ef.create_extension('authorityKeyIdentifier',
'keyid:always,issuer:always')
cert.sign(key, ::OpenSSL::Digest::SHA256.new)
cert
end
# generate a X509 CRL given a CA
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def gen_x509_crl(ca_private_key, info)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(::OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
crl = ::OpenSSL::X509::CRL.new
ef = ::OpenSSL::X509::ExtensionFactory.new
crl.version = 1
crl.issuer = info['issuer'].subject
crl.last_update = Time.now
crl.next_update = Time.now + 3600 * 24 * info['validity']
ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE)
ef.issuer_certificate = info['issuer']
crl.add_extension ::OpenSSL::X509::Extension.new('crlNumber', ::OpenSSL::ASN1::Integer(1))
crl.add_extension ef.create_extension('authorityKeyIdentifier',
'keyid:always,issuer:always')
crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new)
crl
end
# generate the next CRL number available for a X509 CRL given
# @param [OpenSSL::X509::CRL] crl x509 CRL
# @return [Integer]
def get_next_crl_number(crl)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(::OpenSSL::X509::CRL)
crlnum = 1
crl.extensions.each do |e|
crlnum = e.value if e.oid == 'crlNumber'
end
crlnum.to_i + 1
end
# add a serial given in the crl given
# @param [Hash] revoke_info serial to revoke & revokation reason
# @param [OpenSSL::X509::CRL] crl X509 CRL
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def revoke_x509_crl(revoke_info, crl, ca_private_key, info)
raise TypeError, 'revoke_info must be a Ruby Hash oject' unless revoke_info.is_a?(Hash)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(::OpenSSL::X509::CRL)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'revoke_info must contain a serial and a reason' unless revoke_info.key?('serial') && revoke_info.key?('reason')
raise TypeError, 'revoke_info[\'serial\'] must be a Ruby String or Integer object' unless revoke_info['serial'].is_a?(String) || revoke_info['serial'].is_a?(Integer)
raise TypeError, 'revoke_info[\'reason\'] must be a Ruby Integer object' unless revoke_info['reason'].is_a?(Integer)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(::OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
revoked = ::OpenSSL::X509::Revoked.new
revoked.serial = if revoke_info['serial'].is_a?(String)
revoke_info['serial'].to_i(16)
else
revoke_info['serial']
end
revoked.time = Time.now
ext = ::OpenSSL::X509::Extension.new('CRLReason',
::OpenSSL::ASN1::Enumerated(revoke_info['reason']))
revoked.add_extension(ext)
crl.add_revoked(revoked)
crl = renew_x509_crl(crl, ca_private_key, info)
crl
end
# renew a X509 crl given
# @param [OpenSSL::X509::CRL] crl CRL to renew
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def renew_x509_crl(crl, ca_private_key, info)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(::OpenSSL::X509::CRL)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(::OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
crl.last_update = Time.now
crl.next_update = crl.last_update + 3600 * 24 * info['validity']
ef = ::OpenSSL::X509::ExtensionFactory.new
ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE)
ef.issuer_certificate = info['issuer']
crl.extensions = [ ::OpenSSL::X509::Extension.new('crlNumber',
::OpenSSL::ASN1::Integer(get_next_crl_number(crl)))]
crl.add_extension ef.create_extension('authorityKeyIdentifier',
'keyid:always,issuer:always')
crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new)
crl
end
end
end

View File

@@ -0,0 +1,82 @@
#
# Cookbook:: openssl
# Library:: random_password
# Author:: Seth Vargo <sethvargo@gmail.com>
#
# Copyright:: 2015-2017, Seth Vargo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# rubocop:disable UnusedMethodArgument, Style/RaiseArgs
module OpenSSLCookbook
module RandomPassword
# Override the included method to require securerandom if it is not defined.
# This avoids the need to load the class on each Chef run unless the user is
# explicitly requiring it.
def self.included(base)
require 'securerandom' unless defined?(SecureRandom)
end
class InvalidPasswordMode < StandardError
def initialize(given, _acceptable = nil)
super <<-EOH
The given password mode '#{given}' is not valid. Valid password modes are :hex,
:base64, and :random_bytes!
EOH
end
end
#
# Generates a random password using {SecureRandom}.
#
# @example Generating a random (hex) password (of 20 characters)
# random_password #=> "1930e99aa035083bdd93d1d8f11cb7ac8f625c9c"
#
# @example Generating a random base64 password that is 50 characters
# random_password(mode: :base64, length: 50) #=> "72o5oVbKHHEVYj1nOgFB2EijnzZfnrbfasVuF+oRH8wMgb0QWoYZF/OkrQricp1ENoI="
#
# @example Generate a password with a forced encoding
# random_password(encoding: "ASCII")
#
# @param [Hash] options
# @option options [Fixnum] :length
# the number of bits to use in the password
# @option options [Symbol] :mode
# the type of random password to generate - valid values are
# `:hex`, `:base64`, or `:random_bytes`
# @option options [String, Symbol, Constant] :encoding
# the encoding to force (default is "UTF-8")
#
# @return [String]
#
def random_password(options = {})
length = options[:length] || 20
mode = options[:mode] || :hex
encoding = options[:encoding] || 'UTF-8'
# Convert to a "proper" length, since the size is actually in bytes
length = case mode
when :hex
length / 2
when :base64
length * 3 / 4
when :random_bytes
length
else
raise InvalidPasswordMode.new(mode)
end
SecureRandom.send(mode, length).force_encoding(encoding)
end
end
end

View File

@@ -0,0 +1,40 @@
#
# Cookbook:: openssl
# Library:: secure_password
# Author:: Joshua Timberman <joshua@chef.io>
#
# Copyright:: 2009-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include OpenSSLCookbook::Helpers
module Opscode
module OpenSSL
# Generate secure passwords with OpenSSL
module Password
def secure_password(length = 20)
Chef::Log.warn('The Opscode::OpenSSL::Password helper "secure_password" has been deprecated. Use the random_password method in OpenSSLCookbook::RandomPassword instead.')
pw = ''
while pw.length < length
pw << ::OpenSSL::Random.random_bytes(1).gsub(/\W/, '')
end
pw
end
end
end
end

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
#
# Cookbook Name:: openssl
# Recipe:: default
#
# Copyright 2009-2016, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@@ -0,0 +1,42 @@
#
# Cookbook:: openssl
# Recipe:: upgrade
#
# Copyright:: 2015-2017, Chef Software, Inc. <legal@chef.io>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
case node['platform_family']
when 'debian', 'ubuntu'
packages = if platform?('debian') && node['platform_version'].to_i >= 9
%w(libssl1.0.2 openssl)
else
%w(libssl1.0.0 openssl)
end
when 'rhel', 'fedora', 'suse', 'amazon'
packages = %w(openssl)
else
packages = []
end
if packages.empty?
Chef::Log.warn("The openssl::upgrade recipe does not currently support #{node['platform']}. If you believe it could please open a PR at https://github.com/chef-cookbooks/openssl")
else
package packages do
action :upgrade
node['openssl']['restart_services'].each do |ssl_svc|
notifies :restart, "service[#{ssl_svc}]"
end
end
end

View File

@@ -0,0 +1,48 @@
#
# Copyright:: Copyright 2009-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :openssl_dhparam
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
property :generator, equal_to: [2, 5], default: 2
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0640'
action :create do
unless dhparam_pem_valid?(new_resource.path)
converge_by("Create a dhparam file #{new_resource.path}") do
dhparam_content = gen_dhparam(new_resource.key_length, new_resource.generator).to_pem
log "Generating #{new_resource.key_length} bit "\
"dhparam file at #{new_resource.path}, this may take some time"
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
sensitive true
content dhparam_content
end
end
end
end

View File

@@ -0,0 +1,55 @@
#
# Copyright:: Copyright 2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_ec_private_key
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :key_curve, equal_to: %w(secp384r1 secp521r1 prime256v1 secp224r1 secp256k1), default: 'prime256v1'
property :key_pass, String
property :key_cipher, String, default: 'des3', equal_to: ::OpenSSL::Cipher.ciphers
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0640'
property :force, [true, false], default: false
action :create do
unless new_resource.force || priv_key_file_valid?(new_resource.path, new_resource.key_pass)
converge_by("Create an EC private key #{new_resource.path}") do
log "Generating an #{new_resource.key_curve} "\
"EC key file at #{new_resource.name}, this may take some time"
if new_resource.key_pass
unencrypted_ec_key = gen_ec_priv_key(new_resource.key_curve)
ec_key_content = encrypt_ec_key(unencrypted_ec_key, new_resource.key_pass, new_resource.key_cipher)
else
ec_key_content = gen_ec_priv_key(new_resource.key_curve).to_pem
end
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
sensitive true
content ec_key_content
end
end
end
end

View File

@@ -0,0 +1,45 @@
#
# Copyright:: Copyright 2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_ec_public_key
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :private_key_path, String
property :private_key_content, String
property :private_key_pass, String
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0640'
action :create do
raise ArgumentError, "You cannot specify both 'private_key_path' and 'private_key_content' properties at the same time." if new_resource.private_key_path && new_resource.private_key_content
raise ArgumentError, "You must specify the private key with either 'private_key_path' or 'private_key_content' properties." unless new_resource.private_key_path || new_resource.private_key_content
raise "#{new_resource.private_key_path} not a valid private EC key or password is invalid" unless priv_key_file_valid?((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
ec_key_content = gen_ec_pub_key((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
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
content ec_key_content
end
end

View File

@@ -0,0 +1,55 @@
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :openssl_rsa_private_key
provides :openssl_rsa_key # legacy name
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
property :key_pass, String
property :key_cipher, String, default: 'des3', equal_to: ::OpenSSL::Cipher.ciphers
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0640'
property :force, [true, false], default: false
action :create do
unless new_resource.force || priv_key_file_valid?(new_resource.path, new_resource.key_pass)
converge_by("Create an RSA private key #{new_resource.path}") do
log "Generating #{new_resource.key_length} bit "\
"RSA key file at #{new_resource.path}, this may take some time"
if new_resource.key_pass
unencrypted_rsa_key = gen_rsa_priv_key(new_resource.key_length)
rsa_key_content = encrypt_rsa_key(unencrypted_rsa_key, new_resource.key_pass, new_resource.key_cipher)
else
rsa_key_content = gen_rsa_priv_key(new_resource.key_length).to_pem
end
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
sensitive true
content rsa_key_content
end
end
end
end

View File

@@ -0,0 +1,45 @@
#
# Copyright:: Copyright 2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :openssl_rsa_public_key
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :private_key_path, String
property :private_key_content, String
property :private_key_pass, String
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0640'
action :create do
raise ArgumentError, "You cannot specify both 'private_key_path' and 'private_key_content' properties at the same time." if new_resource.private_key_path && new_resource.private_key_content
raise ArgumentError, "You must specify the private key with either 'private_key_path' or 'private_key_content' properties." unless new_resource.private_key_path || new_resource.private_key_content
raise "#{new_resource.private_key_path} not a valid private RSA key or password is invalid" unless priv_key_file_valid?((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
rsa_key_content = gen_rsa_pub_key((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
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
content rsa_key_content
end
end

View File

@@ -0,0 +1,151 @@
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_x509_certificate
provides :openssl_x509 # legacy_name
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :owner, String
property :group, String
property :expire, Integer, default: 365
property :mode, [Integer, String], default: '0644'
property :country, String
property :state, String
property :city, String
property :org, String
property :org_unit, String
property :common_name, String
property :email, String
property :extensions, Hash, default: {}
property :subject_alt_name, Array, default: []
property :key_file, String
property :key_pass, String
property :key_type, equal_to: %w(rsa ec), default: 'rsa'
property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
property :key_curve, equal_to: %w(secp384r1 secp521r1 prime256v1), default: 'prime256v1'
property :csr_file, String
property :ca_cert_file, String
property :ca_key_file, String
property :ca_key_pass, String
action :create do
unless ::File.exist? new_resource.path
converge_by("Create #{@new_resource}") do
file new_resource.path do
action :create_if_missing
mode new_resource.mode
owner new_resource.owner unless new_resource.owner.nil?
group new_resource.group unless new_resource.group.nil?
sensitive true
content cert.to_pem
end
if new_resource.csr_file.nil?
file new_resource.key_file do
action :create_if_missing
mode new_resource.mode
owner new_resource.owner unless new_resource.owner.nil?
group new_resource.group unless new_resource.group.nil?
sensitive true
content key.to_pem
end
end
end
end
end
action_class do
def generate_key_file
unless new_resource.key_file
path, file = ::File.split(new_resource.path)
filename = ::File.basename(file, ::File.extname(file))
new_resource.key_file path + '/' + filename + '.key'
end
new_resource.key_file
end
def key
@key ||= if priv_key_file_valid?(generate_key_file, new_resource.key_pass)
::OpenSSL::PKey.read ::File.read(generate_key_file), new_resource.key_pass
elsif new_resource.key_type == 'rsa'
gen_rsa_priv_key(new_resource.key_length)
else
gen_ec_priv_key(new_resource.key_curve)
end
@key
end
def request
request = if new_resource.csr_file.nil?
gen_x509_request(subject, key)
else
::OpenSSL::X509::Request.new ::File.read(new_resource.csr_file)
end
request
end
def subject
subject = ::OpenSSL::X509::Name.new()
subject.add_entry('C', new_resource.country) unless new_resource.country.nil?
subject.add_entry('ST', new_resource.state) unless new_resource.state.nil?
subject.add_entry('L', new_resource.city) unless new_resource.city.nil?
subject.add_entry('O', new_resource.org) unless new_resource.org.nil?
subject.add_entry('OU', new_resource.org_unit) unless new_resource.org_unit.nil?
subject.add_entry('CN', new_resource.common_name)
subject.add_entry('emailAddress', new_resource.email) unless new_resource.email.nil?
subject
end
def ca_private_key
ca_private_key = if new_resource.csr_file.nil?
key
else
::OpenSSL::PKey.read ::File.read(new_resource.ca_key_file), new_resource.ca_key_pass
end
ca_private_key
end
def ca_info
# Will contain issuer (if any) & expiration
ca_info = {}
unless new_resource.ca_cert_file.nil?
ca_info['issuer'] = ::OpenSSL::X509::Certificate.new ::File.read(new_resource.ca_cert_file)
end
ca_info['validity'] = new_resource.expire
ca_info
end
def extensions
extensions = gen_x509_extensions(new_resource.extensions)
unless new_resource.subject_alt_name.empty?
extensions += gen_x509_extensions('subjectAltName' => { 'values' => new_resource.subject_alt_name, 'critical' => false })
end
extensions
end
def cert
cert = gen_x509_cert(request, extensions, ca_info, ca_private_key)
cert
end
end

View File

@@ -0,0 +1,88 @@
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_x509_crl
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :serial_to_revoke, [Integer, String]
property :revocation_reason, Integer, default: 0
property :expire, Integer, default: 8
property :renewal_threshold, Integer, default: 1
property :ca_cert_file, String, required: true
property :ca_key_file, String, required: true
property :ca_key_pass, String
property :owner, String
property :group, String
property :mode, String
action :create do
file new_resource.path do
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?
content crl.to_pem
action :create
end
end
action_class do
def crl_info
# Will contain issuer & expiration
crl_info = {}
crl_info['issuer'] = ::OpenSSL::X509::Certificate.new ::File.read(new_resource.ca_cert_file)
crl_info['validity'] = new_resource.expire
crl_info
end
def revoke_info
# Will contain Serial to revoke & reason
revoke_info = {}
revoke_info['serial'] = new_resource.serial_to_revoke
revoke_info['reason'] = new_resource.revocation_reason
revoke_info
end
def ca_private_key
ca_private_key = ::OpenSSL::PKey.read ::File.read(new_resource.ca_key_file), new_resource.ca_key_pass
ca_private_key
end
def crl
if crl_file_valid?(new_resource.path)
crl = ::OpenSSL::X509::CRL.new ::File.read(new_resource.path)
else
log "Creating a CRL #{new_resource.path} for CA #{new_resource.ca_cert_file}"
crl = gen_x509_crl(ca_private_key, crl_info)
end
if !new_resource.serial_to_revoke.nil? && serial_revoked?(crl, new_resource.serial_to_revoke) == false
log "Revoking serial #{new_resource.serial_to_revoke} in CRL #{new_resource.path}"
crl = revoke_x509_crl(revoke_info, crl, ca_private_key, crl_info)
elsif crl.next_update <= Time.now + 3600 * 24 * new_resource.renewal_threshold
log "Renewing CRL for CA #{new_resource.ca_cert_file}"
crl = renew_x509_crl(crl, ca_private_key, crl_info)
end
crl
end
end

View File

@@ -0,0 +1,98 @@
#
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
chef_version_for_provides '< 14.4' if respond_to?(:chef_version_for_provides)
resource_name :openssl_x509_request
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :owner, String
property :group, String
property :mode, [Integer, String], default: '0644'
property :country, String
property :state, String
property :city, String
property :org, String
property :org_unit, String
property :common_name, String, required: true
property :email, String
property :key_file, String
property :key_pass, String
property :key_type, equal_to: %w(rsa ec), default: 'ec'
property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
property :key_curve, equal_to: %w(secp384r1 secp521r1 prime256v1), default: 'prime256v1'
action :create do
unless ::File.exist? new_resource.path
converge_by("Create CSR #{@new_resource}") do
file new_resource.name do
owner new_resource.owner unless new_resource.owner.nil?
group new_resource.group unless new_resource.group.nil?
mode new_resource.mode
content csr.to_pem
action :create
end
file new_resource.key_file do
mode new_resource.mode
owner new_resource.owner unless new_resource.owner.nil?
group new_resource.group unless new_resource.group.nil?
content key.to_pem
sensitive true
action :create_if_missing
end
end
end
end
action_class do
def generate_key_file
unless new_resource.key_file
path, file = ::File.split(new_resource.path)
filename = ::File.basename(file, ::File.extname(file))
new_resource.key_file path + '/' + filename + '.key'
end
new_resource.key_file
end
def key
@key ||= if priv_key_file_valid?(generate_key_file, new_resource.key_pass)
::OpenSSL::PKey.read ::File.read(generate_key_file), new_resource.key_pass
elsif new_resource.key_type == 'rsa'
gen_rsa_priv_key(new_resource.key_length)
else
gen_ec_priv_key(new_resource.key_curve)
end
@key
end
def subject
csr_subject = ::OpenSSL::X509::Name.new()
csr_subject.add_entry('C', new_resource.country) unless new_resource.country.nil?
csr_subject.add_entry('ST', new_resource.state) unless new_resource.state.nil?
csr_subject.add_entry('L', new_resource.city) unless new_resource.city.nil?
csr_subject.add_entry('O', new_resource.org) unless new_resource.org.nil?
csr_subject.add_entry('OU', new_resource.org_unit) unless new_resource.org_unit.nil?
csr_subject.add_entry('CN', new_resource.common_name)
csr_subject.add_entry('emailAddress', new_resource.email) unless new_resource.email.nil?
csr_subject
end
def csr
gen_x509_request(subject, key)
end
end