vault 0.12.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5eeb054b599872ef7a225999772c0b486554f339
4
- data.tar.gz: b1524f9c83ea5c2e5c3c74f66fafaa69e47b8c94
2
+ SHA256:
3
+ metadata.gz: 267c85a379172af5c24fd3c3d4e14b9f07991e058f64933b3c56cc07036b053e
4
+ data.tar.gz: 847ead8ea9965e449dfbf11e3447b240e5c016fbe90e177f1ba6adca0615ee18
5
5
  SHA512:
6
- metadata.gz: d49f63c294a4165babfa3c6f2d2dfd90baabff86a964b895eb16b4ab08bd493fb07266c53f95fe2a255e2435df6f2ba42a921a97dfa1b94fe235a8c43e6aa77f
7
- data.tar.gz: c4aa7afc3b28a1aa5912ee184c7a24d07d6c19d61ae922c409cd0c0aaf6cf3efff3c5dd2269ab1d65251a7f1ce35f8cd8810c7b4d516bfd83fff93153ad39ed1
6
+ metadata.gz: 744df9d7282b0f873f008667fbd9c5bd943eea362535cdf872598c5eb5cb9fa36bb91d182a2b3ad0a2877294c16e345d371b33998a83645ba4e6880b13980e0e
7
+ data.tar.gz: 64ac03ddf3a2c5609e2224548353be0d9e640bfba1ec0ec0e215f541f2802db830238373a5b38fb15f77675d75717847468b8e5c2a1331cf609e87ca497e812a
@@ -0,0 +1,85 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ gem: zfhui/ruby-gem@0.2.1
5
+
6
+ references:
7
+ images:
8
+ ubuntu: &UBUNTU_IMAGE ubuntu-1604:201903-01
9
+
10
+ jobs:
11
+ test:
12
+ machine:
13
+ image: *UBUNTU_IMAGE
14
+ parameters:
15
+ ruby-version:
16
+ type: string
17
+ vault-version:
18
+ type: string
19
+ steps:
20
+ - checkout
21
+ # Restore bundle cache
22
+ - restore_cache:
23
+ keys:
24
+ - v1-dependencies-bundler-<< parameters.ruby-version >>-{{ checksum "vault.gemspec" }}
25
+ # fallback to using the latest cache if no exact match is found
26
+ - v1-dependencies-bundler-
27
+ - run:
28
+ name: Install vault
29
+ command: |
30
+ curl -sLo vault.zip https://releases.hashicorp.com/vault/<< parameters.vault-version >>/vault_<< parameters.vault-version >>_linux_amd64.zip
31
+ unzip vault.zip
32
+ mkdir -p ~/bin
33
+ mv vault ~/bin
34
+ export PATH="~/bin:$PATH"
35
+ - run:
36
+ name: Set ruby version
37
+ command: |
38
+ rvm install << parameters.ruby-version >>
39
+ echo . $(rvm << parameters.ruby-version >> do rvm env --path) >> $BASH_ENV
40
+ - run:
41
+ name: Run tests
42
+ command: |
43
+ export VAULT_VERSION=<< parameters.vault-version >>
44
+ ruby --version
45
+ gem install bundler
46
+ bundle -v
47
+ bundle install --jobs=3 --retry=3 --path=vendor/bundle
48
+ bundle exec rake
49
+ # Store bundle cache
50
+ - save_cache:
51
+ key: v1-dependencies-bundler-<< parameters.ruby-version >>-{{ checksum "vault.gemspec" }}
52
+ paths:
53
+ - vendor/bundle
54
+
55
+ build-release:
56
+ working_directory: ~/repo
57
+ executor: gem/default
58
+ steps:
59
+ - gem/build:
60
+ gem-name: vault
61
+ - gem/release:
62
+ gem-name: vault
63
+ gem-credentials-env-name: $RUBYGEMS_API_KEY
64
+
65
+ workflows:
66
+ run-tests:
67
+ jobs:
68
+ - test:
69
+ filters:
70
+ tags:
71
+ only: /^v[0-9]+\.[0-9]+\.[0-9]+.*/
72
+ matrix:
73
+ parameters:
74
+ ruby-version: ["2.7.1", "2.6", "2.5"]
75
+ vault-version: ["1.5.0", "1.4.2", "1.4.1", "1.4.0", "1.3.6"]
76
+ name: test-ruby-<< matrix.ruby-version >>-vault-<< matrix.vault-version >>
77
+ - build-release:
78
+ requires:
79
+ - test
80
+ context: vault-gem-release
81
+ filters:
82
+ tags:
83
+ only: /^v[0-9]+\.[0-9]+\.[0-9]+.*/
84
+ branches:
85
+ ignore: /.*/
@@ -1,5 +1,37 @@
1
1
  # Vault Ruby Changelog
