safedb 0.01.0001
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.yardopts +3 -0
- data/Gemfile +10 -0
- data/LICENSE +21 -0
- data/README.md +793 -0
- data/Rakefile +16 -0
- data/bin/safe +5 -0
- data/lib/configs/README.md +58 -0
- data/lib/extension/array.rb +162 -0
- data/lib/extension/dir.rb +35 -0
- data/lib/extension/file.rb +123 -0
- data/lib/extension/hash.rb +33 -0
- data/lib/extension/string.rb +572 -0
- data/lib/factbase/facts.safedb.net.ini +38 -0
- data/lib/interprete.rb +462 -0
- data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
- data/lib/keytools/kdf.api.rb +243 -0
- data/lib/keytools/kdf.bcrypt.rb +265 -0
- data/lib/keytools/kdf.pbkdf2.rb +262 -0
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1391 -0
- data/lib/keytools/key.db.rb +330 -0
- data/lib/keytools/key.docs.rb +195 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.ident.rb +243 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +259 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +585 -0
- data/lib/logging/gem.logging.rb +132 -0
- data/lib/modules/README.md +43 -0
- data/lib/modules/cryptology/aes-256.rb +154 -0
- data/lib/modules/cryptology/amalgam.rb +70 -0
- data/lib/modules/cryptology/blowfish.rb +130 -0
- data/lib/modules/cryptology/cipher.rb +207 -0
- data/lib/modules/cryptology/collect.rb +138 -0
- data/lib/modules/cryptology/crypt.io.rb +225 -0
- data/lib/modules/cryptology/engineer.rb +99 -0
- data/lib/modules/mappers/dictionary.rb +288 -0
- data/lib/modules/storage/coldstore.rb +186 -0
- data/lib/modules/storage/git.store.rb +399 -0
- data/lib/session/fact.finder.rb +334 -0
- data/lib/session/require.gem.rb +112 -0
- data/lib/session/time.stamp.rb +340 -0
- data/lib/session/user.home.rb +49 -0
- data/lib/usecase/cmd.rb +487 -0
- data/lib/usecase/config/README.md +57 -0
- data/lib/usecase/docker/README.md +146 -0
- data/lib/usecase/docker/docker.rb +49 -0
- data/lib/usecase/edit/README.md +43 -0
- data/lib/usecase/edit/delete.rb +46 -0
- data/lib/usecase/export.rb +40 -0
- data/lib/usecase/files/README.md +37 -0
- data/lib/usecase/files/eject.rb +56 -0
- data/lib/usecase/files/file_me.rb +78 -0
- data/lib/usecase/files/read.rb +169 -0
- data/lib/usecase/files/write.rb +89 -0
- data/lib/usecase/goto.rb +57 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +157 -0
- data/lib/usecase/init.rb +63 -0
- data/lib/usecase/jenkins/README.md +146 -0
- data/lib/usecase/jenkins/jenkins.rb +208 -0
- data/lib/usecase/login.rb +71 -0
- data/lib/usecase/logout.rb +28 -0
- data/lib/usecase/open.rb +71 -0
- data/lib/usecase/print.rb +40 -0
- data/lib/usecase/put.rb +81 -0
- data/lib/usecase/set.rb +44 -0
- data/lib/usecase/show.rb +138 -0
- data/lib/usecase/terraform/README.md +91 -0
- data/lib/usecase/terraform/terraform.rb +121 -0
- data/lib/usecase/token.rb +35 -0
- data/lib/usecase/update/README.md +55 -0
- data/lib/usecase/update/rename.rb +180 -0
- data/lib/usecase/use.rb +41 -0
- data/lib/usecase/verse.rb +20 -0
- data/lib/usecase/view.rb +71 -0
- data/lib/usecase/vpn/README.md +150 -0
- data/lib/usecase/vpn/vpn.ini +31 -0
- data/lib/usecase/vpn/vpn.rb +54 -0
- data/lib/version.rb +3 -0
- data/safedb.gemspec +34 -0
- metadata +193 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
class Logout < UseCase
|
6
|
+
|
7
|
+
def execute
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# Perform pre-conditional validations in preparation to executing the main flow
|
13
|
+
# of events for this use case. This method may throw the below exceptions.
|
14
|
+
#
|
15
|
+
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
16
|
+
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
17
|
+
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
18
|
+
def pre_validation
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
data/lib/usecase/open.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <tt>open use case</tt> allows us to add (put), subtract (del)ete, change
|
6
|
+
# (update) and list the secrets within an envelope (outer path) at a given
|
7
|
+
# position (inner path), whether that envelope exists or not.
|
8
|
+
#
|
9
|
+
# Also see the <b>reopen</b> command which only differs from open in that it
|
10
|
+
# fails if the path specified does not exist in either the sealed or session
|
11
|
+
# envelopes.
|
12
|
+
#
|
13
|
+
# == The Open Path Parameter
|
14
|
+
#
|
15
|
+
# Open must be called with a single <b>path</b> parameter with an optional
|
16
|
+
# single colon separating the outer (path to envelope) from the inner (path
|
17
|
+
# within envelope).
|
18
|
+
#
|
19
|
+
# == Open (Path) Pre-Conditions
|
20
|
+
#
|
21
|
+
# The domain must have been initialized on this machine stating the path to
|
22
|
+
# the base folder that contains the key and crypt material.
|
23
|
+
#
|
24
|
+
# To open a path these conditions must be true.
|
25
|
+
#
|
26
|
+
# - the shell session token must have been set at the session beginning
|
27
|
+
# - a successful <tt>login</tt> command must have been issued
|
28
|
+
# - the external drive (eg usb key) must be configured and accessible
|
29
|
+
#
|
30
|
+
# == Observable Value
|
31
|
+
#
|
32
|
+
# The observable value delivered by +[open]+ boils down to
|
33
|
+
#
|
34
|
+
# - an openkey (eg asdfx1234) and corresponding open encryption key
|
35
|
+
# - open encryption key written to <tt>~/.safedb.net/open.keys/asdfx1234.x.txt</tt>
|
36
|
+
# - the opened path (ending in filename) written to session.cache base in [safe]
|
37
|
+
# - the INI string (were the file to be decrypted) would look like the below
|
38
|
+
#
|
39
|
+
# [session]
|
40
|
+
# base.path = home/wifi
|
41
|
+
#
|
42
|
+
class Open < UseCase
|
43
|
+
|
44
|
+
# The two paths that have been posted to the open command.
|
45
|
+
# First is a relative path to the obfuscated envelope and then
|
46
|
+
# the path in envelope to the point of interest.
|
47
|
+
attr_writer :env_path, :key_path
|
48
|
+
|
49
|
+
def execute
|
50
|
+
|
51
|
+
return unless ops_key_exists?
|
52
|
+
master_db = KeyApi.read_master_db()
|
53
|
+
|
54
|
+
master_db[ ENV_PATH ] = @env_path
|
55
|
+
master_db[ KEY_PATH ] = @key_path
|
56
|
+
|
57
|
+
KeyApi.write_master_db( create_header(), master_db )
|
58
|
+
|
59
|
+
# Show the mini dictionary at the opened chapter and verse location
|
60
|
+
# More work is needed when for when only the chapter is opened in
|
61
|
+
# which case we should show the list of verses and perhaps the count
|
62
|
+
# of key value pairs each verse contains.
|
63
|
+
Show.new.flow_of_events
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
class Print < UseCase
|
6
|
+
|
7
|
+
attr_writer :key_name
|
8
|
+
|
9
|
+
def get_chapter_data( chapter_key )
|
10
|
+
return KeyDb.from_json( KeyApi.content_unlock( chapter_key ) )
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
|
15
|
+
return unless ops_key_exists?
|
16
|
+
|
17
|
+
master_db = get_master_database()
|
18
|
+
|
19
|
+
return if unopened_envelope?( master_db )
|
20
|
+
|
21
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
22
|
+
has_chapter = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
23
|
+
|
24
|
+
chapter_data = get_chapter_data( master_db[ chapter_id ] ) if has_chapter
|
25
|
+
has_verse = has_chapter && chapter_data.has_key?( master_db[ KEY_PATH ] )
|
26
|
+
|
27
|
+
chapter_err_msg = "Nothing was found at chapter " + master_db[ ENV_PATH ]
|
28
|
+
raise ArgumentError, chapter_err_msg unless has_chapter
|
29
|
+
verse_err_msg = "Nothing was found at chapter " + master_db[ ENV_PATH ] + " verse " + master_db[ KEY_PATH ]
|
30
|
+
raise ArgumentError, verse_err_msg unless has_verse
|
31
|
+
|
32
|
+
print chapter_data[ master_db[ KEY_PATH ] ][ @key_name ]
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
end
|
data/lib/usecase/put.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>put use case</b> follows <b>open</b> and it adds secrets into an
|
6
|
+
# <em>(encrypted at rest)</em> <b>envelope</b>. Put can be called many times
|
7
|
+
# and when done, the <b>lock use case</b> can be called to commit all opened
|
8
|
+
# secrets into the configured storage engines.
|
9
|
+
#
|
10
|
+
# Calling <em>put</em> <b>before</b> calling open or <b>after</b> calling lock
|
11
|
+
# is not allowed and will result in an error.
|
12
|
+
#
|
13
|
+
# == Put Pre-Conditions
|
14
|
+
#
|
15
|
+
# When the put use case is called - the below conditions ring true.
|
16
|
+
#
|
17
|
+
# - the <b>folder path</b> ending in ../../my must exist
|
18
|
+
# - a session id, filename and encryption key ( in workstation config )
|
19
|
+
#
|
20
|
+
# == Observable Value
|
21
|
+
#
|
22
|
+
# The observable value delivered by +put+ boils down to
|
23
|
+
#
|
24
|
+
# - a new <b>friends.xyz123abc.os.txt</b> file if this is the first put.
|
25
|
+
# - a new group_name/key_name (like monica/surname) entry is added if required
|
26
|
+
# - a secret value is added against the key or updated if it already exists
|
27
|
+
# - a new session id and encryption key is generated and used to re-encrypt
|
28
|
+
class Put < UseCase
|
29
|
+
|
30
|
+
attr_writer :secret_id, :secret_value
|
31
|
+
|
32
|
+
# Execute the act of putting a string key and string value pair into a
|
33
|
+
# map at the chapter and verse location, overwriting if need be.
|
34
|
+
def execute
|
35
|
+
|
36
|
+
return unless ops_key_exists?
|
37
|
+
master_db = KeyApi.read_master_db()
|
38
|
+
|
39
|
+
return if unopened_envelope?( master_db )
|
40
|
+
|
41
|
+
envelope_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
42
|
+
has_content = KeyApi.db_envelope_exists?( master_db[ envelope_id ] )
|
43
|
+
|
44
|
+
# To get hold of the content we must either
|
45
|
+
#
|
46
|
+
# a) unlock it using the breadcrumbs or
|
47
|
+
# b) start afresh with a new content db
|
48
|
+
content_box = KeyDb.from_json( KeyApi.content_unlock( master_db[ envelope_id ] ) ) if has_content
|
49
|
+
content_box = KeyDb.new() unless has_content
|
50
|
+
content_hdr = create_header()
|
51
|
+
|
52
|
+
# If no content envelope exists we need to place
|
53
|
+
# an empty one inside the appdb content database.
|
54
|
+
master_db[ envelope_id ] = {} unless has_content
|
55
|
+
|
56
|
+
# This is the PUT use case so we append a
|
57
|
+
#
|
58
|
+
# a) key for the new dictionary entry
|
59
|
+
# b) value for the new dictionary entry
|
60
|
+
#
|
61
|
+
# into the current content envelope and write
|
62
|
+
# the envelope to the content filepath.
|
63
|
+
crumbs_dict = master_db[ envelope_id ]
|
64
|
+
content_box.create_entry( master_db[ KEY_PATH ], @secret_id, @secret_value )
|
65
|
+
KeyApi.content_lock( crumbs_dict, content_box.to_json, content_hdr )
|
66
|
+
|
67
|
+
# Three envelope crumbs namely the external ID, the
|
68
|
+
# random iv and the crypt key are written afresh into
|
69
|
+
# the master database.
|
70
|
+
KeyApi.write_master_db( content_hdr, master_db )
|
71
|
+
|
72
|
+
# Show the mini dictionary at the opened chapter and verse location
|
73
|
+
Show.new.flow_of_events
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
data/lib/usecase/set.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <b>set <em>use case</em></b> is the generic tool for setting configuration
|
6
|
+
# directives inside the safe workstation INI formatted file.
|
7
|
+
#
|
8
|
+
# The mirror of this use case is <b><em>unset</em></b>.
|
9
|
+
#
|
10
|
+
# == Observable Value
|
11
|
+
#
|
12
|
+
# The configuration directive will eithe be created (or will overwrite) an existing
|
13
|
+
# directive with the same path.
|
14
|
+
#
|
15
|
+
# The configuration file is printed to inform the user of the current state.
|
16
|
+
#
|
17
|
+
# == Alternative / Error Flows
|
18
|
+
#
|
19
|
+
# Error - if the directive path is not composed of two (fwd slash separated) parts
|
20
|
+
# Error - if the directive path and/or value contains (or not) unacceptable characters
|
21
|
+
#
|
22
|
+
class Set < UseCase
|
23
|
+
|
24
|
+
attr_writer :domain_name
|
25
|
+
|
26
|
+
|
27
|
+
# The <b>use <em>use case</em></b> is borrowed from the database world and it denotes
|
28
|
+
# the domain to be used <b>for now (and evermore)</b> for this workstation until another
|
29
|
+
# use command is issued.
|
30
|
+
#
|
31
|
+
# The parameter domain_name must be set after an object instance is acquired but
|
32
|
+
# before the execute method runs.
|
33
|
+
def execute
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def pre_validation
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
data/lib/usecase/show.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# Show the mini dictionary of key-value pairs within the logged in book
|
6
|
+
# at the opened chapter and verse.
|
7
|
+
#
|
8
|
+
# If no dictionary exists at the opened chapter and verse a suitable
|
9
|
+
# message is pushed out to the console.
|
10
|
+
class Show < UseCase
|
11
|
+
|
12
|
+
def get_chapter_data( chapter_key )
|
13
|
+
return KeyDb.from_json( KeyApi.content_unlock( chapter_key ) )
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
|
18
|
+
return unless ops_key_exists?
|
19
|
+
master_db = KeyApi.read_master_db()
|
20
|
+
|
21
|
+
return if unopened_envelope?( master_db )
|
22
|
+
|
23
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
24
|
+
has_chapter = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
25
|
+
chapter_data = get_chapter_data( master_db[ chapter_id ] ) if has_chapter
|
26
|
+
has_verse = has_chapter && chapter_data.has_key?( master_db[ KEY_PATH ] )
|
27
|
+
|
28
|
+
|
29
|
+
##global_variables - DONE
|
30
|
+
##local_variables - DONE
|
31
|
+
##instance_variables - DONE
|
32
|
+
##class_variables - tough nut to crack with very little benefit (method class_variables not defined)
|
33
|
+
|
34
|
+
=begin
|
35
|
+
puts ""
|
36
|
+
puts "QQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
37
|
+
puts "QQQ ~~~~~~~~~~~~~ Global Variable Array List ~~~~~~~~~~~~~~~~ QQQQQ"
|
38
|
+
puts "QQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
39
|
+
|
40
|
+
puts global_variables.inspect
|
41
|
+
|
42
|
+
puts "QQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
43
|
+
puts "QQQ ~~~~~~~~~~~~~ Global Variable Values Printed ~~~~~~~~~~~~~~~~ QQQQQ"
|
44
|
+
puts "QQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
45
|
+
|
46
|
+
global_variables.sort.each do |name|
|
47
|
+
|
48
|
+
puts "<<< ------------------------------------------------------------------->>>"
|
49
|
+
puts "<<< #{name.to_s} >>>"
|
50
|
+
puts "<<< ------------------------------------------------------------------->>>"
|
51
|
+
next if name.to_s.eql?( "$FILENAME" )
|
52
|
+
global_variable_value = eval "#{name}.inspect"
|
53
|
+
puts "<<< #{global_variable_value}"
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
puts ""
|
58
|
+
puts "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
59
|
+
puts "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
60
|
+
puts ""
|
61
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
62
|
+
puts "QQQQQQQQQQQ Bug Finder QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
63
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
64
|
+
puts ""
|
65
|
+
self.instance_variables.map do |attribute|
|
66
|
+
puts "=============================================="
|
67
|
+
puts "----------------------------------------------"
|
68
|
+
puts attribute
|
69
|
+
pp self.instance_variable_get(attribute)
|
70
|
+
end
|
71
|
+
puts "=============================================="
|
72
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
73
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
74
|
+
puts ""
|
75
|
+
puts "### ------------------------------------"
|
76
|
+
puts "### Inspect View"
|
77
|
+
puts "### ------------------------------------"
|
78
|
+
pp self.inspect
|
79
|
+
puts "### ------------------------------------"
|
80
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
81
|
+
puts "QQQQQQQQQQQ Local Variables QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
82
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
83
|
+
|
84
|
+
local_variables.map do |attribute|
|
85
|
+
puts "=============================================="
|
86
|
+
puts "----------------------------------------------"
|
87
|
+
puts attribute
|
88
|
+
pp binding.local_variable_get(attribute.to_sym)
|
89
|
+
end
|
90
|
+
puts "QQQQQQQQQQQ QQQQQQQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"
|
91
|
+
|
92
|
+
puts ""
|
93
|
+
=end
|
94
|
+
|
95
|
+
|
96
|
+
return unless has_verse
|
97
|
+
|
98
|
+
line_dictionary = chapter_data[ master_db[ KEY_PATH ] ]
|
99
|
+
|
100
|
+
puts ""
|
101
|
+
puts "### ##################################\n"
|
102
|
+
puts "### chapter =>> #{master_db[ ENV_PATH ]}\n"
|
103
|
+
puts "### & verse =>> #{master_db[ KEY_PATH ]}\n"
|
104
|
+
puts "### # lines =>> #{line_dictionary.length}\n"
|
105
|
+
puts "### ##################################\n"
|
106
|
+
puts "--- ----------------------------------\n"
|
107
|
+
puts ""
|
108
|
+
|
109
|
+
showable_content = {}
|
110
|
+
line_dictionary.each do | key_str, value_object |
|
111
|
+
|
112
|
+
is_file = key_str.start_with? FILE_KEY_PREFIX
|
113
|
+
value_object.store( FILE_CONTENT_KEY, SECRET_MASK_STRING ) if is_file
|
114
|
+
showable_content.store( key_str[ FILE_KEY_PREFIX.length .. -1 ], value_object ) if is_file
|
115
|
+
next if is_file
|
116
|
+
|
117
|
+
is_secret = key_str.start_with? "@"
|
118
|
+
showable_val = SECRET_MASK_STRING if is_secret
|
119
|
+
showable_val = value_object unless is_secret
|
120
|
+
showable_content.store( key_str, showable_val )
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
puts JSON.pretty_generate( showable_content )
|
125
|
+
puts "--- ----------------------------------\n"
|
126
|
+
puts "### ##################################\n"
|
127
|
+
puts ""
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
SECRET_MASK_STRING = "***********************"
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
# safe terraform <command>
|
3
|
+
|
4
|
+
### safe terraform | introduction
|
5
|
+
|
6
|
+
This terraform use case exports the AWS IAM user access key, secret key and region key into (very safe) environment variables and then runs the specified terraform be it **init**, **plan**, **apply** or **destroy**.
|
7
|
+
|
8
|
+
|
9
|
+
## safe terraform | credential creation
|
10
|
+
|
11
|
+
The first use case is importing the IAM user credentials into safe.
|
12
|
+
|
13
|
+
$ safe login joebloggs.com # open the book
|
14
|
+
$ safe open iam dev.s3.writer # open chapter and verse
|
15
|
+
$ safe put @access.key ABCD1234EFGH5678 # Put IAM access key in safe
|
16
|
+
$ safe put @secret.key xyzabcd1234efgh5678 # Put IAM secret key in safe
|
17
|
+
$ safe put region.key eu-west-3 # infrastructure in Paris
|
18
|
+
|
19
|
+
$ safe open iam prod.provisioner # open chapter and verse
|
20
|
+
$ safe put @access.key 4321DCBA8765WXYZ # Put IAM access key in safe
|
21
|
+
$ safe put @secret.key 5678uvwx4321abcd9876 # Put IAM secret key in safe
|
22
|
+
$ safe put region.key eu-west-1 # infrastructure in Dublin
|
23
|
+
|
24
|
+
safe logout
|
25
|
+
|
26
|
+
Take care to specify these 3 key names **@access.key**, **@secret.key**, **region.key** and note that safe's convention is to sensitively treat the value's of keys beginning with an **@** sign. **safe show** and other readers **mask out (redact)** these sensitive values.
|
27
|
+
|
28
|
+
|
29
|
+
## safe terraform | running terraform
|
30
|
+
|
31
|
+
Now and forever you can return to the chapter and verse and enjoy a secure credentials transfer where safe makes the IAM user credentials available to Terraform via environment variables. **Never do the plain text credentials touch the floor (disk).**
|
32
|
+
|
33
|
+
### Why no safe terraform init?
|
34
|
+
**safe only gets involved when credentials are involved**.
|
35
|
+
**safe** is not trying to wrap command willy nilly. safe's policy is to keep external tool interfaces as **small** as possible. **`terraform init .`** does not involve credentials so safe does not get involved.
|
36
|
+
|
37
|
+
$ cd /path/to/terraform/dir # go to directory holding your .tf file
|
38
|
+
$ safe login joebloggs.com # login to your chosen book
|
39
|
+
$ safe open iam dev.s3.writer # open chapter and verse holding IAM creds
|
40
|
+
$ terraform init . # the usual terraform init command
|
41
|
+
$ safe terraform plan # credentials are exported then terraform plan is run
|
42
|
+
$ safe terraform apply # credentials are exported then terraform apply is run
|
43
|
+
$ safe terraform destroy # credentials are exported then terraform destroy is run
|
44
|
+
|
45
|
+
You can even change directories and run other terraform projects against the opened IAM user. You can also open an IAM user, run commands, open another run commands and then reopen the first and run commands.
|
46
|
+
|
47
|
+
As long as you stay within your shell window - your safe login will persist. Once your session is finished you either logout or exit the shell.
|
48
|
+
|
49
|
+
### Shortcut Alert
|
50
|
+
|
51
|
+
**safe terraform** is a shortcut for **safe terraform apply**
|
52
|
+
|
53
|
+
$ safe terraform apply
|
54
|
+
$ safe terraform
|
55
|
+
|
56
|
+
## safe terraform | pre-conditions
|
57
|
+
|
58
|
+
To enact a successful safe terraform call you will need
|
59
|
+
|
60
|
+
- to have created an IAM user
|
61
|
+
- to open chapter and verse which
|
62
|
+
- has these 3 keys @access.key @secret.key and region.key (at least)
|
63
|
+
- terraform installed on the machine or container
|
64
|
+
|
65
|
+
|
66
|
+
## safe terraform | benefits
|
67
|
+
|
68
|
+
The safe terraform command is both an ultra secure and extremely convenient way of launching terraform.
|
69
|
+
|
70
|
+
Your precious AWS IAM user credentials do not leave the safe and exist within (environment variable) memory only for the duration of the terraform command.
|
71
|
+
|
72
|
+
It is safe as you need neither expose your AWS credentials in plain text in **~/.aws/credentials**, nor risk them sliding into version control. It is convenient because switching IAM users and AWS regions is as easy as typing the now ubiquitous safe open command.
|
73
|
+
|
74
|
+
|
75
|
+
## quick tip | view then goto
|
76
|
+
|
77
|
+
No need to type out the safe open command everytime. Use it the very first time you create a path to chapter and verse.
|
78
|
+
|
79
|
+
safe open <<chapter>> <<verse>>
|
80
|
+
|
81
|
+
Then use safe view and safe goto instead of safe open.
|
82
|
+
|
83
|
+
$ safe view # list all chapter and verses
|
84
|
+
$ safe goto <<index>> # use the number from safe view to open the location
|
85
|
+
$ safe show # look at your mini dictionary
|
86
|
+
|
87
|
+
|
88
|
+
## safe terraform | only for aws
|
89
|
+
|
90
|
+
This command currently only supports the AWS provider but will be extended to support Google's Compute Engine and more besides.
|
91
|
+
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# This terraform use case exports the AWS IAM user access key, secret key and region key
|
6
|
+
# into (very safe) environment variables and then runs terraform init, plan, apply or destroy.
|
7
|
+
#
|
8
|
+
# This is both ultra secure and extremely convenient because the credentials do not leave
|
9
|
+
# the safe and exist within (environment variable) memory only for the duration of the
|
10
|
+
# terraform command.
|
11
|
+
#
|
12
|
+
# It is safe because you do not need to expose your AWS credentials in plain text.
|
13
|
+
# It is convenient because switching IAM users and AWS regions is as easy as typing the now
|
14
|
+
# ubiquitous safe open command.
|
15
|
+
#
|
16
|
+
# safe open <<chapter>> <<verse>>
|
17
|
+
class Terraform < UseCase
|
18
|
+
|
19
|
+
attr_writer :command
|
20
|
+
|
21
|
+
# This prefix is tagged onto environment variables which Terraform will read
|
22
|
+
# and convert for consumption into module input variables.
|
23
|
+
TERRAFORM_EVAR_PREFIX = "TF_VAR_"
|
24
|
+
|
25
|
+
def execute
|
26
|
+
|
27
|
+
return unless ops_key_exists?
|
28
|
+
master_db = get_master_database()
|
29
|
+
return if unopened_envelope?( master_db )
|
30
|
+
|
31
|
+
# Get the open chapter identifier (id).
|
32
|
+
# Decide whether chapter already exists.
|
33
|
+
# Then get (or instantiate) the chapter's hash data structure
|
34
|
+
chapter_id = ENVELOPE_KEY_PREFIX + master_db[ ENV_PATH ]
|
35
|
+
verse_id = master_db[ KEY_PATH ]
|
36
|
+
chapter_exists = KeyApi.db_envelope_exists?( master_db[ chapter_id ] )
|
37
|
+
|
38
|
+
|
39
|
+
# -- @todo begin
|
40
|
+
# -- Throw an exception (error) if the chapter
|
41
|
+
# -- either exists and is empty or does not exist.
|
42
|
+
# -- @todo end
|
43
|
+
|
44
|
+
|
45
|
+
# Unlock the chapter data structure by supplying
|
46
|
+
# key/value mini-dictionary breadcrumbs sitting
|
47
|
+
# within the master database at the section labelled
|
48
|
+
# envelope@<<actual_chapter_id>>.
|
49
|
+
chapter_data = KeyDb.from_json( KeyApi.content_unlock( master_db[ chapter_id ] ) )
|
50
|
+
|
51
|
+
# Now read the three AWS IAM credentials @access.key, @secret.key and region.key
|
52
|
+
# into the 3 environment variables terraform expects to find.
|
53
|
+
|
54
|
+
# ############## | ############################################################
|
55
|
+
# @todo refactor | ############################################################
|
56
|
+
# -------------- | 000000000000000000000000000000000000000000000000000000000000
|
57
|
+
# export-then-execute
|
58
|
+
# -------------------
|
59
|
+
# Put all the code above in a generic export-then-execute use case
|
60
|
+
# Then you pass in a Key/Value Dictionary
|
61
|
+
#
|
62
|
+
# { "AWS_ACCESS_KEY_ID" => "@access_key",
|
63
|
+
# "AWS_SECRET_ACCESS_KEY" => "@secret_key",
|
64
|
+
# "AWS_DEFAULT_REGION" => "region_key"
|
65
|
+
# }
|
66
|
+
#
|
67
|
+
# And pass in a command array [ "terraform #{command_name} #{auto_approve}", "terraform graph ..." ]
|
68
|
+
#
|
69
|
+
# Validation is done by the generic use case (which loops checking that every value exists
|
70
|
+
# as a key at the opened location.
|
71
|
+
#
|
72
|
+
# If all good the generic use case exports the ENV vars and runs each command in the list.
|
73
|
+
# PS - configure map in INI not code file
|
74
|
+
#
|
75
|
+
# The extra power will speed up generation of environment variable use cases including
|
76
|
+
# ansible, s3 bucket operations, git interactions and more.
|
77
|
+
#
|
78
|
+
# ############## | ############################################################
|
79
|
+
# ############## | ############################################################
|
80
|
+
|
81
|
+
puts ""
|
82
|
+
puts "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
83
|
+
puts ""
|
84
|
+
|
85
|
+
ENV[ "AWS_ACCESS_KEY_ID" ] = chapter_data[ verse_id ][ "@access.key" ]
|
86
|
+
ENV[ "AWS_SECRET_ACCESS_KEY" ] = chapter_data[ verse_id ][ "@secret.key" ]
|
87
|
+
ENV[ "AWS_DEFAULT_REGION" ] = chapter_data[ verse_id ][ "region.key" ]
|
88
|
+
|
89
|
+
mini_dictionary = chapter_data[ verse_id ]
|
90
|
+
mini_dictionary.each do | key_str, value_object |
|
91
|
+
|
92
|
+
is_env_var = key_str.start_with?( ENV_VAR_PREFIX_A ) || key_str.start_with?( ENV_VAR_PREFIX_B )
|
93
|
+
next unless is_env_var
|
94
|
+
|
95
|
+
env_var_name = key_str[ ENV_VAR_PREFIX_A.length .. -1 ] if key_str.start_with? ENV_VAR_PREFIX_A
|
96
|
+
env_var_name = key_str[ ENV_VAR_PREFIX_B.length .. -1 ] if key_str.start_with? ENV_VAR_PREFIX_B
|
97
|
+
env_var_keyname = TERRAFORM_EVAR_PREFIX + env_var_name
|
98
|
+
ENV[ env_var_keyname ] = value_object
|
99
|
+
puts "Environment variable #{env_var_keyname} has been set."
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
puts ""
|
104
|
+
puts "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
105
|
+
puts ""
|
106
|
+
|
107
|
+
auto_approve = @command && @command.eql?( "plan" ) ? "" : "-auto-approve"
|
108
|
+
command_name = @command ? @command : "apply"
|
109
|
+
system "terraform #{command_name} #{auto_approve}"
|
110
|
+
|
111
|
+
puts ""
|
112
|
+
puts "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
113
|
+
puts ""
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module SafeDb
|
4
|
+
|
5
|
+
# The <tt>token use case</tt> prints out an encrypted session token tied
|
6
|
+
# to the workstation and shell environment. See the root README.md on how
|
7
|
+
# to export it and create a simple command alias for it in the ~/.bash_aliases
|
8
|
+
# script which is executed when the shell starts.
|
9
|
+
class Token < UseCase
|
10
|
+
|
11
|
+
|
12
|
+
def execute
|
13
|
+
|
14
|
+
print KeyLocal.generate_shell_key_and_token()
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# Perform pre-conditional validations in preparation to executing the main flow
|
20
|
+
# of events for this use case. This method may throw the below exceptions.
|
21
|
+
#
|
22
|
+
# @raise [SafeDirNotConfigured] if the safe's url has not been configured
|
23
|
+
# @raise [EmailAddrNotConfigured] if the email address has not been configured
|
24
|
+
# @raise [StoreUrlNotConfigured] if the crypt store url is not configured
|
25
|
+
def pre_validation
|
26
|
+
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|