Skip to content

Commit

Permalink
stelligent#90 ApiGateway UsagePlan rule (stelligent#390)
Browse files Browse the repository at this point in the history
* Adding warning rule for RestApi and ApiStage resources to check that they are associated with a UsagePlan

* Added warning rules for V2 ApiStages and V2 Apis with PrototolType: WEBSOCKET

* updates

* Refactoring warning rule for API Gateway Stages without Usage Plans

* removing params.json file
  • Loading branch information
Eric Kascic authored Mar 4, 2020
1 parent 5998bbe commit d0902e3
Show file tree
Hide file tree
Showing 9 changed files with 455 additions and 3 deletions.
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PATH
specs:
cfn-nag (0.0.0)
aws-sdk-s3 (~> 1.60.1)
cfn-model (= 0.4.20)
cfn-model (= 0.4.21)
lightly (~> 0.3.2)
logging (~> 2.2.2)
netaddr (~> 2.0.4)
Expand All @@ -29,7 +29,7 @@ GEM
aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.1)
aws-eventstream (~> 1.0, >= 1.0.2)
cfn-model (0.4.20)
cfn-model (0.4.21)
kwalify (= 0.7.2)
psych (~> 3)
diff-lcs (1.3)
Expand Down
2 changes: 1 addition & 1 deletion cfn-nag.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Gem::Specification.new do |s|
# versus what we used to run tests in cfn-nag before publishing cfn-nag
# they are coupled and we are doing a good bit of experimenting in cfn-model
# i might consider collapsing them again....
s.add_runtime_dependency('cfn-model', '0.4.20')
s.add_runtime_dependency('cfn-model', '0.4.21')
s.add_runtime_dependency('logging', '~> 2.2.2')
s.add_runtime_dependency('netaddr', '~> 2.0.4')
s.add_runtime_dependency('optimist', '~> 3.0.0')
Expand Down
26 changes: 26 additions & 0 deletions lib/cfn-nag/custom_rules/ApiGatewayStageUsagePlanRule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

require 'cfn-nag/violation'
require_relative 'base'

class ApiGatewayStageUsagePlanRule < BaseRule
def rule_text
'AWS::ApiGateway::Stage resources should be associated with an AWS::ApiGateway::UsagePlan. '
end

def rule_type
Violation::WARNING
end

def rule_id
'W64'
end

def audit_impl(cfn_model)
violating_api_gateway_stages = cfn_model.resources_by_type('AWS::ApiGateway::Stage').select do |api_stage|
api_stage.usage_plan_ids.empty?
end

violating_api_gateway_stages.map(&:logical_resource_id)
end
end
44 changes: 44 additions & 0 deletions spec/custom_rules/ApiGatewayStageUsagePlanRule_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'spec_helper'
require 'cfn-model'
require 'cfn-nag/custom_rules/ApiGatewayStageUsagePlanRule'

describe ApiGatewayStageUsagePlanRule do
context "AWS::ApiGateway::UsagePlan exists for all AWS::ApiGateway::Stage resources. " do
it 'Returns an empty list' do
cfn_model = CfnParser.new.parse read_test_template(
'yaml/api_gateway/api_gateway_usage_plan_exists_for_api_stage.yaml'
)

actual_logical_resource_ids = ApiGatewayStageUsagePlanRule.new.audit_impl cfn_model
expected_logical_resource_ids = %w[]

expect(actual_logical_resource_ids).to eq expected_logical_resource_ids
end
end

context "AWS::ApiGateway::UsagePlan does not exist for AWS::ApiGateway::Stage resources. " do
it 'Returns offending logical resource ids.' do
cfn_model = CfnParser.new.parse read_test_template(
'yaml/api_gateway/api_gateway_usage_plan_does_not_exist_for_api_stage.yaml'
)

actual_logical_resource_ids = ApiGatewayStageUsagePlanRule.new.audit_impl cfn_model
expected_logical_resource_ids = %w[ApiGatewayStage1 ApiGatewayStage2 ApiGatewayStage3 ApiGatewayStage4]

expect(actual_logical_resource_ids).to eq expected_logical_resource_ids
end
end

context "AWS::ApiGateway::Stage resource is associated with two AWS::ApiGateway::UsagePlan resources. " do
it 'Returns an empty list' do
cfn_model = CfnParser.new.parse read_test_template(
'yaml/api_gateway/api_gateway_stage_is_associated_with_two_usage_plans.yaml'
)

actual_logical_resource_ids = ApiGatewayStageUsagePlanRule.new.audit_impl cfn_model
expected_logical_resource_ids = %w[]

