summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock15
-rw-r--r--chef.gemspec1
-rw-r--r--lib/chef/dsl/secret.rb9
-rw-r--r--lib/chef/secret_fetcher.rb5
-rw-r--r--lib/chef/secret_fetcher/aws_secrets_manager.rb61
-rw-r--r--spec/unit/secret_fetcher_spec.rb6
6 files changed, 92 insertions, 5 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index be3c34aba1..373aa87087 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -37,6 +37,7 @@ PATH
specs:
chef (17.3.30)
addressable
+ aws-sdk-secretsmanager (~> 1.46)
chef-config (= 17.3.30)
chef-utils (= 17.3.30)
chef-vault
@@ -64,6 +65,7 @@ PATH
uuidtools (>= 2.1.5, < 3.0)
chef (17.3.30-universal-mingw32)
addressable
+ aws-sdk-secretsmanager (~> 1.46)
chef-config (= 17.3.30)
chef-utils (= 17.3.30)
chef-vault
@@ -133,6 +135,18 @@ GEM
mixlib-cli (>= 1.4, < 3.0)
mixlib-shellout (>= 2.0, < 4.0)
ast (2.4.2)
+ aws-eventstream (1.1.1)
+ aws-partitions (1.474.0)
+ aws-sdk-core (3.116.0)
+ aws-eventstream (~> 1, >= 1.0.2)
+ aws-partitions (~> 1, >= 1.239.0)
+ aws-sigv4 (~> 1.1)
+ jmespath (~> 1.0)
+ aws-sdk-secretsmanager (1.46.0)
+ aws-sdk-core (~> 3, >= 3.112.0)
+ aws-sigv4 (~> 1.1)
+ aws-sigv4 (1.2.3)
+ aws-eventstream (~> 1, >= 1.0.2)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
builder (3.2.4)
@@ -222,6 +236,7 @@ GEM
inspec-core (= 4.38.3)
ipaddress (0.8.3)
iso8601 (0.13.0)
+ jmespath (1.4.0)
json (2.5.1)
libyajl2 (2.1.0)
license-acceptance (2.1.13)
diff --git a/chef.gemspec b/chef.gemspec
index 76f562cc71..0f278fff8f 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -55,6 +55,7 @@ Gem::Specification.new do |s|
s.add_dependency "proxifier", "~> 1.0"
+ s.add_dependency "aws-sdk-secretsmanager", "~> 1.46"
s.bindir = "bin"
s.executables = %w{ }
diff --git a/lib/chef/dsl/secret.rb b/lib/chef/dsl/secret.rb
index 5bb1cf5c34..9cc7d6b3da 100644
--- a/lib/chef/dsl/secret.rb
+++ b/lib/chef/dsl/secret.rb
@@ -33,16 +33,19 @@ class Chef
# perform the secret lookup
# @option config [Hash] The configuration that the named service expects
#
+ # @return result [Object] The response object type is determined by the fetcher. See fetcher documentation
+ # to know what to expect for a given service.
+ #
# @example
#
# This example uses the built-in :example secret manager service, which
# accepts a hash of secrets.
#
- # value = secret(name: "test1", service: :example, config: { "test1" => "value1" } )
+ # value = secret(name: "test1", service: :example, config: { "test1" => "value1" })
# log "My secret is #{value}"
#
- # value = secret(name: "test1", service: :aws_secrets_manager, config: { "region" => "us-west-1" })
- # log "My secret is #{value}"
+ # value = secret(name: "test1", service: :aws_secrets_manager, config: { region: "us-west-1" })
+ # log "My secret is #{value.secret_string}"
#
# @note
#
diff --git a/lib/chef/secret_fetcher.rb b/lib/chef/secret_fetcher.rb
index 31499da0fa..dcfb542aa6 100644
--- a/lib/chef/secret_fetcher.rb
+++ b/lib/chef/secret_fetcher.rb
@@ -21,7 +21,7 @@ require_relative "exceptions"
class Chef
class SecretFetcher
- SECRET_FETCHERS = [ :example ].freeze
+ SECRET_FETCHERS = [ :example, :aws_secrets_manager ].freeze
# Returns a configured and validated instance
# of a [Chef::SecretFetcher::Base] for the given
@@ -35,6 +35,9 @@ class Chef
when :example
require_relative "secret_fetcher/example"
Chef::SecretFetcher::Example.new(config)
+ when :aws_secrets_manager
+ require_relative "secret_fetcher/aws_secrets_manager"
+ Chef::SecretFetcher::AWSSecretsManager.new(config)
when nil, ""
raise Chef::Exceptions::Secret::MissingFetcher.new(SECRET_FETCHERS)
else
diff --git a/lib/chef/secret_fetcher/aws_secrets_manager.rb b/lib/chef/secret_fetcher/aws_secrets_manager.rb
new file mode 100644
index 0000000000..f890fb5f2e
--- /dev/null
+++ b/lib/chef/secret_fetcher/aws_secrets_manager.rb
@@ -0,0 +1,61 @@
+#
+# Author:: Marc Paradise (<marc@chef.io>)
+# Copyright:: Copyright (c) Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require_relative "base"
+require "aws-sdk-secretsmanager"
+
+class Chef
+ # == Chef::SecretFetcher::AWSSecretsManager
+ # A fetcher that fetches a secret from AWS Secrets Manager
+ # In this initial iteration it defaults to authentication via instance profile.
+ # It is possible to pass options that configure it to use alternative credentials.
+ #
+ # For configuration options see https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SecretsManager/Client.html#initialize-instance_method
+ #
+ # Note that ~/.aws default and environment-based configurations are supported by default in the
+ # ruby SDK.
+ #
+ # Usage Example:
+ #
+ # fetcher = SecretFetcher.for_service(:aws_secrets_manager, { region: "us-east-1" })
+ # fetcher.fetch("secretkey1")
+ class SecretFetcher
+ class AWSSecretsManager < Base
+ DEFAULT_AWS_OPTS = { }
+ def validate!
+ # Note that we are not doing any validation of required configuration here, we will
+ # rely on the API client to do that for us, since it will work with the merge of
+ # the config we provide, env-based config, and/or an appropriate profile in ~/.aws
+
+ # Instantiating the client is an opportunity for an API provider to do validation,
+ # so we'll do that first here.
+ client
+ end
+
+ # @param identifier [String] the secret_id
+ # @return Aws::SecretsManager::Types::GetSecretValueResponse
+ def do_fetch(identifier)
+ client.get_secret_value(secret_id: identifier)
+ end
+
+ def client
+ @client ||= Aws::SecretsManager::Client.new(DEFAULT_AWS_OPTS.merge(config))
+ end
+ end
+ end
+end
diff --git a/spec/unit/secret_fetcher_spec.rb b/spec/unit/secret_fetcher_spec.rb
index 3aa9efb5f1..c352585266 100644
--- a/spec/unit/secret_fetcher_spec.rb
+++ b/spec/unit/secret_fetcher_spec.rb
@@ -35,10 +35,14 @@ describe Chef::SecretFetcher do
end
context ".for_service" do
- it "resolves a known secrets service to a fetcher" do
+ it "resolves the example fetcher without error" do
Chef::SecretFetcher.for_service(:example, {})
end
+ it "resolves the AWS fetcher without error" do
+ Chef::SecretFetcher.for_service(:aws_secrets_manager, region: "invalid")
+ end
+
it "raises Chef::Exceptions::Secret::MissingFetcher when service is blank" do
expect { Chef::SecretFetcher.for_service(nil, {}) }.to raise_error(Chef::Exceptions::Secret::MissingFetcher)
end