s3-secure 0.3.0 → 0.5.1

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE.txt +201 -22
  4. data/README.md +134 -16
  5. data/lib/s3_secure.rb +3 -2
  6. data/lib/s3_secure/abstract_base.rb +2 -1
  7. data/lib/s3_secure/access_logs.rb +32 -0
  8. data/lib/s3_secure/access_logs/base.rb +4 -0
  9. data/lib/s3_secure/access_logs/disable.rb +37 -0
  10. data/lib/s3_secure/access_logs/enable.rb +41 -0
  11. data/lib/s3_secure/access_logs/list.rb +25 -0
  12. data/lib/s3_secure/access_logs/show.rb +89 -0
  13. data/lib/s3_secure/aws_services.rb +1 -30
  14. data/lib/s3_secure/aws_services/s3.rb +54 -0
  15. data/lib/s3_secure/cli.rb +27 -1
  16. data/lib/s3_secure/command.rb +7 -0
  17. data/lib/s3_secure/encryption.rb +4 -0
  18. data/lib/s3_secure/encryption/disable.rb +5 -9
  19. data/lib/s3_secure/encryption/enable.rb +5 -11
  20. data/lib/s3_secure/encryption/list.rb +12 -16
  21. data/lib/s3_secure/encryption/show.rb +14 -9
  22. data/lib/s3_secure/help/batch.md +14 -0
  23. data/lib/s3_secure/help/encryption/disable.md +5 -0
  24. data/lib/s3_secure/help/encryption/enable.md +6 -0
  25. data/lib/s3_secure/help/encryption/list.md +5 -0
  26. data/lib/s3_secure/help/lifecycle/add.md +13 -0
  27. data/lib/s3_secure/help/lifecycle/list.md +22 -0
  28. data/lib/s3_secure/help/lifecycle/remove.md +5 -0
  29. data/lib/s3_secure/help/lifecycle/show.md +13 -0
  30. data/lib/s3_secure/help/policy/enforce_ssl.md +34 -0
  31. data/lib/s3_secure/help/policy/list.md +5 -0
  32. data/lib/s3_secure/help/policy/unforce_ssl.md +61 -0
  33. data/lib/s3_secure/help/summary.md +22 -0
  34. data/lib/s3_secure/lifecycle.rb +33 -0
  35. data/lib/s3_secure/lifecycle/add.rb +33 -0
  36. data/lib/s3_secure/lifecycle/base.rb +5 -0
  37. data/lib/s3_secure/lifecycle/builder.rb +47 -0
  38. data/lib/s3_secure/lifecycle/list.rb +24 -0
  39. data/lib/s3_secure/lifecycle/remove.rb +28 -0
  40. data/lib/s3_secure/lifecycle/show.rb +40 -0
  41. data/lib/s3_secure/policy.rb +4 -0
  42. data/lib/s3_secure/policy/enforce.rb +6 -10
  43. data/lib/s3_secure/policy/list.rb +13 -17
  44. data/lib/s3_secure/policy/show.rb +11 -10
  45. data/lib/s3_secure/policy/unforce.rb +7 -10
  46. data/lib/s3_secure/remediate_all.rb +12 -0
  47. data/lib/s3_secure/say.rb +7 -0
  48. data/lib/s3_secure/summary.rb +13 -0
  49. data/lib/s3_secure/summary/item.rb +16 -0
  50. data/lib/s3_secure/summary/items.rb +65 -0
  51. data/lib/s3_secure/table.rb +18 -0
  52. data/lib/s3_secure/version.rb +1 -1
  53. data/lib/s3_secure/versioning.rb +31 -0
  54. data/lib/s3_secure/versioning/base.rb +4 -0
  55. data/lib/s3_secure/versioning/disable.rb +19 -0
  56. data/lib/s3_secure/versioning/enable.rb +19 -0
  57. data/lib/s3_secure/versioning/list.rb +24 -0
  58. data/lib/s3_secure/versioning/show.rb +27 -0
  59. data/s3-secure.gemspec +5 -2
  60. data/spec/lib/lifecycle/builder_spec.rb +85 -0
  61. metadata +72 -5
  62. data/lib/s3_secure/help/hello.md +0 -5
@@ -1,28 +1,24 @@
1
1
  class S3Secure::Encryption
2
2
  class List < Base
3
3
  def run
