-# store ssh authorized_keys snippets that roles on different hosts can then
-# collect using ssh::authorized_key_collect
-
+# export sshd's authorized_keys fragments
+#
+# This creates exported sshd `authorized_keys` snippets that different
+# hosts can then collect using `ssh::authorized_key_collect`.
+#
+# This is a replacement for the builtin ssh_authorized_keys, although
+# it requires exported resources to work.
+#
+# The builtin type had too many problems to overcome to be useful in
+# our environment. A short overview of known issues, some of which are
+# security-sensitive:
+#
+# * MODULES-7595: ssh_authorized_key should be able to take a ready-made OpenSSH public key
+# * MODULES-7596: puppet ssh_authorized_key not purged as expected
+# * MODULES-9726: allow read-only authorized_keys
+# * MODULES-7610: sshkey uses name instead of title for duplication check
+#
+# There are many more issues on the sshkeys module, which doesn't seem
+# to be very well maintained anyways:
+#
+# https://tickets.puppetlabs.com/browse/MODULES-9726?jql=project%20%3D%20MODULES%20AND%20component%20%3D%20sshkeys_core
+#
+# @param target_user the filename to save the key under
+#
+# @param collect_tag which tag to export this resource as
+#
+# @param options a list of options, defaults to ["restrict"]
+#
+# @param command the command to enforce for this keyfile
+#
+# @param from a list of IPv4 or IPv6 address to pass to the
+# key's `from=` parameter.
+#
+# @param key the actual public key, including ssh-*, the public key
+# material and the comment
define ssh::authorized_key_add(
String $target_user,
- String $command,
Variant[Array[String], String] $collect_tag,
- String $restrict = 'restrict',
- Optional[String] $key,
- Array[Stdlib::IP::Address] $from_hosts = $base::public_addresses,
+ Array[String] $options = ['restrict'],
+ Optional[String] $command = '',
+ Optional[Array[Stdlib::IP::Address]] $from = $base::public_addresses,
+ Optional[String] $key = undef,
) {
- $from = $from_hosts.join(',')
+ $ssh_from_string = $from.join(',')
+ if $command {
+ $options_command = ["command=\"${command}\""]
+ } else {
+ $options_command = []
+ }
+ if $ssh_from_string {
+ $options_from = ["from=\"${ssh_from_string}\""]
+ } else {
+ $options_from = []
+ }
+ $real_options = $options_command + $options_from + $options
+ $options_string = $real_options.join(',')
if ($key and size(split($key, "\n")) > 1) {
fail('More than one line in key for ssh::authorized_key')
if (size(split($command, '"')) > 1) {
fail('command must not contain double quotes')
}
- if (size(split($from, '"')) > 1) {
- fail('from_hosts must not contain double quotes')
+ if (size(split($ssh_from_string, '"')) > 1) {
+ fail('from must not contain double quotes')
}
if $collect_tag =~ String {
$ssh_tags = $raw_tags.map |$t| { "ssh::authorized_key::fragment::${t}::${target_user}" }
$ferm_tags = $raw_tags.map |$t| { "ssh::authorized_key::ferm::${t}::${target_user}" }
- $from_space = $from_hosts.join(' ')
+ $ferm_from_string = $from.join(' ')
if $key {
@@concat::fragment { "ssh::authorized_key::${name} ${target_user} from ${::hostname}":
tag => $ssh_tags,
target => "/etc/ssh/puppetkeys/${target_user}",
- order => '200',
content => @("EOF"),
# from ${::fqdn}
- command="${command}",from="${from}",${restrict} ${key}
+ ${options_string} ${key}
| EOF
}
} else {
description => "allow ssh for ssh to ${target_user}",
domain => '(ip ip6)',
chain => 'ssh',
- rule => "saddr (${from_space}) ACCEPT",
+ rule => "saddr (${ferm_from_string}) ACCEPT",
}
}