s3-secure 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +3 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +89 -0
  7. data/Guardfile +19 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +56 -0
  10. data/Rakefile +14 -0
  11. data/exe/s3-secure +14 -0
  12. data/lib/s3-secure.rb +1 -0
  13. data/lib/s3_secure.rb +14 -0
  14. data/lib/s3_secure/abstract_base.rb +17 -0
  15. data/lib/s3_secure/autoloader.rb +27 -0
  16. data/lib/s3_secure/aws_services.rb +36 -0
  17. data/lib/s3_secure/batch.rb +25 -0
  18. data/lib/s3_secure/cli.rb +37 -0
  19. data/lib/s3_secure/command.rb +82 -0
  20. data/lib/s3_secure/completer.rb +159 -0
  21. data/lib/s3_secure/completer/script.rb +6 -0
  22. data/lib/s3_secure/completer/script.sh +10 -0
  23. data/lib/s3_secure/encryption.rb +27 -0
  24. data/lib/s3_secure/encryption/base.rb +4 -0
  25. data/lib/s3_secure/encryption/disable.rb +18 -0
  26. data/lib/s3_secure/encryption/enable.rb +42 -0
  27. data/lib/s3_secure/encryption/list.rb +28 -0
  28. data/lib/s3_secure/encryption/show.rb +18 -0
  29. data/lib/s3_secure/help.rb +9 -0
  30. data/lib/s3_secure/help/completion.md +20 -0
  31. data/lib/s3_secure/help/completion_script.md +3 -0
  32. data/lib/s3_secure/help/hello.md +5 -0
  33. data/lib/s3_secure/policy.rb +27 -0
  34. data/lib/s3_secure/policy/base.rb +4 -0
  35. data/lib/s3_secure/policy/checker.rb +15 -0
  36. data/lib/s3_secure/policy/document.rb +27 -0
  37. data/lib/s3_secure/policy/document/base.rb +15 -0
  38. data/lib/s3_secure/policy/document/force_ssl_only_access.rb +33 -0
  39. data/lib/s3_secure/policy/document/force_ssl_only_access_remove.rb +33 -0
  40. data/lib/s3_secure/policy/enforce.rb +36 -0
  41. data/lib/s3_secure/policy/list.rb +29 -0
  42. data/lib/s3_secure/policy/show.rb +19 -0
  43. data/lib/s3_secure/policy/unforce.rb +41 -0
  44. data/lib/s3_secure/version.rb +3 -0
  45. data/s3-secure.gemspec +33 -0
  46. data/spec/lib/cli_spec.rb +12 -0
  47. data/spec/lib/policy/checker_spec.rb +68 -0
  48. data/spec/lib/policy/document/force_ssl_remove_spec.rb +107 -0
  49. data/spec/lib/policy/document_spec.rb +68 -0
  50. data/spec/spec_helper.rb +29 -0
  51. metadata +252 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0ac426bde14db38fecbc1d692dc5c79ddd4078da837d9b6d389752fdb96d5805
