s3-secure 0.1.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.
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