Showing with 260 additions and 103 deletions.
  1. +3 −0 .gitignore
  2. +13 −14 .gitlab-ci.yml
  3. +5 −0 .pdkignore
  4. +6 −2 .rubocop.yml
  5. +20 −18 .travis.yml
  6. +6 −0 .vscode/extensions.json
  7. +11 −10 Gemfile
  8. +44 −18 README.md
  9. +61 −0 REFERENCE.md
  10. +13 −3 Rakefile
  11. +1 −0 appveyor.yml
  12. +1 −1 files/extend.sh
  13. +10 −9 metadata.json
  14. +41 −15 plans/extend_ca_cert.pp
  15. +5 −5 plans/upload_ca_cert.pp
  16. +8 −1 spec/spec_helper.rb
  17. +10 −5 tasks/check_agent_expiry.sh
  18. +1 −1 tasks/check_ca_expiry.sh
  19. +1 −1 tasks/configure_master.sh
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
/convert_report.txt
/update_report.txt
.DS_Store
.project
.envrc
/inventory.yaml
27 changes: 13 additions & 14 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,27 @@ before_script:
- bundle -v
- bundle install --without system_tests --path vendor/bundle --jobs $(nproc)

parallel_spec-Ruby 2.1.9-Puppet ~> 4.0:
stage: unit
image: ruby:2.1.9
syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.5.3-Puppet ~> 6:
stage: syntax
image: ruby:2.5.3
script:
- bundle exec rake parallel_spec
- bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop
variables:
PUPPET_GEM_VERSION: '~> 4.0'
RUBYGEMS_VERSION: '2.7.8'
PUPPET_GEM_VERSION: '~> 6'

syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.4.4-Puppet ~> 5.5:
stage: syntax
image: ruby:2.4.4
parallel_spec-Ruby 2.5.3-Puppet ~> 6:
stage: unit
image: ruby:2.5.3
script:
- bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop
- bundle exec rake parallel_spec
variables:
PUPPET_GEM_VERSION: '~> 5.5'
PUPPET_GEM_VERSION: '~> 6'

parallel_spec-Ruby 2.4.4-Puppet ~> 5.5:
parallel_spec-Ruby 2.4.5-Puppet ~> 5:
stage: unit
image: ruby:2.4.4
image: ruby:2.4.5
script:
- bundle exec rake parallel_spec
variables:
PUPPET_GEM_VERSION: '~> 5.5'
PUPPET_GEM_VERSION: '~> 5'

5 changes: 5 additions & 0 deletions .pdkignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
/convert_report.txt
/update_report.txt
.DS_Store
.project
.envrc
/inventory.yaml
/appveyor.yml
/.fixtures.yml
/Gemfile
Expand All @@ -30,8 +33,10 @@
/.gitlab-ci.yml
/.pdkignore
/Rakefile
/rakelib/
/.rspec
/.rubocop.yml
/.travis.yml
/.yardopts
/spec/
/.vscode/
8 changes: 6 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
require: rubocop-rspec
require:
- rubocop-rspec
- rubocop-i18n
AllCops:
DisplayCopNames: true
TargetRubyVersion: '2.1'
Expand All @@ -19,10 +21,12 @@ AllCops:
Metrics/LineLength:
Description: People have wide screens, use them.
Max: 200
GetText:
Enabled: false
GetText/DecorateString:
Description: We don't want to decorate test output.
Exclude:
- spec/*
- spec/**/*
RSpec/BeforeAfterAll:
Description: Beware of using after(:all) as it may cause state to leak between tests.
A necessary evil in acceptance testing.
Expand Down
38 changes: 20 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
dist: trusty
dist: xenial
language: ruby
cache: bundler
before_install:
Expand All @@ -12,32 +12,34 @@ script:
- 'bundle exec rake $CHECK'
bundler_args: --without system_tests
rvm:
- 2.5.1
env:
global:
- BEAKER_PUPPET_COLLECTION=puppet6 PUPPET_GEM_VERSION="~> 6.0"
- 2.5.3
stages:
- static
- spec
- acceptance
-
if: tag =~ ^v\d
name: deploy
matrix:
fast_finish: true
include:
-
env: CHECK="syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop"
-
env: CHECK=parallel_spec
env: CHECK="check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop syntax lint metadata_lint"
stage: static
-
env: PUPPET_GEM_VERSION="~> 5.0" CHECK=parallel_spec
rvm: 2.4.4
rvm: 2.4.5
stage: spec
-
env: PUPPET_GEM_VERSION="~> 6.0" CHECK=parallel_spec
rvm: 2.5.3
stage: spec
-
env: DEPLOY_TO_FORGE=yes
stage: deploy
branches:
only:
- master
- /^v\d/
notifications:
email: false
deploy:
provider: puppetforge
user: puppet
password:
secure: ""
on:
tags: true
all_branches: true
condition: "$DEPLOY_TO_FORGE = yes"
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"recommendations": [
"jpogran.puppet-vscode",
"rebornix.Ruby"
]
}
21 changes: 11 additions & 10 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments
minor_version = ruby_version_segments[0..1].join('.')

