diff --git a/docs/resources/aws_route_tables.md.erb b/docs/resources/aws_route_tables.md.erb new file mode 100644 index 000000000..02f628ac6 --- /dev/null +++ b/docs/resources/aws_route_tables.md.erb @@ -0,0 +1,49 @@ +--- +title: About the aws_route_tables Resource +--- + +# aws\_route\_table + +Use the `aws_route_tables` InSpec audit resource to test properties of all or a group of Route Tables. A Route Table contains a set of rules, called routes, that are used to determine where network traffic is directed. + +
+ +## Syntax + + # Ensure that there is at least one route table + describe aws_route_tables do + it { should exist } + end + +## Matchers + +### exist + +Indicates that at least one Route Table was found. Use should_not to test that no Route Tables should exist. + + describe aws_route_tables do + it { should exist } + end + + describe aws_route_tables do + it { should_not exist } + end + +## Properties + +### vpc\_ids + +Lists all VPCs that are in the Route Tables. + + describe aws_route_tables do + its('vpc_ids') { should include 'vpc_12345678' } + end + + +### route\_table\_ids + +Lists all of the Route Table IDs. + + describe aws_route_tables do + its('route_table_ids') { should include 'rtb-12345678' } + end diff --git a/lib/resource_support/aws.rb b/lib/resource_support/aws.rb index c412d2468..d29e78bd9 100644 --- a/lib/resource_support/aws.rb +++ b/lib/resource_support/aws.rb @@ -34,6 +34,7 @@ require 'resources/aws/aws_kms_key' require 'resources/aws/aws_kms_keys' require 'resources/aws/aws_rds_instance' require 'resources/aws/aws_route_table' +require 'resources/aws/aws_route_tables' require 'resources/aws/aws_s3_bucket' require 'resources/aws/aws_s3_bucket_object' require 'resources/aws/aws_s3_buckets' diff --git a/lib/resources/aws/aws_route_tables.rb b/lib/resources/aws/aws_route_tables.rb new file mode 100644 index 000000000..ac874e5bd --- /dev/null +++ b/lib/resources/aws/aws_route_tables.rb @@ -0,0 +1,60 @@ +class AwsRouteTables < Inspec.resource(1) + name 'aws_route_tables' + desc 'Verifies settings for AWS Route Tables in bulk' + example ' + describe aws_route_tables do + it { should exist } + end + ' + supports platform: 'aws' + + include AwsPluralResourceMixin + # Underlying FilterTable implementation. + filter = FilterTable.create + filter.add_accessor(:entries) + .add(:exists?) { |x| !x.entries.empty? } + .add(:vpc_ids, field: :vpc_id) + .add(:route_table_ids, field: :route_table_id) + filter.connect(self, :routes_data) + + def routes_data + @table + end + + def to_s + 'Route Tables' + end + + private + + def validate_params(raw_criteria) + unless raw_criteria.is_a? Hash + raise 'Unrecognized criteria for fetching Route Tables. ' \ + "Use 'criteria: value' format." + end + + # No criteria yet + unless raw_criteria.empty? + raise ArgumentError, 'aws_route_tables does not currently accept resource parameters.' + end + raw_criteria + end + + def fetch_from_api + backend = BackendFactory.create(inspec_runner) + catch_aws_errors do + @table = backend.describe_route_tables({}).to_h[:route_tables] + end + end + + class Backend + class AwsClientApi < AwsBackendBase + BackendFactory.set_default_backend self + self.aws_client_class = Aws::EC2::Client + + def describe_route_tables(query = {}) + aws_service_client.describe_route_tables(query) + end + end + end +end diff --git a/test/integration/aws/default/build/route_table.tf b/test/integration/aws/default/build/route_table.tf index 2ac9977e3..ad80428de 100644 --- a/test/integration/aws/default/build/route_table.tf +++ b/test/integration/aws/default/build/route_table.tf @@ -17,32 +17,37 @@ resource "aws_route_table" "rtb" { cidr_block = "172.32.1.0/24" gateway_id = "${data.aws_internet_gateway.default.id}" } +} - tags { - Name = "InSpec" +resource "aws_route_table" "rtb2" { + vpc_id = "${data.aws_vpc.default.id}" + + route { + cidr_block = "172.32.1.0/24" + gateway_id = "${data.aws_internet_gateway.default.id}" } } -output "routetable_rtb_route_table_id" { +output "route_table_1_id" { value = "${aws_route_table.rtb.id}" } -output "routetable_rtb_associations" { +output "route_table_2_id" { + value = "${aws_route_table.rtb2.id}" +} + +output "route_table_1_associations" { value = "${aws_route_table.rtb.associations}" } -output "routetable_rtb_propagating_vgws" { +output "route_table_1_propagating_vgws" { value = "${aws_route_table.rtb.propagating_vgws}" } -output "routetable_rtb_routes" { +output "route_table_1_routes" { value = "${aws_route_table.rtb.routes}" } -output "routetable_rtb_tags" { - value = "${aws_route_table.rtb.tags}" -} - -output "routetable_rtb_vpc_id" { +output "route_table_1_vpc_id" { value = "${aws_route_table.rtb.vpc_id}" } diff --git a/test/integration/aws/default/verify/controls/aws_route_table.rb b/test/integration/aws/default/verify/controls/aws_route_table.rb index 900cf7a62..3c1b92ae7 100644 --- a/test/integration/aws/default/verify/controls/aws_route_table.rb +++ b/test/integration/aws/default/verify/controls/aws_route_table.rb @@ -1,7 +1,7 @@ fixtures = {} [ - 'routetable_rtb_route_table_id', - 'routetable_rtb_vpc_id', + 'route_table_1_id', + 'route_table_1_vpc_id', ].each do |fixture_name| fixtures[fixture_name] = attribute( fixture_name, @@ -17,7 +17,7 @@ control "aws_route_table exists" do end control "aws_route_table recall" do - describe aws_route_table(fixtures['routetable_rtb_route_table_id']) do + describe aws_route_table(fixtures['route_table_1_id']) do it { should exist} end end diff --git a/test/integration/aws/default/verify/controls/aws_route_tables.rb b/test/integration/aws/default/verify/controls/aws_route_tables.rb new file mode 100644 index 000000000..d9ebb9a6e --- /dev/null +++ b/test/integration/aws/default/verify/controls/aws_route_tables.rb @@ -0,0 +1,28 @@ +fixtures = {} +[ + 'route_table_1_id', + 'route_table_2_id', + 'route_table_1_vpc_id', +].each do |fixture_name| + fixtures[fixture_name] = attribute( + fixture_name, + default: "default.#{fixture_name}", + description: 'See ../build/ec2.tf', + ) +end + +control "aws_route_tables recall" do + # Check if at least one route table has been created and test a specific route table was created. + describe aws_route_tables do + it { should exist } + its('route_table_ids') { should include fixtures['route_table_1_id'], fixtures['route_table_2_id'] } + end +end + +control "aws_route_tables properties" do + # test the vpc ids and route table ids + describe aws_route_tables do + its('vpc_ids') { should include fixtures['route_table_1_vpc_id'] } + its('route_table_ids') { should include fixtures['route_table_1_id'], fixtures['route_table_2_id'] } + end +end \ No newline at end of file diff --git a/test/unit/resources/aws_route_tables_test.rb b/test/unit/resources/aws_route_tables_test.rb new file mode 100644 index 000000000..f7f2b8074 --- /dev/null +++ b/test/unit/resources/aws_route_tables_test.rb @@ -0,0 +1,70 @@ +require 'helper' + +class EmptyAwsRouteTablesTest < Minitest::Test + def setup + AwsRouteTables::BackendFactory.select(AwsMRtbB::Empty) + end + + def test_constructor_no_args_ok + AwsRouteTables.new + end + + def test_search_miss + refute AwsRouteTables.new.exists? + end + + def test_constructor_reject_unknown_resource_params + assert_raises(ArgumentError) { AwsRouteTables.new(bla: 'blabla') } + end +end + +class BasicAwsRouteTablesTest2 < Minitest::Test + def setup + AwsRouteTables::BackendFactory.select(AwsMRtbB::Basic) + end + + def test_search_hit + assert AwsRouteTables.new.exists? + end + + def test_property_vpc_ids + basic = AwsRouteTables.new + assert_kind_of(Array, basic.vpc_ids) + assert(basic.vpc_ids.include?('vpc-169f777e')) + assert(basic.vpc_ids.include?('vpc-169f777d')) + refute(basic.vpc_ids.include?(nil)) + end + + def test_property_route_table_ids + basic = AwsRouteTables.new + assert_kind_of(Array, basic.route_table_ids) + assert(basic.route_table_ids.include?('rtb-2c60ec44')) + assert(basic.route_table_ids.include?('rtb-58508630')) + refute(basic.route_table_ids.include?(nil)) + end +end + +# MRtbB = Mock Routetable Backend +module AwsMRtbB + class Empty < AwsBackendBase + def describe_route_tables(query) + OpenStruct.new(route_tables: []) + end + end + + class Basic < AwsBackendBase + def describe_route_tables(query) + fixtures = [ + OpenStruct.new({ + route_table_id: 'rtb-2c60ec44', + vpc_id: 'vpc-169f777e' + }), + OpenStruct.new({ + route_table_id: 'rtb-58508630', + vpc_id: 'vpc-169f777d' + }) + ] + OpenStruct.new({ route_tables: fixtures }) + end + end +end