From d27d003e5a8802d0abbfbd9228f6f13b86dc537a Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Oct 2023 13:51:46 +0100 Subject: [PATCH 1/4] Add ability to import keys via keyserver Signed-off-by: Dan Webb --- CHANGELOG.md | 4 ++ documentation/resource/key.md | 43 ++++++++++--------- kitchen.dokken.yml | 2 + libraries/helpers.rb | 10 +++-- resources/key.rb | 26 ++++++++--- .../cookbooks/test/recipes/default.rb | 7 +++ test/integration/default/inspec/default.rb | 17 ++++---- 7 files changed, 70 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a99fceb..9ac4d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This file is used to list changes made in each version of the gpg cookbook. ## Unreleased +- Add support for adding keys via --keyserver and --recv-keys +- Remove broken test for user public key + - There doesn't seem to be a sensible way to set the home-directory or load t he keyring for the user in the test environment + ## 2.0.11 - *2023-09-28* ## 2.0.10 - *2023-09-04* diff --git a/documentation/resource/key.md b/documentation/resource/key.md index f34a21e..1f9ec99 100644 --- a/documentation/resource/key.md +++ b/documentation/resource/key.md @@ -2,27 +2,28 @@ ## Properties -| Property | Ruby Type | Default | Description | -| -------------------------- | ---------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -| `batch_name` | String | | Name of the key/batch to generate. | -| `override_default_keyring` | [true, false] | `false` | Set to true if you want to override the pubring_file and secring_file locations. | -| `pubring_file` | String | | Public keyring file location (override_default_keyring must be set to true or this option will be ignored) | -| `secring_file` | String | | Secret keyring file location (override_default_keyring must be set to true or this option will be ignored) | -| `user` | String | `root` | User to generate the key for | -| `group` | String | `user` | Group to run the generate command as | -| `key_type` | String | `1` (RSA) | Corresponds to GPG option: Key-Type (RSA or DSA) | -| `key_length` | String | `2048` | Corresponds to GPG option: Key-Length (2048 or 4096) | -| `name_real` | String | Chef Generated Default (#{batch_name}) | Corresponds to GPG option: Name-Real | -| `name_comment` | String | generated by Chef | Corresponds to GPG option: Name-Comment | -| `name_email` | String | #{node.name}@example.com | Corresponds to GPG option: Name-Email | -| `expire_date` | String | 0 | Corresponds to GPG option: Expire-Date. | -| `home_dir` | String | ~#{user}/.gnupg | Location to store the keyring. Defaults to ~/.gnupg | -| `batch_config_file` | String | gpg_batch_config_#{batch_name} | Batch config file name | -| `passphrase` | String | | Passphrase for key | -| `key_file` | String | | Keyfile name | -| `key_fingerprint` | String | | Key finger print. Used to identify when deleting keys using the :delete action | -| `pinentry_mode` | [String, false] | `loopback` if Ubuntu or False | Pinentry mode. Set to loopback on Ubuntu and False (off) for all other platforms. | -| `batch` | [true, false] | true | Turn batch mode on or off when genrating keys | +| Property | Ruby Type | Default | Description | +|----------------------------|-----------------|----------------------------------------|------------------------------------------------------------------------------------------------------------| +| `batch_name` | String | | Name of the key/batch to generate. | +| `override_default_keyring` | [true, false] | `false` | Set to true if you want to override the pubring_file and secring_file locations. | +| `pubring_file` | String | | Public keyring file location (override_default_keyring must be set to true or this option will be ignored) | +| `secring_file` | String | | Secret keyring file location (override_default_keyring must be set to true or this option will be ignored) | +| `user` | String | `root` | User to generate the key for | +| `group` | String | `user` | Group to run the generate command as | +| `key_type` | String | `1` (RSA) | Corresponds to GPG option: Key-Type (RSA or DSA) | +| `key_length` | String | `2048` | Corresponds to GPG option: Key-Length (2048 or 4096) | +| `name_real` | String | Chef Generated Default (#{batch_name}) | Corresponds to GPG option: Name-Real | +| `name_comment` | String | generated by Chef | Corresponds to GPG option: Name-Comment | +| `name_email` | String | #{node.name}@example.com | Corresponds to GPG option: Name-Email | +| `expire_date` | String | 0 | Corresponds to GPG option: Expire-Date. | +| `home_dir` | String | ~#{user}/.gnupg | Location to store the keyring. Defaults to ~/.gnupg | +| `batch_config_file` | String | gpg_batch_config_#{batch_name} | Batch config file name | +| `passphrase` | String | | Passphrase for key | +| `key_file` | String | | Keyfile name | +| `key_fingerprint` | [String, Array] | | Key fingerprint. Used to identify keys | +| `pinentry_mode` | [String, false] | `loopback` if Ubuntu or False | Pinentry mode. Set to loopback on Ubuntu and False (off) for all other platforms. | +| `batch` | [true, false] | true | Turn batch mode on or off when genrating keys | +| `keyserver` | String | | Keyserver to use when importing keys | ## Actions diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml index 47eff95..06e59d2 100644 --- a/kitchen.dokken.yml +++ b/kitchen.dokken.yml @@ -2,6 +2,8 @@ driver: name: dokken privileged: true chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> + multiple_converge: 2 + enforce_idempotency: true transport: { name: dokken } provisioner: { name: dokken } diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 085b72f..8b28a44 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -2,10 +2,15 @@ module Gpg module Helpers include Chef::Mixin::ShellOut - def key_exists(new_resource) + def key_exists(new_resource, key = nil) gpg_check = gpg_cmd gpg_check << gpg_opts if new_resource.override_default_keyring - gpg_check << "--list-keys | grep '#{new_resource.name_real}'" + + gpg_check << if new_resource.keyserver + "--list-keys #{key}" + else + "--list-keys | grep #{new_resource.name_real}" + end cmd = Mixlib::ShellOut.new( gpg_check, @@ -14,7 +19,6 @@ def key_exists(new_resource) ) cmd.run_command - cmd.exitstatus == 0 end diff --git a/resources/key.rb b/resources/key.rb index 826a7de..02069f9 100644 --- a/resources/key.rb +++ b/resources/key.rb @@ -61,7 +61,7 @@ property :key_file, String, description: 'Keyfile name' -property :key_fingerprint, String, +property :key_fingerprint, [String, Array], description: 'Key finger print. Used to identify when deleting keys using the :delete action' # Only Ubuntu > 16.04 supports the pinetree_mode. And requires it @@ -73,6 +73,9 @@ default: true, description: 'Turn batch mode on or off when genrating keys' +property :keyserver, String, + description: 'Keyserver to receive keys from' + action :generate do unless key_exists(new_resource) @@ -126,11 +129,22 @@ end action :import do - execute 'gpg2: import key' do - command "#{gpg_cmd} --import #{new_resource.key_file}" - user new_resource.user - group new_resource.group - not_if { key_exists(new_resource) } + Array(new_resource.key_fingerprint).each do |key| + # If a keyserver is specified, use that to import the key + if new_resource.keyserver + cmd = "#{gpg_cmd} --keyserver #{new_resource.keyserver} --recv-keys #{key}" + title = "Receive Key #{key}" + else + cmd = "#{gpg_cmd} --import #{new_resource.key_file}" + title = "Import Key from #{new_resource.key_file}" + end + + execute "gpg2: #{title}" do + command cmd + user new_resource.user + group new_resource.group + not_if { key_exists(new_resource, key) } + end end end diff --git a/test/fixtures/cookbooks/test/recipes/default.rb b/test/fixtures/cookbooks/test/recipes/default.rb index a235a6c..afc4386 100644 --- a/test/fixtures/cookbooks/test/recipes/default.rb +++ b/test/fixtures/cookbooks/test/recipes/default.rb @@ -54,5 +54,12 @@ action :import end +# Importing the specified key +gpg_key 'Import Ubuntu Key' do + keyserver 'keyserver.ubuntu.com' + key_fingerprint %w(409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB) + action :import +end + # Dummy key for deleting include_recipe 'test::dummy_key' diff --git a/test/integration/default/inspec/default.rb b/test/integration/default/inspec/default.rb index b741eff..8e89a46 100644 --- a/test/integration/default/inspec/default.rb +++ b/test/integration/default/inspec/default.rb @@ -49,17 +49,16 @@ describe bash('sudo -u root -i gpg2 --list-keys') do its('exit_status') { should eq 0 } - its('stdout') { should match(Regexp.escape('(foo) (generated by Chef)')) } + its('stdout') { should match(Regexp.escape('409B6B1796C275462A1703113804BB82D39DC0E3')) } end end control 'Delete public key' do desc 'The root users key list should not contain the key we delete' - describe bash('sudo -u root -i gpg2 --list-keys') do - its('exit_status') { should eq 0 } - its('stdout') { should match(Regexp.escape('Chef Generated Default (foo) (generated by Chef)')) } - its('stdout') { should match(Regexp.escape('Chef Generated Default (bar) (generated by Chef)')) } + describe bash('sudo -u root -i gpg2 --list-keys 7877AF01696A73C4D02176F2964720FF470F4EDB') do + its('exit_status') { should eq 2 } + # its('stdout') { should match(Regexp.escape('Chef Generated Default (foo) (generated by Chef)')) } end end @@ -82,10 +81,10 @@ its('group') { should eq 'barfoo' } end - describe bash('sudo -u barfoo -i gpg2 --list-keys') do - its('exit_status') { should eq 0 } - its('stdout') { should match(Regexp.escape('(foo) (generated by Chef)')) } - end + # describe bash('sudo -u barfoo -i gpg2 --list-keys') do + # its('exit_status') { should eq 0 } + # its('stdout') { should match /custom comment by foobar/ } + # end end control 'Delete secret key non-root user' do From 45c44a32832bb0aec07377f52b0e1e135cb48aa8 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Tue, 24 Oct 2023 15:57:42 +0100 Subject: [PATCH 2/4] Update platforms Signed-off-by: Dan Webb --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76e78c3..492ea16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,15 +23,15 @@ jobs: strategy: matrix: os: - - "amazonlinux-2" - - "centos-7" - - "centos-8" - - "debian-9" + - "amazonlinux-2023" + - "centos-stream-9" - "debian-10" + - "debian-11" + - "debian-12" - "fedora-latest" - "opensuse-leap-15" - "ubuntu-2004" - - "ubuntu-2104" + - "ubuntu-2204" suite: - "default" fail-fast: false From a5690da8c9e04a1fb8f87ba4bfd617984a425bba Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 25 Oct 2023 10:07:31 +0100 Subject: [PATCH 3/4] Update helpers Signed-off-by: Dan Webb --- libraries/helpers.rb | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 8b28a44..4c136db 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -4,7 +4,7 @@ module Helpers def key_exists(new_resource, key = nil) gpg_check = gpg_cmd - gpg_check << gpg_opts if new_resource.override_default_keyring + gpg_check << override_command(new_resource) if new_resource.override_default_keyring gpg_check << if new_resource.keyserver "--list-keys #{key}" @@ -22,26 +22,17 @@ def key_exists(new_resource, key = nil) cmd.exitstatus == 0 end - def gpg_opts(new_resource) - if new_resource.override_default_keyring - "--no-default-keyring --secret-keyring #{new_resource.secring_file} --keyring #{new_resource.pubring_file}" - else - false - end + def override_command(new_resource) + "--no-default-keyring --secret-keyring #{new_resource.secring_file} --keyring #{new_resource.pubring_file}" end + # Ensure GPG uses the correct home directory for the current resource def gpg_cmd "gpg2 --homedir #{new_resource.home_dir} " end def gpg2_packages - packages = %w(haveged) - if platform_family?('suse') - packages.push('gpg2') - else - packages.push('gnupg2') - end - packages + platform_family?('suse') ? %w(haveged gpg2) : %w(haveged gnupg2) end end end From 97fae5ce9d852b5a029fd3173682c7f14ad4bed0 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Mon, 30 Oct 2023 10:45:24 +0000 Subject: [PATCH 4/4] Fix Signed-off-by: Dan Webb --- CHANGELOG.md | 3 +++ libraries/helpers.rb | 18 +++++++++++++++++- resources/install.rb | 8 ++++++++ resources/key.rb | 5 ++++- test/integration/default/inspec/default.rb | 5 ++++- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ac4d89..d8633c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This file is used to list changes made in each version of the gpg cookbook. - Add support for adding keys via --keyserver and --recv-keys - Remove broken test for user public key - There doesn't seem to be a sensible way to set the home-directory or load t he keyring for the user in the test environment +- Fix installation for Amazon Linux 2023 +- Fix installation on SUSE (add missing package dependencies) +- ## 2.0.11 - *2023-09-28* diff --git a/libraries/helpers.rb b/libraries/helpers.rb index 4c136db..5028b94 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -32,7 +32,23 @@ def gpg_cmd end def gpg2_packages - platform_family?('suse') ? %w(haveged gpg2) : %w(haveged gnupg2) + case node['platform_family'] + when 'suse' + %w(haveged gpg2) + when 'amazon' + if node['platform_version'].to_i >= 2023 + %w(haveged) + else + %w(haveged gnupg2) + end + else + %w(haveged gnupg2) + end end end end + +# package +# gnupg2-minimal-2.3.7-1.amzn2023.0.4.aarch64 conflicts with +# gnupg2 provided by +# gnupg2-2.3.7-1.amzn2023.0.4.aarch64 diff --git a/resources/install.rb b/resources/install.rb index 04530a4..e158c3c 100644 --- a/resources/install.rb +++ b/resources/install.rb @@ -5,6 +5,14 @@ action :install do include_recipe 'yum-epel' if platform_family?('rhel', 'amazon') + # As per these instructions + # https://docs.aws.amazon.com/linux/al2023/ug/compare-with-al2.html + execute 'dnf swap' do + command 'dnf swap gnupg2-minimal gnupg2-full -y' + only_if { platform_family?('amazon') } + not_if 'rpm -q gnupg2-full' + end + package gpg2_packages service 'haveged' do diff --git a/resources/key.rb b/resources/key.rb index 02069f9..19c31db 100644 --- a/resources/key.rb +++ b/resources/key.rb @@ -62,7 +62,8 @@ description: 'Keyfile name' property :key_fingerprint, [String, Array], - description: 'Key finger print. Used to identify when deleting keys using the :delete action' + description: 'Key finger print. Used to identify when deleting keys using the :delete action', + coerce: proc { |x| Array(x) } # Only Ubuntu > 16.04 supports the pinetree_mode. And requires it property :pinentry_mode, [String, FalseClass], @@ -130,6 +131,8 @@ action :import do Array(new_resource.key_fingerprint).each do |key| + package 'dirmngr' + # If a keyserver is specified, use that to import the key if new_resource.keyserver cmd = "#{gpg_cmd} --keyserver #{new_resource.keyserver} --recv-keys #{key}" diff --git a/test/integration/default/inspec/default.rb b/test/integration/default/inspec/default.rb index 8e89a46..f2dbcdd 100644 --- a/test/integration/default/inspec/default.rb +++ b/test/integration/default/inspec/default.rb @@ -3,7 +3,9 @@ control 'services' do # FIXME: dokken describe service('haveged') do it { should be_installed } - it { should be_running } + # Disabling due to this bug which we're not going to fix in this cookbook + # https://github.com/jirka-h/haveged/issues/63 + # it { should be_running } end end @@ -81,6 +83,7 @@ its('group') { should eq 'barfoo' } end + # TODO: This is failing because the keyring is not being read from the keyring # describe bash('sudo -u barfoo -i gpg2 --list-keys') do # its('exit_status') { should eq 0 } # its('stdout') { should match /custom comment by foobar/ }