pe_rbac 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 003e9ccdbe211c50b4025335831bcaab7c77d4cf
4
+ data.tar.gz: 40d72b46ffd84a8b9976d81eba7bf93f23e92e65
5
+ SHA512:
6
+ metadata.gz: 5c05146edfa1e4d4eb2392f774699c834388d836d546b34d1aebef2e638f2375b6e3799e317013de34d9dd511b372c95b5730bc12061ba225bee42c26712ed1c
7
+ data.tar.gz: fec01c7aae9f104627bc7bd02ba77fa87544a2d53b6d44306adb96010d1060046d40071d96cdf3a7fe927e0d6c431daa3ed07e621b469fac48a7e5fbf0bf162f
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.gem
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pe_rbac.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Geoff Williams
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # PeRbac
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/pe_rbac`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'pe_rbac'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install pe_rbac
22
+
23
+ ## Usage
24
+
25
+ ### Setting up code manager on the command line
26
+ ```
27
+ pe_rbac code_manager --password t0ps3cret
28
+ ```
29
+ Right now, the command line just provides a means to setup code manager. If you
30
+ want to do more then this, you must use the Ruby API
31
+
32
+ ### Ruby API
33
+ An *IN FLUX* Ruby API exists, see code for more info. This WILL change (well it
34
+ will if I do any more development work on this...) - expect module names,
35
+ functions, etc. to change. In particular, I'm planning:
36
+ * Sub-modules/file reorgs
37
+ * tests!
38
+
39
+ ## Development
40
+
41
+ ### Debugging
42
+ ```
43
+ RESTCLIENT_LOG=stdout bundle exec pe_rbac
44
+ ```
45
+
46
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
47
+
48
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/pe_rbac.
53
+
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
58
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pe_rbac"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/example.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'pe_rbac'
2
+ begin
3
+ # get all users
4
+ resp = PeRbac::get_users
5
+ puts resp
6
+
7
+ # get user by ID
8
+ resp = PeRbac::get_user('4765c077-3675-4a2d-85c0-0c76b82d15cb')
9
+ puts resp
10
+
11
+ # Lookup the ID for a user
12
+ resp = PeRbac::get_user_id('admin')
13
+ puts "FOUND: " + resp
14
+
15
+ # get all roles
16
+ resp = PeRbac::get_roles
17
+ puts resp
18
+
19
+ # get role by ID
20
+ resp = PeRbac::get_role(1)
21
+ puts resp
22
+
23
+ # create user (works - commented out to preven conflict error)
24
+ #resp = PeRbac::create_user('test','test@test.com', 'mr test test')
25
+ #puts resp
26
+
27
+ # update user
28
+ resp = PeRbac::update_user('test','test@test.com.au', 'mrs test test')
29
+ puts resp.code
30
+
31
+ # change password
32
+ resp = PeRbac::change_password('test','12345678')
33
+ puts resp.code
34
+
35
+ # get an API token
36
+ resp = PeRbac::token('test', '12345678')
37
+ puts resp
38
+
39
+ # create or update a user with role access and write a token
40
+ role_ids = PeRbac::get_role_ids('Code Deployers')
41
+ perms = {
42
+ "objectType" => "tokens",
43
+ "action" => "override_lifetime",
44
+ "instance" => nil,
45
+ }
46
+ PeRbac::update_role('Code Deployers', permissions=perms)
47
+ PeRbac::ensure_user('psquared', 'root@localhost', 'psquared', 'changeme', role_ids)
48
+ PeRbac::login('psquared', 'changeme', '10y')
49
+
50
+ # what permissions are there?
51
+ resp = PeRbac::get_permissions
52
+ puts resp.body
53
+
54
+ rescue Exception => e
55
+ puts e.message
56
+ puts e.backtrace
57
+ end
data/exe/pe_rbac ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pe_rbac'
3
+ require 'escort'
4
+
5
+ Escort::App.create do |app|
6
+ app.version "0.0.1"
7
+ app.summary "pe_rbac"
8
+ app.description "create RBAC users and install tokens"
9
+
10
+ app.command :code_manager do |command|
11
+ command.summary "Setup a code manager"
12
+ command.description "Create a deploy user for use with code manager and install token"
13
+ command.action do |options, arguments|
14
+ role = 'Code Deployers'
15
+ cmd = :code_manager # FIXME obtain this automatically
16
+ lifetime = options[:global][:commands][cmd][:options][:lifetime]
17
+ username = options[:global][:commands][cmd][:options][:username]
18
+ password = options[:global][:commands][cmd][:options][:password]
19
+ email = options[:global][:commands][cmd][:options][:email]
20
+ role_ids = PeRbac::get_role_ids(role)
21
+
22
+ perms = {
23
+ "objectType" => "tokens",
24
+ "action" => "override_lifetime",
25
+ "instance" => nil,
26
+ }
27
+ PeRbac::update_role(role, permissions=perms)
28
+ PeRbac::ensure_user(username, email, username, password, role_ids)
29
+ PeRbac::login(username, password, lifetime)
30
+ end
31
+ command.options do |opts|
32
+ opts.opt(:username,
33
+ 'Username for deploy user',
34
+ :long => '--username',
35
+ :default => 'deploy'
36
+ )
37
+ opts.opt(:password,
38
+ 'Initial password for deploy user',
39
+ :long => '--password',
40
+ :default => 'changeme'
41
+ )
42
+ opts.opt(:email,
43
+ 'Email address',
44
+ :long => '--email',
45
+ :default => 'root@localhost'
46
+ )
47
+ opts.opt(:lifetime,
48
+ 'Token validity length',
49
+ :long => '--lifetime',
50
+ :default => '10y'
51
+ )
52
+ end
53
+ end
54
+
55
+ end
data/lib/pe_rbac.rb ADDED
@@ -0,0 +1,240 @@
1
+ require "pe_rbac/version"
2
+ require 'restclient'
3
+ require 'socket'
4
+ require 'json'
5
+
6
+ module PeRbac
7
+ ssldir = '/etc/puppetlabs/puppet/ssl'
8
+ CONF = {
9
+ host: Socket.gethostname,
10
+ port: 4433,
11
+ cert: ssldir + '/certs/pe-internal-orchestrator.pem',
12
+ key: ssldir + '/private_keys/pe-internal-orchestrator.pem',
13
+ cacert: ssldir + '/certs/ca.pem'
14
+ }
15
+
16
+ BASE_URI = '/rbac-api/v1'
17
+
18
+ #
19
+ # user
20
+ #
21
+
22
+ def self.get_users
23
+ JSON.parse(_request(:get, '/users').body)
24
+ end
25
+
26
+ # get the user id for a login or false if missing
27
+ # eg 'admin' => '42bf351c-f9ec-40af-84ad-e976fec7f4bd'
28
+ def self.get_user_id(login)
29
+ users = get_users
30
+ id = false
31
+ i = 0
32
+ while !id and i < users.length do
33
+ if users[i]['login'] == login
34
+ id = users[i]['id']
35
+ end
36
+ i += 1
37
+ end
38
+ id
39
+ end
40
+
41
+ def self.get_user(id)
42
+ JSON.parse(_request(:get, "/users/#{id}").body)
43
+ end
44
+
45
+ def self.ensure_user(login, email, display_name, password=nil, role_ids=[])
46
+ if get_user_id(login)
47
+ # existing user
48
+ update_user(login, email, display_name, role_ids)
49
+ if password
50
+ change_password(login, password)
51
+ end
52
+ else
53
+ # new user
54
+ create_user(login, email, display_name, password, role_ids)
55
+ end
56
+
57
+ end
58
+
59
+ def self.create_user(login, email, display_name, password=nil, role_ids=[])
60
+ # completely different to what the PE console sends... :/
61
+ user={
62
+ "login" => login,
63
+ "email" => email,
64
+ "display_name" => display_name,
65
+ "role_ids" => role_ids,
66
+ }
67
+
68
+ if password
69
+ user["password"] = password
70
+ end
71
+
72
+ _request(:post, '/users', user)
73
+ end
74
+
75
+ def self.update_user(login, email=nil, display_name=nil, role_ids=nil, is_revoked=nil)
76
+ user = get_user(get_user_id(login))
77
+ if ! user['remote']
78
+ # trade-off for auto id lookup is that you cant change logins...
79
+ user['login'] = login ? login : user['login']
80
+ user['email'] = email ? email : user['email']
81
+ user['display_name'] = display_name ? display_name : user['display_name']
82
+ end
83
+ user['role_ids'] = role_ids ? role_ids : user['role_ids']
84
+ user['is_revoked'] = (! is_revoked.nil?) ? is_revoked : user['is_revoked']
85
+
86
+ _request(:put, "/users/#{user['id']}", user)
87
+ end
88
+
89
+ def self.change_password(login, new_password)
90
+ token = _request(:post, "/users/#{get_user_id(login)}/password/reset").body
91
+
92
+ reset = {
93
+ "token" => token,
94
+ "password" => new_password,
95
+ }
96
+
97
+ _request(:post, '/auth/reset', reset)
98
+ end
99
+
100
+ #
101
+ # role
102
+ #
103
+ def self.get_roles
104
+ JSON.parse(_request(:get, "/roles").body)
105
+ end
106
+
107
+ def self.get_role(id)
108
+ JSON.parse(_request(:get, "/roles/#{id}").body)
109
+ end
110
+
111
+ def self.get_role_id(display_name)
112
+ i=0
113
+ found=false
114
+ roles = get_roles()
115
+ while !found and i < roles.length do
116
+ if roles[i]['display_name'] == display_name
117
+ found = roles[i]['id']
118
+ end
119
+ i+=1
120
+ end
121
+ found
122
+ end
123
+
124
+
125
+ # get the role id for a display name
126
+ # eg ['Code Deployers', 'blah'] => [4,8]
127
+ def self.get_role_ids(display_names)
128
+ if ! display_names.is_a? Array
129
+ display_names = [display_names]
130
+ end
131
+ roles = get_roles
132
+ ids = []
133
+ display_names.each { |display_name|
134
+ found=get_role_id(display_name)
135
+ if !found
136
+ raise("RBAC role '#{display_name}' not found")
137
+ end
138
+ ids.push(found)
139
+ }
140
+ ids
141
+ end
142
+
143
+ # CREATE
144
+ def self.ensure_role(display_name, description, permissions=[], users=[])
145
+ if get_role_id(display_name)
146
+ update_role(display_name, description, permissions, users)
147
+ else
148
+ create_role(display_name, description, permissions, users)
149
+ end
150
+ end
151
+
152
+ def self.create_role(display_name, description, permissions=[], users=[])
153
+ role = {
154
+ "display_name" => display_name,
155
+ "description" => description,
156
+ "permissions" => permissions,
157
+ "user_ids" => users,
158
+ "group_ids" => [], # doesn't seem to be used yet
159
+ }
160
+ _request(:post, '/roles', role)
161
+ end
162
+
163
+ def self.update_role(display_name, description=nil, permissions=nil, user_ids=nil, group_ids=nil)
164
+ role_id = get_role_id(display_name)
165
+ if role_id
166
+ role = get_role(role_id)
167
+ role['display_name'] = display_name ? display_name : role['display_name']
168
+ role['description'] = description ? display_name : role['description']
169
+ role['permissions'] = permissions ? display_name : role['permissions']
170
+ role['user_ids'] = user_ids ? display_name : role['user_ids']
171
+ role['group_ids'] = group_ids ? display_name : role['group_ids']
172
+
173
+ _request(:put, "/roles/#{role_id}", role)
174
+ else
175
+ raise("No such role exists: #{display_name} create it first or use ensure_role")
176
+ end
177
+ end
178
+
179
+
180
+ #
181
+ # Permissions
182
+ #
183
+ def self.get_permissions()
184
+ _request(:get, "/types")
185
+ end
186
+
187
+
188
+ #
189
+ # Token
190
+ #
191
+ def self.token(login, password, lifetime=false)
192
+ payload = {
193
+ "login" => login,
194
+ "password" => password,
195
+ }
196
+
197
+ # see https://docs.puppet.com/pe/latest/rbac_token_auth.html#setting-a-token-specific-lifetime
198
+ if lifetime
199
+ payload["lifetime"] = lifetime
200
+ end
201
+
202
+ JSON.parse(_request(:post, '/auth/token', payload))['token']
203
+ end
204
+
205
+ def self.login(login, password, lifetime=false)
206
+ dirname = Dir.home + '/.puppetlabs'
207
+ tokenfile = dirname + '/token'
208
+ if ! Dir.exist?(dirname)
209
+ Dir.mkdir(dirname, 0700)
210
+ end
211
+ File.write(tokenfile, token(login, password, lifetime))
212
+ File.chmod(0600, tokenfile)
213
+ end
214
+
215
+ private
216
+
217
+ def self._request(method, path, payload=nil, raw=false)
218
+ url = "https://#{CONF[:host]}:#{CONF[:port]}#{BASE_URI}#{path}"
219
+ if payload
220
+ if raw
221
+ _payload=payload
222
+ else
223
+ _payload=payload.to_json
224
+ end
225
+ else
226
+ _payload=nil
227
+ end
228
+ RestClient::Request.execute(
229
+ method: method,
230
+ url: url,
231
+ ssl_ca_file: CONF[:cacert],
232
+ ssl_client_cert: OpenSSL::X509::Certificate.new(File.read(CONF[:cert])),
233
+ ssl_client_key: OpenSSL::PKey::RSA.new(File.read(CONF[:key])),
234
+ ssl_version: :TLSv1,
235
+ headers: {:content_type => :json, :accept => :json},
236
+ payload: _payload,
237
+ )
238
+ end
239
+
240
+ end
@@ -0,0 +1,3 @@
1
+ module PeRbac
2
+ VERSION = "0.1.0"
3
+ end
data/pe_rbac.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pe_rbac/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pe_rbac"
8
+ spec.version = PeRbac::VERSION
9
+ spec.authors = ["Geoff Williams"]
10
+ spec.email = ["geoff@geoffwilliams.me.uk"]
11
+
12
+ spec.summary = %q{Ruby API for Puppet Enterprise RBAC}
13
+ spec.description = %q{Programatically do stuff with Puppet Enterprise RBAC}
14
+ spec.homepage = "https://github.com/geoffwilliams/pe_rbac"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.12"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_runtime_dependency "rest-client", "2.0.0"
26
+ spec.add_runtime_dependency "escort", "0.4.0"
27
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pe_rbac
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Geoff Williams
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rest-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: escort
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.4.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.4.0
69
+ description: Programatically do stuff with Puppet Enterprise RBAC
70
+ email:
71
+ - geoff@geoffwilliams.me.uk
72
+ executables:
73
+ - pe_rbac
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/console
83
+ - bin/setup
84
+ - example.rb
85
+ - exe/pe_rbac
86
+ - lib/pe_rbac.rb
87
+ - lib/pe_rbac/version.rb
88
+ - pe_rbac.gemspec
89
+ homepage: https://github.com/geoffwilliams/pe_rbac
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.6
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Ruby API for Puppet Enterprise RBAC
113
+ test_files: []
114
+ has_rdoc: