kms-tools 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36135cba337e0583f02134a249daf299dea7ec5f
4
+ data.tar.gz: 06877816b0f9bab9a09034271c5fe2e0584c9ade
5
+ SHA512:
6
+ metadata.gz: 67c1df3ef40a95e59d1331e5628232b32ae51fe9261990f268114553eebc5b20f9c0ae47f5d2afb42b7daa2088311145633bbfb678cb2a913e7e170670db0a6a
7
+ data.tar.gz: 00083083afa0d09b9b79e71672957a36a4f6fdeacb02ec9fefbe8104a9b1a2b8ec25d6605c044a907eea2e60ce519e015ea033a5be6ab8c751a41ccb5f0055e1
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ Gemfile.lock
2
+ .DS_Store
3
+ .idea
4
+ .yardoc
5
+ doc
6
+ .rspec
7
+ spec/examples.txt
data/.octopolo.yml ADDED
@@ -0,0 +1,4 @@
1
+ github_repo: sportngin/kms-tools
2
+ semantic_versioning: true
3
+ branches_to_keep:
4
+ - master
data/.soyuz.yml ADDED
@@ -0,0 +1,13 @@
1
+ defaults:
2
+ deploy_cmd: gem push *.gem
3
+ before_deploy_cmds:
4
+ - /usr/local/bin/op tag-release
5
+ - sed -i "" -e "s/\".*/\"$(git tag| sort -n -t. -k1,1 -k2,2 -k3,3 | tail -1 | sed s/v//)\"/" lib/kms-tools/version.rb
6
+ - git add lib/kms-tools/version.rb
7
+ - git commit -m "Version Bump" && git push
8
+ - gem build kms-tools.gemspec
9
+ after_deploy_cmds:
10
+ - rm *.gem
11
+ environments:
12
+ -
13
+ rubygems: {}
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 2.0
5
+ - 2.1
6
+ - 2.2
7
+ script: bundle exec rspec
8
+
9
+ branches:
10
+ only:
11
+ - master
@@ -0,0 +1,7 @@
1
+ #### v0.0.1
2
+ #### v0.0.1
3
+ #### 0.0.2
4
+ #### 0.0.1
5
+ #### 0.0.1
6
+ #### 0.1.1
7
+ #### 0.1.0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ ## KmsTools
2
+
3
+ [![Build Status](https://travis-ci.com/sportngin/kms-tools.svg?token=CZhBgnU2zo8LVq9DDxQf&branch=master)](https://travis-ci.com/sportngin/kms-tools)
4
+
5
+ A simplified toolset for encrypting and decrypting data using [Amazon Key Management Service](https://aws.amazon.com/kms/). Since credentials are managed by the [AWS SDK](https://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs), you can use a local credentials file for the CLI and rely on IAM roles to provide access for applications running on AWS instances. This completely removes the need to manage plaintext secret keys even for locally encrypted and decrypted data.
6
+
7
+ ### Local Encryption
8
+ Per the KMS spec, data up to 4KB may be encryptyed with a simple `encrypt` call. Larger blobs of data must be locally encrypted using data keys. KmsTools facilitates this by generating two data keys for each blob encrypted. One is used as the symmetric secret key and the other used as the initialization vector. These two keys are encrypted and then stored along side the encrypted data for later use.
9
+
10
+ Standard lib OpenSSL is used for local encryption. While any block cipher compiled in to OpenSSL can be used for local encryption, it is important to note that the same cipher must be available on any machine attempting to decrypt the same data. So it is recommended to use commonly available ciphers. `aes-256-cbc` is the default.
11
+
12
+ ### .kms Filetype
13
+ To make storage and recall of encryption metadata easier, the `.kms` filetype was developed. This filetype is used when storing encrypted files with the CLI and by default when using [KmsTools::EncryptedFile](https://github.com/sportngin/kms-tools/blob/master/lib/kms-tools/encrypted_file.rb "KmsTools::EncryptedFile"). `.kms` files are a digital envelope made up of 3 specific parts:
14
+ 1. A zero-padded 7 byte integer noting total length of metadata stored
15
+ 2. YAML encoded metadata
16
+ 3. Encrypted binary data
17
+ ```
18
+ meta-length metadata encrypted binary data
19
+ INT YAML BIN
20
+ |-----------|----------------------|---------------------------------------------------------|
21
+ ```
22
+
23
+ While an arbitrary number of metadata elements can be stored as needed, there are a few standard elements
24
+ * OpenSSL cipher used for encryption `required`
25
+ * Encrypted encryption key (decypted with KMS prior to using) `required`
26
+ * Encrypted initialization vector (decypted with KMS prior to using) `required`
27
+ * Original file extension `required`
28
+ * Original data checksum `required`
29
+ * KMS Master Key ARN (Optional but there by default for troubleshooting)
30
+
31
+
32
+ ### CLI
33
+ The CLI exposes most of the functionality of the gem in a simple interface.
34
+
35
+ >Keep in mind that the gem uses standard AWS credential management. So if you are using the CLI on a server without a credentials file in place, all activity will be logged in CloudTrail as the role instead of the user taking action. For this reason it is highly recommended that you run some sort of IDS on instances using roles that have access to KMS to ensure that all KMS activity is properly logged.
36
+
37
+ ```
38
+ NAME
39
+ kms-tools - CLI for encrypting and decrypting information with Amazon KMS
40
+
41
+ SYNOPSIS
42
+ kms-tools [global options] command [command options] [arguments...]
43
+
44
+ VERSION
45
+ 0.0.1
46
+
47
+ GLOBAL OPTIONS
48
+ --[no-]color - Colorize output (default: enabled)
49
+ -d, --debug - Debug output (Includes verbose)
50
+ --help - Show this message
51
+ -k, --master_key=arg - Encrypt using the specified key alias or key id as the customer master key (default: none)
52
+ -p, --profile=arg - AWS credentials profile to use (default: default)
53
+ -r, --region=arg - AWS Region (default: us-east-1)
54
+ -v, --verbose - Verbose output
55
+ --version - Display the program version
56
+
57
+ COMMANDS
58
+ decrypt - Decrypt a text string or a file
59
+ encrypt - Encrypt a text string or a file
60
+ help - Shows a list of commands or help for one command
61
+ list-aliases - List KMS key aliases available to current credentials
62
+ ```
63
+
64
+ Example string encryption/decryption:
65
+ ```
66
+ [~/sportngin/kms-tools] (master)$ bundle exec bin/kms-tools encrypt "something secret"
67
+ Choose which key alias to use as the base Customer Master Key:
68
+ 1. alias/staging/kms-tools1
69
+ 2. alias/staging/kms-tools2
70
+ 3. alias/staging/vpn
71
+ ? 1
72
+ Encrypted ciphertext (copy all text without surrounding whitespace):
73
+
74
+ CiAA6CYSKxFRMav+m01ps0d8V5PrVvbPebe2L7LNbrV7NBKXAQEBAgB4AOgmEisRUTGr/ptNabNHfFeT61b2z3m3ti+yzW61ezQAAABuMGwGCSqGSIb3DQEHBqBfMF0CAQAwWAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAwFjvAk2NeDhOGxlUUCARCAK1hO8B+M6RWjiQckqI4RlGnP8mI/gePSfERHcD0KgwvJwhiPP8z+p0m2TkY=
75
+
76
+
77
+ [~/sportngin/kms-tools] (master)$ bundle exec bin/kms-tools decrypt CiAA6CYSKxFRMav+m01ps0d8V5PrVvbPebe2L7LNbrV7NBKXAQEBAgB4AOgmEisRUTGr/ptNabNHfFeT61b2z3m3ti+yzW61ezQAAABuMGwGCSqGSIb3DQEHBqBfMF0CAQAwWAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAwFjvAk2NeDhOGxlUUCARCAK1hO8B+M6RWjiQckqI4RlGnP8mI/gePSfERHcD0KgwvJwhiPP8z+p0m2TkY=
78
+ Decrypted string:
79
+
80
+ something secret
81
+
82
+
83
+ [~/sportngin/kms-tools] (master)$
84
+ ```
85
+
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+ Rake::RDocTask.new do |rd|
6
+ rd.main = "README.rdoc"
7
+ rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
8
+ rd.title = 'KMS Tools'
9
+ end
10
+
11
+ spec = eval(File.read('kms-tools.gemspec'))
12
+
13
+ Gem::PackageTask.new(spec) do |pkg|
14
+ end
data/bin/kms-tools ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'kms-cli'
4
+
5
+ include GLI::App
6
+
7
+ program_desc 'CLI for encrypting and decrypting information with Amazon KMS'
8
+
9
+ version KmsTools::VERSION
10
+
11
+ subcommand_option_handling :normal
12
+ arguments :strict
13
+
14
+ switch [:v,:verbose], :desc => 'Verbose output', :negatable => false
15
+ switch [:d,:debug], :desc => 'Debug output (Includes verbose)', :negatable => false
16
+ switch [:color], :desc => 'Colorize output', :default_value => true
17
+ flag [:r,:region], :desc => 'AWS Region', :default_value => 'us-east-1'
18
+ flag [:p,:profile], :desc => 'AWS credentials profile to use', :default_value => 'default'
19
+ flag [:k,:master_key], :desc => 'Encrypt using the specified key alias or key id as the customer master key'
20
+
21
+ # Load all the command files
22
+ commands_from '../lib/kms-tools/cli/commands'
23
+
24
+ pre do |global,command,options,args|
25
+ #KmsTools::VerifyAwsConfig.new
26
+ $verbose = global[:verbose] || global[:debug]
27
+ $debug = global[:debug]
28
+ $color = global[:color]
29
+ true
30
+ end
31
+
32
+ post do |global,command,options,args|
33
+ # Post logic here
34
+ # Use skips_post before a command to skip this
35
+ # block on that command only
36
+ end
37
+
38
+ on_error do |exception|
39
+ # Error logic here
40
+ # return false to skip default error handling
41
+ true
42
+ end
43
+
44
+ exit run(ARGV)
data/kms-tools.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # Ensure we require the local version and not one we might have installed already
2
+ require './lib/kms-tools/version'
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'kms-tools'
5
+ s.version = KmsTools::VERSION
6
+ s.author = 'Matt Krieger'
7
+ s.email = 'matt.krieger@sportngin.com'
8
+ s.homepage = 'http://www.sportngin.com'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'CLI for encrypting and decrypting data using Amazon KMS'
11
+ s.files = `git ls-files`.split("
12
+ ")
13
+ s.require_paths << 'lib'
14
+ s.has_rdoc = 'yard'
15
+ s.bindir = 'bin'
16
+ s.executables << 'kms-tools'
17
+
18
+ s.add_dependency 'aws-sdk'
19
+ s.add_dependency "highline"
20
+ s.add_dependency "hashdiff"
21
+
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'yard'
24
+ s.add_development_dependency 'rspec-core'
25
+ s.add_development_dependency 'rspec-expectations'
26
+ s.add_development_dependency 'rspec-mocks'
27
+
28
+ s.add_runtime_dependency "gli", "~>2.13.4"
29
+ end
data/lib/kms-cli.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'kms-tools'
2
+ Dir[File.dirname(__FILE__) + '/kms-tools/cli/*.rb'].each {|file| require file }
data/lib/kms-tools.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'aws-sdk'
2
+ Dir[File.dirname(__FILE__) + '/kms-tools/*.rb'].each {|file| require file }
3
+
4
+ # Chunk size to use when processing streams
5
+ STREAM_CHUNK_SIZE = 1048576
@@ -0,0 +1,88 @@
1
+ module KmsTools
2
+ ##
3
+ # Helper class for {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Client.html Aws::KMS::Client}.
4
+ class Base
5
+ # Default region if nothing is provided because we all use N. Virginia, don't we?
6
+ DEFAULT_REGION = 'us-east-1'
7
+
8
+ # Customer master key used for ann encryption operations
9
+ attr_accessor :master_key
10
+
11
+ # InstantiatedAws::KMS::Client object
12
+ attr_reader :kms
13
+
14
+ ##
15
+ # Instantiates a {http://docs.aws.amazon.com/sdkforruby/api/Aws/KMS/Client.html Aws::KMS::Client} object with provided options.
16
+ #
17
+ # @param [Hash] options
18
+ # @option options [String] :master_key Customer Master Key to use when instantiating the object, this can be a full key ID, an alias, or an ARN
19
+ # @option options [String] :region Set the region for Aws::KMS::Client to use. Defaults to +DEFAULT_REGION+
20
+ # @option options [String] :profile Use the specified profile from an AWS credentials file
21
+ #
22
+ def initialize(options = {})
23
+ @master_key = options[:master_key]
24
+ @region = options[:region]
25
+ @profile = options[:profile]
26
+
27
+ @kms = Aws::KMS::Client.new({
28
+ :region => region,
29
+ :profile => @profile,
30
+ })
31
+ end
32
+
33
+ # Lists all master key aliases available to the current client (Ignores built-aws keys that should not be used by user code).
34
+ # @return [Array]
35
+ def available_aliases
36
+ aliases = kms.list_aliases.aliases.delete_if { |a| a.alias_name.include? "alias/aws/"}
37
+ aliases.map{ |a| a.alias_name }
38
+ end
39
+
40
+ # Key ARN of the currently selected master key
41
+ # @return [String] key ARN
42
+ def master_key_arn
43
+ master_key ? kms.describe_key({:key_id => master_key}).key_metadata.arn : nil
44
+ end
45
+
46
+ # Returns the key ID of the currently selected master key
47
+ # @return [String] key id
48
+ def master_key_id
49
+ master_key ? kms.describe_key({:key_id => master_key}).key_metadata.key_id : nil
50
+ end
51
+
52
+ # Sets the current master key using a key alias. Verifies that the provided key is available prior to setting.
53
+ # @param key_alias [String] Key alias to use, must be available with current credentials/role
54
+ # @return [String]
55
+ def use_key_alias=(key_alias)
56
+ if available_aliases.include? key_alias
57
+ @master_key = key_alias
58
+ else
59
+ raise "Requested key alias not available with current credentials!"
60
+ end
61
+ end
62
+
63
+ # Current client region
64
+ # @return [String]
65
+ def region
66
+ @region ||= DEFAULT_REGION
67
+ end
68
+
69
+ # Short function to encode a blob to Base64
70
+ # @return [String] Base64 encoded string
71
+ def to_64(blob)
72
+ Base64.encode64(blob)
73
+ end
74
+
75
+ # Short function to strict encode a blob to Base64
76
+ # @return [String] Base64 encoded string without linebreaks
77
+ def to_s64(blob)
78
+ Base64.strict_encode64(blob)
79
+ end
80
+
81
+ # Short function to decode a blob from Base64
82
+ # @return [String] blob
83
+ def from_64(blob)
84
+ Base64.decode64(blob)
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,15 @@
1
+ desc 'Decrypt a text string or a file'
2
+
3
+ long_desc %{
4
+ Decrypt a text string or a file.
5
+
6
+ If an argument is not given, stdin will be used.
7
+ }
8
+
9
+ arg_name '[plaintext | path]'
10
+ command 'decrypt' do |c|
11
+ c.action do |global_options,options,args|
12
+ input = args.first || STDIN.read
13
+ KmsTools::CLI::Decrypt.new(global_options, options).decrypt(input)
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ desc "Encrypt a text string or a file."
2
+
3
+ long_desc %{
4
+ Encrypt a text string or a file.
5
+
6
+ If an argument is not given, stdin will be encrypted with the specified key.
7
+ }
8
+
9
+ arg_name '[plaintext]'
10
+ command 'encrypt' do |c|
11
+ c.flag ['data-key'], :desc => "Encrypt data with the specified encrypted data key. If a path is provided, the key will be read from that file.\n\nNOTE: Data keys are required to encrypt more than 4KB of data."
12
+ c.action do |global_options,options,args|
13
+ input = args.first || STDIN.read
14
+ KmsTools::CLI::Encrypt.new(global_options, options).encrypt(input)
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ desc 'List KMS key aliases available to current credentials'
2
+ command 'list-aliases' do |c|
3
+ c.action do |global_options,options,args|
4
+ num = 0
5
+ KmsTools::Base.new(
6
+ { region: global_options[:region],
7
+ profile: global_options[:profile]
8
+ }
9
+ ).available_aliases.each do |a|
10
+ puts "#{num += 1}. #{a}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,55 @@
1
+ module KmsTools
2
+ module CLI
3
+ # Class for handling decrypt operations from the CLI
4
+ class Decrypt
5
+
6
+ # Set up decryption handler
7
+ #
8
+ # @param [Hash] global_options
9
+ # @option global_options [String] :master_key Master key to use if provided by CLI options
10
+ # @option global_options [String] :profile AWS credential profile to us if provided by CLI options
11
+ # @option global_options [String] :region AWS region to use if provided by CLI options
12
+ def initialize(global_options, options)
13
+ @dec = KmsTools::Decrypter.new(global_options)
14
+ @output = options[:output]
15
+ end
16
+
17
+ # Handle decrypt command
18
+ #
19
+ # @param [String] source Encrypted source to decrypt. Can be a string for direct decryption or a path to a KMS file to decrypt
20
+ # @return [String] Returns plaintext if Base64 encoded ciphertext is provided
21
+ # @return [String] Returns path to decrypted file if a source path is provided
22
+ def decrypt(source)
23
+ if File.file?(source)
24
+ save_path = decrypt_file(source)
25
+ Output.say("Decrypted file saved to: #{save_path}")
26
+ elsif source.is_a?(String)
27
+ decrypted_response = @dec.decrypt_string(source)
28
+ if STDIN.tty?
29
+ Output.say("Decrypted string:\n\n#{decrypted_response}\n\n")
30
+ else
31
+ print decrypted_response
32
+ end
33
+ else
34
+ raise "Unknown input to encrypt..."
35
+ end
36
+ source = nil
37
+ end
38
+
39
+ # Decrypt a file from source path
40
+ #
41
+ # @param [String] source path to file to decrypt
42
+ # @return [String] path to decrypted file
43
+ def decrypt_file(source)
44
+ ef = KmsTools::EncryptedFile.new(path: source)
45
+ save_path = Helpers::get_save_path({
46
+ :prompt => "Save decrytped file to",
47
+ :suggested_path => File.absolute_path(source.sub File.extname(source), ef.original_extension)
48
+ })
49
+ ef.save_decrypted(save_path)
50
+ save_path
51
+ end
52
+
53
+ end
54
+ end
55
+ end