secrets-manager 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9881f60a1a1f81f48e84d02a99ce4b99970ef8ca534415fb4b3a343833264609
4
+ data.tar.gz: 5203cca0dc0456e337e073fe141cf4f850bf2e680aef2952c2a3833505e0417a
5
+ SHA512:
6
+ metadata.gz: cc8fca98711dcd170126c276da1809ab266d699726d8469712c3e0299acf833b798dacd6834a0ba56cbfb6c0450cf9c90ff45ecb1cb7dfb198b7baf5965f6c39
7
+ data.tar.gz: ceb8a360399a5bdf04c2ef38969ba88537a231b2a4b0c3f2066798e59adbed67fe5f8662bbf46dec2cc269b74e2324ab25d1d782d2ec7f5020f89308e1daefab
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in secrets-manager.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,51 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ secrets-manager (1.0.0)
5
+ aws-sdk-secretsmanager (>= 1.31.0)
6
+ concurrent-ruby (>= 1.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ aws-eventstream (1.0.3)
12
+ aws-partitions (1.213.0)
13
+ aws-sdk-core (3.68.0)
14
+ aws-eventstream (~> 1.0, >= 1.0.2)
15
+ aws-partitions (~> 1.0)
16
+ aws-sigv4 (~> 1.1)
17
+ jmespath (~> 1.0)
18
+ aws-sdk-secretsmanager (1.31.0)
19
+ aws-sdk-core (~> 3, >= 3.61.1)
20
+ aws-sigv4 (~> 1.1)
21
+ aws-sigv4 (1.1.0)
22
+ aws-eventstream (~> 1.0, >= 1.0.2)
23
+ concurrent-ruby (1.1.5)
24
+ diff-lcs (1.3)
25
+ jmespath (1.4.0)
26
+ rake (10.5.0)
27
+ rspec (3.8.0)
28
+ rspec-core (~> 3.8.0)
29
+ rspec-expectations (~> 3.8.0)
30
+ rspec-mocks (~> 3.8.0)
31
+ rspec-core (3.8.2)
32
+ rspec-support (~> 3.8.0)
33
+ rspec-expectations (3.8.4)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.8.0)
36
+ rspec-mocks (3.8.1)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.8.0)
39
+ rspec-support (3.8.2)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ bundler (~> 2.0)
46
+ rake (~> 10.0)
47
+ rspec (~> 3.0)
48
+ secrets-manager!
49
+
50
+ BUNDLED WITH
51
+ 2.0.2
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # SecretsManager.rb
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'secrets-manager'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install secrets-manager
18
+
19
+ ## Usage
20
+
21
+ To use this gem, you must have an AWS account and permissions to setup secret values using [Secrets Manager](https://aws.amazon.com/secrets-manager/)
22
+
23
+ This gem makes assumptions and has requirements about how you should be storing your secrets.
24
+
25
+ ### Path Name
26
+ This gem uses the concept of env specific secrets within the same account. While separate AWS accounts can be used to maintain separation, it can be desirable to use a single account.
27
+
28
+ The path format is as follows: `{{secret_env}}/{{secret_path}}`. When using this gem you would leave the `secret_env` out of your request.
29
+
30
+ For example, to access the secret `twlio-key`, `$secrets.fetch('twilio-key')`. This would be stored in AWS SM as `dev/twilio-key`.
31
+
32
+ ### Payload
33
+ This gem expects your secret value to be a JSON object. The only required key is `value`. The following keys are optional:
34
+ * `ttl` - Time to live in seconds. Describes how long the secret should live in in-memory cache.
35
+ * `encoding` - Currently, only `base64` is supported as a value. If your `value` is base64 encoded, this will result in a returned secret that is base64 decoded.
36
+
37
+ Example:
38
+ ```
39
+ {"value": "secretvalue", "ttl": 60} // Will live in cache for 60 seconds.
40
+ ```
41
+
42
+ ```
43
+ {"value": "c2VjcmV0dmFsdWU=", "ttl": 60, "encoding": "base64"} // Will live in cache for 60 seconds and is base64 encoded. Result will be "secretvalue"
44
+ ```
45
+
46
+ ### Configuration
47
+ The follow ENV vars are expected:
48
+ * `AWS_SECRETS_ENV` - preceeds all path lookups, ex: `dev`, `staging`, `qa`, `production`
49
+ * `AWS_SECRETS_KEY` - AWS IAM access key
50
+ * `AWS_SECRETS_SECRET` - AWS IAM access secret
51
+
52
+ The manager should be created at boot time, in an initializer for example, and stored as a constant or global.
53
+ ```
54
+ $secrets = SecretsManager.new
55
+ ```
56
+
57
+ ### Lookup
58
+ ```
59
+ $secrets.fetch('services/twilio/api-key')
60
+ $secrets['services/twilio/api-key']
61
+ ```
62
+
63
+ ## Development
64
+
65
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+
67
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
68
+
69
+ ## Contributing
70
+
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/secrets-manager.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "secrets-manager"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "version"
4
+ require "aws-sdk-secretsmanager"
5
+ require "concurrent-ruby"
6
+ require "json"
7
+
8
+ module SecretsManager
9
+ class SecretNotFound < StandardError; end;
10
+
11
+ def self.new(**args)
12
+ Manager.new(**args)
13
+ end
14
+
15
+ class Cache
16
+ def initialize
17
+ @_cache = Concurrent::Map.new
18
+ end
19
+
20
+ def reset
21
+ @_cache = Concurrent::Map.new
22
+ end
23
+
24
+ def set(path, value, ttl = 86400)
25
+ @_cache[path] = {expires_at: (Time.now + ttl), value: value}
26
+ return self
27
+ end
28
+
29
+ def find(path)
30
+ fetched = @_cache[path]
31
+ return unless fetched
32
+ return unless !fetched[:expires_at].nil? && (fetched[:expires_at]) > Time.now
33
+ fetched[:value]
34
+ end
35
+ end
36
+
37
+ class Manager
38
+ attr_reader :cache
39
+
40
+ def initialize(client: nil)
41
+ @cache = Cache.new
42
+ @aws_client = client
43
+ end
44
+
45
+ def secret_env
46
+ ENV['AWS_SECRETS_ENV'] || ENV['RACK_ENV'] || dev
47
+ end
48
+
49
+ def client
50
+ return @aws_client if @aws_client
51
+
52
+ @_client ||= Aws::SecretsManager::Client.new({
53
+ region: ENV.fetch('AWS_SECRETS_REGION', 'us-east-1'),
54
+ credentials: Aws::Credentials.new(ENV['AWS_SECRETS_KEY'], ENV['AWS_SECRETS_SECRET'])
55
+ })
56
+ end
57
+
58
+ def fetch(secret_path)
59
+ resolved_path = secret_env + '/' + secret_path
60
+
61
+ cached_value = cache.find(resolved_path)
62
+ return cached_value if cached_value
63
+
64
+ response = client.get_secret_value(secret_id: resolved_path)
65
+ return nil unless response && response.secret_string
66
+ object = JSON.parse(response.secret_string, symbolize_names: true)
67
+
68
+ value = parse_value(object)
69
+ set_in_memory(resolved_path, value, parse_ttl(object))
70
+ return value
71
+ rescue Aws::SecretsManager::Errors::ResourceNotFoundException => e
72
+ raise SecretsManager::SecretNotFound, "Could not find secret with path #{resolved_path}"
73
+ end
74
+
75
+ def [](path)
76
+ fetch(path)
77
+ end
78
+
79
+ private
80
+ def parse_ttl(data)
81
+ ## Default to one day cache TTL
82
+ return 86400 unless data[:ttl].present?
83
+ data[:ttl].to_i
84
+ end
85
+
86
+ def parse_value(data)
87
+ value = data[:value]
88
+
89
+ if data[:encoding].present?
90
+ case data[:encoding]
91
+ when "base64"
92
+ value = Base64.strict_decode64(value)
93
+ end
94
+ end
95
+
96
+ return value
97
+ end
98
+
99
+ end
100
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module SecretsManager
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,34 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "secrets-manager"
7
+ spec.version = SecretsManager::VERSION
8
+ spec.authors = ["Christopher Ostrowski", "Matt Hooks", "Evan Waters"]
9
+ spec.email = ["chris@dutchie.com", "matt.hooks@dutchie.com", "evan.waters@dutchie.com"]
10
+
11
+ spec.summary = %q{Ruby + AWS Secrets Manager}
12
+ spec.description = %q{Ruby AWS Secrets Manager interface. Allows for env specific secrets, in-memory caching with custom TTL, file storage, and simple API.}
13
+ spec.homepage = "https://github.com/GetDutchie/SecretsManager"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/GetDutchie/SecretsManager.git"
17
+ spec.metadata["changelog_uri"] = "https://github.com/GetDutchie/SecretsManager/blob/master/CHANGELOG.md"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "concurrent-ruby", ">= 1.0"
29
+ spec.add_dependency 'aws-sdk-secretsmanager', '>= 1.31.0'
30
+
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: secrets-manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Ostrowski
8
+ - Matt Hooks
9
+ - Evan Waters
10
+ autorequire:
11
+ bindir: exe
12
+ cert_chain: []
13
+ date: 2019-09-17 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: concurrent-ruby
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '1.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: aws-sdk-secretsmanager
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 1.31.0
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.31.0
43
+ - !ruby/object:Gem::Dependency
44
+ name: bundler
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '2.0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '2.0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rake
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '10.0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '10.0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '3.0'
85
+ description: Ruby AWS Secrets Manager interface. Allows for env specific secrets,
86
+ in-memory caching with custom TTL, file storage, and simple API.
87
+ email:
88
+ - chris@dutchie.com
89
+ - matt.hooks@dutchie.com
90
+ - evan.waters@dutchie.com
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - ".gitignore"
96
+ - ".rspec"
97
+ - ".travis.yml"
98
+ - CHANGELOG.md
99
+ - Gemfile
100
+ - Gemfile.lock
101
+ - README.md
102
+ - Rakefile
103
+ - bin/console
104
+ - bin/setup
105
+ - lib/secrets-manager.rb
106
+ - lib/version.rb
107
+ - secrets-manager.gemspec
108
+ homepage: https://github.com/GetDutchie/SecretsManager
109
+ licenses: []
110
+ metadata:
111
+ homepage_uri: https://github.com/GetDutchie/SecretsManager
112
+ source_code_uri: https://github.com/GetDutchie/SecretsManager.git
113
+ changelog_uri: https://github.com/GetDutchie/SecretsManager/blob/master/CHANGELOG.md
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.0.3
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Ruby + AWS Secrets Manager
133
+ test_files: []