s3-secure 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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