diff --git a/REFERENCE.md b/REFERENCE.md
index f3de537c..d3fa85cf 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -24,6 +24,7 @@
### Defined types
* [`ssh::client::config::user`](#ssh--client--config--user): This defined type manages a users ssh config
+* [`ssh::client::config_file`](#ssh--client--config_file): Resource type for managing a config file in the include dir.
* [`ssh::client::match_block`](#ssh--client--match_block): Add match_block to ssh client config (concat needed)
* [`ssh::server::config::setting`](#ssh--server--config--setting): Internal define to managed ssh server param
* [`ssh::server::config_file`](#ssh--server--config_file): Resource type for managing a config file in the include dir.
@@ -357,6 +358,10 @@ The following parameters are available in the `ssh::client` class:
* [`storeconfigs_group`](#-ssh--client--storeconfigs_group)
* [`config_user`](#-ssh--client--config_user)
* [`config_group`](#-ssh--client--config_group)
+* [`include_dir`](#-ssh--client--include_dir)
+* [`include_dir_mode`](#-ssh--client--include_dir_mode)
+* [`include_dir_purge`](#-ssh--client--include_dir_purge)
+* [`config_files`](#-ssh--client--config_files)
##### `ssh_config`
@@ -454,6 +459,38 @@ Numeric id or name of the group for the config file
Default value: `0`
+##### `include_dir`
+
+Data type: `Optional[Stdlib::Absolutepath]`
+
+Path to ssh include directory.
+
+Default value: `undef`
+
+##### `include_dir_mode`
+
+Data type: `Stdlib::Filemode`
+
+Mode to set on the ssh include directory.
+
+Default value: `'0700'`
+
+##### `include_dir_purge`
+
+Data type: `Boolean`
+
+Purge the ssh include directory if true.
+
+Default value: `true`
+
+##### `config_files`
+
+Data type: `Hash[String, Hash]`
+
+Hash of config files to add to the ssh include directory.
+
+Default value: `{}`
+
### `ssh::hostkeys`
This class manages hostkeys. It is intended to be called from `ssh::server`.
@@ -714,7 +751,7 @@ Default value: `'0700'`
Data type: `Boolean`
-Purge the include directory if true.
+Purge the sshd include directory if true.
Default value: `true`
@@ -722,7 +759,7 @@ Default value: `true`
Data type: `Hash[String, Hash]`
-Hash of config files to add to the ssh include directory.
+Hash of config files to add to the sshd include directory.
Default value: `{}`
@@ -963,6 +1000,52 @@ Default mode for the ssh config file
Default value: `'0600'`
+### `ssh::client::config_file`
+
+Resource type for managing a config file in the include dir.
+
+#### Parameters
+
+The following parameters are available in the `ssh::client::config_file` defined type:
+
+* [`mode`](#-ssh--client--config_file--mode)
+* [`include`](#-ssh--client--config_file--include)
+* [`options`](#-ssh--client--config_file--options)
+* [`path`](#-ssh--client--config_file--path)
+
+##### `mode`
+
+Data type: `Stdlib::Filemode`
+
+File mode for the config file.
+
+Default value: `'0644'`
+
+##### `include`
+
+Data type: `Optional[Stdlib::Absolutepath]`
+
+Absolute path to config file to include at the top of the config file.
+This is intended for including files not managed by this module.
+
+Default value: `undef`
+
+##### `options`
+
+Data type: `Hash`
+
+Dynamic hash for openssh client option
+
+Default value: `{}`
+
+##### `path`
+
+Data type: `Stdlib::Absolutepath`
+
+
+
+Default value: `"${ssh::client::include_dir}/${name}.conf"`
+
### `ssh::client::match_block`
Add match_block to ssh client config (concat needed)
diff --git a/manifests/client.pp b/manifests/client.pp
index d457cf3d..9ea9a6f2 100644
--- a/manifests/client.pp
+++ b/manifests/client.pp
@@ -40,22 +40,39 @@
#
# @param config_user
# Numeric id or name of the user for the config file
+#
# @param config_group
# Numeric id or name of the group for the config file
#
+# @param include_dir
+# Path to ssh include directory.
+#
+# @param include_dir_mode
+# Mode to set on the ssh include directory.
+#
+# @param include_dir_purge
+# Purge the ssh include directory if true.
+#
+# @param config_files
+# Hash of config files to add to the ssh include directory.
+#
class ssh::client (
- Stdlib::Absolutepath $ssh_config,
- Hash $default_options,
- Variant[Integer, String[1]] $config_user,
- Variant[Integer, String[1]] $config_group,
- Optional[String[1]] $client_package_name = undef,
- String $ensure = present,
- Boolean $storeconfigs_enabled = true,
- Hash $options = {},
- Boolean $use_augeas = false,
- Array $options_absent = [],
- Hash $match_block = {},
- Optional[String[1]] $storeconfigs_group = undef,
+ Stdlib::Absolutepath $ssh_config,
+ Hash $default_options,
+ Variant[Integer, String[1]] $config_user,
+ Variant[Integer, String[1]] $config_group,
+ Optional[String[1]] $client_package_name = undef,
+ String $ensure = present,
+ Boolean $storeconfigs_enabled = true,
+ Hash $options = {},
+ Boolean $use_augeas = false,
+ Array $options_absent = [],
+ Hash $match_block = {},
+ Optional[String[1]] $storeconfigs_group = undef,
+ Optional[Stdlib::Absolutepath] $include_dir = undef,
+ Stdlib::Filemode $include_dir_mode = '0700',
+ Boolean $include_dir_purge = true,
+ Hash[String, Hash] $config_files = {},
) {
if $use_augeas {
$merged_options = sshclient_options_to_augeas_ssh_config($options, $options_absent, { 'target' => $ssh_config })
diff --git a/manifests/client/config.pp b/manifests/client/config.pp
index 2547add7..6c50d636 100644
--- a/manifests/client/config.pp
+++ b/manifests/client/config.pp
@@ -7,6 +7,7 @@
assert_private()
$options = $ssh::client::merged_options
+ $include_dir = $ssh::client::include_dir
$use_augeas = $ssh::client::use_augeas
if $use_augeas {
@@ -29,4 +30,21 @@
order => '00',
}
}
+
+ if $ssh::client::include_dir {
+ file { $ssh::client::include_dir:
+ ensure => directory,
+ owner => $ssh::client::config_user,
+ group => $ssh::client::config_group,
+ mode => $ssh::client::include_dir_mode,
+ purge => $ssh::client::include_dir_purge,
+ recurse => $ssh::client::include_dir_purge,
+ }
+
+ $ssh::client::config_files.each |$file, $params| {
+ ssh::client::config_file { $file:
+ * => $params,
+ }
+ }
+ }
}
diff --git a/manifests/client/config_file.pp b/manifests/client/config_file.pp
new file mode 100644
index 00000000..bd16c72b
--- /dev/null
+++ b/manifests/client/config_file.pp
@@ -0,0 +1,35 @@
+# @summary Resource type for managing a config file in the include dir.
+#
+# @param mode
+# File mode for the config file.
+#
+# @param include
+# Absolute path to config file to include at the top of the config file.
+# This is intended for including files not managed by this module.
+#
+# @param options
+# Dynamic hash for openssh client option
+#
+define ssh::client::config_file (
+ Stdlib::Absolutepath $path = "${ssh::client::include_dir}/${name}.conf",
+ Stdlib::Filemode $mode = '0644',
+ Optional[Stdlib::Absolutepath] $include = undef,
+ Hash $options = {},
+) {
+ if !$ssh::client::include_dir {
+ fail('ssh::client::config_file() define not supported if ssh::client::include_dir not set')
+ }
+
+ concat { $path:
+ ensure => present,
+ owner => $ssh::client::config_user,
+ group => $ssh::client::config_group,
+ mode => $mode,
+ }
+
+ concat::fragment { "ssh_config_file ${title}":
+ target => $path,
+ content => template("${module_name}/ssh_config.erb"),
+ order => '00',
+ }
+}
diff --git a/manifests/server.pp b/manifests/server.pp
index fb6a10bd..bc5009dc 100644
--- a/manifests/server.pp
+++ b/manifests/server.pp
@@ -51,10 +51,10 @@
# Mode to set on the sshd include directory.
#
# @param include_dir_purge
-# Purge the include directory if true.
+# Purge the sshd include directory if true.
#
# @param config_files
-# Hash of config files to add to the ssh include directory.
+# Hash of config files to add to the sshd include directory.
#
# @param storeconfigs_enabled
# Host keys will be collected and distributed unless storeconfigs_enabled is false.
diff --git a/spec/classes/client_spec.rb b/spec/classes/client_spec.rb
index d2209019..4254df24 100644
--- a/spec/classes/client_spec.rb
+++ b/spec/classes/client_spec.rb
@@ -23,6 +23,123 @@
it { is_expected.to contain_concat('/etc/ssh/another_ssh_config') }
end
+
+ context 'with include_dir set' do
+ let :params do
+ {
+ include_dir: '/etc/ssh/ssh_config.d',
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+
+ it {
+ is_expected.to contain_file('/etc/ssh/ssh_config.d').with(
+ ensure: 'directory',
+ owner: 0,
+ group: 0,
+ mode: '0700',
+ purge: true,
+ recurse: true,
+ )
+ }
+ end
+
+ context 'with include_dir and include_dir_purge false' do
+ let :params do
+ {
+ include_dir: '/etc/ssh/ssh_config.d',
+ include_dir_purge: false,
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+
+ it {
+ is_expected.to contain_file('/etc/ssh/ssh_config.d').with(
+ ensure: 'directory',
+ purge: false,
+ recurse: false,
+ )
+ }
+ end
+
+ context 'with include_dir and custom mode' do
+ let :params do
+ {
+ include_dir: '/etc/ssh/ssh_config.d',
+ include_dir_mode: '0755',
+ }
+ end
+
+ it {
+ is_expected.to contain_file('/etc/ssh/ssh_config.d').with(
+ mode: '0755',
+ )
+ }
+ end
+
+ context 'with config_files' do
+ let :params do
+ {
+ include_dir: '/etc/ssh/ssh_config.d',
+ config_files: {
+ 'custom' => {
+ 'options' => {
+ 'Host *.example.com' => {
+ 'ProxyJump' => 'bastion.example.com',
+ },
+ },
+ },
+ 'work' => {
+ 'options' => {
+ 'Host *.work.internal' => {
+ 'User' => 'deploy',
+ 'IdentityFile' => '~/.ssh/work_key',
+ },
+ },
+ },
+ },
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+ it { is_expected.to contain_ssh__client__config_file('custom') }
+ it { is_expected.to contain_ssh__client__config_file('work') }
+
+ it {
+ is_expected.to contain_concat('/etc/ssh/ssh_config.d/custom.conf').with(
+ ensure: 'present',
+ owner: 0,
+ group: 0,
+ mode: '0644',
+ )
+ }
+
+ it {
+ is_expected.to contain_concat('/etc/ssh/ssh_config.d/work.conf').with(
+ ensure: 'present',
+ owner: 0,
+ group: 0,
+ mode: '0644',
+ )
+ }
+ end
+
+ context 'without include_dir but with config_files' do
+ let :params do
+ {
+ config_files: {
+ 'custom' => {
+ 'options' => {},
+ },
+ },
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+ it { is_expected.not_to contain_ssh__client__config_file('custom') }
+ end
end
end
end
diff --git a/templates/ssh_config.erb b/templates/ssh_config.erb
index 5546a106..b2788792 100644
--- a/templates/ssh_config.erb
+++ b/templates/ssh_config.erb
@@ -12,6 +12,12 @@
end
-%>
+<%- if @include_dir -%>
+Include <%= @include_dir %>/*.conf
+<%- end -%>
+<%- if @include -%>
+Include <%= @include %>
+<%- end -%>
<%- @options.each do |k, v| -%>
<%- if v.is_a?(Hash) -%>
<%- if k.length > 1024 -%>