cfn-nag 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/cfn_nag_rules +4 -0
- data/lib/cfn_nag.rb +45 -5
- data/lib/custom_rules/security_group_missing_egress.rb +5 -1
- data/lib/custom_rules/user_missing_group.rb +5 -1
- data/lib/json_rules/basic_rules.rb +1 -1
- data/lib/json_rules/cidr_rules.rb +30 -15
- data/lib/json_rules/iam_policy_rules.rb +1 -1
- data/lib/json_rules/iam_user_rules.rb +1 -1
- data/lib/json_rules/port_rules.rb +23 -11
- data/lib/rule.rb +14 -18
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d3284f4eba9d2cab9d7790dab39273f9401fbb09
         | 
| 4 | 
            +
              data.tar.gz: e715f4800f39198bd95bc1fb6044ce1dd64644d6
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 06b61112e6e6cff426fcd6e07af0c0aa75f85f38914816bc1df48286e4aec04d76d9000d61202c9fae3a138e50d55c9af8ca0da56971f07644bdfde4b80f92a8
         | 
| 7 | 
            +
              data.tar.gz: 43147a231964233735ee827ee0f1c9ec4894f6725904e95b137b3e8205181213d5ea5698e75ce704fd695025015e9a31467d65d1e14d0580587d79dfbdc75071
         | 
    
        data/bin/cfn_nag_rules
    ADDED
    
    
    
        data/lib/cfn_nag.rb
    CHANGED
    
    | @@ -4,10 +4,47 @@ require_relative 'custom_rules/user_missing_group' | |
| 4 4 | 
             
            require_relative 'model/cfn_model'
         | 
| 5 5 | 
             
            require_relative 'result_view/simple_stdout_results'
         | 
| 6 6 | 
             
            require_relative 'result_view/json_results'
         | 
| 7 | 
            +
            require 'tempfile'
         | 
| 7 8 |  | 
| 8 9 | 
             
            class CfnNag
         | 
| 9 10 | 
             
              include Rule
         | 
| 10 11 |  | 
| 12 | 
            +
              def initialize
         | 
| 13 | 
            +
                @warning_registry = []
         | 
| 14 | 
            +
                @violation_registry = []
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def dump_rules
         | 
| 18 | 
            +
                dummy_cfn = <<-END
         | 
| 19 | 
            +
                  {
         | 
| 20 | 
            +
                    "Resources": {
         | 
| 21 | 
            +
                      "resource1": {
         | 
| 22 | 
            +
                        "Type" : "AWS::EC2::DHCPOptions",
         | 
| 23 | 
            +
                        "Properties": {
         | 
| 24 | 
            +
                          "DomainNameServers" : [ "10.0.0.1" ]
         | 
| 25 | 
            +
                        }
         | 
| 26 | 
            +
                      }
         | 
| 27 | 
            +
                    }
         | 
| 28 | 
            +
                  }
         | 
| 29 | 
            +
                END
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                Tempfile.open('tempfile') do |dummy_cfn_template|
         | 
| 32 | 
            +
                  dummy_cfn_template.write dummy_cfn
         | 
| 33 | 
            +
                  dummy_cfn_template.rewind
         | 
| 34 | 
            +
                  audit_file(input_json_path: dummy_cfn_template.path)
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                custom_rule_registry.each do |rule_class|
         | 
| 38 | 
            +
                  @violation_registry << rule_class.new.rule_text
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                puts 'WARNING VIOLATIONS:'
         | 
| 42 | 
            +
                puts @warning_registry.sort
         | 
| 43 | 
            +
                puts
         | 
| 44 | 
            +
                puts 'FAILING VIOLATIONS:'
         | 
| 45 | 
            +
                puts @violation_registry.sort
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 11 48 | 
             
              def audit(input_json_path:,
         | 
| 12 49 | 
             
                        output_format:'txt')
         | 
| 13 50 |  | 
| @@ -129,13 +166,16 @@ class CfnNag | |
| 129 166 |  | 
| 130 167 | 
             
              def custom_rules(input_json_path)
         | 
| 131 168 | 
             
                cfn_model = CfnModel.new.parse(IO.read(input_json_path))
         | 
