localvault 1.13.0 → 1.14.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/lib/localvault/cli/rails_import.rb +58 -0
- data/lib/localvault/cli.rb +63 -1
- data/lib/localvault/env_projection.rb +15 -0
- data/lib/localvault/input_validation.rb +1 -1
- data/lib/localvault/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f77c11508eef73c90760e5a927201f6735a16d836e6890161e89a497e28d917
|
|
4
|
+
data.tar.gz: 15400be786d2ba53112d1b6b48a1de5bd0518903e5578c859677ec68320f2b8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8fcd7235f9e330cdf7cf2c17528849f7b64b4388e865351ab53c1758b3390d32dd638c2c21e7ba24ff18e7d9c63e7c5e0bd2c66efa87792380d9d8ef12b61b7
|
|
7
|
+
data.tar.gz: c8491e0b0fcb2e588080496254b4fa04195859ad81d7ce66c38d4e13116d20374fa9f96668cc18cf8dc2a0830affb58ea59df84ed6eb1531c817942f364c54e3
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module LocalVault
|
|
2
|
+
class CLI
|
|
3
|
+
# Finds a Rails app's credentials keys so they can be stored in the vault
|
|
4
|
+
# and injected as RAILS_MASTER_KEY instead of living in a file.
|
|
5
|
+
#
|
|
6
|
+
# Reads only. Removing the key files is the operator's call — this reports
|
|
7
|
+
# what is still on disk and leaves it alone.
|
|
8
|
+
class RailsImport
|
|
9
|
+
Key = Struct.new(:environment, :path, :vault_key, :value, keyword_init: true)
|
|
10
|
+
|
|
11
|
+
MASTER_KEY_PATH = "config/master.key".freeze
|
|
12
|
+
CREDENTIALS_PATH = "config/credentials.yml.enc".freeze
|
|
13
|
+
|
|
14
|
+
def initialize(root = Dir.pwd)
|
|
15
|
+
@root = root
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def rails_app?
|
|
19
|
+
File.exist?(File.join(@root, CREDENTIALS_PATH)) ||
|
|
20
|
+
File.exist?(File.join(@root, MASTER_KEY_PATH)) ||
|
|
21
|
+
Dir.exist?(File.join(@root, "config/credentials"))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Every key file this app has: the default master key plus one per
|
|
25
|
+
# environment (config/credentials/production.key).
|
|
26
|
+
def keys
|
|
27
|
+
[master_key, *environment_keys].compact
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def master_key
|
|
33
|
+
path = File.join(@root, MASTER_KEY_PATH)
|
|
34
|
+
return nil unless File.exist?(path)
|
|
35
|
+
|
|
36
|
+
value = File.read(path).strip
|
|
37
|
+
return nil if value.empty?
|
|
38
|
+
|
|
39
|
+
Key.new(environment: nil, path: MASTER_KEY_PATH, vault_key: "rails.master_key", value: value)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def environment_keys
|
|
43
|
+
Dir.glob(File.join(@root, "config/credentials/*.key")).sort.filter_map do |path|
|
|
44
|
+
environment = File.basename(path, ".key")
|
|
45
|
+
value = File.read(path).strip
|
|
46
|
+
next if value.empty?
|
|
47
|
+
|
|
48
|
+
Key.new(
|
|
49
|
+
environment: environment,
|
|
50
|
+
path: "config/credentials/#{environment}.key",
|
|
51
|
+
vault_key: "rails.#{environment}_key",
|
|
52
|
+
value: value
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/localvault/cli.rb
CHANGED
|
@@ -116,7 +116,7 @@ module LocalVault
|
|
|
116
116
|
# disappearing from help.
|
|
117
117
|
HELP_SECTIONS = [
|
|
118
118
|
["GETTING STARTED", %w[login config init demo]],
|
|
119
|
-
["SECRETS", %w[set get show reveal groups list delete import env exec]],
|
|
119
|
+
["SECRETS", %w[set get show reveal groups list delete import env exec rails]],
|
|
120
120
|
["VAULT MANAGEMENT", %w[vaults switch rekey unlock lock reset rename copy]],
|
|
121
121
|
["SYNC (requires localvault login)", %w[sync]],
|
|
122
122
|
["TEAM SHARING (requires localvault login)", %w[dashboard verify add remove team]],
|
|
@@ -807,6 +807,7 @@ module LocalVault
|
|
|
807
807
|
require_relative "cli/sync"
|
|
808
808
|
require_relative "cli/guard"
|
|
809
809
|
require_relative "cli/identity_cmd"
|
|
810
|
+
require_relative "cli/rails_import"
|
|
810
811
|
|
|
811
812
|
# Thor 1.5 injects a `tree` command into every class. Inside a namespace it
|
|
812
813
|
# lists under a name that isn't even callable (`identity_command tree`), and
|
|
@@ -1649,6 +1650,67 @@ module LocalVault
|
|
|
1649
1650
|
end
|
|
1650
1651
|
end
|
|
1651
1652
|
|
|
1653
|
+
desc "rails", "Import a Rails app's credentials keys into the vault"
|
|
1654
|
+
long_desc <<~DESC
|
|
1655
|
+
Store this Rails app's credentials keys in the vault so you can run it
|
|
1656
|
+
with no key file on disk. Rails reads ENV["RAILS_MASTER_KEY"] whenever
|
|
1657
|
+
config/master.key is absent, so injecting that one variable is enough.
|
|
1658
|
+
|
|
1659
|
+
\x05 localvault rails # import config/master.key (and per-env keys)
|
|
1660
|
+
\x05 localvault rails --check # show what would be imported
|
|
1661
|
+
|
|
1662
|
+
Then run your app with the key injected, never written anywhere:
|
|
1663
|
+
|
|
1664
|
+
\x05 localvault exec --profile rails -- bin/rails server
|
|
1665
|
+
\x05 localvault exec --profile rails -- bin/rails credentials:edit
|
|
1666
|
+
|
|
1667
|
+
For a per-environment key (config/credentials/production.key), map it —
|
|
1668
|
+
Rails reads no variable other than RAILS_MASTER_KEY:
|
|
1669
|
+
|
|
1670
|
+
\x05 localvault exec --map rails.production_key=RAILS_MASTER_KEY -- bin/rails console
|
|
1671
|
+
|
|
1672
|
+
Key files are left exactly as they are. Deleting them is your call.
|
|
1673
|
+
DESC
|
|
1674
|
+
method_option :check, type: :boolean, default: false, desc: "List what would be imported without writing"
|
|
1675
|
+
def rails
|
|
1676
|
+
importer = RailsImport.new
|
|
1677
|
+
unless importer.rails_app?
|
|
1678
|
+
abort_with "No Rails app here — expected config/credentials.yml.enc or config/master.key in #{Dir.pwd}"
|
|
1679
|
+
return CommandStatus.error
|
|
1680
|
+
end
|
|
1681
|
+
|
|
1682
|
+
keys = importer.keys
|
|
1683
|
+
if keys.empty?
|
|
1684
|
+
$stdout.puts "No credentials key files found (config/master.key, config/credentials/*.key)."
|
|
1685
|
+
$stdout.puts "Nothing to import — the app may already run from RAILS_MASTER_KEY."
|
|
1686
|
+
return CommandStatus.ok
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
if options[:check]
|
|
1690
|
+
$stdout.puts "Would import into vault '#{options[:vault] || Config.default_vault}':"
|
|
1691
|
+
keys.each { |key| $stdout.puts " #{key.path} -> #{key.vault_key}" }
|
|
1692
|
+
return CommandStatus.ok
|
|
1693
|
+
end
|
|
1694
|
+
|
|
1695
|
+
vault = open_vault!
|
|
1696
|
+
keys.each do |key|
|
|
1697
|
+
vault.set(key.vault_key, key.value)
|
|
1698
|
+
$stdout.puts "Imported #{key.path} -> #{key.vault_key}"
|
|
1699
|
+
end
|
|
1700
|
+
|
|
1701
|
+
$stdout.puts
|
|
1702
|
+
$stdout.puts "Run without a key file on disk:"
|
|
1703
|
+
$stdout.puts " localvault exec --profile rails -- bin/rails server"
|
|
1704
|
+
keys.select(&:environment).each do |key|
|
|
1705
|
+
$stdout.puts " localvault exec --map #{key.vault_key}=RAILS_MASTER_KEY -- bin/rails console # #{key.environment}"
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1708
|
+
$stdout.puts
|
|
1709
|
+
$stdout.puts "Note: the key files are still on disk (#{keys.map(&:path).join(", ")})."
|
|
1710
|
+
$stdout.puts "They keep working until you remove them — that's your call, not ours."
|
|
1711
|
+
CommandStatus.ok
|
|
1712
|
+
end
|
|
1713
|
+
|
|
1652
1714
|
desc "upgrade", "Upgrade localvault using whichever method installed it"
|
|
1653
1715
|
long_desc <<~DESC
|
|
1654
1716
|
Detect how this copy of localvault was installed and run the matching
|
|
@@ -17,9 +17,24 @@ module LocalVault
|
|
|
17
17
|
"AWS_IAM.secret_access_key" => "AWS_SECRET_ACCESS_KEY",
|
|
18
18
|
"AWS_IAM.session_token" => "AWS_SESSION_TOKEN"
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
# Rails reads its credentials key from ENV["RAILS_MASTER_KEY"] when
|
|
22
|
+
# config/master.key is absent (railties: encrypted(..., env_key:
|
|
23
|
+
# "RAILS_MASTER_KEY")), so injecting that one variable is enough to run a
|
|
24
|
+
# Rails app with no key file on disk.
|
|
25
|
+
"rails" => {
|
|
26
|
+
only: ["rails.*"],
|
|
27
|
+
map: { "rails.master_key" => "RAILS_MASTER_KEY" }
|
|
20
28
|
}
|
|
21
29
|
}.freeze
|
|
22
30
|
|
|
31
|
+
# Per-environment credentials (config/credentials/production.key) still have
|
|
32
|
+
# to arrive as RAILS_MASTER_KEY — Rails reads no other variable. This builds
|
|
33
|
+
# the mapping for one environment.
|
|
34
|
+
def self.rails_environment_mapping(environment)
|
|
35
|
+
{ "rails.#{environment}_key" => "RAILS_MASTER_KEY" }
|
|
36
|
+
end
|
|
37
|
+
|
|
23
38
|
def self.entries(secrets, project: nil, only: nil, except: nil, map: nil, profile: nil, on_skip: nil)
|
|
24
39
|
profile_config = profile_config(profile)
|
|
25
40
|
selectors = parse_selectors(only) || profile_config[:only]
|
data/lib/localvault/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: localvault
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.14.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nauman Tariq
|
|
@@ -115,6 +115,7 @@ files:
|
|
|
115
115
|
- lib/localvault/cli/help_shell.rb
|
|
116
116
|
- lib/localvault/cli/identity_cmd.rb
|
|
117
117
|
- lib/localvault/cli/keys.rb
|
|
118
|
+
- lib/localvault/cli/rails_import.rb
|
|
118
119
|
- lib/localvault/cli/sync.rb
|
|
119
120
|
- lib/localvault/cli/team.rb
|
|
120
121
|
- lib/localvault/cli/team_helpers.rb
|