linux-hub 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1835a8518e08f8db5864552b7c9730ae9e152a0f
4
+ data.tar.gz: 9c17f6eef9941130b02201af019c1e3ff2b00d75
5
+ SHA512:
6
+ metadata.gz: efa0448c9cc2a2b548bca6cc7616e62c0502424b6142dbc3357b71f53f01d8acc228264f279babd1ee4fdea3626eafceabea8c8cb262a8dff405c9729ddb5148
7
+ data.tar.gz: 3c45d0df7255e256f63d7461b42227e633228b342aae63ce394cde747b07e7af069ae417b75fce97cdfc925a40ac2962b78194a4414ee995f6fd1141c439b8ce
@@ -0,0 +1 @@
1
+ config/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ linux-hub (0.0.1)
5
+ octokit
6
+ trollop
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.4.0)
12
+ faraday (0.9.2)
13
+ multipart-post (>= 1.2, < 3)
14
+ multipart-post (2.0.0)
15
+ octokit (4.3.0)
16
+ sawyer (~> 0.7.0, >= 0.5.3)
17
+ sawyer (0.7.0)
18
+ addressable (>= 2.3.5, < 2.5)
19
+ faraday (~> 0.8, < 0.10)
20
+ trollop (2.1.2)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ linux-hub!
27
+
28
+ BUNDLED WITH
29
+ 1.11.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Patrick Robinson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # linux-hub
2
+
3
+ Create Linux users from Github Teams
4
+
5
+ ## Challenges
6
+
7
+ If you want to use immutable AMIs it can be difficult to give users access,
8
+ you need to deploy a new version of your AMI.
9
+
10
+ Netflix [BLESS](https://github.com/Netflix/bless) serves to solve a similar problem, but is much more complicated (and feature rich).
11
+
12
+ ## Solution
13
+
14
+ Github exposes all users public SSH keys via their API
15
+ We can associate users to a Github Team
16
+ We can query the members of a team via the Github API, provided we have an access key with 'read:org' permissions
17
+
18
+ So we can therefore use the Github API to provide authorization and authentication of users to systems.
19
+
20
+ ## Usage
21
+
22
+ The idea of this gem is to be run as a cron job, to synchronise users at a regular interval. You need to create a config file that specifies:
23
+ - The organisation to find the team in
24
+ - The team who are permitted access
25
+ - The access key to query team membership
26
+
27
+ Example config:
28
+ ```yaml
29
+ ---
30
+ organisation: github
31
+ team: sysadmins
32
+ access_key: baconfoobar
33
+ ```
34
+
35
+ Example command:
36
+
37
+ ```
38
+ linux-hub --config-file config/config.yaml --sync-users
39
+ ```
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trollop'
4
+ require 'linux-hub'
5
+
6
+ LinuxHub.invoke
@@ -0,0 +1,42 @@
1
+ require 'yaml'
2
+ require 'octokit'
3
+ require 'linux-hub/github_team'
4
+ require 'linux-hub/github_user'
5
+ require 'linux-hub/github'
6
+ require 'linux-hub/linux_user'
7
+ require 'linux-hub/cli'
8
+
9
+ module LinuxHub
10
+ ACTIONS = [:list, :create_users, :sync_users]
11
+
12
+ def self.invoke
13
+ options = Trollop::options do
14
+ opt :config_file, "The config file to read options from", type: :string, required: true
15
+ opt :list, "List users in the Github Team", type: :boolean
16
+ opt :create_users, "Create users in the Github Team", type: :boolean
17
+ opt :sync_users, "Manage all users in the Github Team", type: :boolean
18
+ end
19
+
20
+ config = load_config(options[:config_file])
21
+ if config["access_token"].nil?
22
+ puts "You need an access token with 'read:org' permissions for the organisation"
23
+ exit 1
24
+ elsif config["organisation"].nil? || config["team"].nil?
25
+ puts "Please provide the team and organisation in the relevant config file"
26
+ end
27
+
28
+ action = options.select { |k,v| ACTIONS.include?(k) && v == true }
29
+
30
+ unless action.length == 1
31
+ puts "Please specify one of the following action commands\n#{ACTIONS}"
32
+ exit 1
33
+ end
34
+
35
+ cli = CLI.new(config)
36
+ cli.send(action.keys.first)
37
+ end
38
+
39
+ def self.load_config(config_file)
40
+ YAML.load_file(config_file)
41
+ end
42
+ end
@@ -0,0 +1,58 @@
1
+ module LinuxHub
2
+ class CLI
3
+ def initialize(config)
4
+ @organization = config["organisation"]
5
+ @team = config["team"]
6
+ @groups = config["groups"]
7
+
8
+ Github.instance.access_token = config["access_token"]
9
+ end
10
+
11
+ def list
12
+ puts github_users.collect(&:authorized_keys)
13
+ end
14
+
15
+ def sync_users
16
+ linux_users = LinuxUser.users_in_group
17
+ linux_usernames = linux_users.collect(&:username)
18
+ github_usernames = github_users.collect(&:username)
19
+ # Equivalent to github_users - linux_users
20
+ users_to_add = github_users.reject { |u| linux_usernames.include? u.username }
21
+ # Equivalent to linux_users - github_users
22
+ users_to_delete = linux_users.reject { |u| github_usernames.include? u.username }
23
+ add_users(users_to_add)
24
+ delete_users(users_to_delete)
25
+ end
26
+
27
+ def create_users
28
+ add_users(github_users)
29
+ end
30
+
31
+ private
32
+
33
+ def add_users(users)
34
+ users.each do |user|
35
+ LinuxUser.new(
36
+ username: user.username,
37
+ groups: @groups,
38
+ ssh_keys: user.ssh_keys
39
+ ).create
40
+ end
41
+ end
42
+
43
+ def delete_users(users)
44
+ users.each do |user|
45
+ LinuxUser.new(
46
+ username: user.username
47
+ ).delete
48
+ end
49
+ end
50
+
51
+ def github_users
52
+ GithubTeam.new(
53
+ organisation: @organization,
54
+ team: @team,
55
+ ).users
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ require 'singleton'
2
+
3
+ module LinuxHub
4
+ class Github
5
+ include Singleton
6
+
7
+ attr_writer :access_token
8
+
9
+ def client
10
+ @client ||= Octokit::Client.new(access_token: @access_token)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ module LinuxHub
2
+ class GithubTeam
3
+ def initialize(organisation:, team:)
4
+ @org = organisation
5
+ @team = team
6
+ end
7
+
8
+ def users
9
+ @users ||= fetch_users
10
+ end
11
+
12
+ def team_id
13
+ @team_id ||= fetch_team_id
14
+ end
15
+
16
+ private
17
+
18
+ def fetch_users
19
+ client.team_members(team_id).collect do |member|
20
+ GithubUser.new(member.login)
21
+ end
22
+ end
23
+
24
+ def fetch_team_id
25
+ client.auto_paginate = true
26
+ team = client.organization_teams(@org).find { |t| t[:name] == @team }
27
+ client.auto_paginate = false
28
+ team.id
29
+ end
30
+
31
+ def client
32
+ Github.instance.client
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ module LinuxHub
2
+ class GithubUser
3
+ attr_reader :username, :email, :ssh_keys
4
+
5
+ def initialize(username)
6
+ @username = username
7
+ fetch_user_details
8
+ end
9
+
10
+ def authorized_keys
11
+ ssh_keys.map do |key|
12
+ "#{key} #{email}"
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def fetch_user_details
19
+ @email = client.user(@username).email || "#{@username}@github"
20
+ @ssh_keys = client.user_keys(@username).collect(&:key)
21
+ end
22
+
23
+ def client
24
+ Github.instance.client
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,106 @@
1
+ module LinuxHub
2
+ class LinuxUser
3
+ # The default group is used to keep track of members
4
+ # Members in this group not in the appropriate Github Team are purged
5
+ DEFAULT_GROUP = 'linuxhub'
6
+
7
+ def self.users_in_group
8
+ File.open("/etc/group") do |f|
9
+ f.each_line do |line|
10
+ user = line.split(":")
11
+ if user.first == DEFAULT_GROUP
12
+ return user[3].chomp.split(',').collect { |u| new(username: u) }
13
+ end
14
+ end
15
+ end
16
+ []
17
+ end
18
+
19
+ attr_reader :username
20
+
21
+ def initialize(username:, groups: [], ssh_keys: [])
22
+ @username = username
23
+ @groups = (groups || []) + [DEFAULT_GROUP]
24
+ @ssh_keys = ssh_keys
25
+ end
26
+
27
+ def create
28
+ create_default_group
29
+ create_user
30
+ create_user_keys
31
+ end
32
+
33
+ def delete
34
+ delete_home
35
+ delete_user
36
+ end
37
+
38
+ private
39
+
40
+ def create_default_group
41
+ return if group_exists?
42
+ %x(groupadd #{DEFAULT_GROUP})
43
+ end
44
+
45
+ def group_exists?
46
+ thing_exists? "/etc/group", DEFAULT_GROUP
47
+ end
48
+
49
+ def create_user
50
+ return if user_exists?
51
+ # Create the user and assign them to some groups
52
+ # Don't create a group for this user
53
+ # Create the home directory for this user
54
+ %x(useradd -G #{@groups.join(',')} -N -m #{@username})
55
+ end
56
+
57
+ def delete_user
58
+ return unless user_exists?
59
+ %x(userdel #{@username})
60
+ end
61
+
62
+ def delete_home
63
+ FileUtils.rm_r(home_dir)
64
+ end
65
+
66
+ def create_user_keys
67
+ ssh_dir = File.join(home_dir, ".ssh")
68
+ Dir.mkdir(ssh_dir, 0700) unless Dir.exist? ssh_dir
69
+ File.open(File.join(ssh_dir, "authorized_keys"), "w", 0600) do |f|
70
+ @ssh_keys.each do |key|
71
+ f.write "#{key}\n"
72
+ end
73
+ end
74
+ FileUtils.chown_R(@username, nil, ssh_dir)
75
+ end
76
+
77
+ def home_dir
78
+ File.open("/etc/passwd") do |f|
79
+ f.each_line do |line|
80
+ user = line.split(":")
81
+ if user.first == @username
82
+ return user[5]
83
+ end
84
+ end
85
+ end
86
+ fail "User not found!"
87
+ end
88
+
89
+ def user_exists?
90
+ thing_exists? "/etc/passwd", @username
91
+ end
92
+
93
+ def thing_exists?(file, value)
94
+ File.open(file) do |f|
95
+ f.each_line do |line|
96
+ user = line.split(":")
97
+ if user.first == value
98
+ f.close
99
+ return true
100
+ end
101
+ end
102
+ end
103
+ false
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'linux-hub'
3
+ s.version = '0.0.1'
4
+ s.summary = "Linux users from Github"
5
+ s.description = "Import linux users from Github Organisations and Teams"
6
+ s.authors = ["Patrick Robinson"]
7
+ s.email = 'therealpatrobinson@gmail.com'
8
+ s.files = `git ls-files`.split($/)
9
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
10
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
11
+ s.require_paths = ['lib']
12
+ s.homepage = 'https://github.com/patrobinson/linux-hub'
13
+ s.license = 'MIT'
14
+
15
+ s.add_dependency 'octokit'
16
+ s.add_dependency 'trollop'
17
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: linux-hub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Patrick Robinson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: octokit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: trollop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Import linux users from Github Organisations and Teams
42
+ email: therealpatrobinson@gmail.com
43
+ executables:
44
+ - linux-hub
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - LICENSE
52
+ - README.md
53
+ - bin/linux-hub
54
+ - lib/linux-hub.rb
55
+ - lib/linux-hub/cli.rb
56
+ - lib/linux-hub/github.rb
57
+ - lib/linux-hub/github_team.rb
58
+ - lib/linux-hub/github_user.rb
59
+ - lib/linux-hub/linux_user.rb
60
+ - linux-hub.gemspec
61
+ homepage: https://github.com/patrobinson/linux-hub
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.4.5.1
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Linux users from Github
85
+ test_files: []
86
+ has_rdoc: