autosign 0.0.1

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: 3d43769ea221d92c48e517138ec7a3c1ba16ed3a
4
+ data.tar.gz: 0a8454928712134b07dfaa5aa16c4451042086ac
5
+ SHA512:
6
+ metadata.gz: fd1b62abf9b19f6806a356a693c42eb91593ca9cad9bcc79240b7df3d01d1b72bc92c6b8cb14647f92cb92a59179831aa7a90e6d379274b536c977b65a844fd1
7
+ data.tar.gz: 4d5660957738acf9edd0413efab0c1fcc029ecc23ba049d75c26807a7e68f2310d5f5e22054a3c1469ab6e8609ec796ce1956968f6445bfb6e28ff3d990eda74
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,73 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ autosign (0.0.1)
5
+ deep_merge
6
+ gli (~> 2)
7
+ iniparse (~> 1)
8
+ jwt (~> 1)
9
+ logging
10
+ require_all
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ CFPropertyList (2.2.8)
16
+ aruba (0.6.2)
17
+ childprocess (>= 0.3.6)
18
+ cucumber (>= 1.1.1)
19
+ rspec-expectations (>= 2.7.0)
20
+ builder (3.2.2)
21
+ childprocess (0.5.6)
22
+ ffi (~> 1.0, >= 1.0.11)
23
+ cucumber (2.0.0)
24
+ builder (>= 2.1.2)
25
+ cucumber-core (~> 1.1.3)
26
+ diff-lcs (>= 1.1.3)
27
+ gherkin (~> 2.12)
28
+ multi_json (>= 1.7.5, < 2.0)
29
+ multi_test (>= 0.1.2)
30
+ cucumber-core (1.1.3)
31
+ gherkin (~> 2.12.0)
32
+ deep_merge (1.0.1)
33
+ diff-lcs (1.2.5)
34
+ facter (2.2.0)
35
+ CFPropertyList (~> 2.2.6)
36
+ ffi (1.9.9)
37
+ gherkin (2.12.2)
38
+ multi_json (~> 1.3)
39
+ gli (2.13.1)
40
+ hiera (1.3.4)
41
+ json_pure
42
+ iniparse (1.4.0)
43
+ json (1.8.3)
44
+ json_pure (1.8.1)
45
+ jwt (1.5.1)
46
+ little-plugger (1.1.3)
47
+ logging (2.0.0)
48
+ little-plugger (~> 1.1)
49
+ multi_json (~> 1.10)
50
+ multi_json (1.11.1)
51
+ multi_test (0.1.2)
52
+ puppet (3.7.0)
53
+ facter (> 1.6, < 3)
54
+ hiera (~> 1.0)
55
+ json_pure
56
+ rake (10.4.2)
57
+ rdoc (4.2.0)
58
+ json (~> 1.4)
59
+ require_all (1.3.2)
60
+ rspec-expectations (3.3.0)
61
+ diff-lcs (>= 1.2.0, < 2.0)
62
+ rspec-support (~> 3.3.0)
63
+ rspec-support (3.3.0)
64
+
65
+ PLATFORMS
66
+ ruby
67
+
68
+ DEPENDENCIES
69
+ aruba
70
+ autosign!
71
+ puppet
72
+ rake
73
+ rdoc
data/README.rdoc ADDED
@@ -0,0 +1,6 @@
1
+ = autosign
2
+
3
+ Describe your project here
4
+
5
+ :include:autosign.rdoc
6
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ require 'cucumber'
6
+ require 'cucumber/rake/task'
7
+ Rake::RDocTask.new do |rd|
8
+ rd.main = "README.rdoc"
9
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
10
+ rd.title = 'Your application title'
11
+ end
12
+
13
+ spec = eval(File.read('autosign.gemspec'))
14
+
15
+ Gem::PackageTask.new(spec) do |pkg|
16
+ end
17
+ CUKE_RESULTS = 'results.html'
18
+ CLEAN << CUKE_RESULTS
19
+ desc 'Run features'
20
+ Cucumber::Rake::Task.new(:features) do |t|
21
+ opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
22
+ opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
23
+ t.cucumber_opts = opts
24
+ t.fork = false
25
+ end
26
+
27
+ desc 'Run features tagged as work-in-progress (@wip)'
28
+ Cucumber::Rake::Task.new('features:wip') do |t|
29
+ tag_opts = ' --tags ~@pending'
30
+ tag_opts = ' --tags @wip'
31
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
32
+ t.fork = false
33
+ end
34
+
35
+ task :cucumber => :features
36
+ task 'cucumber:wip' => 'features:wip'
37
+ task :wip => 'features:wip'
38
+ require 'rake/testtask'
39
+ Rake::TestTask.new do |t|
40
+ t.libs << "test"
41
+ t.test_files = FileList['test/*_test.rb']
42
+ end
43
+
44
+ task :default => [:test,:features]
data/autosign.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require File.join([File.dirname(__FILE__),'lib','autosign','version.rb'])
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'autosign'
5
+ s.version = Autosign::VERSION
6
+ s.author = 'Your Name Here'
7
+ s.email = 'your@email.address.com'
8
+ s.homepage = 'http://your.website.com'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'A description of your project'
11
+ s.files = `git ls-files`.split("
12
+ ")
13
+ s.require_paths << 'lib'
14
+ s.has_rdoc = true
15
+ s.extra_rdoc_files = ['README.rdoc','autosign.rdoc']
16
+ s.rdoc_options << '--title' << 'autosign' << '--main' << 'README.rdoc' << '-ri'
17
+ s.bindir = 'bin'
18
+ s.executables << 'autosign'
19
+ s.add_development_dependency('rake')
20
+ s.add_development_dependency('rdoc')
21
+ s.add_development_dependency('aruba')
22
+ s.add_development_dependency('puppet')
23
+ s.add_runtime_dependency('gli','~> 2')
24
+ s.add_runtime_dependency('jwt','~> 1')
25
+ s.add_runtime_dependency('iniparse','~> 1')
26
+ s.add_runtime_dependency('logging')
27
+ s.add_runtime_dependency('deep_merge')
28
+ s.add_runtime_dependency('require_all')
29
+ end
data/autosign.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ = autosign
2
+
3
+ Generate this with
4
+ autosign rdoc
5
+ After you have described your command line interface
data/bin/autosign ADDED
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'autosign'
4
+ require 'socket' # for determining the current hostname
5
+ include GLI::App
6
+ require 'logging'
7
+
8
+ @logger = Logging.logger['Autosign']
9
+ @logger.level = :warn
10
+
11
+ program_desc 'Easy Puppet Certificate Autosigning'
12
+
13
+ version Autosign::VERSION
14
+
15
+ subcommand_option_handling :normal
16
+ arguments :strict
17
+
18
+ desc 'Configuration file location'
19
+ arg_name 'path'
20
+ flag [:c,:config]
21
+
22
+ desc 'log file location'
23
+ arg_name 'path'
24
+ flag [:l,:logfile]
25
+
26
+ desc 'secret symmetric key'
27
+ arg_name 'secret'
28
+ flag [:s,:secret]
29
+
30
+ desc 'Enable verbose output'
31
+ switch [:v, :verbose]
32
+
33
+ desc 'Enable debug output'
34
+ switch [:d, :debug]
35
+
36
+ desc 'Quiet output - only log errors'
37
+ switch [:q, :quiet]
38
+
39
+ desc 'Generate an autosign token'
40
+ arg_name 'certname or regex the autosign token will be valid for'
41
+ command :generate do |c|
42
+ c.desc 'Generate a reusable token; default is to generate one-time tokens'
43
+ c.switch [:r, :reusable]
44
+
45
+ c.desc 'certname or regex of certnames the autosign token will be valid for'
46
+ c.arg_name 'certname'
47
+ c.flag [:n,:certname]
48
+
49
+ c.desc 'autosign token validity period'
50
+ c.default_value '7200'
51
+ c.arg_name 'seconds'
52
+ c.flag [:t,:validfor]
53
+
54
+ c.action do |global_options,options,args|
55
+ config = Autosign::Config.new({'config_file' => global_options['config']})
56
+ global_options['secret'] = config.settings['jwt_token']['secret'] if global_options['secret'].nil?
57
+ options['validfor'] = config.settings.to_hash['jwt_token']['validity'].to_s if options['validfor'] == '7200'
58
+ @logger.debug "validfor: " + options['validfor']
59
+ help_now!('no secret was defined via --secret or a config file') if global_options['secret'].nil?
60
+ help_now!('certname is required') if options['certname'].nil?
61
+
62
+ help_now!('validfor setting must be an positive integer number of seconds') if !/\A\d+\z/.match(options['validfor'].to_s)
63
+ token = Autosign::Token.new(options['certname'].to_s, options['reusable'], options['validfor'].to_i, Socket.gethostname.to_s, global_options['secret'])
64
+ @logger.info "generated token for: " + options['certname'].to_s
65
+ puts "Autosign token for: " + token.certname
66
+ puts "Valid until: " + Time.at(token.validto).to_s
67
+ puts ""
68
+ puts token.sign.to_s
69
+ puts ""
70
+ end
71
+ end
72
+
73
+ desc 'Validate a previously issued token'
74
+ arg_name 'path'
75
+ command :validate do |c|
76
+ c.desc 'display the contents of the token'
77
+
78
+ c.arg_name 'certname'
79
+ c.flag [:n,:certname]
80
+
81
+ c.action do |global_options,options,args|
82
+ config = Autosign::Config.new({'config_file' => global_options['config']})
83
+ puts config.settings.to_hash['jwt_token']
84
+ global_options['secret'] = config.settings['jwt_token']['secret'] if global_options['secret'].nil?
85
+
86
+ help_now!('no secret was defined via --secret or a config file') if global_options['secret'].nil?
87
+ help_now!('certname is required') if options['certname'].nil?
88
+ help_now!('a single token must be provided as an argument') if args.size != 1
89
+ token = Autosign::Token.validate(options['certname'].to_s, args[0], global_options['secret'])
90
+ if token == true
91
+ puts "token validated successfully"
92
+ @logger.info "token validated successfully"
93
+ else
94
+ @logger.error "Unable to validate token"
95
+ exit_now!("Unable to validate token", 1)
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ desc 'Autosign configuration'
102
+ command :config do |c|
103
+
104
+ c.desc 'Configure a puppet server for autosigning'
105
+ c.command :setup do |setup|
106
+ setup.action do |global_options,options,args|
107
+ @logger.info "setup command ran with #{global_options} #{options} #{args}"
108
+ @logger.info "generated default config file" if Autosign::Config.generate_default
109
+ end
110
+ end
111
+
112
+ c.desc 'Print autosign configuration'
113
+ c.command :print do |print|
114
+ print.action do |global_options,options,args|
115
+ @logger.debug "print command ran with #{global_options} #{options} #{args}"
116
+ config = Autosign::Config.new({'config_file' => global_options['config']})
117
+ puts config.settings.to_s
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ desc 'Install an autosign token; run this prior to running puppet for the first time on an agent'
124
+ arg_name 'token'
125
+ command :use do |c|
126
+ c.action do |global_options,options,args|
127
+ puppet_confdir = %x[puppet config print confdir].chomp
128
+ @logger.debug "use command ran with #{global_options} #{options} #{args}"
129
+ puts "put the following in #{puppet_confdir}/csr_attributes.yaml prior to running puppet agent for the first time:
130
+ custom_attributes:
131
+ challengePassword: \"#{args[0]}\""
132
+ end
133
+ end
134
+
135
+ pre do |global,command,options,args|
136
+ # Pre logic here
137
+ # Return true to proceed; false to abort and not call the
138
+ # chosen command
139
+ # Use skips_pre before a command to skip this block
140
+ # on that command only
141
+ # config = Autosign::Config.new
142
+ # @logger.level = config.settings.to_hash['general']['loglevel'].to_sym unless config.settings.to_hash['general']['loglevel'].nil?
143
+
144
+ @logger.level = :error if global['quiet']
145
+ @logger.level = :info if global['verbose']
146
+ @logger.level = :debug if global['debug']
147
+
148
+ if global['logfile'].nil?
149
+ @logger.add_appenders Logging.appenders.stdout
150
+ else
151
+ @logger.add_appenders Logging.appenders.stdout, Logging.appenders.file(global['logfile'])
152
+ end
153
+
154
+ true
155
+ end
156
+
157
+ post do |global,command,options,args|
158
+ # Post logic here
159
+ # Use skips_post before a command to skip this
160
+ # block on that command only
161
+ end
162
+
163
+ on_error do |exception|
164
+ # Error logic here
165
+ # return false to skip default error handling
166
+ true
167
+ end
168
+
169
+ exit run(ARGV)
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ require 'autosign'
3
+ require 'logging'
4
+
5
+ @logger = Logging.logger['Autosign']
6
+ @logger.level = :debug
7
+ @logger.add_appenders Logging.appenders.stdout
8
+
9
+ ### Get Inputs
10
+ unless ARGV.count == 1
11
+ @logger.error "This executable must be called with a certname as the only parameter and with an X509 CSR piped into STDIN"
12
+ exit 1
13
+ end
14
+
15
+ certname = ARGV[0]
16
+ @logger.debug "certname is " + certname
17
+
18
+ @logger.debug "reading CSR from stdin"
19
+ csr = Autosign::Decoder.decode_csr($stdin.read)
20
+ exit 1 unless csr.is_a?(Hash)
21
+
22
+ @logger.debug "CSR: " + csr.to_s
23
+ ### End Inputs
24
+
25
+ ### validate token
26
+ token_validation = Autosign::Validator.any_validator(csr[:challenge_password].to_s, certname.to_s)
27
+ ### end validation
28
+
29
+ ### Exit with correct exit status
30
+ if token_validation == true
31
+ @logger.info "token validated successfully"
32
+ exit 0
33
+ else
34
+ STDERR.puts "failed to validate token"
35
+ @logger.error "Unable to validate token"
36
+ exit 1
37
+ end
38
+ ### Done exiting
39
+
40
+ # end with an exit 1 just in case
41
+ exit 1
@@ -0,0 +1,78 @@
1
+ Feature: Generate autosign key
2
+ In order to sign puppet certificates automatically
3
+ I want to generate autosign keys programatically
4
+ So I don't have to use static strings as keys
5
+
6
+ Scenario: Generate new token
7
+ Given a pre-shared key of "secret"
8
+ And a hostname of "foo.example.com"
9
+ And a file named "autosign.conf" with:
10
+ """
11
+ [jwt_token]
12
+ validity = 7200
13
+ secret = secret
14
+ """
15
+ When I run `chmod 600 autosign.conf`
16
+ And I run `autosign --config autosign.conf generate --certname foo.example.com`
17
+ Then the output should contain "Autosign token for: foo.example.com"
18
+ And the output should contain "Valid until"
19
+ And the exit status should be 0
20
+
21
+ Scenario: Generate new reusable token
22
+ Given a pre-shared key of "secret"
23
+ And a hostname of "foo.example.com"
24
+ And a file named "autosign.conf" with:
25
+ """
26
+ [jwt_token]
27
+ secret = secret
28
+ validity = 7200
29
+ """
30
+ When I run `chmod 600 autosign.conf`
31
+ When I run `autosign --config autosign.conf generate --certname foo.example.com --reusable`
32
+ Then the output should contain "Autosign token for: foo.example.com"
33
+ And the output should contain "Valid until"
34
+ And the exit status should be 0
35
+
36
+ Scenario: Validate a token
37
+ Given a pre-shared key of "secret"
38
+ And a hostname of "foo.example.com"
39
+ And a file named "autosign.conf" with:
40
+ """
41
+ [jwt_token]
42
+ secret = secret
43
+ """
44
+ When I run `chmod 600 autosign.conf`
45
+ When I run `autosign --config autosign.conf validate --certname "foo.example.com" "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJkYXRhIjoie1wiY2VydG5hbWVcIjpcImZvby5leGFtcGxlLmNvbVwiLFwicmVxdWVzdGVyXCI6XCJEYW5pZWxzLU1hY0Jvb2stUHJvLTIubG9jYWxcIixcInJldXNhYmxlXCI6ZmFsc2UsXCJ2YWxpZGZvclwiOjI5OTk5OTk5OSxcInV1aWRcIjpcIjlkYTA0Yzc4LWQ5NjUtNDk2OC04MWNjLWVhM2RjZDllZjVjMFwifSIsImV4cCI6IjE3MzY0NjYxMzAifQ.PJwY8rIunVyWi_lw0ypFclME0jx3Vd9xJIQSyhN3VUmul3V8u4Tp9XwDgoAu9DVV0-WEG2Tfxs6F8R6Fn71Ndg"`
46
+ Then the output should contain "token validated successfully"
47
+ And the exit status should be 0
48
+
49
+ Scenario: Not validate a bad token
50
+ Given a pre-shared key of "secret"
51
+ And a hostname of "foo.example.com"
52
+ And a file named "autosign.conf" with:
53
+ """
54
+ [jwt_token]
55
+ secret = secret
56
+ """
57
+ When I run `chmod 600 autosign.conf`
58
+ When I run `autosign --config autosign.conf validate --certname "foo.example.com" "invalid_token"`
59
+ Then the exit status should be 1
60
+
61
+ Scenario: Not validate an expired token
62
+ Given a pre-shared key of "secret"
63
+ And a hostname of "foo.example.com"
64
+ And a file named "autosign.conf" with:
65
+ """
66
+ [jwt_token]
67
+ secret = secret
68
+ """
69
+ When I run `chmod 600 autosign.conf`
70
+ When I run `autosign --config autosign.conf validate --certname "foo.example.com" "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJkYXRhIjoie1wiY2VydG5hbWVcIjpcImZvby5leGFtcGxlLmNvbVwiLFwicmVxdWVzdGVyXCI6XCJEYW5pZWxzLU1hY0Jvb2stUHJvLTIubG9jYWxcIixcInJldXNhYmxlXCI6ZmFsc2UsXCJ2YWxpZGZvclwiOjEsXCJ1dWlkXCI6XCJlNjI1Y2I1Ny02NzY5LTQwMzQtODNiZS0zNzkxNmQ5YmMxMDRcIn0iLCJleHAiOiIxNDM2NDY2MzAyIn0.UXEDEbRqEWx5SdSpQjfowU56JubY5Yz2QN6cckby2es-g2P_n2lyAS6AwFeliBXyCDyVUelIT3g1QP4TdB9EEA"`
71
+ Then the exit status should be 1
72
+
73
+ Scenario: Generate a csr_attributes.yaml file
74
+ When I run `autosign use hunter2`
75
+ Then the output should contain "challengePassword: "
76
+ And the output should contain "csr_attributes.yaml"
77
+ And the output should contain "hunter2"
78
+ And the exit status should be 0