group :development do
gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0')
gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0')
gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9')
gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
gem "puppet-module-posix-default-r#{minor_version}", require: false, platforms: [:ruby]
gem "puppet-module-posix-dev-r#{minor_version}", require: false, platforms: [:ruby]
gem "puppet-module-win-default-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw]
gem "puppet-module-win-dev-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw]
gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0')
gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0')
gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9')
gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw]
gem "puppet-module-posix-default-r#{minor_version}", '~> 0.3', require: false, platforms: [:ruby]
gem "puppet-module-posix-dev-r#{minor_version}", '~> 0.3', require: false, platforms: [:ruby]
gem "puppet-module-win-default-r#{minor_version}", '~> 0.3', require: false, platforms: [:mswin, :mingw, :x64_mingw]
gem "puppet-module-win-dev-r#{minor_version}", '~> 0.3', require: false, platforms: [:mswin, :mingw, :x64_mingw]
end

puppet_version = ENV['PUPPET_GEM_VERSION']
Expand Down
62 changes: 44 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,50 @@

## Description

A set of Plans and Tasks to extend the expiration date of the certificate for the certificate authority in Puppet Enterprise and distrubute the certificate to agent nodes.
A set of Plans and Tasks to extend the expiration date of the certificate for the certificate authority in Puppet Enterprise and distribute the certificate to agent nodes.

The functionality of this module is divided into two main plans:

* `ca_extend::extend_ca_cert`
* Extends the CA certificate and configures the master and any compile masters to use the new certificate
* `ca_extend::upload_ca_cert`
* Distributes the certificate to any number of agents. Any protocol supported by Bolt can be used, such as `ssh`, `winrm`, or `PCP`.

Regardless of whether the CA cert has passed expiration or not, the `extend_ca_cert` plan may be used to extend its expiration date in-place and configure the master and compilers to use it.

After the CA is functional again (or if it had yet to expire), there are two options for distributing the new cert to agents.

* Using the `ca_extend::upload_ca_cert` plan or another method to copy the new `ca.pem` into place on agents.
* Deleting `ca.pem` from agents and letting them download the file as part of the next Puppet agent run. The agent will re-download this file only if it is absent, so it must be deleted to get a new copy using this method.

There are also two complementary tasks to check the expiry of the CA cert and any agent certificates.

* `ca_extend::check_agent_expiry`
* Checks if any agent certificates expire by a certain date. Defaults to 3 months from today
* `ca_extend::check_ca_expiry`
* Checks if the CA certificate expires by a certain date. Defaults to 3 months from today

