Puppet Common Modules Ssh

Version 3 (Tom Mortimer-Jones, 06/13/2011 02:14 am)

1 1
# The Manifest
2 1
3 1
Let's talk some code:
4 1
5 1
    # This is an example proposed Puppet Common Module for SSH
6 1
    #
7 1
    # Usage Requirements:
8 1
    # 1) Set $server in site.pp
9 3 Tom Mortimer-Jones
    #    Allows for a different fileserver than the real puppetmaster
10 1
    # 2) Set $os to $operatingsystem
11 1
    #    Saves typing, purely cosmetic
12 1
    # 3) Set $osver to $operatingsystemrelease or $lsbdistrelease
13 1
    #    $operatingsystemrelease is not available on all platforms
14 1
    #
15 1
    
16 1
    class ssh {
17 1
    
18 1
        # Distribution independent packages
19 1
        # See also our Operating System specific sub-classes
20 1
        @package { [
21 1
                "openssh-clients",
22 1
                "openssh-server",
23 1
                "denyhosts"
24 1
            ]:
25 1
            ensure => installed
26 1
        }
27 1
    
28 1
        # Virtual Resources get defined before we include $operatingsystem specific
29 1
        # classes, so that there is at least something to add and/or override.
30 1
        # 
31 1
        # Additionally, this way we can realize() in sub-classes as much as we want
32 1
        # to, and not concern ourselves with duplicate type definitions
33 1
        #
34 1
    
35 1
        @file { "/etc/denyhosts.conf":
36 1
            notify => Service["denyhosts"],
37 1
            require => Package["denyhosts"],
38 1
            source => [
39 1
                "puppet://$server/private/$domain/denyhosts/denyhosts.conf",
40 1
                "puppet://$server/files/denyhosts/denyhosts.conf",
41 1
                "puppet://$server/denyhosts/denyhosts.conf"
42 1
            ]
43 1
        }
44 1
    
45 1
        @file { "/etc/ssh/ssh_config":
46 1
            owner => "root",
47 1
            mode => 644,
48 1
            require => Package["openssh-clients"],
49 1
            source => [
50 1
                #
51 1
                # See rationale for an explanation on this list of sources
52 1
                # http://reductivelabs.com/trac/puppet/wiki/PuppetCommonModules/SSH
53 1
                #
54 1
                "puppet://$server/private/$domain/ssh/$os/$osver/ssh_config.$hostname",
55 1
                "puppet://$server/private/$domain/ssh/$os/$osver/ssh_config",
56 1
                "puppet://$server/private/$domain/ssh/$os/ssh_config.$hostname",
57 1
                "puppet://$server/private/$domain/ssh/$os/ssh_config",
58 1
                "puppet://$server/private/$domain/ssh/ssh_config.$hostname",
59 1
                "puppet://$server/private/$domain/ssh/ssh_config",
60 1
                "puppet://$server/files/ssh/$os/$osver/ssh_config.$hostname",
61 1
                "puppet://$server/files/ssh/$os/$osver/ssh_config",
62 1
                "puppet://$server/files/ssh/$os/ssh_config.$hostname",
63 1
                "puppet://$server/files/ssh/$os/ssh_config",
64 1
                "puppet://$server/files/ssh/ssh_config.$hostname",
65 1
                "puppet://$server/files/ssh/ssh_config",
66 1
                "puppet://$server/ssh/$os/$osver/ssh_config",
67 1
                "puppet://$server/ssh/$os/ssh_config",
68 1
                "puppet://$server/ssh/ssh_config"
69 1
            ],
70 1
            sourceselect => first
71 1
        }
72 1
    
73 1
        @file { "/etc/ssh/sshd_config":
74 1
            owner => "root",
75 1
            mode => 644,
76 1
            notify => Service["openssh-server"],
77 1
            require => Package["openssh-server"],
78 1
            source => [
79 1
                #
80 1
                # See rationale for an explanation on this list of sources
81 1
                # http://reductivelabs.com/trac/puppet/wiki/PuppetCommonModules/SSH
82 1
                #
83 1
                "puppet://$server/private/$domain/ssh/$os/$osver/sshd_config.$hostname",
84 1
                "puppet://$server/private/$domain/ssh/$os/$osver/sshd_config",
85 1
                "puppet://$server/private/$domain/ssh/$os/sshd_config.$hostname",
86 1
                "puppet://$server/private/$domain/ssh/$os/sshd_config",
87 1
                "puppet://$server/private/$domain/ssh/sshd_config.$hostname",
88 1
                "puppet://$server/private/$domain/ssh/sshd_config",
89 1
                "puppet://$server/files/ssh/$os/$osver/sshd_config.$hostname",
90 1
                "puppet://$server/files/ssh/$os/$osver/sshd_config",
91 1
                "puppet://$server/files/ssh/$os/sshd_config.$hostname",
92 1
                "puppet://$server/files/ssh/$os/sshd_config",
93 1
                "puppet://$server/files/ssh/sshd_config.$hostname",
94 1
                "puppet://$server/files/ssh/sshd_config",
95 1
                "puppet://$server/ssh/$os/$osver/sshd_config",
96 1
                "puppet://$server/ssh/$os/sshd_config",
97 1
                "puppet://$server/ssh/sshd_config"
98 1
            ],
99 1
            sourceselect => first
100 1
        }
101 1
    
102 1
        @service { "openssh-server":
103 1
            enable => true,
104 1
            ensure => running,
105 1
            require => [
106 1
                File["/etc/ssh/sshd_config"],
107 1
    
108 1
                Package["openssh-server"]
109 1
            ]
110 1
        }
111 1
    
112 1
    
113 1
        # Include operatingsystem specific subclass
114 1
        include ssh::$operatingsystem
115 1
    
116 1
        class client inherits ssh {
117 1
            realize(Package["openssh-clients"])
118 1
        }
119 1
    
120 1
        class server inherits ssh {
121 1
    
122 1
            realize(Package["openssh-server"])
123 1
    
124 1
            class noclient inherits server {
125 1
                # To create a server that cannot ssh out.
126 1
                # Note that this removes packages depending on
127 1
                # openssh-clients as well.
128 1
    
129 1
                Package["openssh-clients"] {
130 1
                    ensure => absent
131 1
                }
132 1
    
133 1
                realize(Package["openssh-clients"])
134 1
            }
135 1
    
136 1
            class denyhosts inherits server {
137 1
                # Let the server deny hosts
138 1
    
139 1
                realize(
140 1
                    File["/etc/denyhosts.conf"],
141 1
                    Package["denyhosts"],
142 1
                    Package["openssh-server"]
143 1
                )
144 1
    
145 1
                service { "denyhosts":
146 1
                    enable => true,
147 1
                    ensure => running,
148 1
                    require => [
149 1
                        File["/etc/denyhosts.conf"],
150 1
                        Package["denyhosts"]
151 1
                    ]
152 1
                }
153 1
            }
154 1
        }
155 1
    
156 1
        class Debian inherits ssh {
157 1
            File["/etc/ssh/ssh_config"] {
158 1
                group => "root"
159 1
            }
160 1
    
161 1
            Package["openssh-clients"] {
162 1
                name => "openssh-client"
163 1
            }
164 1
    
165 1
            Service["openssh-server"] {
166 1
                name => "ssh",
167 1
                pattern => "sshd"
168 1
            }
169 1
        }
170 1
    
171 1
        class Fedora inherits ssh {
172 1
            File["/etc/ssh/ssh_config"] {
173 1
                group => "root"
174 1
            }
175 1
    
176 1
            Service["openssh-server"] {
177 1
                name => "sshd",
178 1
                hasrestart => true,
179 1
                hasstatus => true,
180 1
                restart => "/etc/init.d/sshd restart",
181 1
                status => "/etc/init.d/sshd status"
182 1
            }
183 1
        }
184 1
    
185 1
        class RedHat inherits Fedora {
186 1
        }
187 1
    
188 1
        class CentOS inherits RedHat {
189 1
        }
190 1
    
191 1
        class Darwin inherits ssh {
192 1
            Package["openssh-clients"] {
193 1
                source => "http://server/foo"
194 1
            }
195 1
    
196 1
            File["/etc/denyhosts.conf"] {
197 1
                group => "wheel"
198 1
            }
199 1
    
200 1
            File["/etc/ssh/ssh_config"] {
201 1
                group => "wheel",
202 1
                path => "/etc/ssh_config"
203 1
            }
204 1
    
205 1
            File["/etc/ssh/sshd_config"] {
206 1
                group => "wheel",
207 1
                path => "/etc/sshd_config"
208 1
            }
209 1
    
210 1
        }
211 1
    }