| 132 | 
            -
                 | 
| 133 | 
            -
                  SecurityGroupMissingEgressRule,
         | 
| 134 | 
            -
                  UserMissingGroupRule
         | 
| 135 | 
            -
                ]
         | 
| 136 | 
            -
                rules.each do |rule_class|
         | 
| 169 | 
            +
                custom_rule_registry.each do |rule_class|
         | 
| 137 170 | 
             
                  audit_result = rule_class.new.audit(cfn_model)
         | 
| 138 171 | 
             
                  @violations << audit_result unless audit_result.nil?
         | 
| 139 172 | 
             
                end
         | 
| 140 173 | 
             
              end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
              def custom_rule_registry
         | 
| 176 | 
            +
                [
         | 
| 177 | 
            +
                  SecurityGroupMissingEgressRule,
         | 
| 178 | 
            +
                  UserMissingGroupRule
         | 
| 179 | 
            +
                ]
         | 
| 180 | 
            +
              end
         | 
| 141 181 | 
             
            end
         | 
| @@ -2,6 +2,10 @@ require_relative '../violation' | |
| 2 2 |  | 
| 3 3 | 
             
            class SecurityGroupMissingEgressRule
         | 
| 4 4 |  | 
| 5 | 
            +
              def rule_text
         | 
| 6 | 
            +
                'Missing egress rule means all traffic is allowed outbound.  Make this explicit if it is desired configuration'
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
              def audit(cfn_model)
         | 
| 6 10 | 
             
                logical_resource_ids = []
         | 
| 7 11 | 
             
                cfn_model.security_groups.each do |security_group|
         | 
| @@ -12,7 +16,7 @@ class SecurityGroupMissingEgressRule | |
| 12 16 |  | 
| 13 17 | 
             
                if logical_resource_ids.size > 0
         | 
| 14 18 | 
             
                  Violation.new(type: Violation::FAILING_VIOLATION,
         | 
| 15 | 
            -
                                message:  | 
| 19 | 
            +
                                message: rule_text,
         | 
| 16 20 | 
             
                                logical_resource_ids: logical_resource_ids)
         | 
| 17 21 | 
             
                else
         | 
| 18 22 | 
             
                  nil
         | 
| @@ -2,6 +2,10 @@ require_relative '../violation' | |
| 2 2 |  | 
| 3 3 | 
             
            class UserMissingGroupRule
         | 
| 4 4 |  | 
| 5 | 
            +
              def rule_text
         | 
| 6 | 
            +
                'User is not assigned to a group'
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
              def audit(cfn_model)
         | 
| 6 10 | 
             
                logical_resource_ids = []
         | 
| 7 11 | 
             
                cfn_model.iam_users.each do |iam_user|
         | 
| @@ -12,7 +16,7 @@ class UserMissingGroupRule | |
| 12 16 |  | 
| 13 17 | 
             
                if logical_resource_ids.size > 0
         | 
| 14 18 | 
             
                  Violation.new(type: Violation::FAILING_VIOLATION,
         | 
| 15 | 
            -
                                message:  | 
| 19 | 
            +
                                message: rule_text,
         | 
| 16 20 | 
             
                                logical_resource_ids: logical_resource_ids)
         | 
| 17 21 | 
             
                else
         | 
| 18 22 | 
             
                  nil
         | 
| @@ -28,19 +28,34 @@ warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | selec | |
| 28 28 | 
             
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2::SecurityGroupIngress" and .Properties.CidrIp|type == "string")|select(.Properties.CidrIp | test("^\\\d{1,3}\\\.\\\d{1,3}\\\.\\\d{1,3}\\\.\\\d{1,3}/(?!32)$") )]|map(.LogicalResourceId)',
         | 
| 29 29 | 
             
                    message: 'Security Group Standalone Ingress cidr found that is not /32'
         | 
| 30 30 |  | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 31 | 
            +
            non_32_cidr_jq_expression = <<END
         | 
