masson
Version:
Module execution engine for cluster deployments.
200 lines (174 loc) • 6.58 kB
Markdown
---
title: SSH
module: masson/core/ssh
layout: module
---
# SSH
misc = require 'mecano/lib/misc'
each = require 'each'
module.exports = []
module.exports.push 'masson/bootstrap/'
module.exports.push 'masson/core/users'
module.exports.push 'masson/core/yum'
## Configuration
Configuration extends the configuration of the "masson/core/users" with
new properties "authorized\_keys", "rsa" and "rsa_pub" and also define
two new properties "sshd\_config" and "banner".
* `users.[].authorized_keys` (string, array)
A list of SSH public keys added to the "~/.ssh/authorized_keys" file, optional.
* `users.[].rsa` (string)
Private SSH key of the user, optional.
* `users.[].rsa_pub` (string)
Public SSH key of the user, optional.
* `ssh.sshd_config` (object)
Configure the SSH daemon by updating the "/etc/ssh/sshd_config" file with
key/value properties, optional.
* `ssh.banner` (object)
Write a banner file in the system and register it with the "/etc/ssh/sshd_config" file, optional.
```json
{
"users": [{
"name": "root"
"authorized_keys": [ "ssh-rsa AAAA...ZZZZ me@email.com" ],
"rsa": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCA...PKToe4z7C9BqMT7Og==\n-----END RSA PRIVATE KEY-----"
"rsa_pub": "ssh-rsa AAAA...YYYY user@hadoop"
},{
"name": "sweet"
"home": "/home/sweet"
"authorized_keys": [ "ssh-rsa AAAA...XXXX you@email.com" ]
}]
"ssh": {
"sshd_config": {
"UsePAM": "yes"
"Port": 2222
},
"banner": {
"destination": "/etc/banner",
"content": "Welcome to Hadoop!"
}
}
}
```
module.exports.push (ctx) ->
require('./users').configure ctx
ctx.config.ssh ?= {}
ctx.config.ssh.sshd_config ?= null
for _, user of ctx.config.users
user.authorized_keys ?= []
user.authorized_keys = [user.authorized_keys] if typeof user.authorized_keys is 'string'
## Authorized Keys
Update the "~/.ssh/authorized_keys" file for each users and add the public SSH keys
defined inside "users.[].authorized_keys".
module.exports.push name: 'SSH # Authorized Keys', timeout: -1, callback: (ctx, next) ->
modified = false
each(ctx.config.users)
.on 'item', (user, next) ->
return next() unless user.home
ctx.mkdir
destination: "#{user.home or '/home/'+user.name}/.ssh"
uid: user.name
gid: null
mode: 0o700 # was "permissions: 16832"
, (err, created) ->
return next err if err
write = for key in user.authorized_keys
match: new RegExp ".*#{misc.regexp.escape key}.*", 'mg'
replace: key
append: true
ctx.write
destination: "#{user.home or '/home/'+user.name}/.ssh/authorized_keys"
write: write
uid: user.name
gid: null
mode: 0o600
, (err, written) ->
return next err if err
modified = true if written
next()
.on 'both', (err) ->
next err, if modified then ctx.OK else ctx.PASS
## Configure
Configure the SSH daemon by updated the "/etc/ssh/sshd_config" file with the
properties found in the "ssh.sshd_config" object.
module.exports.push name: 'SSH # Configure', timeout: -1, callback: (ctx, next) ->
{sshd_config} = ctx.config.ssh
return next() unless sshd_config
write = for k, v of sshd_config
match: new RegExp "^#{k}.*$", 'mg'
replace: "#{k} #{v}"
append: true
ctx.log 'Write configuration in /etc/ssh/sshd_config'
ctx.write
write: write
destination: '/etc/ssh/sshd_config'
, (err, written) ->
return next err if err
return next null, ctx.PASS unless written
ctx.log 'Restart sshd'
ctx.service
name: 'openssh'
srv_name: 'sshd'
action: 'restart'
, (err, restarted) ->
next err, ctx.OK
## Public and Private Key
Deploy user SSH keys. The private key is defined by the "users.[].rsa"
propery and is written in "~/.ssh/id\_rsa". The public key is defined by
the "users.[].rsa\_pub" propery and is written in "~/.ssh/id\_rsa.pub".
module.exports.push name: 'SSH # Public and Private Key', timeout: -1, callback: (ctx, next) ->
ok = false
each(ctx.config.users)
.on 'item', (user, next) ->
return next() unless user.home
return next new Error "Property rsa_pub required if rsa defined" if user.rsa and not user.rsa_pub
return next new Error "Property rsa required if rsa_pub defined" if user.rsa_pub and not user.rsa
return next() unless user.rsa
ctx.write
destination: "#{user.home or '/home/'+user.name}/.ssh/id_rsa"
content: user.rsa
uid: user.name
gid: null
mode: 0o600
, (err, written) ->
return next err if err
ok = true if written
ctx.write
destination: "#{user.home or '/home/'+user.name}/.ssh/id_rsa.pub"
content: user.rsa_pub
uid: user.name
gid: null
mode: 0o600
, (err, written) ->
return next err if err
ok = true if written
next()
.on 'both', (err) ->
next err, if ok then ctx.OK else ctx.PASS
# Banner
Write the banner file in the system and register it with the SSH
daemon configuration file. The banner is a short message which appear
on the console once a user successfull logged-in with SSH. The "sshd"
service will be restarted if this action had any effect.
module.exports.push name: 'SSH # Banner', timeout: 100000, callback: (ctx, next) ->
{banner} = ctx.config.ssh
return next() unless banner
ctx.log 'Upload banner content'
banner.content += '\n\n' if banner.content
ctx.upload banner, (err, uploaded) ->
return next err if err
ctx.log 'Write banner path to configuration'
ctx.write
match: new RegExp "^Banner.*$", 'mg'
replace: "Banner #{banner.destination}"
append: true
destination: '/etc/ssh/sshd_config'
, (err, written) ->
return next err if err
return next null, ctx.PASS if not written and not uploaded
ctx.log 'Restarting SSH'
ctx.service
name: 'openssh'
srv_name: 'sshd'
action: 'restart'
, (err, restarted) ->
next err, ctx.OK