terracop 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +20 -0
  3. data/.gitignore +14 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +14 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +14 -0
  8. data/Gemfile +10 -0
  9. data/Gemfile.lock +66 -0
  10. data/LICENSE.md +21 -0
  11. data/README.md +49 -0
  12. data/Rakefile +8 -0
  13. data/bin/console +15 -0
  14. data/bin/setup +8 -0
  15. data/bin/terracop +52 -0
  16. data/default_config.yml +1 -0
  17. data/lib/terracop/cop/aws/describe_security_group_rules.rb +35 -0
  18. data/lib/terracop/cop/aws/ensure_tags.rb +51 -0
  19. data/lib/terracop/cop/aws/iam_role_policy.rb +47 -0
  20. data/lib/terracop/cop/aws/open_egress.rb +42 -0
  21. data/lib/terracop/cop/aws/open_ingress.rb +44 -0
  22. data/lib/terracop/cop/aws/open_ssh.rb +39 -0
  23. data/lib/terracop/cop/aws/security_group_rule_cop.rb +45 -0
  24. data/lib/terracop/cop/aws/unrestricted_egress_ports.rb +37 -0
  25. data/lib/terracop/cop/aws/unrestricted_ingress_ports.rb +38 -0
  26. data/lib/terracop/cop/aws/wide_egress.rb +53 -0
  27. data/lib/terracop/cop/aws/wide_ingress.rb +53 -0
  28. data/lib/terracop/cop/base.rb +105 -0
  29. data/lib/terracop/cop/style/dash_in_resource_name.rb +35 -0
  30. data/lib/terracop/cop/style/resource_type_in_name.rb +53 -0
  31. data/lib/terracop/cop/style/snake_case.rb +35 -0
  32. data/lib/terracop/formatters/default.rb +25 -0
  33. data/lib/terracop/formatters/html.rb +16 -0
  34. data/lib/terracop/formatters/json.rb +53 -0
  35. data/lib/terracop/formatters/report.html.erb +289 -0
  36. data/lib/terracop/plan_loader.rb +39 -0
  37. data/lib/terracop/runner.rb +50 -0
  38. data/lib/terracop/state_loader.rb +39 -0
  39. data/lib/terracop/version.rb +5 -0
  40. data/lib/terracop.rb +49 -0
  41. data/terracop.gemspec +45 -0
  42. metadata +200 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 74d2da000770e8368a6f10a0743761edde55a5da61828714725b7567462c13c0