4
+ data.tar.gz: 2f8a8aaf36996722a23c4b0afd95ff05936ed12e4c1e384f9594cd4b22cc4054
5
+ SHA512:
6
+ metadata.gz: c0ff5d52734ae470d203b43c19fff7c87924709b15cb5f86420faa2886a4e43bc4ead66cd531fd9a98dcb480143db2286a9c58af8d3be1e4357966d357c78ac4
7
+ data.tar.gz: 95ca0ef971df08986f2dfb7b9fd6bcec8d1097d44fb38fc999d456e6863f0a7ba28767824a9c203c4c9f78c81b9074f16811f762efc8fc3276ec25f2e4bdcf93
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ _yardoc
7
+ coverage
8
+ doc/
9
+ InstalledFiles
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --color
3
+ --format documentation
@@ -0,0 +1,7 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
+
6
+ ## [0.1.0]
7
+ - Initial release.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem dependencies in s3-secure.gemspec
4
+ gemspec
5
+
6
+ gem "codeclimate-test-reporter", group: :test, require: nil
@@ -0,0 +1,89 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ s3-secure (0.1.0)
5
+ activesupport
6
+ aws-sdk-s3
7
+ memoist
8
+ rainbow
9
+ thor
10
+ zeitwerk
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activesupport (6.0.1)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ zeitwerk (~> 2.2)
21
+ aws-eventstream (1.0.3)
22
+ aws-partitions (1.240.0)
23
+ aws-sdk-core (3.78.0)
24
+ aws-eventstream (~> 1.0, >= 1.0.2)
25
+ aws-partitions (~> 1, >= 1.239.0)
26
+ aws-sigv4 (~> 1.1)
27
+ jmespath (~> 1.0)
28
+ aws-sdk-kms (1.25.0)
29
+ aws-sdk-core (~> 3, >= 3.71.0)
30
+ aws-sigv4 (~> 1.1)
31
+ aws-sdk-s3 (1.56.0)
32
+ aws-sdk-core (~> 3, >= 3.77.0)
33
+ aws-sdk-kms (~> 1)
34
+ aws-sigv4 (~> 1.1)
35
+ aws-sigv4 (1.1.0)
36
+ aws-eventstream (~> 1.0, >= 1.0.2)
37
+ byebug (11.0.1)
38
+ cli_markdown (0.1.0)
39
+ codeclimate-test-reporter (1.0.9)
40
+ simplecov (<= 0.13)
41
+ concurrent-ruby (1.1.5)
42
+ diff-lcs (1.3)
43
+ docile (1.1.5)
44
+ i18n (1.7.0)
45
+ concurrent-ruby (~> 1.0)
46
+ jmespath (1.4.0)
47
+ json (2.2.0)
48
+ memoist (0.16.1)
49
+ minitest (5.13.0)
50
+ rainbow (3.0.0)
51
+ rake (13.0.1)
52
+ rspec (3.9.0)
53
+ rspec-core (~> 3.9.0)
54
+ rspec-expectations (~> 3.9.0)
55
+ rspec-mocks (~> 3.9.0)
56
+ rspec-core (3.9.0)
57
+ rspec-support (~> 3.9.0)
58
+ rspec-expectations (3.9.0)
59
+ diff-lcs (>= 1.2.0, < 2.0)
60
+ rspec-support (~> 3.9.0)
61
+ rspec-mocks (3.9.0)
62
+ diff-lcs (>= 1.2.0, < 2.0)
63
+ rspec-support (~> 3.9.0)
64
+ rspec-support (3.9.0)
65
+ simplecov (0.13.0)
66
+ docile (~> 1.1.0)
67
+ json (>= 1.8, < 3)
68
+ simplecov-html (~> 0.10.0)
69
+ simplecov-html (0.10.2)
70
+ thor (0.20.3)
71
+ thread_safe (0.3.6)
72
+ tzinfo (1.2.5)
73
+ thread_safe (~> 0.1)
74
+ zeitwerk (2.2.1)
75
+
76
+ PLATFORMS
77
+ ruby
78
+
79
+ DEPENDENCIES
80
+ bundler
81
+ byebug
82
+ cli_markdown
83
+ codeclimate-test-reporter
84
+ rake
85
+ rspec
86
+ s3-secure!
87
+
88
+ BUNDLED WITH
89
+ 2.0.2
@@ -0,0 +1,19 @@
1
+ guard "bundler", cmd: "bundle" do
2
+ watch("Gemfile")
3
+ watch(/^.+\.gemspec/)
4
+ end
5
+
6
+ guard :rspec, cmd: "bundle exec rspec" do
7
+ require "guard/rspec/dsl"
8
+ dsl = Guard::RSpec::Dsl.new(self)
9
+
10
+ # RSpec files
11
+ rspec = dsl.rspec
12
+ watch(rspec.spec_helper) { rspec.spec_dir }
13
+ watch(rspec.spec_support) { rspec.spec_dir }
14
+ watch(rspec.spec_files)
15
+
16
+ # Ruby files
17
+ ruby = dsl.ruby
18
+ dsl.watch_spec_files_for(ruby.lib_files)
19
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2019 Tung Nguyen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ # s3-secure
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/s3-secure.png)](http://badge.fury.io/rb/s3-secure)
4
+
5
+ [![BoltOps Badge](https://img.boltops.com/boltops/badges/boltops-badge.png)](https://www.boltops.com)
6
+
7
+ The s3-secure tool can be used to harden your s3 bucket security posture. The tool is useful if you have a lot of buckets to update. It supports:
8
+
9
+ * enabling encryption
10
+ * adding an enforce ssl bucket policy
11
+
12
+ ## Usage
13
+
14
+ Summary of encryption commands:
15
+
16
+ s3-secure encryption list
17
+ s3-secure encryption show BUCKET
18
+ s3-secure encryption enable BUCKET
19
+ s3-secure encryption disable BUCKET
20
+
21
+ Summary of policy commands:
22
+
23
+ s3-secure policy list
24
+ s3-secure policy show BUCKET
25
+ s3-secure policy enforce_ssl BUCKET
26
+ s3-secure policy unforce_ssl BUCKET
27
+
28
+ ## Batch Commands
29
+
30
+ There are some supported batch commands:
31
+
32
+ s3-secure batch encryption enable FILE.txt
33
+ s3-secure batch encryption disable FILE.txt
34
+ s3-secure batch policy enforce_ssl FILE.txt
35
+ s3-secure batch policy unforce_ssl FILE.txt
36
+
37
+ The format of FILE.txt is a list of bucket names separated by newlines. Example:
38
+
39
+ buckets.txt:
40
+
41
+ my-bucket-1
42
+ my-bucket-2
43
+
44
+ ## Installation
45
+
46
+ Install with the `gem` command:
47
+
48
+ gem install s3-secure
49
+
50
+ ## Contributing
51
+
52
+ 1. Fork it
53
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
54
+ 3. Commit your changes (`git commit -am "Add some feature"`)
55
+ 4. Push to the branch (`git push origin my-new-feature`)
56
+ 5. Create new Pull Request
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task default: :spec
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ require_relative "lib/s3-secure"
9
+ require "cli_markdown"
10
+ desc "Generates cli reference docs as markdown"
11
+ task :docs do
12
+ mkdir_p "docs/_includes"
13
+ CliMarkdown::Creator.create_all(cli_class: S3Secure::CLI, cli_name: "s3-secure")
14
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Trap ^C
4
+ Signal.trap("INT") {
5
+ puts "\nCtrl-C detected. Exiting..."
6
+ sleep 0.1
7
+ exit
8
+ }
9
+
10
+ $:.unshift(File.expand_path("../../lib", __FILE__))
11
+ require "s3-secure"
12
+ require "s3_secure/cli"
13
+
14
+ S3Secure::CLI.start(ARGV)
@@ -0,0 +1 @@
1
+ require_relative "s3_secure"
@@ -0,0 +1,14 @@
1
+ $:.unshift(File.expand_path("../", __FILE__))
2
+ require "json"
3
+ require "memoist"
4
+ require "rainbow/ext/string"
5
+ require "s3_secure/version"
6
+ require "active_support/core_ext/module" # for delegate
7
+ require "active_support/core_ext/string"
8
+
9
+ require "s3_secure/autoloader"
10
+ S3Secure::Autoloader.setup
11
+
12
+ module S3Secure
13
+ class Error < StandardError; end
14
+ end
@@ -0,0 +1,17 @@
1
+ module S3Secure
2
+ class AbstractBase
3
+ include S3Secure::AwsServices
4
+ extend Memoist
5
+
6
+ def initialize(options={})
7
+ @options = options
8
+ @bucket = options[:bucket] # not set on the list command but common enough to set here
9
+ end
10
+
11
+ def buckets
12
+ resp = s3_client.list_buckets
13
+ resp.buckets.map(&:name)
14
+ end
15
+ memoize :buckets
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ require "zeitwerk"
2
+
3
+ module S3Secure
4
+ class Autoloader
5
+ class Inflector < Zeitwerk::Inflector
6
+ def camelize(basename, _abspath)
7
+ map = {
8
+ cli: "CLI",
9
+ force_ssl_only_access: "ForceSSLOnlyAccess",
10
+ force_ssl_only_access_remove: "ForceSSLOnlyAccessRemove",
11
+ version: "VERSION",
12
+ }
13
+ map[basename.to_sym] || super
14
+ end
15
+ end
16
+
17
+ class << self
18
+ def setup
19
+ loader = Zeitwerk::Loader.new
20
+ loader.inflector = Inflector.new
21
+ loader.push_dir(File.dirname(__dir__)) # lib
22
+ loader.ignore("#{File.dirname(__dir__)}/s3-secure.rb")
23
+ loader.setup
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require "aws-sdk-s3"
2
+
3
+ module S3Secure
4
+ module AwsServices
5
+ extend Memoist
6
+
7
+ @@buckets = {} # holds bucket => region map
8
+ def s3_regional_client(bucket)
9
+ region = @@buckets[bucket]
10
+
11
+ unless region
12
+ resp = s3_client.get_bucket_location(bucket: bucket)
13
+ region = resp.location_constraint
14
+ region = 'us-east-1' if region.empty? # "" means us-east-1
15
+ end
16
+
17
+ new_s3_regional_client(region)
18
+ end
19
+
20
+ def new_s3_regional_client(region=nil)
21
+ options = {}
22
+ options[:endpoint] = "https://s3.#{region}.amazonaws.com" if region
23
+ options[:region] = region if region
24
+ Aws::S3::Client.new(options)
25
+ end
26
+ memoize :new_s3_regional_client
27
+
28
+ # Generic s3 client. Will be configured to whatever region user has locally configured in ~/.aws/config
29
+ # Used to call get_bucket_location to get each specific bucket's location.
30
+ # Generally use the s3_regional_client instead of this.
31
+ def s3_client
32
+ Aws::S3::Client.new
33
+ end
34
+ memoize :s3_client
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ module S3Secure
2
+ class Batch
3
+ extend Memoist
4
+
5
+ def initialize(*params)
6
+ @params = params
7
+ @command, @subcommand, @file = params
8
+ end
9
+
10
+ def run
11
+ buckets.each do |bucket|
12
+ args = @params
13
+ args.pop
14
+ args << bucket
15
+ puts "Running: s3-secure #{args.join(' ')}".color(:green)
16
+ S3Secure::CLI.start(args)
17
+ end
18
+ end
19
+
20
+ def buckets
21
+ IO.readlines(@file).map(&:strip).reject(&:empty?)
22
+ end
23
+ memoize :buckets
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ module S3Secure
2
+ class CLI < Command
3
+ class_option :verbose, type: :boolean
4
+ class_option :noop, type: :boolean
5
+
6
+ desc "encryption SUBCOMMAND", "encryption subcommands"
7
+ long_desc Help.text(:encryption)
8
+ subcommand "encryption", Encryption
9
+
10
+ desc "policy SUBCOMMAND", "policy subcommands"
11
+ long_desc Help.text(:policy)
12
+ subcommand "policy", Policy
13
+
14
+ desc "batch *PARAMS", "Batch wrapper method"
15
+ long_desc Help.text(:batch)
16
+ def batch(*params)
17
+ Batch.new(*params).run
18
+ end
19
+
20
+ desc "completion *PARAMS", "Prints words for auto-completion."
21
+ long_desc Help.text(:completion)
22
+ def completion(*params)
23
+ Completer.new(CLI, *params).run
24
+ end
25
+
26
+ desc "completion_script", "Generates a script that can be eval to setup auto-completion."
27
+ long_desc Help.text(:completion_script)
28
+ def completion_script
29
+ Completer::Script.generate
30
+ end
31
+
32
+ desc "version", "prints version"
33
+ def version
34
+ puts VERSION
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,82 @@
1
+ require "thor"
2
+
3
+ # Override thor's long_desc identation behavior
4
+ # https://github.com/erikhuda/thor/issues/398
5
+ class Thor
6
+ module Shell
7
+ class Basic
8
+ def print_wrapped(message, options = {})
9
+ message = "\n#{message}" unless message[0] == "\n"
10
+ stdout.puts message
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ module S3Secure
17
+ class Command < Thor
18
+ class << self
19
+ def dispatch(m, args, options, config)
20
+ # Allow calling for help via:
21
+ # s3-secure command help
22
+ # s3-secure command -h
23
+ # s3-secure command --help
24
+ # s3-secure command -D
25
+ #
26
+ # as well thor's normal way:
27
+ #
28
+ # s3-secure help command
29
+ help_flags = Thor::HELP_MAPPINGS + ["help"]
30
+ if args.length > 1 && !(args & help_flags).empty?
31
+ args -= help_flags
32
+ args.insert(-2, "help")
33
+ end
34
+
35
+ # s3-secure version
36
+ # s3-secure --version
37
+ # s3-secure -v
38
+ version_flags = ["--version", "-v"]
39
+ if args.length == 1 && !(args & version_flags).empty?
40
+ args = ["version"]
41
+ end
42
+
43
+ super
44
+ end
45
+
46
+ # Override command_help to include the description at the top of the
47
+ # long_description.
48
+ def command_help(shell, command_name)
49
+ meth = normalize_command_name(command_name)
50
+ command = all_commands[meth]
51
+ alter_command_description(command)
52
+ super
53
+ end
54
+
55
+ def alter_command_description(command)
56
+ return unless command
57
+
58
+ # Add description to beginning of long_description
59
+ long_desc = if command.long_description
60
+ "#{command.description}\n\n#{command.long_description}"
61
+ else
62
+ command.description
63
+ end
64
+
65
+ # add reference url to end of the long_description
66
+ unless website.empty?
67
+ full_command = [command.ancestor_name, command.name].compact.join('-')
68
+ url = "#{website}/reference/s3-secure-#{full_command}"
69
+ long_desc += "\n\nHelp also available at: #{url}"
70
+ end
71
+
72
+ command.long_description = long_desc
73
+ end
74
+ private :alter_command_description
75
+
76
+ # meant to be overriden
77
+ def website
78
+ ""
79
+ end
80
+ end
81
+ end
82
+ end