2
2
 
3
+ ## v0.15.0 (July 29, 2020)
4
+
5
+ IMPROVEMENTS
6
+
7
+ - Added support for Resource Quotas
8
+
9
+ ## v0.14.0 (May 28, 2020)
10
+
11
+ IMPROVEMENTS
12
+
13
+ - Added support for the Transform Secrets Engine
14
+
15
+ ## v0.13.2 (May 7, 2020)
16
+
17
+ BUG FIXES
18
+
19
+ - Fixed the ability to use namespace as an option for each request. Previously, that option was ignored.
20
+ - aws-sigv4 gem was unlocked after a bug in 1.1.2 broke CI
21
+
22
+ ## v0.13.1 (April 28, 2020)
23
+
24
+ IMPROVEMENTS
25
+
26
+ - Added support for defining a namespace when initializing the client, as well as options for changing the namespace via method.
27
+ - Added support for sys/namespaces API. Ability to Get, Create, Delete, and List namespaces has been provided.
28
+
29
+ ## v0.13.0 (October 1, 2019)
30
+
31
+ IMPROVEMENTS
32
+
33
+ - Add support for versioned KV secrets in the client
34
+
3
35
  ## v0.12.0 (August 14, 2018)
4
36
 
5
37
  IMPROVEMENTS
data/README.md CHANGED
@@ -28,6 +28,8 @@ Start a Vault client:
28
28
  ```ruby
29
29
  Vault.address = "http://127.0.0.1:8200" # Also reads from ENV["VAULT_ADDR"]
30
30
  Vault.token = "abcd-1234" # Also reads from ENV["VAULT_TOKEN"]
31
+ # Optional - if using the Namespace enterprise feature
32
+ # Vault.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
31
33
 
32
34
  Vault.sys.mounts #=> { :secret => #<struct Vault::Mount type="generic", description="generic secret storage"> }
33
35
  ```
@@ -43,6 +45,8 @@ Vault.configure do |config|
43
45
 
44
46
  # The token to authenticate with Vault, also read as ENV["VAULT_TOKEN"]
45
47
  config.token = "abcd-1234"
48
+ # Optional - if using the Namespace enterprise feature
49
+ # config.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
46
50
 
47
51
  # Proxy connection information, also read as ENV["VAULT_PROXY_(thing)"]
48
52
  config.proxy_address = "..."
@@ -85,7 +89,8 @@ And if you want to authenticate with a `AWS EC2` :
85
89
  # Export VAULT_ADDR to ENV then
86
90
  # Get the pkcs7 value from AWS
87
91
  signature = `curl http://169.254.169.254/latest/dynamic/instance-identity/pkcs7`
88
- vault_token = Vault.auth.aws_ec2(ENV['EC2_ROLE'], signature, nil)
92
+ iam_role = `curl http://169.254.169.254/latest/meta-data/iam/security-credentials/`
93
+ vault_token = Vault.auth.aws_ec2(iam_role, signature, nil)
89
94
  vault_client = Vault::Client.new(address: ENV["VAULT_ADDR"], token: vault_token.auth.client_token)
90
95
  ```
91
96
 
@@ -117,7 +122,9 @@ For advanced users, the first argument of the block is the attempt number and th
117
122
 
118
123
  ```ruby
119
124
  Vault.with_retries(Vault::HTTPConnectionError, Vault::HTTPError) do |attempt, e|
120
- log "Received exception #{e} from Vault - attempt #{attempt}"
125
+ if e
126
+ log "Received exception #{e} from Vault - attempt #{attempt}"
127
+ end
121
128
  Vault.logical.read("secret/bacon")
122
129
  end
