Class: S3

Inherits:
Mapper show all
Defined in:
lib/aws_recon/collectors/s3.rb

Overview

Collect S3 Resources

Constant Summary

Constants inherited from Mapper

Mapper::SINGLE_REGION_SERVICES

Instance Method Summary collapse

Methods inherited from Mapper

#initialize

Constructor Details

This class inherits a constructor from Mapper

Instance Method Details

#collectObject

Returns an array of resources.

Since S3 is a global service, the bucket operation calls can be parallelized.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/aws_recon/collectors/s3.rb', line 13

def collect
  resources = []

  #
  # list_buckets
  #
  @client.list_buckets.each_with_index do |response, page|
    log(response.context.operation_name, page)

    Parallel.map(response.buckets.each, in_threads: @options.threads) do |bucket|
      @thread = Parallel.worker_number
      log(response.context.operation_name, bucket.name)

      struct = OpenStruct.new(bucket)
      struct.type = 'bucket'
      struct.arn = "arn:aws:s3:::#{bucket.name}"

      # check bucket region constraint
      location = @client.get_bucket_location({ bucket: bucket.name }).location_constraint

      # if you use a region other than the us-east-1 endpoint
      # to create a bucket, you must set the location_constraint
      # bucket parameter to the same region. (https://docs.aws.amazon.com/general/latest/gr/s3.html)
      client = if location.empty?
                 struct.location = 'us-east-1'
                 @client
               else
                 location = 'eu-west-1' if location == 'EU'
                 struct.location = location
                 Aws::S3::Client.new({ region: location })
               end

      operations = [
        { func: 'get_bucket_acl', key: 'acl', field: nil },
        { func: 'get_bucket_encryption', key: 'encryption', field: 'server_side_encryption_configuration' },
        { func: 'get_bucket_replication', key: 'replication', field: 'replication_configuration' },
        { func: 'get_bucket_policy', key: 'policy', field: 'policy' },
        { func: 'get_bucket_policy_status', key: 'public', field: 'policy_status' },
        { func: 'get_public_access_block', key: 'public_access_block', field: 'public_access_block_configuration' },
        { func: 'get_object_lock_configuration', key: 'object_lock_configuration', field: 'object_lock_configuration' },
        { func: 'get_bucket_tagging', key: 'tagging', field: nil },
        { func: 'get_bucket_logging', key: 'logging', field: 'logging_enabled' },
        { func: 'get_bucket_versioning', key: 'versioning', field: nil },
        { func: 'get_bucket_website', key: 'website', field: nil },
        { func: 'get_bucket_ownership_controls', key: 'ownership_controls', field: 'ownership_controls' }
      ]

      operations.each do |operation|
        op = OpenStruct.new(operation)

        resp = client.send(op.func, { bucket: bucket.name })

        struct[op.key] = if op.key == 'policy'
                           resp.policy.string.parse_policy
                         else
                           op.field ? resp.send(op.field).to_h : resp.to_h
                         end

      rescue Aws::S3::Errors::ServiceError => e
        log_error(bucket.name, op.func, e.code)

        raise e unless suppressed_errors.include?(e.code) && !@options.quit_on_exception
      end

      resources.push(struct.to_h)

    rescue Aws::S3::Errors::NoSuchBucket
      # skip missing bucket
    end
  end

  resources
end