aaronlippold / inspec-aws

InSpec for AWS (Incubation)
https://www.inspec.io/
Other
1 stars 1 forks source link

New Resource aws_cloudtrail_trails #32

Open rx294 opened 6 years ago

rx294 commented 6 years ago

Test Cloud Trails Configurations In support for over 19 cis aws foundation controls

Support tests such as

  describe aws_cloudtrail_trails.where(is_multi_region_trail: true) do
    it { should exist }
  end

  describe aws_cloudtrail_trails.where(log_file_validation_enabled: false) do
    it { should_not exist }
  end

  aws_cloudtrail_trails.entries.each do |trail|
    describe trail do
      its('cloud_watch_logs_log_group_arn') { should_not be_nil }
      its('status.latest_cloud_watch_logs_delivery_time') { should cmp > Time.now - 86400 }
    end
  end

AWS CLI

aws cloudtrail describe-trails
{
    "trailList": [
        {
            "IncludeGlobalServiceEvents": true,
            "Name": "test_tail",
            "TrailARN": "arn:aws:cloudtrail:us-east-1:484747447281:trail/test_tail",
            "LogFileValidationEnabled": true,
            "IsMultiRegionTrail": true,
            "HasCustomEventSelectors": false,
            "S3BucketName": "aws-demo-s3-bucket-6731201fbe26c7f4",
            "CloudWatchLogsRoleArn": "arn:aws:iam::484747447281:role/CloudTrail_CloudWatchLogs_Role",
            "CloudWatchLogsLogGroupArn": "arn:aws:logs:us-east-1:484747447281:log-group:test:*",
            "HomeRegion": "us-east-1"
        },
        {
            "IncludeGlobalServiceEvents": true,
            "Name": "test_tail2",
            "TrailARN": "arn:aws:cloudtrail:us-east-1:484747447281:trail/test_tail2",
            "LogFileValidationEnabled": true,
            "IsMultiRegionTrail": false,
            "HasCustomEventSelectors": false,
            "S3BucketName": "aws-demo-s3-bucket-f8a94d40a2fa19ee",
            "HomeRegion": "us-east-1"
        }
    ]
}

Code Suggestion:


require_relative '_aws'

class AwsCloudTrailTrails < Inspec.resource(1)
  name 'aws_cloudtrail_trails'
  desc 'Verifies settings for AWS IAM users'
  example '
    describe aws_cloudtrail_trails.where(is_multi_region_trail: false) do
      it { should_not exist }
    end

    describe aws_cloudtrail_trails.where(include_global_service_events: false) do
      it { should_not exist }
    end
  '

  filter = FilterTable.create
  filter.add_accessor(:where)
        .add_accessor(:entries)
        .add(:exists?) { |x| !x.entries.empty? }
        .add(:name, field: :name)
        .add(:s3_bucket_name, field: :s3_bucket_name)
        .add(:s3_key_prefix, field: :s3_key_prefix)
        .add(:sns_topic_name, field: :sns_topic_name)
        .add(:sns_topic_arn, field: :sns_topic_arn)
        .add(:include_global_service_events, field: :include_global_service_events)
        .add(:is_multi_region_trail, field: :is_multi_region_trail)
        .add(:home_region, field: :home_region)
        .add(:trail_arn, field: :trail_arn)
        .add(:log_file_validation_enabled, field: :log_file_validation_enabled)
        .add(:cloud_watch_logs_log_group_arn, field: :cloud_watch_logs_log_group_arn)
        .add(:cloud_watch_logs_role_arn, field: :cloud_watch_logs_role_arn)
        .add(:kms_key_id, field: :kms_key_id)
        .add(:has_custom_event_selectors, field: :has_custom_event_selectors)
  filter.connect(self, :collect_trail_details)

  # No resource params => no overridden constructor
  # AWS API only offers filtering on path prefix;
  # little other opportunity for server-side filtering.

  def collect_trail_details
    backend = Backend.create
    trails = backend.list_trails.trail_list.map(&:to_h)
    trails.each do |trail|
      begin
        status = Hashie::Mash.new(backend.trail_status(name: trail[:name]).to_h)
        trail[:status] = status
      rescue Aws::IAM::Errors::NoSuchEntity
        user[:status] = {}
      end
    end
    trails
  end

  def to_s
    'CloudTrails Trails'
  end

  # Entry cooker.  Needs discussion.
  # def users
  # end

  #===========================================================================#
  #                        Backend Implementation
  #===========================================================================#
  class Backend
    #=====================================================#
    #                 Concrete Implementation
    #=====================================================#
    # Uses AWS API to really talk to AWS
    class AwsClientApi < Backend
      # TODO: delegate this out
      def list_trails(query = {})
        AWSConnection.new.cloudtrail_client.describe_trails(query)
      end
      def trail_status(query)
        AWSConnection.new.cloudtrail_client.get_trail_status(query)
      end
    end

    #=====================================================#
    #                   Factory Interface
    #=====================================================#
    # TODO: move this to a mix-in
    DEFAULT_BACKEND = AwsClientApi
    @selected_backend = DEFAULT_BACKEND

    def self.create
      @selected_backend.new
    end

    def self.select(klass)
      @selected_backend = klass
    end
  end
end
rx294 commented 6 years ago

Ref #146