123
130
  ```
@@ -206,7 +213,8 @@ Development
206
213
 
207
214
  Important Notes:
208
215
 
209
- - **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.
216
+ - **All new features must include test coverage.** At a bare minimum, Unit tests are required. It is preferred if you include integration tests as well.
210
217
  - **The tests must be be idempotent.** The HTTP calls made during a test should be able to be run over and over.
211
218
  - **Tests are order independent.** The default RSpec configuration randomizes the test order, so this should not be a problem.
212
219
  - **Integration tests require Vault** Vault must be available in the path for the integration tests to pass.
220
+ - **In order to be considered an integration test:** The test MUST use the `vault_test_client` or `vault_redirect_test_client` as the client. This spawns a process, or uses an already existing process from another test, to run against.
@@ -5,8 +5,10 @@ module Vault
5
5
  require_relative "api/auth_tls"
6
6
  require_relative "api/auth"
7
7
  require_relative "api/help"
8
+ require_relative "api/kv"
8
9
  require_relative "api/logical"
9
10
  require_relative "api/secret"
10
11
  require_relative "api/sys"
12
+ require_relative "api/transform"
11
13
  end
12
14
  end
@@ -0,0 +1,207 @@
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 {KV} methods.
9
+ # @return [KV]
10
+ def kv(mount)
11
+ KV.new(self, mount)
12
+ end
13
+ end
14
+
15
+ class KV < Request
16
+ attr_reader :mount
17
+
18
+ def initialize(client, mount)
19
+ super client
20
+
21
+ @mount = mount
22
+ end
23
+
24
+ # List the names of secrets at the given path, if the path supports
25
+ # listing. If the the path does not exist, an empty array will be returned.
26
+ #
27
+ # @example
28
+ # Vault.kv("secret").list("foo") #=> ["bar", "baz"]
29
+ #
30
+ # @param [String] path
31
+ # the path to list
32
+ #
33
+ # @return [Array<String>]
34
+ def list(path = "", options = {})
35
+ headers = extract_headers!(options)
36
+ json = client.list("/v1/#{mount}/metadata/#{encode_path(path)}", {}, headers)
37
+ json[:data][:keys] || []
38
+ rescue HTTPError => e
39
+ return [] if e.code == 404
40
+ raise
41
+ end
42
+
43
+ # Read the secret at the given path. If the secret does not exist, +nil+
44
+ # will be returned. The latest version is returned by default, but you
45
+ # can request a specific version.
46
+ #
47
+ # @example
48
+ # Vault.kv("secret").read("password") #=> #<Vault::Secret lease_id="">
49
+ #
50
+ # @param [String] path
51
+ # the path to read
52
+ # @param [Integer] version
53
+ # the version of the secret
54
+ #
55
+ # @return [Secret, nil]
56
+ def read(path, version = nil, options = {})
57
+ headers = extract_headers!(options)
58
+ params = {}
59
+ params[:version] = version unless version.nil?
60
+
61
+ json = client.get("/v1/#{mount}/data/#{encode_path(path)}", params, headers)
62
+ return Secret.decode(json[:data])
63
+ rescue HTTPError => e
64
+ return nil if e.code == 404
65
+ raise
66
+ end
67
+
68
+ # Read the metadata of a secret at the given path. If the secret does not
69
+ # exist, nil will be returned.
70
+ #
71
+ # @example
72
+ # Vault.kv("secret").read_metadata("password") => {...}
73
+ #
74
+ # @param [String] path
75
+ # the path to read
76
+ #
77
+ # @return [Hash, nil]
78
+ def read_metadata(path)
79
+ client.get("/v1/#{mount}/metadata/#{encode_path(path)}")[:data]
80
+ rescue HTTPError => e
81
+ return nil if e.code == 404
82
+ raise
83
+ end
84
+
85
+ # Write the secret at the given path with the given data. Note that the
86
+ # data must be a {Hash}!
87
+ #
88
+ # @example
89
+ # Vault.logical.write("secret/password", value: "secret") #=> #<Vault::Secret lease_id="">
90
+ #
91
+ # @param [String] path
92
+ # the path to write
93
+ # @param [Hash] data
94
+ # the data to write
95
+ #
96
+ # @return [Secret]
97
+ def write(path, data = {}, options = {})
98
+ headers = extract_headers!(options)
99
+ json = client.post("/v1/#{mount}/data/#{encode_path(path)}", JSON.fast_generate(:data => data), headers)
100
+ if json.nil?
101
+ return true
102
+ else
103
+ return Secret.decode(json)
104
+ end
105
+ end
106
+
107
+ # Write the metadata of a secret at the given path. Note that the data must
108
+ # be a {Hash}.
109
+ #
110
+ # @example
111
+ # Vault.kv("secret").write_metadata("password", max_versions => 3)
112
+ #
113
+ # @param [String] path
114
+ # the path to write
115
+ # @param [Hash] metadata
116
+ # the metadata to write
117
+ #
118
+ # @return [true]
119
+ def write_metadata(path, metadata = {})
120
+ client.post("/v1/#{mount}/metadata/#{encode_path(path)}", JSON.fast_generate(metadata))
121
+
122
+ true
123
+ end
124
+
125
+ # Delete the secret at the given path. If the secret does not exist, vault
126
+ # will still return true.
127
+ #
128
+ # @example
129
+ # Vault.logical.delete("secret/password") #=> true
130
+ #
131
+ # @param [String] path
132
+ # the path to delete
133
+ #
134
+ # @return [true]
135
+ def delete(path)
136
+ client.delete("/v1/#{mount}/data/#{encode_path(path)}")
137
+
138
+ true
139
+ end
140
+
141
+ # Mark specific versions of a secret as deleted.
142
+ #
143
+ # @example
144
+ # Vault.kv("secret").delete_versions("password", [1, 2])
145
+ #
146
+ # @param [String] path
147
+ # the path to remove versions from
148
+ # @param [Array<Integer>] versions
149
+ # an array of versions to remove
150
+ #
151
+ # @return [true]
152
+ def delete_versions(path, versions)
153
+ client.post("/v1/#{mount}/delete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
154
+
155
+ true
156
+ end
157
+
158
+ # Mark specific versions of a secret as active.
159
+ #
160
+ # @example
161
+ # Vault.kv("secret").undelete_versions("password", [1, 2])
162
+ #
163
+ # @param [String] path
164
+ # the path to enable versions for
165
+ # @param [Array<Integer>] versions
166
+ # an array of versions to mark as undeleted
167
+ #
168
+ # @return [true]
169
+ def undelete_versions(path, versions)
170
+ client.post("/v1/#{mount}/undelete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
171
+
172
+ true
173
+ end
174
+
175
+ # Completely remove a secret and its metadata.
176
+ #
177
+ # @example
178
+ # Vault.kv("secret").destroy("password")
179
+ #
180
+ # @param [String] path
181
+ # the path to remove
182
+ #
183
+ # @return [true]
184
+ def destroy(path)
185
+ client.delete("/v1/#{mount}/metadata/#{encode_path(path)}")
186
+
187
+ true
188
+ end
189
+
190
+ # Completely remove specific versions of a secret.
191
+ #
192
+ # @example
193
+ # Vault.kv("secret").destroy_versions("password", [1, 2])
194
+ #
195
+ # @param [String] path
196
+ # the path to remove versions from
197
+ # @param [Array<Integer>] versions
198
+ # an array of versions to destroy
199
+ #
200
+ # @return [true]
201
+ def destroy_versions(path, versions)
202
+ client.post("/v1/#{mount}/destroy/#{encode_path(path)}", JSON.fast_generate(versions: versions))
203
+
204
+ true
205
+ end
206
+ end
207
+ end
@@ -32,6 +32,18 @@ module Vault
32
32
  # @return [Hash<Symbol, Object>]
33
33
  field :data, freeze: true
34
34
 
35
+ # @!attribute [r] metadata
36
+ # Read-only metadata information related to the secret.
37
+ #
38
+ # @example Reading metadata
39
+ # secret = Vault.logical(:versioned).read("secret", "foo")
40
+ # secret.metadata[:created_time] #=> "2018-12-08T04:22:54.168065Z"
41
+ # secret.metadata[:version] #=> 1
42
+ # secret.metadata[:destroyed] #=> false
43
+ #
44
+ # @return [Hash<Symbol, Object>]
45
+ field :metadata, freeze: true
46
+
35
47
  # @!attribute [r] lease_duration
36
48
  # The number of seconds this lease is valid. If this number is 0 or nil,
37
49
  # the secret does not expire.
@@ -21,5 +21,7 @@ require_relative "sys/init"
21
21
  require_relative "sys/leader"
22
22
  require_relative "sys/lease"
23
23
  require_relative "sys/mount"
24
+ require_relative "sys/namespace"
24
25
  require_relative "sys/policy"
26
+ require_relative "sys/quota"
25
27
  require_relative "sys/seal"
@@ -16,6 +16,11 @@ module Vault
16
16
  # Type of the mount.
17
17
  # @return [String]
18
18
  field :type
19
+
20
+ # @!attribute [r] type
21
+ # Options given to the mount.
22
+ # @return [Hash<Symbol, Object>]
23
+ field :options
19
24
  end
20
25
 
21
26
  class Sys < Request
@@ -44,8 +49,8 @@ module Vault
44
49
  # the type of mount
45
50
  # @param [String] description
46
51
  # a human-friendly description (optional)
47
- def mount(path, type, description = nil)
48
- payload = { type: type }
52
+ def mount(path, type, description = nil, options = {})
53
+ payload = options.merge type: type
49
54
  payload[:description] = description if !description.nil?
50
55
 
51
56
  client.post("/v1/sys/mounts/#{encode_path(path)}", JSON.fast_generate(payload))
@@ -0,0 +1,83 @@
1
+ module Vault
2
+ class Namespace < Response
3
+ # @!attribute [r] id
4
+ # ID of the namespace
5
+ # @return [String]
6
+ field :id
7
+
8
+ # @!attribute [r] path
9
+ # Path of the namespace, includes parent paths if nested.
10
+ # @return [String]
11
+ field :path
12
+ end
13
+
14
+ class Sys
15
+ # List all namespaces in a given scope. Ignores nested namespaces.
16
+ #
17
+ # @example
18
+ # Vault.sys.namespaces #=> { :foo => #<struct Vault::Namespace id="xxxx1", path="foo/" }
19
+ #
20
+ # @return [Hash<Symbol, Namespace>]
21
+ def namespaces(scoped=nil)
22
+ path = ["v1", scoped, "sys", "namespaces"].compact
23
+ json = client.list(path.join("/"))
24
+ json = json[:data] if json[:data]
25
+ if json[:key_info]
26
+ json = json[:key_info]
27
+ hash = {}
28
+ json.each do |k,v|
29
+ hash[k.to_s.chomp("/").to_sym] = Namespace.decode(v)
30
+ end
31
+ hash
32
+ else
33
+ json
34
+ end
35
+ end
36
+
37
+ # Create a namespace. Nests the namespace if a namespace header is provided.
38
+ #
39
+ # @example
40
+ # Vault.sys.create_namespace("foo")
41
+ #
42
+ # @param [String] namespace
43
+ # the potential path of the namespace, without any parent path provided
44
+ #
45
+ # @return [true]
46
+ def create_namespace(namespace)
47
+ client.put("/v1/sys/namespaces/#{namespace}", {})
48
+ return true
49
+ end
50
+
51
+ # Delete a namespace. Raises an error if the namespace provided is not empty.
52
+ #
53
+ # @example
54
+ # Vault.sys.delete_namespace("foo")
55
+ #
56
+ # @param [String] namespace
57
+ # the path of the namespace to be deleted
58
+ #
59
+ # @return [true]
60
+ def delete_namespace(namespace)
61
+ client.delete("/v1/sys/namespaces/#{namespace}")
62
+ return true
63
+ end
64
+
65
+ # Retrieve a namespace by path.
66
+ #
67
+ # @example
68
+ # Vault.sys.get_namespace("foo")
69
+ #
70
+ # @param [String] namespace
71
+ # the path of the namespace ot be retrieved
72
+ #
73
+ # @return [Namespace]
74
+ def get_namespace(namespace)
75
+ json = client.get("/v1/sys/namespaces/#{namespace}")
76
+ if data = json.dig(:data)
77
+ Namespace.decode(data)
78
+ else
79
+ json
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,107 @@
1
+ module Vault
2
+ class Quota < Response
3
+ # @!attribute [r] name
4
+ # Name of the quota rule.
5
+ # @return [String]
6
+ field :name
7
+
8
+ # @!attribute [r] path
9
+ # Namespace/Path combination the quota applies to.
10
+ # @return [String]
11
+ field :path
12
+
13
+ # @!attribute [r] type
14
+ # Type of the quota rule, must be one of "lease-count" or "rate-limit"
15
+ # @return [String]
16
+ field :type
17
+ end
18
+
19
+ class RateLimitQuota < Quota
20
+ # @!attribute [r] rate
21
+ # The rate at which allowed requests are refilled per second by the quota
22
+ # rule.
23
+ # @return [Float]
24
+ field :rate
25
+
26
+ # @!attribute [r] burst
27
+ # The maximum number of requests at any given second allowed by the quota
28
+ # rule.
29
+ # @return [Int]
30
+ field :burst
31
+ end
32
+
33
+ class LeaseCountQuota < Quota
34
+ # @!attribute [r] counter
35
+ # Number of currently active leases for the quota.
36
+ # @return [Int]
37
+ field :counter
38
+
39
+ # @!attribute [r] max_leases
40
+ # The maximum number of allowed leases for this quota.
41
+ # @return [Int]
42
+ field :max_leases
43
+ end
44
+
45
+ class Sys
46
+ def quotas(type)
47
+ path = generate_path(type)
48
+ json = client.list(path)
49
+ if data = json.dig(:data, :key_info)
50
+ data.map do |item|
51
+ type_class(type).decode(item)
52
+ end
53
+ else
54
+ json
55
+ end
56
+ end
57
+
58
+ def create_quota(type, name, opts={})
59
+ path = generate_path(type, name)
60
+ client.post(path, JSON.fast_generate(opts))
61
+ return true
62
+ end
63
+
64
+ def delete_quota(type, name)
65
+ path = generate_path(type, name)
66
+ client.delete(path)
67
+ return true
68
+ end
69
+
70
+ def get_quota(type, name)
71
+ path = generate_path(type, name)
72
+ response = client.get(path)
73
+ if data = response[:data]
74
+ type_class(type).decode(data)
75
+ end
76
+ end
77
+
78
+ def get_quota_config
79
+ client.get("v1/sys/quotas/config")
80
+ end
81
+
82
+ def update_quota_config(opts={})
83
+ client.post("v1/sys/quotas/config", JSON.fast_generate(opts))
84
+ return true
85
+ end
86
+
87
+ private
88
+
89
+ def generate_path(type, name=nil)
90
+ verify_type(type)
91
+ path = ["v1", "sys", "quotas", type, name].compact
92
+ path.join("/")
93
+ end
94
+
95
+ def verify_type(type)
96
+ return if ["rate-limit", "lease-count"].include?(type)
97
+ raise ArgumentError, "type must be one of \"rate-limit\" or \"lease-count\""
98
+ end
99
+
100
+ def type_class(type)
101
+ case type
102
+ when "lease-count" then LeaseCountQuota
103
+ when "rate-limit" then RateLimitQuota
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,29 @@
1
+ require_relative '../client'
2
+ require_relative '../request'
3
+
4
+ module Vault
5
+ class Client
6
+ # A proxy to the {Transform} methods.
7
+ # @return [Transform]
8
+ def transform
9
+ @transform ||= Transform.new(self)
10
+ end
11
+ end
12
+
13
+ class Transform < Request
14
+ def encode(role_name:, **opts)
15
+ opts ||= {}
16
+ client.post("/v1/transform/encode/#{encode_path(role_name)}", JSON.fast_generate(opts))
17
+ end
18
+
19
+ def decode(role_name:, **opts)
20
+ opts ||= {}
21
+ client.post("/v1/transform/decode/#{encode_path(role_name)}", JSON.fast_generate(opts))
22
+ end
23
+ end
24
+ end
25
+
26
+ require_relative 'transform/alphabet'
27
+ require_relative 'transform/role'
28
+ require_relative 'transform/template'
29
+ require_relative 'transform/transformation'
@@ -0,0 +1,43 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Alphabet < Response
7
+ # @!attribute [r] id
8
+ # String listing all possible characters of the alphabet
9
+ # @return [String]
10
+ field :alphabet
11
+ end
12
+
13
+ def create_alphabet(name, alphabet:, **opts)
14
+ opts ||= {}
15
+ opts[:alphabet] = alphabet
16
+ client.post("/v1/transform/alphabet/#{encode_path(name)}", JSON.fast_generate(opts))
17
+ return true
18
+ end
19
+
20
+ def get_alphabet(name)
21
+ json = client.get("/v1/transform/alphabet/#{encode_path(name)}")
22
+ if data = json.dig(:data)
23
+ Alphabet.decode(data)
24
+ else
25
+ json
26
+ end
27
+ end
28
+
29
+ def delete_alphabet(name)
30
+ client.delete("/v1/transform/alphabet/#{encode_path(name)}")
31
+ true
32
+ end
33
+
34
+ def alphabets
35
+ json = client.list("/v1/transform/alphabet")
36
+ if keys = json.dig(:data, :keys)
37
+ keys
38
+ else
39
+ json
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Role < Response
7
+ # @!attribute [r] transformations
8
+ # Array of all transformations the role has access to
9
+ # @return [Array<String>]
10
+ field :transformations
11
+ end
12
+
13
+ def create_role(name, **opts)
14
+ opts ||= {}
15
+ client.post("/v1/transform/role/#{encode_path(name)}", JSON.fast_generate(opts))
16
+ return true
17
+ end
18
+
19
+ def get_role(name)
20
+ json = client.get("/v1/transform/role/#{encode_path(name)}")
21
+ if data = json.dig(:data)
22
+ Role.decode(data)
23
+ else
24
+ json
25
+ end
26
+ end
27
+
28
+ def delete_role(name)
29
+ client.delete("/v1/transform/role/#{encode_path(name)}")
30
+ true
31
+ end
32
+
33
+ def roles
34
+ json = client.list("/v1/transform/role")
35
+ if keys = json.dig(:data, :keys)
36
+ keys
37
+ else
38
+ json
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Template < Response
7
+ # @!attribute [r] alphabet
8
+ # Name of the alphabet to be used in the template
9
+ # @return [String]
10
+ field :alphabet
11
+
12
+ # @!attribute [r] pattern
13
+ # Regex string to detect and match for the template
14
+ # @return [String]
15
+ field :pattern
16
+
17
+ # @!attribute [r] type
18
+ # Type of the template, currently, only "regex" is supported
19
+ # @return [String]
20
+ field :type
21
+ end
22
+
23
+ def create_template(name, type:, pattern:, **opts)
24
+ opts ||= {}
25
+ opts[:type] = type
26
+ opts[:pattern] = pattern
27
+ client.post("/v1/transform/template/#{encode_path(name)}", JSON.fast_generate(opts))
28
+ return true
29
+ end
30
+
31
+ def get_template(name)
32
+ json = client.get("/v1/transform/template/#{encode_path(name)}")
33
+ if data = json.dig(:data)
34
+ Template.decode(data)
35
+ else
36
+ json
37
+ end
38
+ end
39
+
40
+ def delete_template(name)
41
+ client.delete("/v1/transform/template/#{encode_path(name)}")
42
+ true
43
+ end
44
+
45
+ def templates
46
+ json = client.list("/v1/transform/template")
47
+ if keys = json.dig(:data, :keys)
48
+ keys
49
+ else
50
+ json
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Transformation < Response
7
+ # @!attribute [r] allowed_roles
8
+ # Array of role names that are allowed to use this transformation
9
+ # @return [Array<String>]
10
+ field :allowed_roles
11
+
12
+ # @!attribute [r] templates
13
+ # Array of template names accessible to this transformation
14
+ # @return [Array<String>]
15
+ field :templates
16
+
17
+ # @!attribute [r] tweak_source
18
+ # String representing how a tweak is provided for this transformation.
19
+ # Available tweaks are "supplied", "generated", and "internal"
20
+ # @return [String]
21
+ field :tweak_source
22
+
23
+ # @!attribute [r] type
24
+ # String representing the type of transformation this is.
25
+ # Available types are "fpe", and "masking"
26
+ # @return [String]
27
+ field :type
28
+ end
29
+
30
+ def create_transformation(name, type:, template:, **opts)
31
+ opts ||= {}
32
+ opts[:type] = type
33
+ opts[:template] = template
34
+ client.post("/v1/transform/transformation/#{encode_path(name)}", JSON.fast_generate(opts))
35
+ return true
36
+ end
37
+
38
+ def get_transformation(name)
39
+ json = client.get("/v1/transform/transformation/#{encode_path(name)}")
40
+ if data = json.dig(:data)
41
+ Transformation.decode(data)
42
+ else
43
+ json
44
+ end
45
+ end
46
+
47
+ def delete_transformation(name)
48
+ client.delete("/v1/transform/transformation/#{encode_path(name)}")
49
+ true
50
+ end
51
+
52
+ def transformations
53
+ json = client.list("/v1/transform/transformation")
54
+ if keys = json.dig(:data, :keys)
55
+ keys
56
+ else
57
+ json
58
+ end
59
+ end
60
+ end
61
+ end
@@ -16,6 +16,9 @@ module Vault
16
16
  # The name of the header used to hold the Vault token.
17
17
  TOKEN_HEADER = "X-Vault-Token".freeze
18
18
 
19
+ # The name of the header used to hold the Namespace.
20
+ NAMESPACE_HEADER = "X-Vault-Namespace".freeze
21
+
19
22
  # The name of the header used to hold the wrapped request ttl.
20
23
  WRAP_TTL_HEADER = "X-Vault-Wrap-TTL".freeze
21
24
 
@@ -255,6 +258,12 @@ module Vault
255
258
  headers[TOKEN_HEADER] ||= token
256
259
  end
257
260
 
261
+ # Add the Vault Namespace header - users could still override this on a
262
+ # per-request basis
263
+ if !namespace.nil?
264
+ headers[NAMESPACE_HEADER] ||= namespace
265
+ end
266
+
258
267
  # Add headers
259
268
  headers.each do |key, value|
260
269
  request.add_field(key, value)
@@ -7,6 +7,7 @@ module Vault
7
7
  :address,
8
8
  :token,
9
9
  :hostname,
10
+ :namespace,
10
11
  :open_timeout,
11
12
  :proxy_address,
12
13
  :proxy_password,
@@ -61,6 +61,13 @@ module Vault
61
61
  nil
62
62
  end
63
63
 
64
+
65
+ # Vault Namespace, if any.
66
+ # @return [String, nil]
67
+ def namespace
68
+ ENV["VAULT_NAMESPACE"]
69
+ end
70
+
64
71
  # The SNI host to use when connecting to Vault via TLS.
65
72
  # @return [String, nil]
66
73
  def hostname
@@ -29,6 +29,7 @@ module Vault
29
29
  def extract_headers!(options = {})
30
30
  extract = {
31
31
  wrap_ttl: Vault::Client::WRAP_TTL_HEADER,
32
+ namespace: Vault::Client::NAMESPACE_HEADER,
32
33
  }
33
34
 
34
35
  {}.tap do |h|
@@ -1,3 +1,3 @@
1
1
  module Vault
2
- VERSION = "0.12.0"
2
+ VERSION = "0.15.0"
3
3
  end
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_runtime_dependency "aws-sigv4"
23
23
 
24
- spec.add_development_dependency "bundler"
25
- spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "bundler", "~> 2"
25
+ spec.add_development_dependency "pry", "~> 0.13.1"
26
26
  spec.add_development_dependency "rake", "~> 12.0"
27
27
  spec.add_development_dependency "rspec", "~> 3.5"
28
- spec.add_development_dependency "yard"
29
- spec.add_development_dependency "webmock", "~> 2.3"
28
+ spec.add_development_dependency "yard", "~> 0.9.24"
29
+ spec.add_development_dependency "webmock", "~> 3.8.3"
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vault
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seth Vargo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-14 00:00:00.000000000 Z
11
+ date: 2020-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sigv4
@@ -28,30 +28,30 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '2'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.13.1
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.13.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -84,30 +84,30 @@ dependencies:
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.9.24
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 0.9.24
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: webmock
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '2.3'
103
+ version: 3.8.3
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.3'
110
+ version: 3.8.3
111
111
  description: Vault is a Ruby API client for interacting with a Vault server.
112
112
  email:
113
113
  - sethvargo@gmail.com
@@ -115,9 +115,9 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - ".circleci/config.yml"
118
119
  - ".gitignore"
119
120
  - ".rspec"
120
- - ".travis.yml"
121
121
  - CHANGELOG.md
122
122
  - Gemfile
123
123
  - LICENSE
@@ -130,6 +130,7 @@ files:
130
130
  - lib/vault/api/auth_tls.rb
131
131
  - lib/vault/api/auth_token.rb
132
132
  - lib/vault/api/help.rb
133
+ - lib/vault/api/kv.rb
133
134
  - lib/vault/api/logical.rb
134
135
  - lib/vault/api/secret.rb
135
136
  - lib/vault/api/sys.rb
@@ -140,8 +141,15 @@ files:
140
141
  - lib/vault/api/sys/leader.rb
141
142
  - lib/vault/api/sys/lease.rb
142
143
  - lib/vault/api/sys/mount.rb
144
+ - lib/vault/api/sys/namespace.rb
143
145
  - lib/vault/api/sys/policy.rb
146
+ - lib/vault/api/sys/quota.rb
144
147
  - lib/vault/api/sys/seal.rb
148
+ - lib/vault/api/transform.rb
149
+ - lib/vault/api/transform/alphabet.rb
150
+ - lib/vault/api/transform/role.rb
151
+ - lib/vault/api/transform/template.rb
152
+ - lib/vault/api/transform/transformation.rb
145
153
  - lib/vault/client.rb
146
154
  - lib/vault/configurable.rb
147
155
  - lib/vault/defaults.rb
@@ -177,8 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
185
  - !ruby/object:Gem::Version
178
186
  version: '0'
179
187
  requirements: []
180
- rubyforge_project:
181
- rubygems_version: 2.6.14
188
+ rubygems_version: 3.1.2
182
189
  signing_key:
183
190
  specification_version: 4
184
191
  summary: Vault is a Ruby API client for interacting with a Vault server.
@@ -1,26 +0,0 @@
1
- dist: trusty
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
-
6
- env:
7
- - VAULT_VERSION=0.8.3
8
- - VAULT_VERSION=0.7.3
9
- - VAULT_VERSION=0.6.5
10
- - VAULT_VERSION=0.5.3
11
-
12
- before_install:
13
- - curl -sLo vault.zip https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
14
- - unzip vault.zip
15
- - mkdir -p ~/bin
16
- - mv vault ~/bin
17
- - export PATH="~/bin:$PATH"
18
-
19
- branches:
20
- only:
21
- - master
22
-
23
- rvm:
24
- - 2.2
25
- - 2.3
26
- - 2.4