| 32 | 
            +
            [.Resources |
         | 
| 33 | 
            +
             with_entries(.value.LogicalResourceId = .key)[] |
         | 
| 34 | 
            +
             select(.Type == "AWS::EC2::SecurityGroup") |
         | 
| 35 | 
            +
             if (.Properties.SecurityGroupIngress|type == "object")
         | 
| 36 | 
            +
             then (
         | 
| 37 | 
            +
                   select(.Properties.SecurityGroupIngress.CidrIp|type == "string")|
         | 
| 38 | 
            +
                   select(.Properties.SecurityGroupIngress.CidrIp|test("^\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}/(?!32)$"))
         | 
| 39 | 
            +
                  )
         | 
| 40 | 
            +
             else (
         | 
| 41 | 
            +
                    if (.Properties.SecurityGroupIngress|type == "array")
         | 
| 42 | 
            +
                    then (
         | 
| 43 | 
            +
                           select(.Properties.SecurityGroupIngress[].CidrIp|type == "string")|
         | 
| 44 | 
            +
                           select(.Properties.SecurityGroupIngress[].CidrIp |
         | 
| 45 | 
            +
                                  (
         | 
| 46 | 
            +
                                    if (.|type=="string")
         | 
| 47 | 
            +
                                    then test("^\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}/(?!32)$")
         | 
| 48 | 
            +
                                    else empty
         | 
| 49 | 
            +
                                    end
         | 
| 50 | 
            +
                                  )
         | 
| 51 | 
            +
                                 )
         | 
| 52 | 
            +
                         )
         | 
| 53 | 
            +
                    else empty
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  )
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
              ]|map(.LogicalResourceId)
         | 
| 58 | 
            +
            END
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            warning jq: non_32_cidr_jq_expression,
         | 
| 37 61 | 
             
                    message: 'Security Groups found with cidr that is not /32'
         | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
            #for inline, this covers it, but with an externalized egress rule... the expression gets real evil
         | 
| 41 | 
            -
            #i guess the ideal would be to do a join of ingress and egress rules with the parent sg
         | 
| 42 | 
            -
            #but it gets real hairy with FnGetAtt for GroupId and all that.... think it best to
         | 
| 43 | 
            -
            #write some imperative code in custom rules to take care of things
         | 
| 44 | 
            -
            # violation '.Resources[]|select(.Type == "AWS::EC2::SecurityGroup")|select(.Properties.SecurityGroupEgress == null or .Properties.SecurityGroupEgress.length? == 0)' do |security_groups|
         | 
| 45 | 
            -
            #   puts "Security Groups found without egress json_rules: #{security_groups}"
         | 
| 46 | 
            -
            # end
         | 
| @@ -55,7 +55,7 @@ END | |
| 55 55 |  | 
| 56 56 | 
             
            warning jq: allow_not_action_filter +
         | 
| 57 57 | 
             
                        "[#{resources_by_type('AWS::IAM::Role')}|select(.Properties.AssumeRolePolicyDocument|allow_not_action)]|map(.LogicalResourceId)",
         | 
| 58 | 
            -
                    message: 'IAM role should not allow Allow+NotAction'
         | 
| 58 | 
            +
                    message: 'IAM role should not allow Allow+NotAction on trust permissinos'
         | 
| 59 59 |  | 
| 60 60 |  | 
| 61 61 | 
             
            warning jq: allow_not_action_filter +
         | 
| @@ -8,5 +8,5 @@ violation jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | sel | |
| 8 8 |  | 
| 9 9 | 
             
            violation jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::IAM::ManagedPolicy")|'\
         | 
| 10 10 | 
             
                          'select(.Properties.Users|length > 0)]|map(.LogicalResourceId) ',
         | 
| 11 | 
            -
                      message: 'IAM policy should not apply directly to users.  Should be on group'
         | 
| 11 | 
            +
                      message: 'IAM managed policy should not apply directly to users.  Should be on group'
         | 
| 12 12 |  | 
| @@ -1,17 +1,29 @@ | |
| 1 | 
            -
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] |  | 
| 1 | 
            +
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | '\
         | 
| 2 | 
            +
                        'select(.Type == "AWS::EC2::SecurityGroup")| '\
         | 
| 3 | 
            +
                        'if (.Properties.SecurityGroupIngress|type == "object") '\
         | 