## Setup
This module requires a [Bolt installation](https://puppet.com/docs/bolt/latest/bolt_installing.html) >= 1.8.0 on either a client machine or the Puppet master

The recommended installation procedure for this module is to use a [Bolt Puppetfile](https://puppet.com/docs/bolt/latest/installing_tasks_from_the_forge.html#task-8928). From within a [Boltdir](https://puppet.com/docs/bolt/latest/bolt_project_directories.html#embedded-project-directory), specify this module and `puppetlabs-stdlib` as dependencies and run `bolt puppetfile install`. For example:
The recommended installation procedure for this module is to use a [Bolt Puppetfile](https://puppet.com/docs/bolt/latest/installing_tasks_from_the_forge.html#task-8928). From within a [Boltdir](https://puppet.com/docs/bolt/latest/bolt_project_directories.html#embedded-project-directory), specify this module and `puppetlabs-stdlib` as dependencies and run `bolt puppetfile install`. For example, to install Bolt and the required modules on an EL 7 master:

```
sudo rpm -Uvh https://yum.puppet.com/puppet-tools-release-el-7.noarch.rpm
sudo yum install puppet-bolt
```

```
~/Boltdir$ cat Puppetfile
mkdir -p ~/Boltdir
cd !$
cat >>Puppetfile <<EOF
mod 'puppetlabs-stdlib'
mod 'm0dular/ca_extend',
git: 'git@github.com:m0dular/ca_extend.git'
mod 'puppetlabs-ca_extend'
EOF
~/Boltdir$ bolt puppetfile install
Successfully synced modules from /home/adrian/Boltdir/Puppetfile to /home/adrian/Boltdir/modules
bolt puppetfile install
```

## Dependencies
Expand All @@ -43,22 +71,20 @@ Alternatively, one can use an `ssh` config file if only using this protocol to c

### Connecting to PuppetDB

Another convenient way to specify targets for the `ca_extend::upload_ca_cert` plan is by connecting Bolt to [PuppetDB](https://puppet.com/docs/bolt/latest/bolt_command_reference.html#command-options), after which the [--query](https://puppet.com/docs/bolt/latest/bolt_command_reference.html#command-options) can be used to specify a node list. See `REFERENCE.md` for an example.

## Usage

The functionality of this module is divided into two main plans:

* `ca_extend::extend_ca_cert` to extend the certificate and configure the master and any compile masters to use the new certificate
* `ca_extend::upload_ca_cert` to distribute the certificate to any number of agents. Any protocol supported by Bolt can be used, such as `ssh`, `winrm`, or `PCP`.
Another convenient way to specify targets for the `ca_extend::upload_ca_cert` plan is by connecting Bolt to [PuppetDB](https://puppet.com/docs/bolt/latest/bolt_connect_puppetdb.html), after which the [--query](https://puppet.com/docs/bolt/latest/bolt_command_reference.html#command-options) can be used to specify a node list. See `REFERENCE.md` for an example.

### Usage
### Examples

```
bolt plan run ca_extend::extend_ca_cert master=<master_fqdn> compile_masters=<comma_separated_compile_master_fqdns>
```

```
bolt plan run ca_extend::upload_ca_cert cert=<path_to_cert> --nodes <TargetSpec>
```
See `REFERENCE.md` for example commands
```
bolt task run ca_extend::check_ca_expiry --nodes <TargetSpec>
```
```
bolt task run ca_extend::check_agent_expiry --nodes <TargetSpec>
```
See `REFERENCE.md` for more detailed example commands
61 changes: 61 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,64 @@ Finished: plan ca_extend::upload_ca_cert in 17.41 sec
}
}
```

## Tasks

### `ca_extend::check_ca_expiry`

#### Arguments

* cert - Optional location of certificate on disk to check. Defaults to /etc/puppetlabs/puppet/ssl/certs/ca.pem.
* date - Optional YYYY-MM-DD format date against which to check for expiration. Defaults to 3 months in the future.

This task accepts any valid TargetSpec(s) specified by the `--nodes` option. Can be run on any \*nix agent node or the master.

#### Steps

* Uses `openssl` and Unix `date` to determine if the certificate will expire.

#### Output

A JSON object with the status and expiration date, e.g.

```
{
"status": "valid",
"expiry date": "Feb 16 01:00:09 2034 GMT"
}
```

### `ca_extend::check_agent_expiry`

#### Arguments

* date - Optional YYYY-MM-DD format date against which to check for expiration

This task accepts any valid TargetSpec(s) specified by the `--nodes` option. Should be run on the master.

#### Steps

* Uses `openssl` and Unix `date` to determine if the signed agent certificates under `/etc/puppetlabs/puppet/ssl/ca/signed/` will expire.

#### Output

A JSON object with keys for valid and expiring certificates, e.g.

```
{
"valid": [
"/etc/puppetlabs/puppet/ssl/ca/signed/c4lscpmafhaxjr8.delivery.puppetlabs.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/cd4pe-containers.platform9.puppet.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/iwj6668y4s3vq40.delivery.puppetlabs.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/koo1nzsozj2xeqh.delivery.puppetlabs.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/mafy3pgo98v2vne.delivery.puppetlabs.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/pe-201901-agent.platform9.puppet.net.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/pe-201901-compile.puppetdebug.vlan.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/pe-201901-master.puppetdebug.vlan.pem",
"/etc/puppetlabs/puppet/ssl/ca/signed/qgocotu07r3rdpa.delivery.puppetlabs.net.pem"
],
"expiring": [
]
}
```
16 changes: 13 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any?
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-syntax/tasks/puppet-syntax'
require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any?
Expand All @@ -14,15 +15,24 @@ end

def changelog_project
return unless Rake.application.top_level_tasks.include? "changelog"
returnVal = nil || JSON.load(File.read('metadata.json'))['name']
raise "unable to find the changelog_project in .sync.yml or the name in metadata.json" if returnVal.nil?

returnVal = nil
returnVal ||= begin
metadata_source = JSON.load(File.read('metadata.json'))['source']
metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z})

metadata_source_match && metadata_source_match[1]
end

raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil?

puts "GitHubChangelogGenerator project:#{returnVal}"
returnVal
end

def changelog_future_release
return unless Rake.application.top_level_tasks.include? "changelog"
returnVal = JSON.load(File.read('metadata.json'))['version']
returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version']
raise "unable to find the future_release (version) in metadata.json" if returnVal.nil?
puts "GitHubChangelogGenerator future_release:#{returnVal}"
returnVal
Expand Down
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ version: 1.1.x.{build}
branches:
only:
- master
- release
skip_commits:
message: /^\(?doc\)?.*/
clone_depth: 10
Expand Down
2 changes: 1 addition & 1 deletion files/extend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ if (( chain_length > 1 )); then
printf 'This script only works on CA files that contain a single certificate.\n' >&2
exit 1
elif (( chain_length != 1 )); then
printf 'No certificates found in: %s\n' "${chain_length}" "${ca_cert}" >&2
printf 'No certificates found in: %s\n' "${ca_cert}" >&2
exit 1
else
printf '%s certificate found in: %s\n' "${chain_length}" "${ca_cert}" >&2
Expand Down
Loading