vault 0.1.0 → 0.1.1
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 +7 -0
- data/.gitignore +41 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +32 -0
- data/LICENSE +362 -0
- data/README.md +80 -54
- data/Rakefile +4 -40
- data/lib/vault.rb +33 -46
- data/lib/vault/api.rb +9 -0
- data/lib/vault/api/auth_token.rb +90 -0
- data/lib/vault/api/help.rb +23 -0
- data/lib/vault/api/logical.rb +66 -0
- data/lib/vault/api/secret.rb +23 -0
- data/lib/vault/api/sys.rb +24 -0
- data/lib/vault/api/sys/audit.rb +60 -0
- data/lib/vault/api/sys/auth.rb +58 -0
- data/lib/vault/api/sys/init.rb +46 -0
- data/lib/vault/api/sys/leader.rb +25 -0
- data/lib/vault/api/sys/lease.rb +51 -0
- data/lib/vault/api/sys/mount.rb +75 -0
- data/lib/vault/api/sys/policy.rb +76 -0
- data/lib/vault/api/sys/seal.rb +49 -0
- data/lib/vault/client.rb +285 -0
- data/lib/vault/configurable.rb +48 -0
- data/lib/vault/defaults.rb +68 -0
- data/lib/vault/errors.rb +48 -0
- data/lib/vault/request.rb +19 -0
- data/lib/vault/response.rb +20 -0
- data/lib/vault/version.rb +1 -6
- data/vault.gemspec +25 -0
- metadata +97 -98
- data/MIT-LICENSE +0 -20
- data/lib/vault/associations.rb +0 -39
- data/lib/vault/attribute_accessors.rb +0 -29
- data/lib/vault/bulk_attributes.rb +0 -17
- data/lib/vault/dirty.rb +0 -37
- data/lib/vault/finders.rb +0 -24
- data/lib/vault/persistance.rb +0 -47
- data/lib/vault/properties.rb +0 -68
- data/lib/vault/scoping.rb +0 -64
- data/lib/vault/storage.rb +0 -4
- data/lib/vault/storage/in_memory_store.rb +0 -14
- data/lib/vault/storage/yaml_store.rb +0 -52
- data/lib/vault/validations.rb +0 -13
- data/spec/active_model_compliance_spec.rb +0 -33
- data/spec/spec_helper.rb +0 -8
- data/spec/support/helpers.rb +0 -16
- data/spec/support/storage_api.rb +0 -14
- data/spec/vault/associations_spec.rb +0 -73
- data/spec/vault/finders_spec.rb +0 -69
- data/spec/vault/persistance_spec.rb +0 -126
- data/spec/vault/properties_spec.rb +0 -59
- data/spec/vault/scoping_spec.rb +0 -53
- data/spec/vault/storage/in_memory_store_spec.rb +0 -5
- data/spec/vault/storage/yaml_store_spec.rb +0 -29
- data/spec/vault_spec.rb +0 -33
data/README.md
CHANGED
@@ -1,73 +1,99 @@
|
|
1
|
-
Vault
|
2
|
-
|
1
|
+
Vault Ruby Client
|
2
|
+
=================
|
3
|
+
[](http://travis-ci.org/hashicorp/vault-ruby)
|
3
4
|
|
4
|
-
|
5
|
-
include Vault
|
5
|
+
Vault is the official Ruby client for interacting with [Vault](https://vaultproject.io) by HashiCorp.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
7
|
+
Quick Start
|
8
|
+
-----------
|
9
|
+
Install via Rubygems:
|
11
10
|
|
12
|
-
|
13
|
-
user.save
|
11
|
+
$ gem install vault
|
14
12
|
|
15
|
-
|
16
|
-
User.all #=> [user]
|
17
|
-
User.size #=> 1
|
13
|
+
or add it to your Gemfile if you're using Bundler:
|
18
14
|
|
19
|
-
|
20
|
-
|
15
|
+
```ruby
|
16
|
+
gem "vault", "~> 0.1"
|
17
|
+
```
|
21
18
|
|
22
|
-
|
23
|
-
which you included the `Vault` module) has its own, independent storage.
|
19
|
+
and then run the `bundle` command to install.
|
24
20
|
|
25
|
-
|
21
|
+
Start a Vault client:
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
```ruby
|
24
|
+
Vault.address = "http://127.0.0.1:8200" # Also reads from ENV["VAULT_ADDR"]
|
25
|
+
Vault.token = "abcd-1234" # Also reads from ENV["VAULT_TOKEN"]
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
* `Store#[](key)` receiving the key it should return a hash of all attributes
|
33
|
-
**except for the key**.
|
34
|
-
* `Store#[]=(key, attributes)` attributes will be a hash with the attributes
|
35
|
-
**except** for the key.
|
36
|
-
* `Store#delete(key)` shall delete the item without the given key.
|
37
|
-
* `Store#filter(hash)` should return a new object of the same class as the
|
38
|
-
original store, but only with objects whose properties match those of the
|
39
|
-
argument.
|
27
|
+
Vault.sys.mounts #=> { :secret => #<struct Vault::Mount type="generic", description="generic secret storage"> }
|
28
|
+
```
|
40
29
|
|
41
|
-
|
30
|
+
Usage
|
31
|
+
-----
|
32
|
+
The following configuration options are available:
|
42
33
|
|
43
|
-
|
44
|
-
|
34
|
+
```ruby
|
35
|
+
Vault::Client.configure do |config|
|
36
|
+
# The address of the Vault server, also read as ENV["VAULT_TOKEN"]
|
37
|
+
config.address = "https://127.0.0.1:8200"
|
45
38
|
|
46
|
-
|
47
|
-
|
39
|
+
# The token to authenticate with Vault, also read as ENV["VAULT_TOKEN"]
|
40
|
+
config.token = "abcd-1234"
|
48
41
|
|
49
|
-
|
42
|
+
# Proxy connection information, also read as ENV["VAULT_PROXY_(thing)"]
|
43
|
+
config.proxy_address = "..."
|
44
|
+
config.proxy_port = "..."
|
45
|
+
config.proxy_username = "..."
|
46
|
+
config.proxy_password = "..."
|
50
47
|
|
51
|
-
|
52
|
-
|
48
|
+
# Custom SSL PEM, also read as ENV["VAULT_SSL_CERT"]
|
49
|
+
config.ssl_pem_file = "/path/on/disk.pem"
|
53
50
|
|
54
|
-
|
55
|
-
|
51
|
+
# Use SSL verification, also read as ENV["VAULT_SSL_VERIFY"]
|
52
|
+
config.ssl_verify = false
|
53
|
+
end
|
54
|
+
```
|
56
55
|
|
57
|
-
|
58
|
-
-----------------------------
|
56
|
+
If you do not want the Vault singleton, of if you need to communicate with multiple Vault servers at once, you can create indepenent client objects:
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
* Commit, do not mess with Rakefile, version, or history. (if you want to have
|
65
|
-
your own version, that is fine but bump version in a commit by itself I can
|
66
|
-
ignore when I pull.)
|
67
|
-
* Send me a pull request. Bonus points for topic branches.
|
58
|
+
```ruby
|
59
|
+
client_1 = Vault::Client.new(address: "https://vault.mycompany.com")
|
60
|
+
client_2 = Vault::Client.new(address: "https://other-vault.mycompany.com")
|
61
|
+
```
|
68
62
|
|
69
|
-
|
70
|
-
|
63
|
+
### Making requests
|
64
|
+
All of the methods and API calls are heavily documented with examples inline using YARD. In order to keep the examples versioned with the code, the README only lists a few examples for using the Vault gem. Please see the inline documentation for the full API documentation. The tests in the 'spec' directory are an additional source of examples.
|
71
65
|
|
72
|
-
|
73
|
-
|
66
|
+
#### Seal Status
|
67
|
+
```ruby
|
68
|
+
Vault.sys.seal_status
|
69
|
+
#=> #<Vault::SealStatus sealed=false, t=1, n=1, progress=0>
|
70
|
+
```
|
71
|
+
|
72
|
+
#### Create a Secret
|
73
|
+
```ruby
|
74
|
+
Vault.logical.write("secret/bacon", delicious: true, cooktime: "11")
|
75
|
+
#=> #<Vault::Secret lease_id="">
|
76
|
+
```
|
77
|
+
|
78
|
+
#### Retrieve a Secret
|
79
|
+
```ruby
|
80
|
+
Vault.logical.read("secret/bacon")
|
81
|
+
#=> #<Vault::Secret lease_id="">
|
82
|
+
```
|
83
|
+
|
84
|
+
#### Seal the Vault
|
85
|
+
```ruby
|
86
|
+
Vault.sys.seal #=> true
|
87
|
+
```
|
88
|
+
|
89
|
+
Development
|
90
|
+
-----------
|
91
|
+
1. Clone the project on GitHub
|
92
|
+
2. Create a feature branch
|
93
|
+
3. Submit a Pull Request
|
94
|
+
|
95
|
+
Important Notes:
|
96
|
+
|
97
|
+
- **All new features must include test coverage.** At a bare minimum, Unit tests are required. It is preferred if you include acceptance tests as well.
|
98
|
+
- **The tests must be be idempotent.** The HTTP calls made during a test should be able to be run over and over.
|
99
|
+
- **Tests are order independent.** The default RSpec configuration randomizes the test order, so this should not be a problem.
|
data/Rakefile
CHANGED
@@ -1,42 +1,6 @@
|
|
1
|
-
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
2
3
|
|
3
|
-
|
4
|
-
require "rake/gempackagetask"
|
5
|
-
require "rake/rdoctask"
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
begin
|
10
|
-
require "spec/rake/spectask"
|
11
|
-
|
12
|
-
Spec::Rake::SpecTask.new(:spec) do |spec|
|
13
|
-
spec.pattern = "spec/**/*_spec.rb"
|
14
|
-
spec.spec_opts << "--color" << "--format specdoc"
|
15
|
-
end
|
16
|
-
|
17
|
-
task :default => ["spec"]
|
18
|
-
rescue LoadError
|
19
|
-
end
|
20
|
-
|
21
|
-
spec = Gem::Specification.new do |s|
|
22
|
-
s.name = "vault"
|
23
|
-
s.version = Vault::Version::STRING
|
24
|
-
s.summary = "Provides a very lightweight ODM"
|
25
|
-
s.author = "Nicolás Sanguinetti"
|
26
|
-
s.email = "hi@nicolassanguinetti.info"
|
27
|
-
s.homepage = "http://github.com/foca/vault"
|
28
|
-
|
29
|
-
s.has_rdoc = true
|
30
|
-
s.extra_rdoc_files = %w(README.md MIT-LICENSE)
|
31
|
-
|
32
|
-
s.files = Dir['Rakefile', '{bin,lib,man,test,spec}/**/*', 'README*', '*LICENSE*'] & `git ls-files -z`.split("\0")
|
33
|
-
|
34
|
-
s.require_paths = ["lib"]
|
35
|
-
|
36
|
-
s.add_dependency("activemodel", "3.0.0.beta.3")
|
37
|
-
s.add_development_dependency("rspec", "~> 1.3")
|
38
|
-
end
|
39
|
-
|
40
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
41
|
-
pkg.gem_spec = spec
|
42
|
-
end
|
6
|
+
task default: :spec
|
data/lib/vault.rb
CHANGED
@@ -1,53 +1,40 @@
|
|
1
|
-
require "set"
|
2
|
-
require "active_model"
|
3
|
-
require "active_support/core_ext/hash/except"
|
4
|
-
require "active_support/core_ext/module/delegation"
|
5
|
-
require "active_support/core_ext/class/attribute_accessors"
|
6
|
-
|
7
1
|
module Vault
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
included do
|
29
|
-
extend ActiveModel::Naming
|
30
|
-
extend Properties
|
31
|
-
extend Finders
|
32
|
-
extend Scoping
|
33
|
-
extend Associations
|
34
|
-
|
35
|
-
include BulkAttributes
|
36
|
-
include AttributeAccessors
|
37
|
-
include Persistance
|
38
|
-
include Dirty
|
39
|
-
include Validations
|
40
|
-
|
41
|
-
# Convenience methods to provide ActiveModel's API
|
42
|
-
include ActiveModel::Conversion
|
2
|
+
require_relative "vault/client"
|
3
|
+
require_relative "vault/configurable"
|
4
|
+
require_relative "vault/defaults"
|
5
|
+
require_relative "vault/errors"
|
6
|
+
require_relative "vault/response"
|
7
|
+
require_relative "vault/version"
|
8
|
+
|
9
|
+
require_relative "vault/api"
|
10
|
+
|
11
|
+
extend Vault::Configurable
|
12
|
+
|
13
|
+
# API client object based off the configured options in {Configurable}.
|
14
|
+
#
|
15
|
+
# @return [Vault::Client]
|
16
|
+
def self.client
|
17
|
+
if !defined?(@client) || !@client.same_options?(options)
|
18
|
+
@client = Vault::Client.new(options)
|
19
|
+
end
|
20
|
+
@client
|
43
21
|
end
|
44
22
|
|
45
|
-
|
46
|
-
|
23
|
+
# Delegate all methods to the client object, essentially making the module
|
24
|
+
# object behave like a {Client}.
|
25
|
+
def self.method_missing(m, *args, &block)
|
26
|
+
if client.respond_to?(m)
|
27
|
+
client.send(m, *args, &block)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
47
31
|
end
|
48
|
-
alias_method :id, :key
|
49
32
|
|
50
|
-
|
51
|
-
|
33
|
+
# Delegating +respond_to+ to the {Client}.
|
34
|
+
def self.respond_to_missing?(m, include_private = false)
|
35
|
+
client.respond_to?(m) || super
|
52
36
|
end
|
53
37
|
end
|
38
|
+
|
39
|
+
# Load the initial default values
|
40
|
+
Vault.setup!
|
data/lib/vault/api.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
require_relative "secret"
|
4
|
+
require_relative "../client"
|
5
|
+
require_relative "../request"
|
6
|
+
require_relative "../response"
|
7
|
+
|
8
|
+
module Vault
|
9
|
+
class Client
|
10
|
+
# A proxy to the {AuthToken} methods.
|
11
|
+
# @return [AuthToken]
|
12
|
+
def auth_token
|
13
|
+
@auth_token ||= AuthToken.new(self)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class AuthToken < Request
|
18
|
+
# Create an authentication token.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# Vault.auth_token.create #=> #<Vault::Secret lease_id="">
|
22
|
+
#
|
23
|
+
# @param [Hash] options
|
24
|
+
#
|
25
|
+
# @return [Secret]
|
26
|
+
def create(options = {})
|
27
|
+
json = client.post("/v1/auth/token/create", JSON.fast_generate(options))
|
28
|
+
return Secret.decode(json)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Renew the given authentication token.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# Vault.auth_token.renew("abcd-1234") #=> #<Vault::Secret lease_id="">
|
35
|
+
#
|
36
|
+
# @param [String] id
|
37
|
+
# the auth id
|
38
|
+
# @param [Fixnum] increment
|
39
|
+
#
|
40
|
+
# @return [Secret]
|
41
|
+
def renew(id, increment = 0)
|
42
|
+
json = client.put("/v1/auth/token/renew/#{id}", JSON.fast_generate(
|
43
|
+
increment: increment,
|
44
|
+
))
|
45
|
+
return Secret.decode(json)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Revoke exactly the orphans at the id.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# Vault.auth_token.revoke_orphan("abcd-1234") #=> true
|
52
|
+
#
|
53
|
+
# @param [String] id
|
54
|
+
# the auth id
|
55
|
+
#
|
56
|
+
# @return [true]
|
57
|
+
def revoke_orphan(id)
|
58
|
+
client.put("/v1/auth/token/revoke-orphan/#{id}", nil)
|
59
|
+
return true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Revoke all auth at the given prefix.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# Vault.auth_token.revoke_prefix("abcd-1234") #=> true
|
66
|
+
#
|
67
|
+
# @param [String] id
|
68
|
+
# the auth id
|
69
|
+
#
|
70
|
+
# @return [true]
|
71
|
+
def revoke_prefix(prefix)
|
72
|
+
client.put("/v1/auth/token/revoke-prefix/#{prefix}", nil)
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Revoke all auths in the tree.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# Vault.auth_token.revoke_tree("abcd-1234") #=> true
|
80
|
+
#
|
81
|
+
# @param [String] id
|
82
|
+
# the auth id
|
83
|
+
#
|
84
|
+
# @return [true]
|
85
|
+
def revoke_tree(id)
|
86
|
+
client.put("/v1/auth/token/revoke/#{id}", nil)
|
87
|
+
return true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "../client"
|
2
|
+
require_relative "../response"
|
3
|
+
|
4
|
+
module Vault
|
5
|
+
# Help is the response from a help query.
|
6
|
+
class Help < Response.new(:help, :see_also); end
|
7
|
+
|
8
|
+
class Client
|
9
|
+
# Gets help for the given path.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# Vault.help #=> #<Vault::Help help="..." see_also="...">
|
13
|
+
#
|
14
|
+
# @param [String] path
|
15
|
+
# the path to get help for
|
16
|
+
#
|
17
|
+
# @return [Help]
|
18
|
+
def help(path)
|
19
|
+
json = self.get("/v1/#{path}", help: 1)
|
20
|
+
return Help.decode(json)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative "secret"
|
2
|
+
require_relative "../client"
|
3
|
+
require_relative "../request"
|
4
|
+
require_relative "../response"
|
5
|
+
|
6
|
+
module Vault
|
7
|
+
class Client
|
8
|
+
# A proxy to the {Logical} methods.
|
9
|
+
# @return [Logical]
|
10
|
+
def logical
|
11
|
+
@logical ||= Logical.new(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Logical < Request
|
16
|
+
# Read the secret at the given path. If the secret does not exist, +nil+
|
17
|
+
# will be returned.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# Vault.logical.read("secret/password") #=> #<Vault::Secret lease_id="">
|
21
|
+
#
|
22
|
+
# @param [String] path
|
23
|
+
# the path to read
|
24
|
+
#
|
25
|
+
# @return [Secret, nil]
|
26
|
+
def read(path)
|
27
|
+
json = client.get("/v1/#{path}")
|
28
|
+
return Secret.decode(json)
|
29
|
+
rescue HTTPError => e
|
30
|
+
return nil if e.code == 404
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
|
34
|
+
# Write the secret at the given path with the given data. Note that the
|
35
|
+
# data must be a {Hash}!
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# Vault.logical.write("secret/password", value: "secret") #=> #<Vault::Secret lease_id="">
|
39
|
+
#
|
40
|
+
# @param [String] path
|
41
|
+
# the path to write
|
42
|
+
# @param [Hash] data
|
43
|
+
# the data to write
|
44
|
+
#
|
45
|
+
# @return [Secret]
|
46
|
+
def write(path, data = {})
|
47
|
+
client.put("/v1/#{path}", JSON.fast_generate(data))
|
48
|
+
return read(path)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Delete the secret at the given path. If the secret does not exist, vault
|
52
|
+
# will still return true.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# Vault.logical.delete("secret/password") #=> true
|
56
|
+
#
|
57
|
+
# @param [String] path
|
58
|
+
# the path to delete
|
59
|
+
#
|
60
|
+
# @return [true]
|
61
|
+
def delete(path)
|
62
|
+
client.delete("/v1/#{path}")
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|