| 4 | 
            +
                        'then select(.Properties.SecurityGroupIngress.ToPort != .Properties.SecurityGroupIngress.FromPort) '\
         | 
| 5 | 
            +
                        'else if (.Properties.SecurityGroupIngress|type == "array") '\
         | 
| 6 | 
            +
                        '     then select([.Properties.SecurityGroupIngress[].ToPort] != [.Properties.SecurityGroupIngress[].FromPort]) '\
         | 
| 7 | 
            +
                        '     else empty '\
         | 
| 8 | 
            +
                        '     end '\
         | 
| 9 | 
            +
                        'end '\
         | 
| 10 | 
            +
                        ']|map(.LogicalResourceId)',
         | 
| 2 11 | 
             
                    message:  'Security Groups found ingress with port range instead of just a single port'
         | 
| 3 12 |  | 
| 4 | 
            -
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2:: | 
| 5 | 
            -
                    message:  'Security  | 
| 6 | 
            -
             | 
| 7 | 
            -
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2::SecurityGroup" and (.Properties.SecurityGroupEgress|type == "object"))|select(.Properties.SecurityGroupEgress.ToPort != .Properties.SecurityGroupEgress.FromPort)]|map(.LogicalResourceId)',
         | 
| 8 | 
            -
                    message:  'Security Groups found egress with port range instead of just a single port'
         | 
| 13 | 
            +
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2::SecurityGroupIngress")|select(.Properties.ToPort != .Properties.FromPort)]|map(.LogicalResourceId)',
         | 
| 14 | 
            +
                    message:  'Security Group ingress with port range instead of just a single port'
         | 
| 9 15 |  | 
| 10 | 
            -
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] |  | 
| 16 | 
            +
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | '\
         | 
| 17 | 
            +
                        'select(.Type == "AWS::EC2::SecurityGroup")| '\
         | 
| 18 | 
            +
                        'if (.Properties.SecurityGroupEgress|type == "object") '\
         | 
| 19 | 
            +
                        'then select(.Properties.SecurityGroupEgress.ToPort != .Properties.SecurityGroupEgress.FromPort) '\
         | 
| 20 | 
            +
                        'else if (.Properties.SecurityGroupEgress|type == "array") '\
         | 
| 21 | 
            +
                        '     then select([.Properties.SecurityGroupEgress[].ToPort] != [.Properties.SecurityGroupEgress[].FromPort]) '\
         | 
| 22 | 
            +
                        '     else empty '\
         | 
| 23 | 
            +
                        '     end '\
         | 
| 24 | 
            +
                        'end'\
         | 
| 25 | 
            +
                        ']|map(.LogicalResourceId)',
         | 
| 11 26 | 
             
                    message:  'Security Groups found egress with port range instead of just a single port'
         | 
| 12 27 |  | 
| 13 | 
            -
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2::SecurityGroupIngress")|select(.Properties.ToPort != .Properties.FromPort)]|map(.LogicalResourceId)',
         | 
| 14 | 
            -
                    message:  'Security Groups found ingress with port range instead of just a single port'
         | 
| 15 | 
            -
             | 
| 16 28 | 
             
            warning jq: '[.Resources|with_entries(.value.LogicalResourceId = .key)[] | select(.Type == "AWS::EC2::SecurityGroupEgress")|select(.Properties.ToPort != .Properties.FromPort)]|map(.LogicalResourceId)',
         | 
| 17 | 
            -
                    message:  'Security  | 
| 29 | 
            +
                    message:  'Security Group egress with port range instead of just a single port'
         | 
    
        data/lib/rule.rb
    CHANGED
    
    | @@ -17,13 +17,15 @@ module Rule | |
| 17 17 | 
             
              end
         | 
| 18 18 |  | 
| 19 19 | 
             
              def warning(jq:, message:)
         | 
| 20 | 
            +
                @warning_registry << message
         | 
| 21 | 
            +
             | 
| 20 22 | 
             
                return if @stop_processing
         | 
| 21 23 |  | 
| 22 24 | 
             
                Logging.logger['log'].debug jq
         | 