4
+ presenter = CliFormat::Presenter.new(@options)
5
+ presenter.header = ["Bucket", "Has Encryption?"]
6
+
4
7
  buckets.each do |bucket|
5
- @s3 = s3_regional_client(bucket)
6
- puts "Policy for bucket #{bucket.color(:green)}"
7
- encryption_rules = get_encryption_rules(bucket)
8
+ $stderr.puts "Getting encryption for bucket #{bucket.color(:green)}"
9
+ show = Show.new(bucket: bucket)
8
10
 
9
- if encryption_rules
10
- puts encryption_rules
11
+ row = [bucket, show.enabled?]
12
+ if @options[:encryption].nil?
13
+ presenter.rows << row # always show policy
14
+ elsif @options[:encryption]
15
+ presenter.rows << row if show.enabled? # only show if bucket has some encryption rules
11
16
  else
12
- puts "Bucket does not have bucket encryption enabled"
17
+ presenter.rows << row unless show.enabled? # only show if bucket doesnt have any encryption rules
13
18
  end
14
19
  end
15
- end
16
-
17
- def get_encryption_rules(bucket)
18
- resp = @s3.get_bucket_encryption(bucket: bucket)
19
- resp.server_side_encryption_configuration.rules # Aws::Xml::DefaultList object
20
- rescue Aws::S3::Errors::ServerSideEncryptionConfigurationNotFoundError
21
- end
22
20
 
23
- # Useful when calling List outside of the list CLI
24
- def set_s3(client)
25
- @s3 = client
21
+ presenter.show
26
22
  end
27
23
  end
28
24
  end
@@ -1,18 +1,23 @@
1
1
  class S3Secure::Encryption
2
2
  class Show < Base
3
3
  def run
4
- @s3 = s3_regional_client(@bucket)
5
-
6
- list = S3Secure::Encryption::List.new(@options)
7
- list.set_s3(@s3)
8
-
9
- rules = list.get_encryption_rules(@bucket)
10
4
  if rules
11
- puts "Bucket #{@bucket} is configured with these encryption rules:"
12
- puts rules.map(&:to_h)
5
+ say "Bucket #{@bucket} is configured with these encryption rules:"
6
+ say rules.map(&:to_h)
13
7
  else
14
- puts "Bucket #{@bucket} is not configured with encryption at the bucket level"
8
+ say "Bucket #{@bucket} is not configured with encryption at the bucket level"
15
9
  end
16
10
  end
11
+
12
+ def enabled?
13
+ !!(rules && !rules.empty?)
14
+ end
15
+
16
+ def rules
17
+ resp = s3.get_bucket_encryption(bucket: @bucket)
18
+ resp.server_side_encryption_configuration.rules # Aws::Xml::DefaultList object
19
+ rescue Aws::S3::Errors::ServerSideEncryptionConfigurationNotFoundError
20
+ end
21
+ memoize :rules
17
22
  end
18
23
  end
