From da84dbb1f16e7c4b8541a2327e02110ce8bc82c3 Mon Sep 17 00:00:00 2001 From: "Eric D. Helms" Date: Tue, 12 Apr 2022 22:03:31 -0400 Subject: [PATCH] Add pull-mqtt support to smart_proxy_remote_execution --- .fixtures.yml | 2 + examples/remote_execution_script_pull_mqtt.pp | 4 + .../plugin/remote_execution/mosquitto.pp | 94 +++++++++++++++++++ manifests/plugin/remote_execution/script.pp | 8 +- .../remote_execution_script_pull_mqtt_spec.rb | 60 ++++++++++++ templates/plugin/foreman.acl.epp | 9 ++ 6 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 examples/remote_execution_script_pull_mqtt.pp create mode 100644 manifests/plugin/remote_execution/mosquitto.pp create mode 100644 spec/acceptance/remote_execution_script_pull_mqtt_spec.rb create mode 100644 templates/plugin/foreman.acl.epp diff --git a/.fixtures.yml b/.fixtures.yml index aada0403e..f1dc51b8c 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -27,3 +27,5 @@ fixtures: sshkeys_core: repo: "https://github.com/puppetlabs/puppetlabs-sshkeys_core" puppet_version: ">= 6.0.0" + mosquitto: + repo: "https://github.com/voxpupuli/puppet-mosquitto" diff --git a/examples/remote_execution_script_pull_mqtt.pp b/examples/remote_execution_script_pull_mqtt.pp new file mode 100644 index 000000000..2602b1710 --- /dev/null +++ b/examples/remote_execution_script_pull_mqtt.pp @@ -0,0 +1,4 @@ +include foreman_proxy +class { 'foreman_proxy::plugin::remote_execution::script': + mode => 'pull-mqtt', +} diff --git a/manifests/plugin/remote_execution/mosquitto.pp b/manifests/plugin/remote_execution/mosquitto.pp new file mode 100644 index 000000000..39d55f134 --- /dev/null +++ b/manifests/plugin/remote_execution/mosquitto.pp @@ -0,0 +1,94 @@ +# = Foreman Proxy Remote Execution Mosquitto Configuration +# +# This class configures mosquitto for use by Remote Execution pull transport +# +# === Parameters: +# +# $ssl_ca:: SSL CA to validate the client certificates used to access mosquitto +# +# $ssl_cert:: SSL certificate to be used to run mosquitto via SSL. +# +# $ssl_key:: Corresponding key to a ssl_cert certificate +# +# === Advanced parameters: +# +# $port:: Port mosquitto will run on +# +# $require_certificate:: When true the client must provide a valid certificate in order to connect successfully +# +# $use_identity_as_username:: Use the CN value from the client certificate as a username +# +class foreman_proxy::plugin::remote_execution::mosquitto ( + Stdlib::Port $port = 1883, + Stdlib::Absolutepath $ssl_ca = $foreman_proxy::ssl_ca, + Stdlib::Absolutepath $ssl_cert = $foreman_proxy::ssl_cert, + Stdlib::Absolutepath $ssl_key = $foreman_proxy::ssl_key, + Boolean $require_certificate = true, + Boolean $use_identity_as_username = true, +) { + $mosquitto_config_dir = '/etc/mosquitto' + $mosquitto_ssl_dir = "${mosquitto_config_dir}/ssl" + + class { 'mosquitto': + package_name => 'mosquitto', + config => [ + "listener ${port}", + "acl_file ${mosquitto_config_dir}/foreman.acl", + "cafile ${mosquitto_ssl_dir}/ssl_ca.pem", + "certfile ${mosquitto_ssl_dir}/ssl_cert.pem", + "keyfile ${mosquitto_ssl_dir}/ssl_key.pem", + "require_certificate ${require_certificate}", + "use_identity_as_username ${use_identity_as_username}", + ], + } + + file { $mosquitto_config_dir: + ensure => directory, + owner => 'root', + group => 'mosquitto', + mode => '0755', + require => Package['mosquitto'], + } + + file { "${mosquitto_config_dir}/foreman.acl": + ensure => 'file', + content => epp( + "${module_name}/plugin/foreman.acl.epp", + { user => $facts['networking']['fqdn'] } + ), + owner => 'root', + group => 'mosquitto', + mode => '0640', + } + + file { $mosquitto_ssl_dir: + ensure => directory, + owner => 'root', + group => 'mosquitto', + mode => '0755', + } + + file { "${mosquitto_ssl_dir}/ssl_cert.pem": + ensure => 'file', + content => file($ssl_cert), + owner => 'root', + group => 'mosquitto', + mode => '0440', + } + + file { "${mosquitto_ssl_dir}/ssl_key.pem": + ensure => 'file', + content => file($ssl_key), + owner => 'root', + group => 'mosquitto', + mode => '0440', + } + + file { "${mosquitto_ssl_dir}/ssl_ca.pem": + ensure => 'file', + content => file($ssl_ca), + owner => 'root', + group => 'mosquitto', + mode => '0440', + } +} diff --git a/manifests/plugin/remote_execution/script.pp b/manifests/plugin/remote_execution/script.pp index f20ca5a25..0fc34d7fc 100644 --- a/manifests/plugin/remote_execution/script.pp +++ b/manifests/plugin/remote_execution/script.pp @@ -46,7 +46,7 @@ Stdlib::Absolutepath $local_working_dir = '/var/tmp', Stdlib::Absolutepath $remote_working_dir = '/var/tmp', Boolean $ssh_kerberos_auth = false, - Enum['ssh', 'ssh-async'] $mode = 'ssh', + Enum['ssh', 'ssh-async', 'pull-mqtt'] $mode = 'ssh', Optional[Foreman_proxy::Sshloglevel] $ssh_log_level = undef, Boolean $cockpit_integration = true, ) { @@ -70,4 +70,10 @@ group => $foreman_proxy::user, } } + + if $mode == 'pull-mqtt' { + class { 'foreman_proxy::plugin::remote_execution::mosquitto': + } + } + } diff --git a/spec/acceptance/remote_execution_script_pull_mqtt_spec.rb b/spec/acceptance/remote_execution_script_pull_mqtt_spec.rb new file mode 100644 index 000000000..18ce34ff9 --- /dev/null +++ b/spec/acceptance/remote_execution_script_pull_mqtt_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper_acceptance' + +describe 'Scenario: install foreman-proxy with remote_execution script plugin with pull-mqtt' do + before(:context) { purge_installed_packages } + + include_examples 'the example', 'remote_execution_script_pull_mqtt.pp' + + it_behaves_like 'the default foreman proxy application' + + describe port(1883) do + it { is_expected.to be_listening } + end + + describe file('/etc/mosquitto/foreman.acl') do + it { should be_file } + its(:content) { should match(%r{pattern read yggdrasil\/%u\/data\/in}) } + its(:content) { should match(%r{pattern write yggdrasil\/%u\/control\/out}) } + its(:content) { should match(%r{user #{host_inventory['fqdn']}}) } + its(:content) { should match(%r{topic write yggdrasil\/\+\/data\/in}) } + its(:content) { should match(%r{topic read yggdrasil\/\+\/control\/out}) } + end + + describe x509_certificate('/etc/mosquitto/ssl/ssl_cert.pem') do + it { should be_certificate } + it { should be_valid } + end + + describe file('/etc/mosquitto/ssl/ssl_cert.pem') do + it { should be_file } + it { should be_mode 440 } + it { should be_owned_by 'root' } + it { should be_grouped_into 'mosquitto' } + end + + describe x509_private_key('/etc/mosquitto/ssl/ssl_key.pem') do + it { should_not be_encrypted } + it { should be_valid } + it { should have_matching_certificate('/etc/mosquitto/ssl/ssl_cert.pem') } + end + + describe file('/etc/mosquitto/ssl/ssl_key.pem') do + it { should be_file } + it { should be_mode 440 } + it { should be_owned_by 'root' } + it { should be_grouped_into 'mosquitto' } + end + + describe x509_certificate('/etc/mosquitto/ssl/ssl_ca.pem') do + it { should be_certificate } + it { should be_valid } + end + + describe file('/etc/mosquitto/ssl/ssl_ca.pem') do + it { should be_file } + it { should be_mode 440 } + it { should be_owned_by 'root' } + it { should be_grouped_into 'mosquitto' } + end + +end diff --git a/templates/plugin/foreman.acl.epp b/templates/plugin/foreman.acl.epp new file mode 100644 index 000000000..ad8332af3 --- /dev/null +++ b/templates/plugin/foreman.acl.epp @@ -0,0 +1,9 @@ +<%- | + String[1] $user, +| -%> +pattern read yggdrasil/%u/data/in +pattern write yggdrasil/%u/control/out + +user <%= $user %> +topic write yggdrasil/+/data/in +topic read yggdrasil/+/control/out