| 23 25 |  | 
| 24 26 | 
             
                stdout = jq_command(@input_json_path, jq)
         | 
| 25 27 | 
             
                result = $?.exitstatus
         | 
| 26 | 
            -
                scrape_jq_output_for_error(stdout)
         | 
| 28 | 
            +
                scrape_jq_output_for_error(jq, stdout)
         | 
| 27 29 |  | 
| 28 30 | 
             
                resource_ids = parse_logical_resource_ids(stdout)
         | 
| 29 31 | 
             
                new_warnings = resource_ids.size
         | 
| @@ -39,7 +41,6 @@ module Rule | |
| 39 41 | 
             
                             fail_if_found: false,
         | 
| 40 42 | 
             
                             fatal: true,
         | 
| 41 43 | 
             
                             message: message,
         | 
| 42 | 
            -
                             message_type: Violation::FAILING_VIOLATION,
         | 
| 43 44 | 
             
                             raw: true)
         | 
| 44 45 | 
             
              end
         | 
| 45 46 |  | 
| @@ -47,8 +48,7 @@ module Rule | |
| 47 48 | 
             
                failing_rule(jq_expression: jq,
         | 
| 48 49 | 
             
                             fail_if_found: false,
         | 
| 49 50 | 
             
                             fatal: true,
         | 
| 50 | 
            -
                             message: message | 
| 51 | 
            -
                             message_type: Violation::FAILING_VIOLATION)
         | 
| 51 | 
            +
                             message: message)
         | 
| 52 52 | 
             
              end
         | 
| 53 53 |  | 
| 54 54 | 
             
              def raw_fatal_violation(jq:, message:)
         | 
| @@ -56,7 +56,6 @@ module Rule | |
| 56 56 | 
             
                             fail_if_found: true,
         | 
| 57 57 | 
             
                             fatal: true,
         | 
| 58 58 | 
             
                             message: message,
         | 
| 59 | 
            -
                             message_type: Violation::FAILING_VIOLATION,
         | 
| 60 59 | 
             
                             raw: true)
         | 
| 61 60 | 
             
              end
         | 
| 62 61 |  | 
| @@ -64,22 +63,19 @@ module Rule | |
| 64 63 | 
             
                failing_rule(jq_expression: jq,
         | 
| 65 64 | 
             
                             fail_if_found: true,
         | 
| 66 65 | 
             
                             fatal: true,
         | 
| 67 | 
            -
                             message: message | 
| 68 | 
            -
                             message_type: Violation::FAILING_VIOLATION)
         | 
| 66 | 
            +
                             message: message)
         | 
| 69 67 | 
             
              end
         | 
| 70 68 |  | 
| 71 69 | 
             
              def violation(jq:, message:)
         | 
| 72 70 | 
             
                failing_rule(jq_expression: jq,
         | 
| 73 71 | 
             
                             fail_if_found: true,
         | 
| 74 | 
            -
                             message: message | 
| 75 | 
            -
                             message_type: Violation::FAILING_VIOLATION)
         | 
| 72 | 
            +
                             message: message)
         | 
| 76 73 | 
             
              end
         | 
| 77 74 |  | 
| 78 75 | 
             
              def assertion(jq:, message:)
         | 
| 79 76 | 
             
                failing_rule(jq_expression: jq,
         | 
| 80 77 | 
             
                             fail_if_found: false,
         | 
| 81 | 
            -
                             message: message | 
| 82 | 
            -
                             message_type: Violation::FAILING_VIOLATION)
         | 
| 78 | 
            +
                             message: message)
         | 
| 83 79 | 
             
              end
         | 
| 84 80 |  | 
| 85 81 | 
             
              def self.empty?(array)
         | 
| @@ -129,8 +125,8 @@ module Rule | |
| 129 125 | 
             
                JSON.load(stdout)
         | 
| 130 126 | 
             
              end
         | 
| 131 127 |  | 
| 132 | 
            -
              def scrape_jq_output_for_error(stdout)
         | 
| 133 | 
            -
                fail  | 
| 128 | 
            +
              def scrape_jq_output_for_error(command, stdout)
         | 
