diff --git a/doc/resource_types.md b/doc/resource_types.md index 5388e059d..1b119a3fb 100644 --- a/doc/resource_types.md +++ b/doc/resource_types.md @@ -1109,6 +1109,12 @@ end ``` +### be_inbound_opened_only + +### be_opened_only + +### be_outbound_opened_only + ### its(:inbound), its(:outbound) ```ruby diff --git a/lib/awspec/matcher.rb b/lib/awspec/matcher.rb index 4093da490..f03a90dd0 100644 --- a/lib/awspec/matcher.rb +++ b/lib/awspec/matcher.rb @@ -8,6 +8,7 @@ # SecurityGroup require 'awspec/matcher/be_opened' +require 'awspec/matcher/be_opened_only' # Route53 require 'awspec/matcher/have_record_set' diff --git a/lib/awspec/matcher/be_opened_only.rb b/lib/awspec/matcher/be_opened_only.rb new file mode 100644 index 000000000..9afba3f5a --- /dev/null +++ b/lib/awspec/matcher/be_opened_only.rb @@ -0,0 +1,17 @@ +RSpec::Matchers.define :be_opened_only do |port| + match do |sg| + sg.opened_only?(port, @protocol, @cidr) + end + + chain :protocol do |protocol| + @protocol = protocol + end + + chain :for do |cidr| + @cidr = cidr + end + + chain :target do |cidr| + @cidr = cidr + end +end diff --git a/lib/awspec/stub/security_group.rb b/lib/awspec/stub/security_group.rb index 065c1fd06..191db91b7 100644 --- a/lib/awspec/stub/security_group.rb +++ b/lib/awspec/stub/security_group.rb @@ -33,6 +33,28 @@ } ] }, + { + from_port: 60_000, + to_port: 60_000, + ip_protocol: 'tcp', + ip_ranges: [ + { + cidr_ip: '100.456.789.012/32' + } + ], + user_id_group_pairs: [] + }, + { + from_port: 70_000, + to_port: 70_000, + ip_protocol: 'tcp', + ip_ranges: [ + { + cidr_ip: '100.456.789.012/32' + } + ], + user_id_group_pairs: [] + }, { from_port: 50_000, to_port: 50_009, @@ -47,12 +69,12 @@ ], ip_permissions_egress: [ { - from_port: nil, - to_port: nil, - ip_protocol: '-1', + from_port: 50_000, + to_port: 50_000, + ip_protocol: 'tcp', ip_ranges: [ { - cidr_ip: '0.0.0.0/0' + cidr_ip: '100.456.789.012/32' } ] } diff --git a/lib/awspec/type/security_group.rb b/lib/awspec/type/security_group.rb index a5164aaea..2ba20174c 100644 --- a/lib/awspec/type/security_group.rb +++ b/lib/awspec/type/security_group.rb @@ -14,6 +14,11 @@ def opened?(port = nil, protocol = nil, cidr = nil) outbound_opened?(port, protocol, cidr) end + def opened_only?(port = nil, protocol = nil, cidr = nil) + return inbound_opened_only?(port, protocol, cidr) if @inbound + outbound_opened_only?(port, protocol, cidr) + end + def inbound_opened?(port = nil, protocol = nil, cidr = nil) @resource_via_client[:ip_permissions].find do |permission| next true unless port @@ -38,6 +43,18 @@ def inbound_opened?(port = nil, protocol = nil, cidr = nil) end end + def inbound_opened_only?(port = nil, protocol = nil, cidr = nil) + permissions = @resource_via_client[:ip_permissions].select do |permission| + port_between?(port, permission[:from_port], permission[:to_port]) + end + permissions = permissions.select { |permission| permission[:ip_protocol] == protocol } + cidrs = [] + permissions.each do |permission| + permission[:ip_ranges].select { |ip_range| cidrs.push(ip_range[:cidr_ip]) } + end + cidrs == [cidr] + end + def outbound_opened?(port = nil, protocol = nil, cidr = nil) @resource_via_client[:ip_permissions_egress].find do |permission| next true unless port @@ -62,6 +79,18 @@ def outbound_opened?(port = nil, protocol = nil, cidr = nil) end end + def outbound_opened_only?(port = nil, protocol = nil, cidr = nil) + permissions = @resource_via_client[:ip_permissions_egress].select do |permission| + port_between?(port, permission[:from_port], permission[:to_port]) + end + permissions = permissions.select { |permission| permission[:ip_protocol] == protocol } + cidrs = [] + permissions.each do |permission| + permission[:ip_ranges].select { |ip_range| cidrs.push(ip_range[:cidr_ip]) } + end + cidrs == [cidr] + end + def inbound @inbound = true self diff --git a/spec/generator/spec/security_group_spec.rb b/spec/generator/spec/security_group_spec.rb index 1064c2068..11f458e11 100644 --- a/spec/generator/spec/security_group_spec.rb +++ b/spec/generator/spec/security_group_spec.rb @@ -14,11 +14,13 @@ its(:inbound) { should be_opened(80).protocol('tcp').for('123.456.789.012/32') } its(:inbound) { should be_opened(80).protocol('tcp').for('456.789.123.456/32') } its(:inbound) { should be_opened(22).protocol('tcp').for('group-name-sg') } + its(:inbound) { should be_opened(60000).protocol('tcp').for('100.456.789.012/32') } + its(:inbound) { should be_opened(70000).protocol('tcp').for('100.456.789.012/32') } its(:inbound) { should be_opened('50000-50009').protocol('tcp').for('123.456.789.012/32') } - its(:outbound) { should be_opened } - its(:inbound_rule_count) { should eq 4 } + its(:outbound) { should be_opened(50000).protocol('tcp').for('100.456.789.012/32') } + its(:inbound_rule_count) { should eq 6 } its(:outbound_rule_count) { should eq 1 } - its(:inbound_permissions_count) { should eq 3 } + its(:inbound_permissions_count) { should eq 5 } its(:outbound_permissions_count) { should eq 1 } it { should belong_to_vpc('my-vpc') } end diff --git a/spec/type/security_group_spec.rb b/spec/type/security_group_spec.rb index 715b4bcff..aca515f93 100644 --- a/spec/type/security_group_spec.rb +++ b/spec/type/security_group_spec.rb @@ -10,12 +10,15 @@ its(:inbound) { should be_opened(22).protocol('tcp').for('sg-5a6b7cd8') } its(:inbound) { should be_opened('50000-50009').protocol('tcp').for('123.456.789.012/32') } its(:inbound) { should_not be_opened('50010-50019').protocol('tcp').for('123.456.789.012/32') } - its(:outbound) { should be_opened } - its(:inbound_permissions_count) { should eq 3 } - its(:ip_permissions_count) { should eq 3 } + its(:outbound) { should be_opened(50_000) } + its(:inbound) { should be_opened_only(60_000).protocol('tcp').for('100.456.789.012/32') } + its(:inbound) { should be_opened_only(70_000).protocol('tcp').for('100.456.789.012/32') } + its(:outbound) { should be_opened_only(50_000).protocol('tcp').for('100.456.789.012/32') } + its(:inbound_permissions_count) { should eq 5 } + its(:ip_permissions_count) { should eq 5 } its(:outbound_permissions_count) { should eq 1 } its(:ip_permissions_egress_count) { should eq 1 } - its(:inbound_rule_count) { should eq 4 } + its(:inbound_rule_count) { should eq 6 } its(:outbound_rule_count) { should eq 1 } # its(:inbound) { should be_opened(22).protocol('tcp').for('group-name-sg') } # its(:inbound) { should be_opened(22).protocol('tcp').for('my-db-sg') } @@ -29,13 +32,13 @@ describe security_group('my-security-group-name') do it { should exist } - its(:outbound) { should be_opened } + its(:outbound) { should be_opened(50_000) } its(:inbound) { should be_opened(80) } it { should belong_to_vpc('my-vpc') } end describe security_group('my-security-tag-name') do - its(:outbound) { should be_opened } + its(:outbound) { should be_opened(50_000) } its(:inbound) { should be_opened(80) } it { should belong_to_vpc('my-vpc') } end