safedb 0.01.0001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +21 -0
  6. data/README.md +793 -0
  7. data/Rakefile +16 -0
  8. data/bin/safe +5 -0
  9. data/lib/configs/README.md +58 -0
  10. data/lib/extension/array.rb +162 -0
  11. data/lib/extension/dir.rb +35 -0
  12. data/lib/extension/file.rb +123 -0
  13. data/lib/extension/hash.rb +33 -0
  14. data/lib/extension/string.rb +572 -0
  15. data/lib/factbase/facts.safedb.net.ini +38 -0
  16. data/lib/interprete.rb +462 -0
  17. data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
  18. data/lib/keytools/kdf.api.rb +243 -0
  19. data/lib/keytools/kdf.bcrypt.rb +265 -0
  20. data/lib/keytools/kdf.pbkdf2.rb +262 -0
  21. data/lib/keytools/kdf.scrypt.rb +190 -0
  22. data/lib/keytools/key.64.rb +326 -0
  23. data/lib/keytools/key.algo.rb +109 -0
  24. data/lib/keytools/key.api.rb +1391 -0
  25. data/lib/keytools/key.db.rb +330 -0
  26. data/lib/keytools/key.docs.rb +195 -0
  27. data/lib/keytools/key.error.rb +110 -0
  28. data/lib/keytools/key.id.rb +271 -0
  29. data/lib/keytools/key.ident.rb +243 -0
  30. data/lib/keytools/key.iv.rb +107 -0
  31. data/lib/keytools/key.local.rb +259 -0
  32. data/lib/keytools/key.now.rb +402 -0
  33. data/lib/keytools/key.pair.rb +259 -0
  34. data/lib/keytools/key.pass.rb +120 -0
  35. data/lib/keytools/key.rb +585 -0
  36. data/lib/logging/gem.logging.rb +132 -0
  37. data/lib/modules/README.md +43 -0
  38. data/lib/modules/cryptology/aes-256.rb +154 -0
  39. data/lib/modules/cryptology/amalgam.rb +70 -0
  40. data/lib/modules/cryptology/blowfish.rb +130 -0
  41. data/lib/modules/cryptology/cipher.rb +207 -0
  42. data/lib/modules/cryptology/collect.rb +138 -0
  43. data/lib/modules/cryptology/crypt.io.rb +225 -0
  44. data/lib/modules/cryptology/engineer.rb +99 -0
  45. data/lib/modules/mappers/dictionary.rb +288 -0
  46. data/lib/modules/storage/coldstore.rb +186 -0
  47. data/lib/modules/storage/git.store.rb +399 -0
  48. data/lib/session/fact.finder.rb +334 -0
  49. data/lib/session/require.gem.rb +112 -0
  50. data/lib/session/time.stamp.rb +340 -0
  51. data/lib/session/user.home.rb +49 -0
  52. data/lib/usecase/cmd.rb +487 -0
  53. data/lib/usecase/config/README.md +57 -0
  54. data/lib/usecase/docker/README.md +146 -0
  55. data/lib/usecase/docker/docker.rb +49 -0
  56. data/lib/usecase/edit/README.md +43 -0
  57. data/lib/usecase/edit/delete.rb +46 -0
  58. data/lib/usecase/export.rb +40 -0
  59. data/lib/usecase/files/README.md +37 -0
  60. data/lib/usecase/files/eject.rb +56 -0
  61. data/lib/usecase/files/file_me.rb +78 -0
  62. data/lib/usecase/files/read.rb +169 -0
  63. data/lib/usecase/files/write.rb +89 -0
  64. data/lib/usecase/goto.rb +57 -0
  65. data/lib/usecase/id.rb +36 -0
  66. data/lib/usecase/import.rb +157 -0
  67. data/lib/usecase/init.rb +63 -0
  68. data/lib/usecase/jenkins/README.md +146 -0
  69. data/lib/usecase/jenkins/jenkins.rb +208 -0
  70. data/lib/usecase/login.rb +71 -0
  71. data/lib/usecase/logout.rb +28 -0
  72. data/lib/usecase/open.rb +71 -0
  73. data/lib/usecase/print.rb +40 -0
  74. data/lib/usecase/put.rb +81 -0
  75. data/lib/usecase/set.rb +44 -0
  76. data/lib/usecase/show.rb +138 -0
  77. data/lib/usecase/terraform/README.md +91 -0
  78. data/lib/usecase/terraform/terraform.rb +121 -0
  79. data/lib/usecase/token.rb +35 -0
  80. data/lib/usecase/update/README.md +55 -0
  81. data/lib/usecase/update/rename.rb +180 -0
  82. data/lib/usecase/use.rb +41 -0
  83. data/lib/usecase/verse.rb +20 -0
  84. data/lib/usecase/view.rb +71 -0
  85. data/lib/usecase/vpn/README.md +150 -0
  86. data/lib/usecase/vpn/vpn.ini +31 -0
  87. data/lib/usecase/vpn/vpn.rb +54 -0
  88. data/lib/version.rb +3 -0
  89. data/safedb.gemspec +34 -0
  90. 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
+
@@ -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
@@ -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
@@ -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
@@ -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
+