Class: Chef::SecretFetcher::AzureKeyVault

Inherits:
Base
  • Object
show all
Defined in:
lib/chef/secret_fetcher/azure_key_vault.rb

Overview

== Chef::SecretFetcher::AzureKeyVault A fetcher that fetches a secret from Azure Key Vault. Supports fetching with version.

In this initial iteration this authenticates via token obtained from the OAuth2 /token endpoint.

Validation of required configuration (vault name) is not performed until fetch time, to allow for embedding the vault name in with the secret name, such as "my_vault/secretkey1".

fetcher = SecretFetcher.for_service(:azure_key_vault, { vault: "my_vault" }, run_context) fetcher.fetch("secretkey1", "v1")

fetcher = SecretFetcher.for_service(:azure_key_vault, {}, run_context) fetcher.fetch("my_vault/secretkey1", "v1")

fetcher = SecretFetcher.for_service(:azure_key_vault, { client_id: "540d76b6-7f76-456c-b68b-ccae4dc9d99d" }, run_context) fetcher.fetch("my_vault/secretkey1", "v1")

Instance Attribute Summary

Attributes inherited from Base

#config, #run_context

Instance Method Summary collapse

Methods inherited from Base

#fetch, #initialize

Constructor Details

This class inherits a constructor from Chef::SecretFetcher::Base

Instance Method Details

#do_fetch(name, version) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/chef/secret_fetcher/azure_key_vault.rb', line 36

def do_fetch(name, version)
  token = fetch_token
  vault, name = resolve_vault_and_secret_name(name)
  if vault.nil?
    raise Chef::Exceptions::Secret::ConfigurationInvalid.new("You must provide a vault name to fetcher options as vault: 'vault_name' or in the secret name as 'vault_name/secret_name'")
  end

  # Note that `version` is optional after the final `/`. If nil/"", the latest secret version will be fetched.
  secret_uri = URI.parse("https://#{vault}.vault.azure.net/secrets/#{name}/#{version}?api-version=7.2")
  http = Net::HTTP.new(secret_uri.host, secret_uri.port)
  http.use_ssl = true

  response = http.get(secret_uri, { "Authorization" => "Bearer #{token}",
                                    "Content-Type" => "application/json" })

  # If an exception is not raised, we can be reasonably confident of the
  # shape of the result.
  result = JSON.parse(response.body)
  if result.key? "value"
    result["value"]
  else
    raise Chef::Exceptions::Secret::FetchFailed.new("#{result["error"]["code"]}: #{result["error"]["message"]}")
  end
end

#validate!Object



61
62
63
# File 'lib/chef/secret_fetcher/azure_key_vault.rb', line 61

def validate!
  raise Chef::Exceptions::Secret::ConfigurationInvalid, "You may only specify one (these are mutually exclusive): :object_id, :client_id, or :mi_res_id" if [config_object_id, client_id, mi_res_id].count { |x| !x.nil? } > 1
end