vault 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/hashicorp/vault-ruby.png?branch=master)](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
|