Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
= Moonshine_SSH | ||
|
||
== A plugin for Moonshine[http://github.com/railsmachine/moonshine] | ||
|
||
This plugin provides a few security improvements for your default SSH | ||
configuration. It also gives you the ability to easily customize your | ||
settings. Browse through the sshd_config in the <tt>templates/</tt> directory | ||
to see the available settings. | ||
|
||
The new configuration file is tested before it's used, so there's less | ||
chance that you'll accidentally lock yourself out. | ||
|
||
=== Instructions | ||
|
||
* <tt>script/plugin install git://github.com/railsmachine/moonshine_ssh.git</tt> | ||
* Edit moonshine.yml to customize plugin settings if desired: | ||
:ssh | ||
:port: 9022 | ||
:allow_users: | ||
- rob | ||
- rails | ||
* Include the plugin and recipe you in your manifest: | ||
plugin :ssh | ||
recipe :ssh | ||
|
||
=== SFTP-only users | ||
|
||
OpenSSH supports chrooting users natively. You can create users who will be chrooted | ||
and only allowed to use SFTP (no console access) by adding the following to your | ||
moonshine.yml: | ||
|
||
:ssh: | ||
:sftponly: true | ||
|
||
Then add this to your manifest: | ||
|
||
plugin :ssh | ||
recipe :ssh | ||
|
||
This creates a user called sftponly with a randomized password. To allow access, you can manag authorized_keys through your manifest: | ||
|
||
file '/home/sftponly/home/sftponly/.ssh/authorized_keys', | ||
:ensure => :present, | ||
:content => YOUR_SSH_PUBKEYS | ||
|
||
Once connected via sftp, the user will be chrooted to /home/sftponly where they will only see a | ||
'home' directory. The user can upload files to /home/sftponly. For a normal user, the uploaded | ||
files will be located at /home/sftponly/home/sftponly. | ||
|
||
==== Advanced | ||
|
||
For a more complicated example, we'll consider a user called 'rob' who needs to upload | ||
files into a directory under the Rails application's shared/ directory. Since he will | ||
be chrooted, he can't have direct access to the directory. Also, the directory is owned | ||
by the rails group, so he'll need to be a member of that. Finally, we don't want to worry | ||
about public keys, so he'll need a password. | ||
|
||
In your moonshine.yml: | ||
|
||
:ssh: | ||
:sftponly: | ||
:users: | ||
:rob: | ||
:groups: rails | ||
:password: sooper_sekrit | ||
|
||
In your manifest: | ||
|
||
plugin :ssh | ||
recipe :ssh | ||
def mount_assets | ||
file '/home/rob/home/rob/assets', | ||
:ensure => :directory, | ||
:owner => 'rob', | ||
:require => file('/home/rob/home/rob') | ||
|
||
mount '/home/rob/home/rob/assets', | ||
:ensure => :mounted, | ||
:device => "#{configuration[:deploy_to]}/shared/assets/", | ||
:options => 'bind', | ||
:fstype => :none, | ||
:atboot => true, | ||
:remounts => true, | ||
:require => file('/home/rob/home/rob/assets') | ||
end | ||
recipe :mount_assets | ||
|
||
Then deploy, and you're done! The user's /home/rob/assets directory is now actually the shared assets directory. Anything uploaded there will be available to the application automatically. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
module SSH | ||
|
||
# Ensures the SSH server is installed, running, and configured | ||
# per specifications. Use <tt>configure</tt> to change defaults. | ||
# The available options can be gathered by perusing the sshd_config | ||
# template. | ||
# | ||
# configure(:ssh => {:permit_root_login => 'yes', :port => 9022}) | ||
# | ||
def ssh(options = {}) | ||
|
||
package 'ssh', :ensure => :installed | ||
service 'ssh', :enable => true, :ensure => :running | ||
|
||
if options[:sftponly] | ||
options[:subsystem] = {:sftp => 'internal-sftp'} | ||
sftponly(options[:sftponly]) | ||
end | ||
|
||
file '/etc/ssh/sshd_config.new', | ||
:mode => '644', | ||
:content => template(File.join(File.dirname(__FILE__), '..', 'templates', 'sshd_config'), binding), | ||
:require => package('ssh'), | ||
:notify => exec('update_sshd_config') | ||
|
||
exec 'cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config', | ||
:alias => 'update_sshd_config', | ||
:onlyif => '/usr/sbin/sshd -t -f /etc/ssh/sshd_config.new', | ||
:refreshonly => true, | ||
:require => file('/etc/ssh/sshd_config.new'), | ||
:notify => service('ssh') | ||
|
||
end | ||
|
||
private | ||
|
||
# Sets up users and directories for chrooted, sftp-only access | ||
# By default, the chroot is /home/USERNAME and the user's home | ||
# will be inside that, at /home/USERNAME/home/USERNAME | ||
def sftponly(options) | ||
|
||
group 'sftponly', :ensure => :present | ||
|
||
exec "fake shell", | ||
:command => "echo /bin/false >> /etc/shells", | ||
:onlyif => "test -z `grep /bin/false /etc/shells`" | ||
|
||
(options[:users]||'sftponly').to_a.each do |user,hash| | ||
user = user.to_s | ||
|
||
chroot = options[:chroot_directory] || "/home/#{user}" | ||
homedir = chroot + ( hash[:home] || "/home/#{user}" ) | ||
|
||
parent_directories homedir, :owner => 'root', :mode => '755' | ||
file homedir, | ||
:ensure => :directory, | ||
:owner => user, | ||
:group => user, | ||
:require => user(user) | ||
|
||
user user, | ||
:ensure => :present, | ||
:home => "/home/#{user}/home/#{user}", | ||
:shell => "/bin/false", | ||
:groups => (['sftponly'] + hash[:groups].to_a).uniq, | ||
:require => [group('sftponly'),exec('fake shell')], | ||
:notify => exec("#{user} password") | ||
|
||
password = hash[:password] || rand_pass(6) | ||
exec "#{user} password", | ||
:command => "echo #{user}:#{password} | chpasswd", | ||
:refreshonly => true | ||
|
||
end | ||
end | ||
|
||
def parent_directories(path,options) | ||
options.merge!({:ensure => :directory}) | ||
while path != "/" | ||
path = File.split(path)[0] | ||
file path, options | ||
end | ||
end | ||
|
||
def rand_pass(len) | ||
Array.new(len/2) { rand(256) }.pack('C*').unpack('H*').first | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
require "#{File.dirname(__FILE__)}/../lib/ssh.rb" | ||
|
||
include SSH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
require 'rubygems' | ||
ENV['RAILS_ENV'] = 'test' | ||
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..' | ||
|
||
require File.join(File.dirname(__FILE__), '..', '..', 'moonshine', 'lib', 'moonshine.rb') | ||
require File.join(File.dirname(__FILE__), '..', 'lib', 'ssh.rb') | ||
|
||
require 'shadow_puppet/test' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
require File.join(File.dirname(__FILE__), 'spec_helper.rb') | ||
|
||
class SSHManifest < Moonshine::Manifest | ||
plugin :ssh | ||
end | ||
|
||
describe SSH do | ||
|
||
before do | ||
@manifest = SSHManifest.new | ||
end | ||
|
||
|
||
it "should be executable" do | ||
@manifest.should be_executable | ||
end | ||
|
||
it "should load the template file" do | ||
File.should_receive(:read).with(File.expand_path(File.join(File.dirname(__FILE__), '..', 'templates', 'sshd_config'))).and_return "SSH CONFIG" | ||
@manifest.ssh | ||
end | ||
|
||
it "should set default values" do | ||
@manifest.ssh | ||
@manifest.files.should include("/etc/ssh/sshd_config.new") | ||
sshd_config = @manifest.files["/etc/ssh/sshd_config.new"].content | ||
sshd_config.should match /Port 22/ | ||
sshd_config.should match /PermitRootLogin no/ | ||
end | ||
|
||
it "should check the configuration file before updating" do | ||
@manifest.ssh | ||
@manifest.execs.should include("cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config") | ||
@manifest.execs["cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config"].onlyif.should match /sshd -t/ | ||
end | ||
|
||
it "should allow customization" do | ||
@manifest.ssh( :port => 9022 ) | ||
@manifest.files["/etc/ssh/sshd_config.new"].content.should match /Port 9022/ | ||
end | ||
|
||
describe "configured for sftponly" do | ||
|
||
before do | ||
@manifest.ssh(:sftponly => { | ||
:users => { | ||
:rob => { | ||
:password => 'sekrit', | ||
:groups => 'rails' | ||
} | ||
} | ||
}) | ||
end | ||
|
||
it "should create the sftponly group" do | ||
@manifest.groups.should include('sftponly') | ||
end | ||
|
||
it "should add the user" do | ||
@manifest.users.should include('rob') | ||
@manifest.execs['rob password'].command.should == "echo rob:sekrit | chpasswd" | ||
end | ||
|
||
it "should add user to sftponly and extra groups if requested" do | ||
@manifest.users['rob'].groups.should == ['sftponly','rails'] | ||
end | ||
|
||
it "should create the home directory" do | ||
@manifest.files.should include('/home/rob/home/rob') | ||
@manifest.files['/home/rob/home/rob'].owner.should == 'rob' | ||
@manifest.files['/home/rob/home'].owner.should == 'root' | ||
@manifest.files['/home/rob'].owner.should == 'root' | ||
end | ||
|
||
it "should set the sftp subsystem" do | ||
@manifest.files['/etc/ssh/sshd_config.new'].content.should match /Subsystem sftp internal-sftp/ | ||
end | ||
|
||
it "should add a group matcher to the sshd config" do | ||
@manifest.files['/etc/ssh/sshd_config.new'].content.should match /Match Group sftponly/ | ||
@manifest.files['/etc/ssh/sshd_config.new'].content.should match /ChrootDirectory \/home\/%u/ | ||
end | ||
|
||
end | ||
|
||
end |
Oops, something went wrong.