keyman 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ keyman (1.0.0)
5
+ net-ssh (~> 2.6.3)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ net-ssh (2.6.3)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ keyman!
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Keyman
2
+
3
+ This simple little utility allows you to manage the authorized_keys files for a
4
+ number of servers & users. It is designed to provide easy access to ensure that
5
+ you can revoke & grant access to appropriate people on multiple servers.
6
+
7
+ **Please Note: this utility is somewhat un-tested and not currently used in any
8
+ production environment. Your mileage may vary and we recommend testing in a
9
+ non-production environment prior to use.**
10
+
11
+ ## Installation
12
+
13
+ To install, just install the Rubygem.
14
+
15
+ ```bash
16
+ $ gem install keyman
17
+ ```
18
+
19
+ Once installed, you will need to create yourself a **manifest directory**. This
20
+ directory will contain all your configuration for your key manager. You should
21
+ create an empty directory and add two files, a `servers.rb` and a `users.rb` file.
22
+
23
+ ## Example Users/Groups Manifest File
24
+
25
+ The below file is an example of a `users.rb` manifest file.
26
+
27
+ ```ruby
28
+ group :admins do
29
+ user :adam, 'ssh-rsa AAAAB3NzaC1yc2EAAAA[...]=='
30
+ user :charlie, 'ssh-rsa AAAAB3NzaC1yc2EAAAA[...]=='
31
+ user :nathan, 'ssh-rsa AAAAB3NzaC1yc2EAAAA[...]=='
32
+ end
33
+
34
+ group :staff do
35
+ user :jack, 'ssh-rsa AAAAB3NzaC1yc2EAAAA[...]=='
36
+ user :dan, 'ssh-rsa AAAAB3NzaC1yc2EAAAA[...]=='
37
+ end
38
+ ```
39
+
40
+ ## Example Server Manifest File
41
+
42
+ The below file is an example of a `servers.rb` file.
43
+
44
+ ```ruby
45
+ # An example configuration for a server where all admin users have
46
+ # access as 'root' and all staff users have access as 'app'.
47
+ server do
48
+ host 'app01.myapplication.com'
49
+ user 'root', :admins
50
+ user 'app', :admins, :staff
51
+ end
52
+
53
+ # An example configuration for a server where admins plus one other user
54
+ # have access as root only.
55
+ server do
56
+ host 'database01.myapplication.com'
57
+ user 'root', :admins, :dan
58
+ end
59
+ ```
60
+
61
+ ## Pushing files to servers
62
+
63
+ In order to push files to the server, you must already have YOUR key on the
64
+ machine in order to authenticate. If you do not, you will not have access
65
+ and will therefore be unable to push configuration.
66
+
67
+ ```bash
68
+ $ cd path/to/manifest
69
+ # to push configuration to all servers
70
+ $ keyman push
71
+ # to push configuration to a specific server
72
+ $ keyman push database01.myapplication.com
73
+ ```
74
+
75
+ There are other commands available within the app, you can view these by
76
+ viewing the inline help.
77
+
78
+ ```bash
79
+ $ keyman help
80
+ ```
data/bin/keyman ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ require 'keyman'
3
+ begin
4
+
5
+ # Convert command line arguments into the appropriate ruby objects
6
+ args = ARGV.dup
7
+ final_args = []
8
+ options = {}
9
+ until args.empty?
10
+ arg = args.shift
11
+ if arg =~ /\A\-/
12
+ options[arg.gsub(/\A\-+/, '').to_sym] = args.shift
13
+ else
14
+ final_args << arg
15
+ end
16
+ end
17
+
18
+ command = final_args.first
19
+ case command
20
+ when 'help', nil
21
+ puts "This is the Keyman utility. You can use this to execute your key manifest"
22
+ puts "commands. In order to use this, you must be currently within your"
23
+ puts "manifest directory."
24
+ puts
25
+ puts " keys {server} {user} - displays the authorized keys file for a server's user"
26
+ puts " push - pushes the latest files to all servers"
27
+ puts " push {server} - pushes the latest file to the specified server"
28
+ puts " servers - displays a list of all servers"
29
+ puts " permissions {server} - displays the permissions for given server"
30
+ puts " users - displays a list of all users & groups"
31
+ puts
32
+ else
33
+ Keyman.run(final_args, options)
34
+ end
35
+
36
+ rescue Keyman::Error => e
37
+ puts "\e[31m" + e.message + "\e[0m"
38
+ Process.exit(1)
39
+ end
data/keyman.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
2
+ require 'keyman'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'keyman'
6
+ s.version = Keyman::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.summary = "A simple library for managing distributed SSH keys"
9
+ s.description = s.summary
10
+ s.files = Dir["**/*"]
11
+ s.bindir = "bin"
12
+ s.executables << 'keyman'
13
+ s.require_path = 'lib'
14
+ s.has_rdoc = false
15
+ s.author = "Adam Cooke"
16
+ s.email = "adam@atechmedia.com"
17
+ s.homepage = "http://atechmedia.com"
18
+ s.add_dependency('net-ssh', '~> 2.6.3')
19
+ end
20
+
@@ -0,0 +1,24 @@
1
+ module Keyman
2
+ class Group
3
+
4
+ attr_accessor :name, :users
5
+
6
+ def initialize
7
+ @users = []
8
+ end
9
+
10
+ # Add a new group with the given name
11
+ def self.add(name, &block)
12
+ g = Group.new
13
+ g.name = name
14
+ g.instance_eval(&block)
15
+ Keyman.groups << g
16
+ end
17
+
18
+ # Add a new user to the group
19
+ def user(*args)
20
+ @users << User.add(*args)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module Keyman
2
+ class Keyfile
3
+
4
+ class << self
5
+ def group(name, &users_block)
6
+ Group.add(name, &users_block)
7
+ end
8
+
9
+ def server(&block)
10
+ Server.add(&block)
11
+ end
12
+
13
+ def user(username, key)
14
+ User.add(username, key)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,81 @@
1
+ module Keyman
2
+ class Server
3
+
4
+ attr_accessor :host, :users, :location
5
+
6
+ def initialize
7
+ @users = {}
8
+ end
9
+
10
+ # Adds a new server by accepting a block of objects
11
+ def self.add(&block)
12
+ s = self.new
13
+ s.instance_eval(&block)
14
+ Keyman.servers << s
15
+ s
16
+ end
17
+
18
+ # Returns or sets the hostname of the server which should be used when connecting
19
+ # and identifying this server
20
+ def host(host = nil)
21
+ host ? @host = host : @host
22
+ end
23
+
24
+ # Sets a user on the server along with the access objects which should be
25
+ # granted access
26
+ def user(name, *access_objects)
27
+ @users[name] = access_objects
28
+ end
29
+
30
+ # Returns or sets the location of the server
31
+ def location(location = nil)
32
+ location ? @location = location : @location
33
+ end
34
+
35
+ # Returns an array of users who have access to this server. Includes
36
+ # all objects from within the server
37
+ def authorized_users(username)
38
+ @users[username].map do |k|
39
+ obj = Keyman.user_or_group_for(k)
40
+ obj.is_a?(Group) ? obj.users : obj
41
+ end.flatten.uniq
42
+ end
43
+
44
+ # Returns a full string output for the authorized_keys file. Passes
45
+ # the user who's file you wish to generate.
46
+ def authorized_keys(username)
47
+ Array.new.tap do |a|
48
+ a << "# SSH Authorized Keys file generated automatically by Keyman"
49
+ a << "# Generated at: #{Time.now.utc} for #{@host}"
50
+ a << nil
51
+ authorized_users(username).each do |u|
52
+ a << "# #{u.name}"
53
+ a << u.key + "\n"
54
+ end
55
+ end.join("\n")
56
+ end
57
+
58
+ # Push the authorized keys file to the appropriate server for the users
59
+ # configured here. This will not succeed if the current user does not
60
+ # already have a key on the server.
61
+ def push!
62
+ @users.each do |user, objects|
63
+ begin
64
+ Timeout.timeout(10) do |t|
65
+ Net::SSH.start(self.host, user) do |ssh|
66
+ ssh.exec!("mkdir -p ~/.ssh")
67
+ file = authorized_keys(user).gsub("\n", "\\n").gsub("\t", "\\t")
68
+ ssh.exec!("echo -e '#{file}' > ~/.ssh/authorized_keys")
69
+ end
70
+ end
71
+ puts "\e[32mPushed authorized_keys to #{user}@#{self.host}\e[0m"
72
+ rescue Timeout::Error
73
+ puts "\e[31mTimed out while uploading authorized_keys to #{user}@#{self.host}\e[0m"
74
+ rescue
75
+ puts "\e[31mFailed to upload authorized_keys to #{user}@#{self.host}\e[0m"
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,21 @@
1
+ module Keyman
2
+ class User
3
+
4
+ attr_accessor :name, :key
5
+
6
+ # Add a new user with the given details
7
+ def self.add(name, key)
8
+ existing = Keyman.users.select { |u| u.name == name.to_sym }.first
9
+ if existing
10
+ existing
11
+ else
12
+ u = self.new
13
+ u.name = name.to_sym
14
+ u.key = key
15
+ Keyman.users << u
16
+ u
17
+ end
18
+ end
19
+
20
+ end
21
+ end
data/lib/keyman.rb ADDED
@@ -0,0 +1,104 @@
1
+ require 'net/ssh'
2
+
3
+ require 'keyman/user'
4
+ require 'keyman/group'
5
+ require 'keyman/server'
6
+ require 'keyman/keyfile'
7
+
8
+
9
+ module Keyman
10
+
11
+ # The current version of the keyman system
12
+ VERSION = '1.0.0'
13
+
14
+ # An error which will be raised
15
+ class Error < StandardError; end
16
+
17
+ class << self
18
+ # Storage for all the users, groups & servers which are loaded
19
+ # from the manifest
20
+ attr_accessor :users
21
+ attr_accessor :groups
22
+ attr_accessor :servers
23
+
24
+ # Load a manifest from the given folder
25
+ def load(directory)
26
+ self.users = []
27
+ self.groups = []
28
+ self.servers = []
29
+ if File.directory?(directory)
30
+ ['groups.rb', 'servers.rb'].each do |file|
31
+ path = File.join(directory, file)
32
+ if File.exist?(path)
33
+ Keyman::Keyfile.class_eval(File.read(path))
34
+ else
35
+ raise Error, "No '#{file}' was found in your manifest directory. Abandoning..."
36
+ end
37
+ end
38
+ else
39
+ raise Error, "No folder found at '#{directory}'"
40
+ end
41
+ end
42
+
43
+ # Return a user or a group for the given name
44
+ def user_or_group_for(name)
45
+ self.users.select { |u| u.name == name.to_sym }.first || self.groups.select { |u| u.name == name.to_sym }.first
46
+ end
47
+
48
+ # Execute a CLI command
49
+ def run(args, options = {})
50
+ load('./')
51
+ case args.first
52
+ when 'keys'
53
+ if server = self.servers.select { |s| s.host == args[1] }.first
54
+ if server.users[args[2]]
55
+ puts server.authorized_keys(args[2])
56
+ else
57
+ raise Error, "'#{args[2]}' is not a valid user for this host"
58
+ end
59
+ else
60
+ raise Error, "No server found with the hostname '#{args[1]}'"
61
+ end
62
+ when 'permissions'
63
+ if server = self.servers.select { |s| s.host == args[1] }.first
64
+ server.users.each do |username, objects|
65
+ puts '-' * 80
66
+ puts "\e[32m#{username}\e[0m can be used by:"
67
+ puts '-' * 80
68
+ server.authorized_users(username).each do |o|
69
+ puts " * #{o.name}"
70
+ end
71
+ end
72
+ else
73
+ raise Error, "No server found with the hostname '#{args[1]}'"
74
+ end
75
+ when 'push'
76
+ if args[1]
77
+ # push single server
78
+ if server = self.servers.select { |s| s.host == args[1] }.first
79
+ server.push!
80
+ else
81
+ raise Error, "No server found with the hostname '#{args[1]}'"
82
+ end
83
+ else
84
+ self.servers.each(&:push!)
85
+ end
86
+ when 'servers'
87
+ self.servers.each do |server|
88
+ puts " * " + server.host
89
+ end
90
+ when 'users'
91
+ self.groups.each do |group|
92
+ puts "-" * 80
93
+ puts group.name
94
+ puts "-" * 80
95
+ group.users.each do |u|
96
+ puts "\e[32m#{u.name}\e[0m"
97
+ puts "\e[37m#{u.key}\e[0m"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keyman
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Cooke
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: net-ssh
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.6.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.6.3
30
+ description: A simple library for managing distributed SSH keys
31
+ email: adam@atechmedia.com
32
+ executables:
33
+ - keyman
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - bin/keyman
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - keyman.gemspec
41
+ - lib/keyman/group.rb
42
+ - lib/keyman/keyfile.rb
43
+ - lib/keyman/server.rb
44
+ - lib/keyman/user.rb
45
+ - lib/keyman.rb
46
+ - README.md
47
+ homepage: http://atechmedia.com
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 1.8.23
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: A simple library for managing distributed SSH keys
71
+ test_files: []