expect(actual_logical_resource_ids).to eq expected_logical_resource_ids
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
Resources:
ApiGatewayUsagePlan1:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: !Ref ApiGatewayStage1
UsagePlanName: testusageplan1

ApiGatewayUsagePlan2:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: !Ref ApiGatewayStage1
UsagePlanName: testusageplan2

ApiGatewayStage1:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
Parameters:
ApiGatewayRestApiTestingParam:
Type: String
Default: TestingRestApi
ApiGatewayRestApiTestingParam2:
Type: String
Default: TestingRestApi2

Resources:
ApiGatewayUsagePlan1:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: testapistage
- ApiId: testapi
Stage: testapistage
UsagePlanName: testusageplan1

ApiGatewayUsagePlan2:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: testapistage
- ApiId: testapi
Stage: testapistage
UsagePlanName: testusageplan2

ApiGatewayStage1:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage2:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage3:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage4:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
################################
# THIS IS FOR FUTURE USAGE #
################################

#---
#Parameters:
# ApiGatewayDeploymentStageName3:
# Type: String
# Default: stage-3
# ApiGatewayDeploymentStageName4:
# Type: String
# Default: stage-4
# ApiGatewayDeploymentStageName5:
# Type: String
# Default: stage-5
# ApiGatewayDeploymentStageName6:
# Type: String
# Default: stage-6
# ApiGatewayDeploymentStageName7:
# Type: String
# Default: stage-7
# ApiGatewayDeploymentStageName8:
# Type: String
# Default: stage-8
#
#Resources:
# ApiGatewayUsagePlan1:
# Type: AWS::ApiGateway::UsagePlan
# Properties:
# ApiStages:
# - ApiId: test_api1
# Stage: stage-1
# - ApiId: test_api2
# Stage: stage-2
# UsagePlanName: testusageplan1
#
# ApiGatewayUsagePlan2:
# Type: AWS::ApiGateway::UsagePlan
# Properties:
# ApiStages:
# - ApiId: test_api3
# Stage: !Ref ApiGatewayDeploymentStageName3
# - ApiId: test_api4
# Stage: !Ref ApiGatewayDeploymentStageName4
# UsagePlanName: testusageplan1
#
# ApiGatewayUsagePlan3:
# Type: AWS::ApiGateway::UsagePlan
# Properties:
# ApiStages:
# - ApiId: test_api5
# Stage: hardcoded-stage-5
# - ApiId: test_api6
# Stage: hardcoded-stage-6
# UsagePlanName: testusageplan1
#
# ApiGatewayUsagePlan4:
# Type: AWS::ApiGateway::UsagePlan
# Properties:
# ApiStages:
# - ApiId: test_api7
# Stage: !Ref ApiGatewayDeploymentStageName7
# - ApiId: test_api8
# Stage: !Ref ApiGatewayDeploymentStageName8
# UsagePlanName: testusageplan1
#
# ApiGatewayDeployment1:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api1
# StageName: hardcoded-stage-1
#
# ApiGatewayDeployment2:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api2
# StageName: 'hardcoded-stage-2'
#
# ApiGatewayDeployment3:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api3
# StageName: 'hardcoded-stage-3'
#
# ApiGatewayDeployment4:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api4
# StageName: 'hardcoded-stage-4'
#
# ApiGatewayDeployment5:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api5
# StageName: !Ref ApiGatewayDeploymentStageName5
#
# ApiGatewayDeployment6:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api6
# StageName: !Ref ApiGatewayDeploymentStageName6
#
# ApiGatewayDeployment7:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api7
# StageName: !Ref ApiGatewayStage1
#
# ApiGatewayDeployment8:
# Type: AWS::ApiGateway::Deployment
# Properties:
# RestApiId: test_api8
# StageName: !Ref ApiGatewayStage2
#
# ApiGatewayStage1:
# Type: AWS::ApiGateway::Stage
# Properties:
# RestApiId: testapi
#
# ApiGatewayStage2:
# Type: AWS::ApiGateway::Stage
# Properties:
# RestApiId: testapi
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
Resources:
ApiGatewayUsagePlan1:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: !Ref ApiGatewayStage1
- ApiId: testapi
Stage: !Ref ApiGatewayStage2
UsagePlanName: testusageplan1

ApiGatewayUsagePlan2:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: testapi
Stage: !Ref ApiGatewayStage3
- ApiId: testapi
Stage: !Ref ApiGatewayStage4
UsagePlanName: testusageplan2

ApiGatewayStage1:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage2:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage3:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi

ApiGatewayStage4:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: testapi
Loading

0 comments on commit d0902e3

Please sign in to comment.