| 129 | 
            +
                fail "jq rule is likely not correct: #{command}\n\n#{stdout}" if stdout.include? 'jq: error'
         | 
| 134 130 | 
             
              end
         | 
| 135 131 |  | 
| 136 132 | 
             
              # fail_if_found: this is false for an assertion, true for a violation.  either way this rule ups the "failure" count
         | 
| @@ -142,21 +138,21 @@ module Rule | |
| 142 138 | 
             
              def failing_rule(jq_expression:,
         | 
| 143 139 | 
             
                               fail_if_found:,
         | 
| 144 140 | 
             
                               message:,
         | 
| 145 | 
            -
                               message_type:,
         | 
| 146 141 | 
             
                               fatal: false,
         | 
| 147 142 | 
             
                               raw: false)
         | 
| 143 | 
            +
                @violation_registry << message
         | 
| 148 144 | 
             
                return if @stop_processing
         | 
| 149 145 |  | 
| 150 146 | 
             
                Logging.logger['log'].debug jq_expression
         | 
| 151 147 |  | 
| 152 148 | 
             
                stdout = jq_command(@input_json_path, jq_expression)
         | 
| 153 149 | 
             
                result = $?.exitstatus
         | 
| 154 | 
            -
                scrape_jq_output_for_error(stdout)
         | 
| 150 | 
            +
                scrape_jq_output_for_error(jq_expression, stdout)
         | 
| 155 151 | 
             
                if (fail_if_found and result == 0) or
         | 
| 156 152 | 
             
                   (not fail_if_found and result != 0)
         | 
| 157 153 |  | 
| 158 154 | 
             
                  if raw
         | 
| 159 | 
            -
                    add_violation(type:  | 
| 155 | 
            +
                    add_violation(type: Violation::FAILING_VIOLATION,
         | 
| 160 156 | 
             
                                  message: message,
         | 
| 161 157 | 
             
                                  violating_code: stdout)
         | 
| 162 158 |  | 
| @@ -167,7 +163,7 @@ module Rule | |
| 167 163 | 
             
                    resource_ids = parse_logical_resource_ids(stdout)
         | 
| 168 164 |  | 
| 169 165 | 
             
                    if resource_ids.size > 0
         | 
| 170 | 
            -
                      add_violation(type:  | 
| 166 | 
            +
                      add_violation(type: Violation::FAILING_VIOLATION,
         | 
| 171 167 | 
             
                                    message: message,
         | 
| 172 168 | 
             
                                    logical_resource_ids: resource_ids)
         | 
| 173 169 |  | 
| @@ -181,7 +177,7 @@ module Rule | |
| 181 177 |  | 
| 182 178 | 
             
              # the -e will return an exit code
         | 
| 183 179 | 
             
              def jq_command(input_json_path, jq_expression)
         | 
| 184 | 
            -
                command = "cat #{input_json_path} | jq '#{jq_expression}' -e"
         | 
| 180 | 
            +
                command = "cat #{input_json_path} | jq '#{jq_expression}' -e 2>&1"
         | 
| 185 181 |  | 
| 186 182 | 
             
                Logging.logger['log'].debug command
         | 
| 187 183 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: cfn-nag
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.17
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - someguy
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016-03- | 
| 11 | 
            +
            date: 2016-03-02 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: logging
         | 
| @@ -42,10 +42,12 @@ description: Auditing tool for Cloudformation templates | |
| 42 42 | 
             
            email: 
         | 
| 43 43 | 
             
            executables:
         | 
| 44 44 | 
             
            - cfn_nag
         | 
| 45 | 
            +
            - cfn_nag_rules
         | 
| 45 46 | 
             
            extensions: []
         | 
| 46 47 | 
             
            extra_rdoc_files: []
         | 
| 47 48 | 
             
            files:
         | 
| 48 49 | 
             
            - bin/cfn_nag
         | 
| 50 | 
            +
            - bin/cfn_nag_rules
         | 
| 49 51 | 
             
            - lib/cfn_nag.rb
         | 
| 50 52 | 
             
            - lib/custom_rules/security_group_missing_egress.rb
         | 
| 51 53 | 
             
            - lib/custom_rules/user_missing_group.rb
         |