4
+ data.tar.gz: 05b65c4774aa057bed14d6cc4760c73354ae8675897d3fd7921d2e44952d426d
5
+ SHA512:
6
+ metadata.gz: 303ef1de659d6d6192c20e4ff171b4078e6df28b3c14a1cb2201ea1971c0e2d587c357d1f862b951a194ca60326fb898853bf1476bf487af045a2ac029537c3b
7
+ data.tar.gz: bb449b0e607af344ac09e5acec0b198e91d8fe4d2a7c1ac55d53e49a1c3dbd815eaa680675a53a211ce5e03a3c9d00bd8d1d5f8a55de3561d1f206a85ba1804f
@@ -0,0 +1,20 @@
1
+ name: Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - uses: actions/checkout@v1
12
+ - name: Set up Ruby 2.6
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+ - name: Build and test with Rake
17
+ run: |
18
+ gem install bundler
19
+ bundle install --jobs 4 --retry 3
20
+ bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .DS_Store
14
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ Metrics/BlockLength:
5
+ Exclude:
6
+ - spec/**/*
7
+ - terracop.gemspec
8
+
9
+ Style/AsciiComments:
10
+ # I will use emojis!
11
+ Enabled: false
12
+
13
+ RSpec/NestedGroups:
14
+ Max: 7
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.1.0
8
+
9
+ - Initial release.
10
+ - Can load Terraform 0.12 state and plan files.
11
+ - Performs a number of generic checks on all resources.
12
+ - Performs some AWS-specific security checks on some resources.
13
+ - Loads a default configuration file.
14
+ - Allows configuration overrides through `.terracop.yml`.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in terracop.gemspec
6
+ gemspec
7
+
8
+ # Use latest unreleased simplecov to get Branch Coverage
9
+ # gem 'simplecov', git: 'https://github.com/colszowka/simplecov.git'
10
+ # gem 'simplecov-html', git: 'https://github.com/colszowka/simplecov-html.git'
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ terracop (0.1.0)
5
+ colorize (~> 0.8)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.0)
11
+ byebug (11.0.1)
12
+ colorize (0.8.1)
13
+ diff-lcs (1.3)
14
+ docile (1.3.2)
15
+ jaro_winkler (1.5.4)
16
+ json (2.3.0)
17
+ parallel (1.19.1)
18
+ parser (2.6.5.0)
19
+ ast (~> 2.4.0)
20
+ rainbow (3.0.0)
21
+ rake (10.5.0)
22
+ rspec (3.9.0)
23
+ rspec-core (~> 3.9.0)
24
+ rspec-expectations (~> 3.9.0)
25
+ rspec-mocks (~> 3.9.0)
26
+ rspec-core (3.9.0)
27
+ rspec-support (~> 3.9.0)
28
+ rspec-expectations (3.9.0)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.9.0)
31
+ rspec-mocks (3.9.0)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.9.0)
34
+ rspec-support (3.9.0)
35
+ rubocop (0.78.0)
36
+ jaro_winkler (~> 1.5.1)
37
+ parallel (~> 1.10)
38
+ parser (>= 2.6)
39
+ rainbow (>= 2.2.2, < 4.0)
40
+ ruby-progressbar (~> 1.7)
41
+ unicode-display_width (>= 1.4.0, < 1.7)
42
+ rubocop-rspec (1.37.1)
43
+ rubocop (>= 0.68.1)
44
+ ruby-progressbar (1.10.1)
45
+ simplecov (0.17.1)
46
+ docile (~> 1.1)
47
+ json (>= 1.8, < 3)
48
+ simplecov-html (~> 0.10.0)
49
+ simplecov-html (0.10.2)
50
+ unicode-display_width (1.6.0)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ bundler (~> 2.0)
57
+ byebug (~> 11.0)
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ rubocop (~> 0.78)
61
+ rubocop-rspec (~> 1.37)
62
+ simplecov (~> 0.10)
63
+ terracop!
64
+
65
+ BUNDLED WITH
66
+ 2.0.2
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # The MIT License (MIT)
2
+ Copyright &copy; 2019 Francesco Boffa
3
+
4
+ * * *
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+ this software and associated documentation files (the “Software”), to deal in
8
+ the Software without restriction, including without limitation the rights to
9
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
+ the Software, and to permit persons to whom the Software is furnished to do so,
11
+ subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Terracop
2
+
3
+ Terracop is a HashiCorp [Terraform](https://www.terraform.io/) state / plan
4
+ parser and analyzer. Put it in a CI pipeline to analyze your Terraform plans
5
+ or run it on already applied states and see what could be improved.
6
+
7
+ The checks run by Terracop go anywhere from resource names guidelines to
8
+ identifying security holes in your configuration.
9
+
10
+ _Terracop is massively inspired by [Rubocop](https://github.com/rubocop-hq/rubocop)._
11
+
12
+ ## Installation
13
+
14
+ **Terracop** installation is pretty standard:
15
+
16
+ $ gem install terracop
17
+
18
+ If you'd rather install RuboCop using bundler, don't require it in your Gemfile:
19
+
20
+ gem 'terracop', require: false
21
+
22
+ ## Compatibility
23
+
24
+ Terracop can work with state and plan files generated by Terraform 0.12.
25
+
26
+ ## Usage
27
+
28
+ You can run terracop from the same directory where you would run terraform and
29
+ it will automatically pull the state file and analyze it.
30
+
31
+ If you want to analyze a state file somewhere on your machine you can pass it
32
+ like this:
33
+
34
+ $ terracop --state path/to/state/file
35
+
36
+ Terracop can (will) parse also terraform plan files, in order to report
37
+ potential issues before you apply the plan and make the problem permanent. Eg:
38
+
39
+ $ terraform plan -out tfplan
40
+ $ terracop --plan tfplan
41
+ $ terraform apply tfplan
42
+
43
+ ## Contributing
44
+
45
+ Bug reports and pull requests are welcome on GitHub at https://github.com/aomega08/terracop.
46
+
47
+ ## Copyright
48
+
49
+ Copyright (c) 2019-2020 Francesco Boffa. See [LICENSE.md](LICENSE.md) for further details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'terracop'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/terracop ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+
6
+ require 'bundler/setup'
7
+ require 'optparse'
8
+ require 'terracop'
9
+
10
+ formatter = :default
11
+ state = nil
12
+ plan = nil
13
+ type = :state
14
+
15
+ OptionParser.new do |opts|
16
+ opts.banner += ' <state_file.json>'
17
+
18
+ opts.on(
19
+ '-f', '--format FORMAT', /(default|html|json)/,
20
+ 'Use a specific formatter for the output'
21
+ ) do |arg|
22
+ formatter = arg[0].to_sym
23
+ end
24
+
25
+ opts.on('-s', '--state FILE', 'Specify the state file to analyze') do |arg|
26
+ state = arg
27
+ end
28
+
29
+ opts.on('-p', '--plan FILE', 'Specify the terraform plan to analyze') do |arg|
30
+ plan = arg
31
+ type = :plan
32
+ end
33
+
34
+ opts.on_tail('-h', '--help', 'Prints this help') do
35
+ puts opts
36
+ exit
37
+ end
38
+
39
+ opts.on_tail('-v', '--version', 'Show version') do
40
+ puts Terracop::VERSION
41
+ exit
42
+ end
43
+
44
+ opts.parse!
45
+ end
46
+
47
+ if state && plan
48
+ puts 'You can analyze either a state or a plan, but not both.'
49
+ exit
50
+ end
51
+
52
+ Terracop::Runner.new(type, state || plan, formatter).run
@@ -0,0 +1 @@
1
+ ---
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/base'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop checks for AWS Security Group rules with no description.
9
+ # Reading terraform code can immediately tell why a rule is in place, but
10
+ # the AWS console is a bit more cryptic and a description can help.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # resource "aws_security_group_rule" "rule" {
15
+ # source_security_group_id = "sg-123456"
16
+ # }
17
+ #
18
+ # # good
19
+ # resource "aws_security_group_rule" "rule" {
20
+ # source_security_group_id = "sg-123456"
21
+ # description = "Traffic from the load balancer"
22
+ # }
23
+ class DescribeSecurityGroupRules < Base
24
+ register
25
+ applies_to :aws_security_group_rule
26
+
27
+ def check
28
+ return unless attributes['description'] == ''
29
+
30
+ offense('Add a description to security group rules.')
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/base'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop makes sure that AWS resources that can be tagged, are indeed
9
+ # tagged.
10
+ # By default it just checks that resources have at least one tag, any tag.
11
+ # It is configurable to enforce the existance of some specific tags.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # resource "aws_alb" "lb" {
16
+ # name_prefix = "app"
17
+ # }
18
+ #
19
+ # # good
20
+ # resource "aws_alb" "lb" {
21
+ # name_prefix = "app"
22
+ # tags = {
23
+ # environment = "staging"
24
+ # }
25
+ # }
26
+ class EnsureTags < Base
27
+ register
28
+
29
+ def check
30
+ return unless attributes['tags']
31
+
32
+ if self.class.config['Required']
33
+ check_required(self.class.config['Required'])
34
+ elsif attributes['tags'].empty?
35
+ offense 'Tag resources properly.'
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def check_required(required_tags)
42
+ required_tags.each do |key|
43
+ unless attributes['tags'][key]
44
+ offense "Required tag \"#{key}\" is missing on this resource."
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/base'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop warns against the use of inline role policies.
9
+ # Inline policies tend to be copy/pasted, sometimes with minor changes
10
+ # and are not shown in the "Policies" tab of AWS IAM.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # resource "aws_role" "role" { }
15
+ #
16
+ # resource "aws_iam_role_policy" "policy" {
17
+ # role = aws_role.role.id
18
+ # name = "policy"
19
+ #
20
+ # policy = <some policy>
21
+ # }
22
+ #
23
+ # # good
24
+ # resource "aws_role" "role" { }
25
+ #
26
+ # resource "aws_iam_policy" "policy" {
27
+ # name = "test-policy"
28
+ #
29
+ # policy = <some policy>
30
+ # }
31
+ #
32
+ # resource "aws_iam_role_policy_attachment" "attach" {
33
+ # role = aws_iam_role.role.name
34
+ # policy_arn = aws_iam_policy.policy.arn
35
+ # }
36
+ class IamRolePolicy < Base
37
+ register
38
+ applies_to :aws_iam_role_policy
39
+
40
+ def check
41
+ offense('Use aws_iam_role_policy_attachment instead of attaching ' \
42
+ 'inline policies with aws_iam_role_policy.')
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/aws/security_group_rule_cop'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop warns against an egress rule to 0.0.0.0/0.
9
+ # While very common, and not necessarily an offense, you may want to lock
10
+ # the outbound traffic to some specific addresses (or even other security
11
+ # groups), especially in highly regulated environments.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # resource "aws_security_group_rule" "egress" {
16
+ # type = "egress"
17
+ # cidr_blocks = ["0.0.0.0/0"]
18
+ # }
19
+ #
20
+ # # good
21
+ # resource "aws_security_group_rule" "egress" {
22
+ # type = "egress"
23
+ # cidr_blocks = ["10.4.0.0/16"]
24
+ # }
25
+ #
26
+ # # better
27
+ # resource "aws_security_group_rule" "egress" {
28
+ # type = "egress"
29
+ # security_group_id = aws_security_group.destination.id
30
+ # }
31
+ class OpenEgress < SecurityGroupRuleCop
32
+ register
33
+
34
+ def check
35
+ return unless egress? && any_ip?
36
+
37
+ offense('Avoid allowing egress traffic to 0.0.0.0/0.', :security)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/aws/security_group_rule_cop'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop warns against an ingress rule from 0.0.0.0/0.
9
+ # With a couple of specific exceptions, you don't want to allow traffic
10
+ # from anywhere in the world to most of your infrastructure.
11
+ # A common exception is the external Load Balancer receiving traffic
12
+ # for a website. Use the `Except` configuration to whitelist that specific
13
+ # rule.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # resource "aws_security_group_rule" "ingress" {
18
+ # type = "ingress"
19
+ # cidr_blocks = ["0.0.0.0/0"]
20
+ # }
21
+ #
22
+ # # good
23
+ # resource "aws_security_group_rule" "ingress" {
24
+ # type = "ingress"
25
+ # cidr_blocks = ["10.4.0.0/16"]
26
+ # }
27
+ #
28
+ # # better
29
+ # resource "aws_security_group_rule" "ingress" {
30
+ # type = "ingress"
31
+ # security_group_id = aws_security_group.source.id
32
+ # }
33
+ class OpenIngress < SecurityGroupRuleCop
34
+ register
35
+
36
+ def check
37
+ return unless ingress? && any_ip?
38
+
39
+ offense('Avoid allowing ingress traffic from 0.0.0.0/0.', :security)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/aws/security_group_rule_cop'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop warns against an ingress rule from 0.0.0.0/0 on port 22 (SSH).
9
+ # That is a Very Bad Idea™.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # resource "aws_security_group_rule" "ingress" {
14
+ # type = "ingress"
15
+ # cidr_blocks = ["0.0.0.0/0"]
16
+ # # Notice this port range includes 22
17
+ # from_port = 10
18
+ # to_port = 30
19
+ # }
20
+ #
21
+ # # good
22
+ # resource "aws_security_group_rule" "ingress" {
23
+ # type = "ingress"
24
+ # cidr_blocks = ["1.2.3.4/32"]
25
+ # from_port = 22
26
+ # to_port = 22
27
+ # }
28
+ class OpenSsh < SecurityGroupRuleCop
29
+ register
30
+
31
+ def check
32
+ return unless ingress? && any_ip? && tcp? && port?(22)
33
+
34
+ offense('Do not leave port 22 (SSH) open to the world.', :security)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/base'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # Base class that provides helper methods for other Cops checking
9
+ # Security Group rules.
10
+ class SecurityGroupRuleCop < Base
11
+ applies_to :aws_security_group_rule
12
+
13
+ protected
14
+
15
+ def ingress?
16
+ attributes['type'] == 'ingress'
17
+ end
18
+
19
+ def egress?
20
+ attributes['type'] == 'egress'
21
+ end
22
+
23
+ def any_ip?
24
+ attributes['cidr_blocks'].include?('0.0.0.0/0')
25
+ end
26
+
27
+ def tcp?
28
+ attributes['protocol'] == 'tcp'
29
+ end
30
+
31
+ def udp?
32
+ attributes['protocol'] == 'udp'
33
+ end
34
+
35
+ def port?(port)
36
+ (attributes['from_port']..attributes['to_port']).include?(port)
37
+ end
38
+
39
+ def any_port?
40
+ (attributes['from_port']..attributes['to_port']).count == 65_536
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terracop/cop/aws/security_group_rule_cop'
4
+
5
+ module Terracop
6
+ module Cop
7
+ module Aws
8
+ # This cop warns against egress security group rules that allow any port.
9
+ # This would, for example, allow an attacker to use your machine to send
10
+ # spam emails, since you left port 25 outbound open.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # resource "aws_security_group_rule" "egress" {
15
+ # type = "egress"
16
+ # from_port = 0
17
+ # to_port = 65535
18
+ # }
19
+ #
20
+ # # good
21
+ # resource "aws_security_group_rule" "egress" {
22
+ # type = "egress"
23
+ # from_port = 443
24
+ # to_port = 443
25
+ # }
26
+ class UnrestrictedEgressPorts < SecurityGroupRuleCop
27
+ register
28
+
29
+ def check
30
+ return unless egress? && (tcp? || udp?) && any_port?
31
+
32
+ offense('Limit egress traffic to small port ranges.', :security)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end