212 1
213 1
Hope you liked it ;-)
214 1
215 1
# Rationale
216 1
217 1
Here's a little rationale on the things you just read and probably
218 1
had some questions about.
219 1
220 1
## Yuk, this is one large file
221 1
222 1
1.  It fits better on a wiki page ;-)
223 1
2.  Red Hat / CentOS has puppet-0.24.4 and does not do the import
224 1
    magic. It could do the imports, but it requires import statements
225 1
    per file (not exactly making the module any more portable).
226 1
227 1
## Virtual Resource in top class
228 1
229 1
Defining the resources shared over multiple of the ssh sub-classes
230 1
as a virtual resource in the top-class allows us to override
231 1
parameters in operating system specific sub-classes, as well as
232 1
realize() the virtual resources more then once, not only throughout
233 1
the module, but also when required by other modules (can't come up
234 1
with an appropriate example).
235 1
236 1
## Operating system specific classes
237 1
238 1
The operating system specific sub-classes you see in the module are
239 1
meant to provide the most flexible and efficient operating system
240 1
specific attributes to resources (especially the virtual resources
241 1
defined at the beginning).
242 1
243 1
## Huge list of possible sources
244 1
245 1
The huge list of possible sources is something I've worked out over
246 1
several customers.
247 1
248 1
### $server
249 1
250 1
Setting $server in site.pp for example allows you to use a server
251 1
other then your puppetmaster as a dedicated fileserver.
252 1
253 1
### $os ?? $osver ??
254 1
255 1
A very, very nasty example is using "UsePAM yes" in
256 1
/etc/ssh/sshd\_config on Red Hat Enterprise Linux 3 machines ^1^.
257 1
The SSH server won't stop working (e.g. not error out with Syntax
258 1
Error Messages), but remote access over SSH is impossible. This
259 1
introduced the requirement of being able to have Operating System
260 1
($os) and Operating System version ($osver) specific files. It is
261 1
not required to maintain the trees, but the module obviously needs
262 1
to provide the best default for every operating system and
263 1
operating system version that has these kind of exceptions.
264 1
265 1
Using $os is far from required; these are variables that have been
266 1
assigned in site.pp because I'm a lazy guy and dislike typing
267 1
$operatingsystem twice.
268 1
269 1
Using $osver however is something that surfaced when it seemed
270 1
$operatingsystemrelease was not available on Fedora / Red Hat /
271 1
CentOS boxes. Instead, I'm using $lsbdistrelease (and sometimes a
272 1
custom fact such as $operatingsystemmajorrelease). However, using
273 1
$operatingsystemrelease and/or $lsbdistrelease isn't very efficient
274 1
(again the typing comes to mind), so I assign these facts to the
275 1
$osver variable.
276 1
277 1
### $domain ??
278 1
279 1
When merging organizations, working with the legacy (non-managed)
280 1
domain from the merger requires you to specify some kind of level
281 1
of distinction between organizations. I've chosen to use the domain
282 1
name space, which also allows me to run these domain specific trees
283 1
from separate Source Control Management systems, and thus separate
284 1
access control.
285 1
286 1
I needed to use a fact here, since that is defined before a
287 1
manifest is parsed, and you cannot override a fact. So far for the
288 1
domain specific tree.
289 1
290 1
### Then why files/ ??
291 1
292 1
The merger continues (or you had none to begin with), and the
293 1
files/ fileserver mount allows you to source the file in a
294 1
puppetmaster global sense, without modifying the module. Modifying
295 1
the module means committing, possibly pushing (but not likely) the
296 1
changes somewhere, and resolving potential conflicts afterwards.
297 1
298 1
### Module default
299 1
300 1
The module default should be similar to the default configuration
301 1
on a distribution, or the best overall default if that is something
302 1
that can ever be agreed upon.
303 1
304 1
### Using the $hostname
305 1
306 1
Using the hostname, you are able to provide specific configuration
307 1
on a per host basis, or on a per group of hosts basis. If some of
308 1
the SSH server you have in your organization require only users in
309 1
the group wheel to be able to login (for example), then create a
310 1
file called sshd\_config.wheel-only and create a symbolic link
311 1
sshd\_config.$hostname => sshd\_config.wheel-only.
312 1
313 1
Possible improvement: Using the $fqdn of a machine instead might
314 1
work better in some cases.
315 1
316 1
Another option is to specify variables throughout the manifests,
317 1
which is practically never going to end given the amount of
318 1
tweakable settings per application, and is no more efficient then
319 1
creating the symbolic link.
320 1
321 1
^1\ yes,\ rebuilding\ the\ ruby\ stack\ is\ included\ to\ make\ RHEL3\ machines\ do\ puppet^