@@ -0,0 +1,14 @@
1
+ There are some supported batch commands:
2
+
3
+ s3-secure batch encryption enable FILE.txt
4
+ s3-secure batch encryption disable FILE.txt
5
+ s3-secure batch policy enforce_ssl FILE.txt
6
+ s3-secure batch policy unforce_ssl FILE.txt
7
+
8
+ The format of FILE.txt is a list of bucket names separated by newlines. Example:
9
+
10
+ buckets.txt:
11
+
12
+ my-bucket-1
13
+ my-bucket-2
14
+
@@ -0,0 +1,5 @@
1
+ ## Example
2
+
3
+ $ s3-secure encryption disable a-test-bucket-in-us-east-1
4
+ Bucket a-test-bucket-in-us-east-1 encryption has been removed
5
+ $
@@ -0,0 +1,6 @@
1
+ ## Example
2
+
3
+ $ s3-secure encryption enable a-test-bucket-in-us-east-1
4
+ Encyption enabled on bucket a-test-bucket-in-us-east-1 with rules:
5
+ {:apply_server_side_encryption_by_default=>{:sse_algorithm=>"AES256"}}
6
+ $
@@ -0,0 +1,5 @@
1
+ ## Examples
2
+
3
+ s3-secure encryption list # shows all buckets with and without polices
4
+ s3-secure encryption list --encryption # only shows buckets with encryption
5
+ s3-secure encryption list --no-encryption # only shows buckets without encryption
@@ -0,0 +1,13 @@
1
+ ## Example
2
+
3
+ $ s3-secure lifecycle add a-test-bucket-in-us-east-1
4
+ Added lifecycle policy to bucket a-test-bucket-in-us-east-1
5
+ $
6
+
7
+ By default, the add command will only add a lifecycle policy if you none exists.
8
+
9
+ It may be useful to test adding an additional lifecycle policy, for this you can use both the `--additive` and `--prefix` options. Note, you must make sure that the lifecycle policies can work together. For example, they must have different prefixes.
10
+
11
+ $ s3-secure lifecycle add a-test-bucket-in-us-east-1 --additive --prefix /foo
12
+ Added lifecycle policy to bucket a-test-bucket-in-us-east-1
13
+ $
@@ -0,0 +1,22 @@
1
+ ## Examples
2
+
3
+ $ s3-secure lifecycle list
4
+ +----------------------------+----------------------+
5
+ | Bucket | Has Lifecycle Rules? |
6
+ +----------------------------+----------------------+
7
+ | a-test-bucket-in-us-east-1 | false |
8
+ | a-test-bucket-in-us-west-1 | true |
9
+ +----------------------------+----------------------+
10
+ $ s3-secure lifecycle list --lifecycle true
11
+ +----------------------------+----------------------+
12
+ | Bucket | Has Lifecycle Rules? |
13
+ +----------------------------+----------------------+
14
+ | a-test-bucket-in-us-west-1 | true |
15
+ +----------------------------+----------------------+
16
+ $ s3-secure lifecycle list --lifecycle false
17
+ +----------------------------+----------------------+
18
+ | Bucket | Has Lifecycle Rules? |
19
+ +----------------------------+----------------------+
20
+ | a-test-bucket-in-us-east-1 | false |
21
+ +----------------------------+----------------------+
22
+ $
@@ -0,0 +1,5 @@
1
+ ## Examples
2
+
3
+ $ s3-secure lifecycle remove a-test-bucket-in-us-east-1
4
+ Removed the s3-secure-automated-cleanup lifecycle rule on bucket a-test-bucket-in-us-east-1
5
+ $
@@ -0,0 +1,13 @@
1
+ ## Examples
2
+
3
+ $ s3-secure lifecycle show a-test-bucket-in-us-east-1
4
+ This S3 bucket has lifecycle rules
5
+ Bucket lifecycle details:
6
+ {:rules=>
7
+ [{:expiration=>{:expired_object_delete_marker=>true},
8
+ :id=>"s3-secure-automated-cleanup",
9
+ :prefix=>"/bar",
10
+ :status=>"Enabled",
11
+ :noncurrent_version_expiration=>{:noncurrent_days=>365},
12
+ :abort_incomplete_multipart_upload=>{:days_after_initiation=>30}}]}
13
+ $
@@ -0,0 +1,34 @@
1
+ ## Example
2
+
3
+ $ s3-secure policy enforce_ssl a-test-bucket-in-us-east-1
4
+ Add bucket policy to bucket a-test-bucket-in-us-east-1:
5
+ {
6
+ "Version": "2012-10-17",
7
+ "Statement": [
8
+ {
9
+ "Sid": "IPAllow",
10
+ "Effect": "Deny",
11
+ "Principal": "*",
12
+ "Action": "s3:*",
13
+ "Resource": "arn:aws:s3:::a-test-bucket-in-us-east-1/*",
14
+ "Condition": {
15
+ "NotIpAddress": {
16
+ "aws:SourceIp": "54.240.143.0/24"
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "Sid": "ForceSSLOnlyAccess",
22
+ "Effect": "Deny",
23
+ "Principal": "*",
24
+ "Action": "s3:GetObject",
25
+ "Resource": "arn:aws:s3:::a-test-bucket-in-us-east-1/*",
26
+ "Condition": {
27
+ "Bool": {
28
+ "aws:SecureTransport": "false"
29
+ }
30
+ }
31
+ }
32
+ ]
33
+ }
34
+ $
@@ -0,0 +1,5 @@
1
+ ## Examples
2
+
3
+ s3-secure policy list # shows all buckets with and without polices
4
+ s3-secure policy list --policy # only shows buckets with policy
5
+ s3-secure policy list --no-policy # only shows buckets without policy
@@ -0,0 +1,61 @@
1
+ ## Example
2
+
3
+ If the policy only has the ForceSSLOnlyAccess statement, then the entire bucket policy is removed:
4
+
5
+ $ s3-secure policy unforce_ssl a-test-bucket-in-us-west-1
6
+ Remove bucket policy to bucket a-test-bucket-in-us-west-1:
7
+ $
8
+
9
+ If the policy has other statements, then only the ForceSSLOnlyAccess is removed any other policies are kept in tact.
10
+
11
+ $ s3-secure policy show a-test-bucket-in-us-east-1
12
+ Bucket a-test-bucket-in-us-east-1 is configured with this policy:
13
+ {
14
+ "Version": "2012-10-17",
15
+ "Statement": [
16
+ {
17
+ "Sid": "IPAllow",
18
+ "Effect": "Deny",
19
+ "Principal": "*",
20
+ "Action": "s3:*",
21
+ "Resource": "arn:aws:s3:::a-test-bucket-in-us-east-1/*",
22
+ "Condition": {
23
+ "NotIpAddress": {
24
+ "aws:SourceIp": "54.240.143.0/24"
25
+ }
26
+ }
27
+ },
28
+ {
29
+ "Sid": "ForceSSLOnlyAccess",
30
+ "Effect": "Deny",
31
+ "Principal": "*",
32
+ "Action": "s3:GetObject",
33
+ "Resource": "arn:aws:s3:::a-test-bucket-in-us-east-1/*",
34
+ "Condition": {
35
+ "Bool": {
36
+ "aws:SecureTransport": "false"
37
+ }
38
+ }
39
+ }
40
+ ]
41
+ }
42
+ $ s3-secure policy unforce_ssl a-test-bucket-in-us-east-1
43
+ Remove bucket policy statement from bucket a-test-bucket-in-us-east-1:
44
+ {
45
+ "Version": "2012-10-17",
46
+ "Statement": [
47
+ {
48
+ "Sid": "IPAllow",
49
+ "Effect": "Deny",
50
+ "Principal": "*",
51
+ "Action": "s3:*",
52
+ "Resource": "arn:aws:s3:::a-test-bucket-in-us-east-1/*",
53
+ "Condition": {
54
+ "NotIpAddress": {
55
+ "aws:SourceIp": "54.240.143.0/24"
56
+ }
57
+ }
58
+ }
59
+ ]
60
+ }
61
+ $
@@ -0,0 +1,22 @@
1
+ ## Examples
2
+
3
+ $ s3-secure summary
4
+ Determining bucket security-related settings...
5
+ +----------------------------+------+------------+
6
+ | Bucket | SSL? | Encrypted? |
7
+ +----------------------------+------+------------+
8
+ | a-test-bucket-in-us-east-1 | yes | no |
9
+ | a-test-bucket-in-us-west-1 | no | no |
10
+ +----------------------------+------+------------+
11
+ $
12
+
13
+ There are `--ssl no` and `--encrypted no` filtering options:
14
+
15
+ $ s3-secure summary --ssl no --encrypted no
16
+ Determining bucket security-related settings...
17
+ +----------------------------+------+------------+
18
+ | Bucket | SSL? | Encrypted? |
19
+ +----------------------------+------+------------+
20
+ | a-test-bucket-in-us-west-1 | no | no |
21
+ +----------------------------+------+------------+
22
+ $
@@ -0,0 +1,33 @@
1
+ module S3Secure
2
+ class Lifecycle < Command
3
+ class_option :quiet, type: :boolean
4
+
5
+ desc "list", "List bucket lifecycles"
6
+ long_desc Help.text("lifecycle/list")
7
+ option :format, desc: "Format options: #{CliFormat.formats.join(', ')}"
8
+ option :lifecycle, desc: "Filter for lifecycle: all, true, false"
9
+ def list
10
+ List.new(options).run
11
+ end
12
+
13
+ desc "show BUCKET", "show bucket lifecycle"
14
+ long_desc Help.text("lifecycle/show")
15
+ def show(bucket)
16
+ Show.new(options.merge(bucket: bucket)).run
17
+ end
18
+
19
+ desc "add BUCKET", "add bucket lifecycle"
20
+ long_desc Help.text("lifecycle/add")
21
+ option :additive, type: :boolean, desc: "Force adding another lifecycle rule even if one exists. Note, may fail, need a different prefix filter"
22
+ option :prefix, desc: "Filter prefix. Used with additive mode."
23
+ def add(bucket)
24
+ Add.new(options.merge(bucket: bucket)).run
25
+ end
26
+
27
+ desc "remove BUCKET", "remove bucket lifecycle"
28
+ long_desc Help.text("lifecycle/remove")
29
+ def remove(bucket)
30
+ Remove.new(options.merge(bucket: bucket)).run
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ class S3Secure::Lifecycle
2
+ class Add < Base
3
+ RULE_ID = Base::RULE_ID
4
+
5
+ def run
6
+ show = Show.new(@options)
7
+ if @options[:additive]
8
+ current_rules = show.get_lifecycle_rules(@bucket)
9
+ builder = Builder.new(current_rules)
10
+ rules = builder.rules_with_addition(@options[:prefix])
11
+ if current_rules.size == rules.size
12
+ say "WARN: rule wasnt added because a #{RULE_ID} already exists".color(:yellow)
13
+ else
14
+ s3.put_bucket_lifecycle_configuration(
15
+ bucket: @bucket, # required
16
+ lifecycle_configuration: {rules: rules}
17
+ )
18
+ end
19
+ elsif show.any?
20
+ say "Bucket #{@bucket} is has a lifecycle policy already."
21
+ return
22
+ else
23
+ options = {
24
+ bucket: @bucket, # required
25
+ lifecycle_configuration: {rules: [Builder::DEFAULT_RULE]}
26
+ }
27
+ s3.put_bucket_lifecycle_configuration(options)
28
+ end
29
+
30
+ say "Added lifecycle policy to bucket #{@bucket}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ class S3Secure::Lifecycle
2
+ class Base < S3Secure::AbstractBase
3
+ RULE_ID = "s3-secure-automated-cleanup"
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ class S3Secure::Lifecycle
2
+ class Builder
3
+ # Note: put_bucket_lifecycle_configuration and put_bucket_lifecycle understand different payloads.
4
+ # put_bucket_lifecycle is old and shouldnt be used
5
+ RULE_ID = Base::RULE_ID
6
+ DEFAULT_RULE = {
7
+ expiration: {expired_object_delete_marker: true},
8
+ id: RULE_ID,
9
+ status: "Enabled",
10
+ prefix: "",
11
+ noncurrent_version_expiration: {noncurrent_days: 365},
12
+ abort_incomplete_multipart_upload: {days_after_initiation: 30}
13
+ }
14
+
15
+ def initialize(rules)
16
+ @rules = rules || []
17
+ end
18
+
19
+ def has?(id)
20
+ !!@rules.detect { |rule| rule[:id] == id }
21
+ end
22
+
23
+ def rules_with_addition(prefix=nil)
24
+ rules = @rules.dup
25
+ unless has?(RULE_ID)
26
+ rule = DEFAULT_RULE
27
+ rule[:prefix] = prefix if prefix
28
+ rules << rule
29
+ end
30
+ rules
31
+ end
32
+
33
+ def rules_with_removal
34
+ rules = @rules.dup
35
+ rules.delete_if { |rule| rule[:id] == RULE_ID }
36
+ rules
37
+ end
38
+
39
+ def build(type)
40
+ if type == :remove
41
+ remove_lifecycle
42
+ else
43
+ add_lifecycle
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ class S3Secure::Lifecycle
2
+ class List < Base
3
+ def run
4
+ presenter = CliFormat::Presenter.new(@options)
5
+ presenter.header = ["Bucket", "Has Lifecycle Rules?"]
6
+
7
+ buckets.each do |bucket|
8
+ $stderr.puts "Getting lifecycle policy for bucket #{bucket.color(:green)}"
9
+
10
+ show = Show.new(bucket: bucket)
11
+ row = [bucket, show.any?]
12
+ if @options[:lifecycle].nil?
13
+ presenter.rows << row # always show policy
14
+ elsif @options[:lifecycle]
15
+ presenter.rows << row if status # only show if bucket has some encryption rules
16
+ else
17
+ presenter.rows << row unless status # only show if bucket doesnt have any encryption rules
18
+ end
19
+ end
20
+
21
+ presenter.show
22
+ end
23
+ end
24
+ end