pupistry 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -1
- data/{bin → exe}/pupistry +45 -76
- data/lib/pupistry.rb +1 -1
- data/lib/pupistry/agent.rb +40 -60
- data/lib/pupistry/artifact.rb +136 -172
- data/lib/pupistry/bootstrap.rb +30 -35
- data/lib/pupistry/config.rb +59 -31
- data/lib/pupistry/gpg.rb +71 -102
- data/lib/pupistry/storage_aws.rb +56 -61
- data/lib/pupistry/version.rb +3 -0
- data/resources/aws/cfn_pupistry_bucket_and_iam.template +11 -1
- data/resources/packer/amazon_linux.json +17 -0
- data/resources/packer/test_user_data.txt +33 -0
- metadata +92 -5
data/lib/pupistry/bootstrap.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
# rubocop:disable Style/Documentation, Style/GlobalVars
|
1
2
|
require 'rubygems'
|
2
|
-
require
|
3
|
+
require 'base64'
|
3
4
|
require 'erubis'
|
4
5
|
|
5
6
|
module Pupistry
|
@@ -10,98 +11,92 @@ module Pupistry
|
|
10
11
|
attr_accessor :contents
|
11
12
|
|
12
13
|
def initialize
|
13
|
-
|
14
14
|
# We need to find where the templates are located - either it should be
|
15
15
|
# in the current working directory, or if we are an installed gem, we
|
16
16
|
# can try the gem's installed path.
|
17
17
|
|
18
|
-
if Dir.
|
18
|
+
if Dir.exist?('resources/bootstrap/')
|
19
19
|
# Use local PWD version first if possible
|
20
20
|
@template_dir = Dir.pwd
|
21
21
|
else
|
22
22
|
# Check for GEM installed location
|
23
23
|
begin
|
24
|
-
@template_dir = Gem::Specification.find_by_name(
|
24
|
+
@template_dir = Gem::Specification.find_by_name('pupistry').gem_dir
|
25
25
|
rescue Gem::LoadError
|
26
26
|
$logger.error "Unable to find templates/ directory, doesn't appear we are running from project dir nor as a Gem"
|
27
27
|
return false
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
@template_dir = @template_dir.chomp(
|
31
|
+
@template_dir = @template_dir.chomp('/') + '/resources/bootstrap/'
|
32
32
|
|
33
|
-
|
33
|
+
if Dir.exist?(@template_dir)
|
34
|
+
$logger.debug "Using directory #{@template_dir} for bootstrap templates"
|
35
|
+
else
|
34
36
|
$logger.error "Unable to find templates dir at #{@template_dir}, unable to proceed."
|
35
37
|
return false
|
36
|
-
else
|
37
|
-
$logger.debug "Using directory #{@template_dir} for bootstrap templates"
|
38
38
|
end
|
39
|
-
|
40
39
|
end
|
41
|
-
|
42
40
|
|
43
41
|
def list
|
44
42
|
# Simply glob the templates directory and list their names.
|
45
|
-
$logger.debug
|
43
|
+
$logger.debug 'Finding all available templates'
|
46
44
|
|
47
45
|
Dir.glob("#{@template_dir}/*.erb").each do |file|
|
48
|
-
puts "- #{File.basename(file,
|
46
|
+
puts "- #{File.basename(file, '.erb')}"
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
52
|
-
|
53
|
-
def build template
|
50
|
+
def build(template)
|
54
51
|
# Build a template with the configured parameters already to go and save
|
55
52
|
# into the object, so it can be outputted in the desired format.
|
56
53
|
|
57
54
|
$logger.debug "Generating a bootstrap script for #{template}"
|
58
55
|
|
59
|
-
unless File.
|
60
|
-
$logger.error
|
56
|
+
unless File.exist?("#{@template_dir}/#{template}.erb")
|
57
|
+
$logger.error 'The requested template does not exist, unable to build'
|
61
58
|
return 0
|
62
59
|
end
|
63
60
|
|
64
61
|
# Assume values we care about
|
65
62
|
template_values = {
|
66
|
-
s3_bucket: $config[
|
67
|
-
s3_prefix: $config[
|
68
|
-
gpg_disable: $config[
|
69
|
-
gpg_signing_key: $config[
|
70
|
-
puppetcode: $config[
|
71
|
-
access_key_id: $config[
|
72
|
-
secret_access_key: $config[
|
73
|
-
region: $config[
|
74
|
-
proxy_uri: $config[
|
75
|
-
daemon_frequency: $config[
|
76
|
-
daemon_minimal: $config[
|
63
|
+
s3_bucket: $config['general']['s3_bucket'],
|
64
|
+
s3_prefix: $config['general']['s3_prefix'],
|
65
|
+
gpg_disable: $config['general']['gpg_disable'],
|
66
|
+
gpg_signing_key: $config['general']['gpg_signing_key'],
|
67
|
+
puppetcode: $config['agent']['puppetcode'],
|
68
|
+
access_key_id: $config['agent']['access_key_id'],
|
69
|
+
secret_access_key: $config['agent']['secret_access_key'],
|
70
|
+
region: $config['agent']['region'],
|
71
|
+
proxy_uri: $config['agent']['proxy_uri'],
|
72
|
+
daemon_frequency: $config['agent']['daemon_frequency'],
|
73
|
+
daemon_minimal: $config['agent']['daemon_minimal']
|
77
74
|
}
|
78
75
|
|
79
76
|
# Generate template using ERB
|
80
77
|
begin
|
81
78
|
@contents = Erubis::Eruby.new(File.read("#{@template_dir}/#{template}.erb")).result(template_values)
|
82
|
-
rescue
|
83
|
-
$logger.error
|
79
|
+
rescue StandardError => e
|
80
|
+
$logger.error 'An unexpected error occured when trying to generate the bootstrap template'
|
84
81
|
raise e
|
85
82
|
end
|
86
|
-
|
87
83
|
end
|
88
84
|
|
89
85
|
def output_plain
|
90
86
|
# Do nothing clever, just output the template data.
|
91
|
-
puts
|
87
|
+
puts '-- Bootstrap Start --'
|
92
88
|
puts @contents
|
93
|
-
puts
|
89
|
+
puts '-- Bootstrap End --'
|
94
90
|
end
|
95
91
|
|
96
92
|
def output_base64
|
97
93
|
# Some providers like AWS can accept the data in Base64 version which is
|
98
94
|
# smaller and less likely to get messed up by copy and paste or weird
|
99
95
|
# formatting issues.
|
100
|
-
puts
|
96
|
+
puts '-- Bootstrap Start --'
|
101
97
|
puts Base64.encode64(@contents)
|
102
|
-
puts
|
98
|
+
puts '-- Bootstrap End --'
|
103
99
|
end
|
104
|
-
|
105
100
|
end
|
106
101
|
end
|
107
102
|
|
data/lib/pupistry/config.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# rubocop:disable Style/Documentation, Style/GlobalVars
|
1
2
|
require 'rubygems'
|
2
3
|
require 'fileutils'
|
3
4
|
require 'tempfile'
|
4
5
|
require 'yaml'
|
6
|
+
require 'safe_yaml'
|
5
7
|
|
6
8
|
module Pupistry
|
7
9
|
# Pupistry::Config
|
@@ -10,50 +12,79 @@ module Pupistry
|
|
10
12
|
#
|
11
13
|
|
12
14
|
class Config
|
13
|
-
|
14
|
-
def self.load file
|
15
|
+
def self.load(file)
|
15
16
|
$logger.debug "Loading configuration file #{file}"
|
17
|
+
|
18
|
+
# Load YAML file with minimum safety/basic checks
|
19
|
+
unless File.exist?(file)
|
20
|
+
$logger.fatal 'The configuration file provided does not exist, or cannot be accessed'
|
21
|
+
exit 0
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
$config = YAML.load(File.open(file), safe: true, raise_on_unknown_tag: true)
|
26
|
+
rescue => ex
|
27
|
+
$logger.fatal 'The supplied file is not a valid YAML configuration file'
|
28
|
+
$logger.debug ex.message
|
29
|
+
exit 0
|
30
|
+
end
|
31
|
+
|
16
32
|
|
17
|
-
|
18
|
-
|
33
|
+
# Run checks for minimum configuration parameters
|
34
|
+
# TODO: Is there a smarter way of doing this? Maybe a better config parser?
|
35
|
+
begin
|
36
|
+
fail 'Missing general:app_cache' unless defined? $config['general']['app_cache']
|
37
|
+
fail 'Missing general:s3_bucket' unless defined? $config['general']['s3_bucket']
|
38
|
+
fail 'Missing general:gpg_disable' unless defined? $config['general']['gpg_disable']
|
39
|
+
fail 'Missing agent:puppetcode' unless defined? $config['agent']['puppetcode']
|
40
|
+
rescue => ex
|
41
|
+
$logger.fatal 'The supplied configuration files doesn\'t include the minimum expect configuration parameters'
|
42
|
+
$logger.debug ex.message
|
19
43
|
exit 0
|
20
44
|
end
|
21
45
|
|
22
|
-
|
46
|
+
|
23
47
|
|
24
48
|
# Make sure cache directory exists, create it otherwise
|
25
|
-
$config[
|
49
|
+
$config['general']['app_cache'] = File.expand_path($config['general']['app_cache']).chomp('/')
|
26
50
|
|
27
|
-
unless Dir.
|
51
|
+
unless Dir.exist?($config['general']['app_cache'])
|
28
52
|
begin
|
29
|
-
FileUtils.mkdir_p($config[
|
30
|
-
FileUtils.chmod(0700, $config[
|
31
|
-
rescue
|
32
|
-
$logger.fatal "Unable to create cache directory at \"#{$config[
|
53
|
+
FileUtils.mkdir_p($config['general']['app_cache'])
|
54
|
+
FileUtils.chmod(0700, $config['general']['app_cache']) # Generally only the user running Pupistry should have access
|
55
|
+
rescue StandardError => e
|
56
|
+
$logger.fatal "Unable to create cache directory at \"#{$config['general']['app_cache']}\"."
|
33
57
|
raise e
|
34
58
|
end
|
35
59
|
end
|
36
60
|
|
37
61
|
# Write test file to confirm writability
|
38
62
|
begin
|
39
|
-
FileUtils.touch($config[
|
40
|
-
FileUtils.rm($config[
|
41
|
-
rescue
|
42
|
-
$logger.fatal "Unexpected exception when creating testfile in cache directory at \"#{$config[
|
63
|
+
FileUtils.touch($config['general']['app_cache'] + '/testfile')
|
64
|
+
FileUtils.rm($config['general']['app_cache'] + '/testfile')
|
65
|
+
rescue StandardError => e
|
66
|
+
$logger.fatal "Unexpected exception when creating testfile in cache directory at \"#{$config['general']['app_cache']}\", is the directory writable?"
|
43
67
|
raise e
|
44
68
|
end
|
45
69
|
|
70
|
+
|
71
|
+
# Check if Puppet is available
|
72
|
+
unless system('puppet --version 2>&1 > /dev/null')
|
73
|
+
$logger.fatal "Unable to find an installation of Puppet - please make sure Puppet is installed from either OS package or Gem"
|
74
|
+
exit 0
|
75
|
+
end
|
76
|
+
|
46
77
|
end
|
47
78
|
|
48
79
|
def self.find_and_load
|
49
|
-
$logger.debug
|
80
|
+
$logger.debug 'Looking for configuration file in common locations'
|
50
81
|
|
51
82
|
# If the HOME environmental hasn't been set (which can happen when
|
52
83
|
# running via some cloud user-data/init systems) the app will die
|
53
84
|
# horribly, we should set a HOME path default.
|
54
85
|
unless ENV['HOME']
|
55
|
-
$logger.warn
|
56
|
-
ENV['HOME'] =
|
86
|
+
$logger.warn 'No HOME environmental set, defaulting to /tmp'
|
87
|
+
ENV['HOME'] = '/tmp'
|
57
88
|
end
|
58
89
|
|
59
90
|
# Locations in order of preference:
|
@@ -64,29 +95,26 @@ module Pupistry
|
|
64
95
|
config = ''
|
65
96
|
local_dir = Dir.pwd
|
66
97
|
|
67
|
-
if File.
|
98
|
+
if File.exist?("#{local_dir}/settings.yaml")
|
68
99
|
config = "#{local_dir}/settings.yaml"
|
69
100
|
|
70
|
-
elsif File.
|
71
|
-
config = File.expand_path
|
101
|
+
elsif File.exist?(File.expand_path '~/.pupistry/settings.yaml')
|
102
|
+
config = File.expand_path '~/.pupistry/settings.yaml'
|
72
103
|
|
73
|
-
elsif File.
|
74
|
-
config =
|
104
|
+
elsif File.exist?('/usr/local/etc/pupistry/settings.yaml')
|
105
|
+
config = '/usr/local/etc/pupistry/settings.yaml'
|
75
106
|
|
76
|
-
elsif File.
|
77
|
-
config =
|
107
|
+
elsif File.exist?('/etc/pupistry/settings.yaml')
|
108
|
+
config = '/etc/pupistry/settings.yaml'
|
78
109
|
|
79
110
|
else
|
80
|
-
$logger.error
|
81
|
-
$logger.error
|
111
|
+
$logger.error 'No configuration file provided.'
|
112
|
+
$logger.error 'See pupistry help for information on configuration'
|
82
113
|
exit 0
|
83
114
|
end
|
84
115
|
|
85
|
-
|
86
|
-
|
116
|
+
load(config)
|
87
117
|
end
|
88
|
-
|
89
|
-
|
90
118
|
end
|
91
119
|
end
|
92
120
|
# vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent
|
data/lib/pupistry/gpg.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# rubocop:disable Style/Documentation, Style/GlobalVars
|
1
2
|
require 'rubygems'
|
2
3
|
require 'yaml'
|
4
|
+
require 'safe_yaml'
|
3
5
|
require 'fileutils'
|
4
6
|
require 'base64'
|
5
7
|
|
@@ -11,25 +13,22 @@ module Pupistry
|
|
11
13
|
attr_accessor :checksum
|
12
14
|
attr_accessor :signature
|
13
15
|
|
14
|
-
def initialize
|
15
|
-
|
16
|
+
def initialize(checksum)
|
16
17
|
# Need a checksum to do signing for
|
17
18
|
if checksum
|
18
19
|
@checksum = checksum
|
19
20
|
else
|
20
|
-
$logger.fatal
|
21
|
+
$logger.fatal 'Probable bug, need a checksum provided with GPG validation'
|
21
22
|
exit 0
|
22
23
|
end
|
23
24
|
|
24
25
|
# Make sure that we have GPG available
|
25
|
-
unless system(
|
26
|
+
unless system('gpg --version >> /dev/null 2>&1') # rubocop:disable Style/GuardClause
|
26
27
|
$logger.fatal "'gpg' command is not available, unable to do any signature creation or verification."
|
27
28
|
exit 0
|
28
29
|
end
|
29
|
-
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
32
|
# Sign the artifact and return the signature. Does not validation of the signature.
|
34
33
|
#
|
35
34
|
# false Failure
|
@@ -41,19 +40,17 @@ module Pupistry
|
|
41
40
|
# Clean up the existing signature file
|
42
41
|
signature_cleanup
|
43
42
|
|
44
|
-
|
45
|
-
Dir.chdir("#{$config["general"]["app_cache"]}/artifacts/") do
|
46
|
-
|
43
|
+
Dir.chdir("#{$config['general']['app_cache']}/artifacts/") do
|
47
44
|
# Generate the signature file and pick up the signature data
|
48
45
|
unless system "gpg --use-agent --detach-sign artifact.#{@checksum}.tar.gz"
|
49
|
-
$logger.error
|
46
|
+
$logger.error 'Unable to sign the artifact, an unexpected failure occured. No file uploaded.'
|
50
47
|
return false
|
51
48
|
end
|
52
49
|
|
53
|
-
if File.
|
54
|
-
$logger.info
|
50
|
+
if File.exist?("artifact.#{@checksum}.tar.gz.sig")
|
51
|
+
$logger.info 'A signature file was successfully generated.'
|
55
52
|
else
|
56
|
-
$logger.error
|
53
|
+
$logger.error 'A signature file was NOT generated.'
|
57
54
|
return false
|
58
55
|
end
|
59
56
|
|
@@ -61,43 +58,37 @@ module Pupistry
|
|
61
58
|
# metadata into a single file and extracting it out when needed, than
|
62
59
|
# having to keep track of yet-another-file. Because we encode into
|
63
60
|
# ASCII here, no need to call GPG with --armor either.
|
64
|
-
|
61
|
+
|
65
62
|
@signature = Base64.encode64(File.read("artifact.#{@checksum}.tar.gz.sig"))
|
66
63
|
|
67
64
|
unless @signature
|
68
|
-
$logger.error
|
65
|
+
$logger.error 'An unexpected issue occured and no signature was generated'
|
69
66
|
return false
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
73
|
-
|
74
70
|
# Make sure the public key has been uploaded if it hasn't already
|
75
71
|
pubkey_upload
|
76
72
|
|
77
|
-
|
73
|
+
@signature
|
78
74
|
end
|
79
75
|
|
80
|
-
|
81
76
|
# Verify the signature for a particular artifact.
|
82
77
|
#
|
83
78
|
# true Signature is legit
|
84
79
|
# false Signature is invalid (security issue!)
|
85
80
|
#
|
86
81
|
def artifact_verify
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
if File.exists?("artifact.#{@checksum}.tar.gz.sig")
|
91
|
-
$logger.debug "Signature already extracted on disk, running verify...."
|
82
|
+
Dir.chdir("#{$config['general']['app_cache']}/artifacts/") do
|
83
|
+
if File.exist?("artifact.#{@checksum}.tar.gz.sig")
|
84
|
+
$logger.debug 'Signature already extracted on disk, running verify....'
|
92
85
|
else
|
93
|
-
$logger.debug
|
86
|
+
$logger.debug 'Extracting signature from manifest data...'
|
94
87
|
signature_extract
|
95
88
|
end
|
96
89
|
|
97
90
|
# Verify the signature
|
98
|
-
unless
|
99
|
-
pubkey_install
|
100
|
-
end
|
91
|
+
pubkey_install unless pubkey_exist?
|
101
92
|
|
102
93
|
output_verify = `gpg --quiet --status-fd 1 --verify artifact.#{@checksum}.tar.gz.sig 2>&1`
|
103
94
|
|
@@ -106,9 +97,8 @@ module Pupistry
|
|
106
97
|
|
107
98
|
# Was it valid?
|
108
99
|
output_verify.each_line do |line|
|
109
|
-
|
110
100
|
if /\[GNUPG:\]\sGOODSIG\s[A-Z0-9]*#{$config["general"]["gpg_signing_key"]}\s/.match(line)
|
111
|
-
$logger.info "Artifact #{@checksum} has a valid signature belonging to #{$config[
|
101
|
+
$logger.info "Artifact #{@checksum} has a valid signature belonging to #{$config['general']['gpg_signing_key']}"
|
112
102
|
return true
|
113
103
|
end
|
114
104
|
|
@@ -116,32 +106,27 @@ module Pupistry
|
|
116
106
|
$logger.fatal "Artifact #{@checksum} has AN INVALID GPG SECURITY SIGNATURE and could be CORRUPT or TAMPERED with."
|
117
107
|
exit 0
|
118
108
|
end
|
119
|
-
|
120
109
|
end
|
121
110
|
|
122
111
|
# Unexpected error
|
123
|
-
$logger.error
|
112
|
+
$logger.error 'An unexpected validation issue occured, see below debug information:'
|
124
113
|
|
125
114
|
output_verify.each_line do |line|
|
126
115
|
$logger.error "GPG: #{line}"
|
127
116
|
end
|
128
|
-
|
129
117
|
end
|
130
118
|
|
131
119
|
# Something went wrong
|
132
120
|
$logger.fatal "Artifact #{@checksum} COULD NOT BE GPG VALIDATED and could be CORRUPT or TAMPERED with."
|
133
121
|
exit 0
|
134
|
-
|
135
122
|
end
|
136
123
|
|
137
|
-
|
138
124
|
# Generally we should clean up old signature files before and after using them
|
139
125
|
#
|
140
126
|
def signature_cleanup
|
141
|
-
FileUtils.rm("#{$config[
|
127
|
+
FileUtils.rm("#{$config['general']['app_cache']}/artifacts/artifact.#{@checksum}.tar.gz.sig", force: true)
|
142
128
|
end
|
143
129
|
|
144
|
-
|
145
130
|
# Extract the signature from the manifest file and write it to file in native binary format.
|
146
131
|
#
|
147
132
|
# false Unable to extract
|
@@ -149,103 +134,90 @@ module Pupistry
|
|
149
134
|
# base64 Encoded signature
|
150
135
|
#
|
151
136
|
def signature_extract
|
152
|
-
|
153
|
-
manifest = YAML::load(File.open($config["general"]["app_cache"] + "/artifacts/manifest.#{@checksum}.yaml"))
|
154
|
-
|
155
|
-
if manifest['gpgsig']
|
156
|
-
# We have the base64 version
|
157
|
-
@signature = manifest['gpgsig']
|
137
|
+
manifest = YAML.load(File.open($config['general']['app_cache'] + "/artifacts/manifest.#{@checksum}.yaml"), safe: true, raise_on_unknown_tag: true)
|
158
138
|
|
159
|
-
|
160
|
-
|
139
|
+
if manifest['gpgsig']
|
140
|
+
# We have the base64 version
|
141
|
+
@signature = manifest['gpgsig']
|
161
142
|
|
162
|
-
|
163
|
-
|
164
|
-
return false
|
165
|
-
end
|
143
|
+
# Decode the base64 and write the signature file
|
144
|
+
File.write("#{$config['general']['app_cache']}/artifacts/artifact.#{@checksum}.tar.gz.sig", Base64.decode64(@signature))
|
166
145
|
|
167
|
-
|
168
|
-
|
169
|
-
|
146
|
+
return @signature
|
147
|
+
else
|
148
|
+
return false
|
170
149
|
end
|
171
150
|
|
151
|
+
rescue StandardError => e
|
152
|
+
$logger.error 'Something unexpected occured when reading the manifest file'
|
153
|
+
raise e
|
172
154
|
end
|
173
155
|
|
174
|
-
|
175
156
|
# Save the signature into the manifest file
|
176
157
|
#
|
177
158
|
def signature_save
|
178
|
-
|
179
|
-
|
180
|
-
manifest['gpgsig'] = @signature
|
181
|
-
|
182
|
-
File.open("#{$config["general"]["app_cache"]}/artifacts/manifest.#{@checksum}.yaml",'w') do |fh|
|
183
|
-
fh.write YAML::dump(manifest)
|
184
|
-
end
|
159
|
+
manifest = YAML.load(File.open($config['general']['app_cache'] + "/artifacts/manifest.#{@checksum}.yaml"), safe: true, raise_on_unknown_tag: true)
|
160
|
+
manifest['gpgsig'] = @signature
|
185
161
|
|
186
|
-
|
187
|
-
|
188
|
-
rescue Exception => e
|
189
|
-
$logger.error "Something unexpected occured when updating the manifest file with GPG signature"
|
190
|
-
return false
|
162
|
+
File.open("#{$config['general']['app_cache']}/artifacts/manifest.#{@checksum}.yaml", 'w') do |fh|
|
163
|
+
fh.write YAML.dump(manifest)
|
191
164
|
end
|
192
165
|
|
193
|
-
|
166
|
+
return true
|
194
167
|
|
168
|
+
rescue StandardError
|
169
|
+
$logger.error 'Something unexpected occured when updating the manifest file with GPG signature'
|
170
|
+
return false
|
171
|
+
end
|
195
172
|
|
196
173
|
# Check if the public key is installed on this machine?
|
197
174
|
#
|
198
|
-
def
|
199
|
-
|
175
|
+
def pubkey_exist?
|
200
176
|
# We prefix with 0x to avoid matching on strings in key names
|
201
|
-
if system "gpg --status-fd a --list-keys 0x#{$config[
|
202
|
-
$logger.debug
|
177
|
+
if system "gpg --status-fd a --list-keys 0x#{$config['general']['gpg_signing_key']} 2>&1 >> /dev/null"
|
178
|
+
$logger.debug 'Public key exists on this system'
|
203
179
|
return true
|
204
180
|
else
|
205
|
-
$logger.debug
|
181
|
+
$logger.debug 'Public key does not exist on this system'
|
206
182
|
return false
|
207
183
|
end
|
208
184
|
end
|
209
|
-
|
210
185
|
|
211
186
|
# Extract & upload the public key to the s3 bucket for other users
|
212
187
|
#
|
213
188
|
def pubkey_upload
|
214
|
-
unless File.
|
189
|
+
unless File.exist?("#{$config['general']['app_cache']}/artifacts/#{$config['general']['gpg_signing_key']}.publickey")
|
215
190
|
|
216
191
|
# GPG key does not exist locally, we therefore assume it's not in the S3
|
217
192
|
# bucket either, so we should export out and upload. Technically this may
|
218
193
|
# result in a few extra uploads (once for any new machine using Pupistry)
|
219
194
|
# but it doesn't cause any issue and saves me writing more code ;-)
|
220
|
-
|
221
|
-
$logger.info "Exporting GPG key #{$config[
|
195
|
+
|
196
|
+
$logger.info "Exporting GPG key #{$config['general']['gpg_signing_key']} and uploading to S3 bucket..."
|
222
197
|
|
223
198
|
# If it doesn't exist on this machine, then we're a bit stuck!
|
224
|
-
unless
|
225
|
-
$logger.error "The public key #{$config[
|
199
|
+
unless pubkey_exist?
|
200
|
+
$logger.error "The public key #{$config['general']['gpg_signing_key']} does not exist on this system, so unable to export it out"
|
226
201
|
return false
|
227
202
|
end
|
228
203
|
|
229
204
|
# Export out key
|
230
|
-
unless system "gpg --export --armour 0x#{$config[
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
205
|
+
unless system "gpg --export --armour 0x#{$config['general']['gpg_signing_key']} > #{$config['general']['app_cache']}/artifacts/#{$config['general']['gpg_signing_key']}.publickey"
|
206
|
+
$logger.error 'A fault occured when trying to export the GPG key'
|
207
|
+
return false
|
208
|
+
end
|
235
209
|
|
236
210
|
# Upload
|
237
|
-
s3 = Pupistry::
|
211
|
+
s3 = Pupistry::StorageAWS.new 'build'
|
238
212
|
|
239
|
-
unless s3.upload "#{$config[
|
240
|
-
$logger.error
|
213
|
+
unless s3.upload "#{$config['general']['app_cache']}/artifacts/#{$config['general']['gpg_signing_key']}.publickey", "#{$config['general']['gpg_signing_key']}.publickey"
|
214
|
+
$logger.error 'Unable to upload GPG key to S3 bucket'
|
241
215
|
return false
|
242
216
|
end
|
243
217
|
|
244
218
|
end
|
245
|
-
|
246
219
|
end
|
247
220
|
|
248
|
-
|
249
221
|
# Install the public key. This is a potential avenue for exploit, if a
|
250
222
|
# machine is being built for the first time, it has no existing trust of
|
251
223
|
# the GPG key, other than transit encryption to the S3 bucket. To protect
|
@@ -256,28 +228,25 @@ module Pupistry
|
|
256
228
|
# the GPG public key for them direct from the S3 repo.
|
257
229
|
#
|
258
230
|
def pubkey_install
|
259
|
-
|
260
|
-
$logger.warn "Installing GPG key #{$config["general"]["gpg_signing_key"]}..."
|
231
|
+
$logger.warn "Installing GPG key #{$config['general']['gpg_signing_key']}..."
|
261
232
|
|
262
|
-
|
233
|
+
s3 = Pupistry::StorageAWS.new 'agent'
|
263
234
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
unless system "gpg --import < #{$config["general"]["app_cache"]}/artifacts/#{$config["general"]["gpg_signing_key"]}.publickey > /dev/null 2>&1"
|
270
|
-
$logger.error "A fault occured when trying to import the GPG key"
|
271
|
-
return false
|
272
|
-
end
|
235
|
+
unless s3.download "#{$config['general']['gpg_signing_key']}.publickey", "#{$config['general']['app_cache']}/artifacts/#{$config['general']['gpg_signing_key']}.publickey"
|
236
|
+
$logger.error 'Unable to download GPG key from S3 bucket, this will prevent validation of signature'
|
237
|
+
return false
|
238
|
+
end
|
273
239
|
|
274
|
-
|
275
|
-
$logger.error
|
240
|
+
unless system "gpg --import < #{$config['general']['app_cache']}/artifacts/#{$config['general']['gpg_signing_key']}.publickey > /dev/null 2>&1"
|
241
|
+
$logger.error 'A fault occured when trying to import the GPG key'
|
276
242
|
return false
|
277
243
|
end
|
278
|
-
end
|
279
244
|
|
280
|
-
|
245
|
+
rescue StandardError
|
246
|
+
$logger.error 'Something unexpected occured when installing the GPG public key'
|
247
|
+
return false
|
248
|
+
end
|
249
|
+
end
|
281
250
|
end
|
282
251
|
|
283
252
|
# vim:shiftwidth=2:tabstop=2:softtabstop=2:expandtab:smartindent
|