Note that exim contains tracker-specific configuration
[mirror/dsa-puppet.git] / modules / ssh / manifests / authorized_key_add.pp
1 # export sshd's authorized_keys fragments
2 #
3 # This creates exported sshd `authorized_keys` snippets that different
4 # hosts can then collect using `ssh::authorized_key_collect`.
5 #
6 # This is a replacement for the builtin ssh_authorized_keys, although
7 # it requires exported resources to work.
8 #
9 # The builtin type had too many problems to overcome to be useful in
10 # our environment. A short overview of known issues, some of which are
11 # security-sensitive:
12 #
13 # * MODULES-7595: ssh_authorized_key should be able to take a ready-made OpenSSH public key
14 # * MODULES-7596: puppet ssh_authorized_key not purged as expected
15 # * MODULES-9726: allow read-only authorized_keys
16 # * MODULES-7610: sshkey uses name instead of title for duplication check
17 #
18 # There are many more issues on the sshkeys module, which doesn't seem
19 # to be very well maintained anyways:
20 #
21 # https://tickets.puppetlabs.com/browse/MODULES-9726?jql=project%20%3D%20MODULES%20AND%20component%20%3D%20sshkeys_core
22 #
23 # @param target_user the filename to save the key under
24 #
25 # @param collect_tag which tag to export this resource as
26 #
27 # @param options a list of options, defaults to ["restrict"]
28 #
29 # @param command the command to enforce for this keyfile
30 #
31 # @param from a list of IPv4 or IPv6 address to pass to the
32 #                   key's `from=` parameter.
33 #
34 # @param key the actual public key, including ssh-*, the public key
35 #            material and the comment
36 define ssh::authorized_key_add(
37   String $target_user,
38   Variant[Array[String], String] $collect_tag,
39   Array[String] $options = ['restrict'],
40   Optional[String] $command = '',
41   Optional[Array[Stdlib::IP::Address]] $from = $base::public_addresses,
42   Optional[String] $key = undef,
43 ) {
44   $ssh_from_string = $from.join(',')
45   if $command {
46     $options_command = ["command=\"${command}\""]
47   } else {
48     $options_command = []
49   }
50   if $ssh_from_string {
51     $options_from = ["from=\"${ssh_from_string}\""]
52   } else {
53     $options_from = []
54   }
55   $real_options = $options_command + $options_from + $options
56   $options_string = $real_options.join(',')
57
58   if ($key and size(split($key, "\n")) > 1) {
59     fail('More than one line in key for ssh::authorized_key')
60   }
61   if (size(split($command, '"')) > 1) {
62     fail('command must not contain double quotes')
63   }
64   if (size(split($ssh_from_string, '"')) > 1) {
65     fail('from must not contain double quotes')
66   }
67
68   if $collect_tag =~ String {
69     $raw_tags = [ $collect_tag ]
70   } else {
71     $raw_tags = $collect_tag
72   }
73   $ssh_tags = $raw_tags.map |$t| { "ssh::authorized_key::fragment::${t}::${target_user}" }
74   $ferm_tags = $raw_tags.map |$t| { "ssh::authorized_key::ferm::${t}::${target_user}" }
75
76   $ferm_from_string = $from.join(' ')
77
78   if $key {
79     @@concat::fragment { "ssh::authorized_key::${name} ${target_user} from ${::hostname}":
80       tag     => $ssh_tags,
81       target  => "/etc/ssh/puppetkeys/${target_user}",
82       content => @("EOF"),
83                  # from ${::fqdn}
84                  ${options_string} ${key}
85                  | EOF
86     }
87   } else {
88     notify { "Warning, ssh key for ${name}, ${target_user} not defined (yet?).":
89       loglevel => warning,
90     }
91   }
92
93   @@ferm::rule { "ssh-${raw_tags[0]}_${target_user}-${name}_from_${::hostname}":
94     tag         => $ferm_tags,
95     description => "allow ssh for ssh to ${target_user}",
96     domain      => '(ip ip6)',
97     chain       => 'ssh',
98     rule        => "saddr (${ferm_from_string}) ACCEPT",
99   }
100 }