terracop 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ruby.yml +20 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +14 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.md +21 -0
- data/README.md +49 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bin/terracop +52 -0
- data/default_config.yml +1 -0
- data/lib/terracop/cop/aws/describe_security_group_rules.rb +35 -0
- data/lib/terracop/cop/aws/ensure_tags.rb +51 -0
- data/lib/terracop/cop/aws/iam_role_policy.rb +47 -0
- data/lib/terracop/cop/aws/open_egress.rb +42 -0
- data/lib/terracop/cop/aws/open_ingress.rb +44 -0
- data/lib/terracop/cop/aws/open_ssh.rb +39 -0
- data/lib/terracop/cop/aws/security_group_rule_cop.rb +45 -0
- data/lib/terracop/cop/aws/unrestricted_egress_ports.rb +37 -0
- data/lib/terracop/cop/aws/unrestricted_ingress_ports.rb +38 -0
- data/lib/terracop/cop/aws/wide_egress.rb +53 -0
- data/lib/terracop/cop/aws/wide_ingress.rb +53 -0
- data/lib/terracop/cop/base.rb +105 -0
- data/lib/terracop/cop/style/dash_in_resource_name.rb +35 -0
- data/lib/terracop/cop/style/resource_type_in_name.rb +53 -0
- data/lib/terracop/cop/style/snake_case.rb +35 -0
- data/lib/terracop/formatters/default.rb +25 -0
- data/lib/terracop/formatters/html.rb +16 -0
- data/lib/terracop/formatters/json.rb +53 -0
- data/lib/terracop/formatters/report.html.erb +289 -0
- data/lib/terracop/plan_loader.rb +39 -0
- data/lib/terracop/runner.rb +50 -0
- data/lib/terracop/state_loader.rb +39 -0
- data/lib/terracop/version.rb +5 -0
- data/lib/terracop.rb +49 -0
- data/terracop.gemspec +45 -0
- 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
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
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 © 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
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
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
|
data/default_config.yml
ADDED
@@ -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
|