secrets_parser 0.0.5
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 +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/README.md +93 -0
- data/Rakefile +6 -0
- data/lib/secrets_parser/helpers.rb +12 -0
- data/lib/secrets_parser/parser.rb +101 -0
- data/lib/secrets_parser/version.rb +3 -0
- data/lib/secrets_parser.rb +2 -0
- data/secrets_parser.gemspec +35 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30084b08de2283f2b2c3bb313c3dfbe3d57ca15d
|
4
|
+
data.tar.gz: 2715b1bc6044484f8a63f4b368c6c7223da8ae60
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0c8201ba248c880d24856bcb9b0499342ca2d854254af2779821997801ceeacfc894eddf90142811c5866d1a5808490d814f83fc0ce72c9c5b9717ddf5371701
|
7
|
+
data.tar.gz: ecf987be6b1e3f5eac87e55642e9636088d77ef7b7673dc48e3069d2e3853fb89c34f570f2025337ddb9a3f6248a3c9fadd7eebb35dc90288bc0bcb155cf184e
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at josacar@users.noreply.github.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Secrets Parser
|
2
|
+
|
3
|
+
This gem parse the secrets reading a field in a JSON file, download the encrypted secrets file from S3 and change the values for the encrypted ones.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
For using correctly this gem, we will need 4 basic things: a JSON file to parse, an S3 bucket and a JSON file encrypted with a AWS KMS key that will store the secret values.
|
8
|
+
|
9
|
+
#### JSON File to parse
|
10
|
+
|
11
|
+
This file is where there are going to be the references to the secrets in S3. Example:
|
12
|
+
|
13
|
+
```
|
14
|
+
{
|
15
|
+
"variables": {
|
16
|
+
"MY_SECRET": "secret:bucket_name/path:my_secret",
|
17
|
+
"OTHER_SECRET": "secret:bucket_name/path:other_secret"
|
18
|
+
}
|
19
|
+
}
|
20
|
+
```
|
21
|
+
|
22
|
+
The example has 2 secrets in it, these references have 3 parts:
|
23
|
+
|
24
|
+
* `secret:` : This is needed to let the gem idetify that the value is a reference to a secret.
|
25
|
+
* `bucket_name/path` : Path where is located the secret file, bucket_name + path, the extension of the file is inside the gem and it's `json.encrypted`, so in this case, there is a file in this bucket named *secret-testing.json.encrypted*.
|
26
|
+
* `:my_secret` and `:other_secret` : That's the key that's inside the encrypted file.
|
27
|
+
|
28
|
+
*This allow us to let the secret managers decide where to put those secrets*
|
29
|
+
|
30
|
+
#### KMS Key
|
31
|
+
|
32
|
+
AWS KMS key used to encrypt the secrets and the S3 bucket where secrets are going to be stored.
|
33
|
+
|
34
|
+
#### S3 Bucket
|
35
|
+
|
36
|
+
Just a AWS S3 Bucket, it's recommended to have it encrypted at rest too with the same KMS key.
|
37
|
+
|
38
|
+
#### Encrypted JSON file
|
39
|
+
|
40
|
+
Here is where secrets are going to be stored, a simple JSON with all the keys and secrets. Example:
|
41
|
+
|
42
|
+
```
|
43
|
+
{
|
44
|
+
"my_secret": "This is a secret weeee",
|
45
|
+
"other_secret": "PINCODE: 12345"
|
46
|
+
}
|
47
|
+
```
|
48
|
+
|
49
|
+
After configuring it, encrypt it with:
|
50
|
+
```
|
51
|
+
aws kms encrypt --key-id $YOUR_KMS_KEY_ID --plaintext fileb://YOUR_FILE.json --output text --query CiphertextBlob | base64 --decode > YOUR_FILE.json.encrypted
|
52
|
+
```
|
53
|
+
|
54
|
+
After that, upload it to your S3 and copy the reference in your JSON.
|
55
|
+
|
56
|
+
### Usage example
|
57
|
+
|
58
|
+
First, set the AWS credentials needed for accesing the S3 bucket and decrypting files.
|
59
|
+
|
60
|
+
**Ruby example code:**
|
61
|
+
|
62
|
+
```
|
63
|
+
#!/usr/bin/env ruby
|
64
|
+
|
65
|
+
require 'bundler/setup'
|
66
|
+
require 'secrets_parser'
|
67
|
+
require 'aws-sdk-s3'
|
68
|
+
|
69
|
+
file_json = './app.json' #Path to your json file to be parsed, now using the described in the example
|
70
|
+
field_to_parse = 'variables' # Field to parse
|
71
|
+
|
72
|
+
parser = Secrets::Parser.new
|
73
|
+
parser.set_config do |config|
|
74
|
+
config[:s3_client] = Aws::S3::Client.new(region: ENV['AWS_DEFAULT_REGION'])
|
75
|
+
config[:kms_client] = Aws::KMS::Client.new(region: ENV['AWS_DEFAULT_REGION'])
|
76
|
+
end
|
77
|
+
|
78
|
+
parsed_file = parser.parse(file_json, field_to_parse)
|
79
|
+
|
80
|
+
puts JSON.pretty_generate(parsed_file)
|
81
|
+
|
82
|
+
```
|
83
|
+
|
84
|
+
**Output:**
|
85
|
+
|
86
|
+
```
|
87
|
+
{
|
88
|
+
"variables": {
|
89
|
+
"my_secret": "This is a secret weeee",
|
90
|
+
"other_secret": "PINCODE: 12345"
|
91
|
+
}
|
92
|
+
}
|
93
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Secrets
|
2
|
+
module Helpers
|
3
|
+
def self.expand_param_from_env(value)
|
4
|
+
dollar_match_expression = /\$([A-Za-z0-9_]*)/
|
5
|
+
value.scan(dollar_match_expression).each do |match|
|
6
|
+
break unless ENV.include? match[0]
|
7
|
+
value = value.gsub("$#{match[0]}", ENV[match[0]])
|
8
|
+
end
|
9
|
+
value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'aws-sdk-s3'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module Secrets
|
6
|
+
class Parser
|
7
|
+
SECRETS_FILE_SUFFIX = '.json.encrypted'.freeze
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@config = {
|
11
|
+
s3_client: nil,
|
12
|
+
kms_client: nil
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_config
|
17
|
+
yield @config
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse(file_to_parse, field_to_parse)
|
21
|
+
Aws.config.update(
|
22
|
+
region: ENV['AWS_DEFAULT_REGION']
|
23
|
+
)
|
24
|
+
|
25
|
+
app_json = JSON.parse(IO.read(file_to_parse))
|
26
|
+
app_variables = app_json[field_to_parse]
|
27
|
+
|
28
|
+
app_json[field_to_parse] = parse_secrets_from app_variables
|
29
|
+
|
30
|
+
app_json
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def secret?(string)
|
36
|
+
if string.is_a? String
|
37
|
+
string.start_with? 'secret:'
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def secret_file_path_from(secret)
|
44
|
+
secret_file_path = secret[secret.index(':') + 1..secret.rindex(':') - 1]
|
45
|
+
Helpers.expand_param_from_env secret_file_path
|
46
|
+
end
|
47
|
+
|
48
|
+
def secret_key_from(secret)
|
49
|
+
secret[secret.rindex(':') + 1..secret.length]
|
50
|
+
end
|
51
|
+
|
52
|
+
def download(file)
|
53
|
+
bucket_name = file[0, file.index('/')]
|
54
|
+
file = file[file.index('/') + 1..file.length] + SECRETS_FILE_SUFFIX
|
55
|
+
tmp_file = "/tmp/secrets#{SECRETS_FILE_SUFFIX}"
|
56
|
+
|
57
|
+
File.open(tmp_file, 'wb') do |secret_file|
|
58
|
+
@config[:s3_client].get_object({ bucket: bucket_name, key: file }, target: secret_file)
|
59
|
+
end
|
60
|
+
|
61
|
+
tmp_file
|
62
|
+
end
|
63
|
+
|
64
|
+
def decrypt(file)
|
65
|
+
kms = @config[:kms_client]
|
66
|
+
|
67
|
+
kms.decrypt(
|
68
|
+
ciphertext_blob: IO.read(file)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def extract_secrets_from(secret_file)
|
73
|
+
encrypted_secrets_file = download secret_file
|
74
|
+
decrypted_secrets_file = decrypt encrypted_secrets_file
|
75
|
+
|
76
|
+
JSON.parse(decrypted_secrets_file.plaintext)
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_secrets_from(variables)
|
80
|
+
secret_variables = {}
|
81
|
+
|
82
|
+
variables.each_pair do |k, v|
|
83
|
+
next unless secret? v
|
84
|
+
|
85
|
+
secret = v
|
86
|
+
|
87
|
+
secret_file = secret_file_path_from(secret)
|
88
|
+
secret_key = secret_key_from(secret)
|
89
|
+
|
90
|
+
unless secret_variables.key? secret_file
|
91
|
+
secret_variables[secret_file] = extract_secrets_from secret_file
|
92
|
+
end
|
93
|
+
|
94
|
+
variables[k] = secret_variables[secret_file][secret_key]
|
95
|
+
end
|
96
|
+
|
97
|
+
variables
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'secrets_parser/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'secrets_parser'
|
7
|
+
spec.version = SecretsParser::VERSION
|
8
|
+
spec.license = 'MIT'
|
9
|
+
spec.authors = ['Paco Sanchez']
|
10
|
+
spec.email = ['sanchezpaco@users.noreply.github.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Write a short summary, because RubyGems requires one.}
|
13
|
+
spec.description = %q{Write a longer description or delete this line.}
|
14
|
+
spec.homepage = 'https://github.com/peertransfer/secrets_parser'
|
15
|
+
|
16
|
+
if spec.respond_to?(:metadata)
|
17
|
+
#spec.metadata['allowed_push_host'] = 'https://travis-ci.org/'
|
18
|
+
else
|
19
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
20
|
+
'public gem pushes.'
|
21
|
+
end
|
22
|
+
|
23
|
+
files = Dir['lib/**/*.rb', 'bin/*']
|
24
|
+
rootfiles = ['Gemfile', 'secrets_parser.gemspec', 'README.md', 'Rakefile', 'CODE_OF_CONDUCT.md']
|
25
|
+
dotfiles = []
|
26
|
+
spec.files = files + rootfiles + dotfiles
|
27
|
+
|
28
|
+
spec.bindir = 'bin'
|
29
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ['lib']
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: secrets_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paco Sanchez
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Write a longer description or delete this line.
|
56
|
+
email:
|
57
|
+
- sanchezpaco@users.noreply.github.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- CODE_OF_CONDUCT.md
|
63
|
+
- Gemfile
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/secrets_parser.rb
|
67
|
+
- lib/secrets_parser/helpers.rb
|
68
|
+
- lib/secrets_parser/parser.rb
|
69
|
+
- lib/secrets_parser/version.rb
|
70
|
+
- secrets_parser.gemspec
|
71
|
+
homepage: https://github.com/peertransfer/secrets_parser
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.5.1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Write a short summary, because RubyGems requires one.
|
95
|
+
test_files: []
|