Skip to content

Commit

Permalink
Merge pull request #101 from sarika-subram/main
Browse files Browse the repository at this point in the history
Add Apigateway
  • Loading branch information
sarika-subram authored May 17, 2024
2 parents 638cea0 + 681bb42 commit 858449d
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 47 deletions.
2 changes: 1 addition & 1 deletion info.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"cloudfront": 8, "cloudtrail": 18, "cloudwatch": 18, "dynamodb": 24, "ec2": 49, "efs": 3, "eks": 7, "elasticache": 10, "guardduty": 4, "iam": 37, "kms": 4, "lambda": 15, "opensearch": 18, "rds": 82, "s3": 12}
{"apigateway": 9, "cloudfront": 8, "cloudtrail": 18, "cloudwatch": 18, "dynamodb": 24, "ec2": 54, "efs": 3, "eks": 7, "elasticache": 10, "guardduty": 4, "iam": 37, "kms": 4, "lambda": 15, "opensearch": 22, "rds": 82, "redshift": 9, "s3": 16}
76 changes: 76 additions & 0 deletions services/apigateway/Apigateway.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import boto3
import botocore
import requests

from utils.Config import Config
from services.Service import Service
from services.apigateway.drivers.ApiGatewayCommon import ApiGatewayCommon
from services.apigateway.drivers.ApiGatewayRest import ApiGatewayRest

class Apigateway(Service):


def __init__(self, region):
super().__init__(region)
ssBoto = self.ssBoto

self.apis = []
self.apisv2 = []

self.apiClient = ssBoto.client('apigateway', config=self.bConfig)
self.apiv2Client = ssBoto.client('apigatewayv2', config=self.bConfig)

return

def getRestApis(self):
apis = []

try:
apis = self.apiClient.get_rest_apis()
self.apis = apis.get('items')
while apis.get('position') is not None:
apis = self.apiClient.get_rest_apis(position=apis.get('position'))
self.apis = self.apis + apis.get('items')

except botocore.exceptions.ClientError as e:
ecode = e.response['Error']['Code']

def getApis(self):
apis = []

try:
apis = self.apiv2Client.get_apis()
self.apisv2 = apis.get('Items')
while apis.get('position') is not None:
apis = self.apiv2Client.get_apis(position=apis.get('position'))
self.apisv2 = self.apisv2 + apis.get('Items')

except botocore.exceptions.ClientError as e:
ecode = e.response['Error']['Code']

def advise(self):
try:
objs = {}
self.getApis()
for api in self.apisv2:
objName = api['ProtocolType'] + '::' + api['Name']
print('... (APIGateway) inspecting ' + objName)
obj = ApiGatewayCommon(api, self.apiv2Client)
obj.run(self.__class__)
objs[objName] = obj.getInfo()
del obj

self.getRestApis()
for api in self.apis:
objName = 'REST' + '::' + api['name']
print('... (APIGateway) inspecting ' + objName)
obj = ApiGatewayRest(api, self.apiClient)
obj.run(self.__class__)
objs[objName] = obj.getInfo()
del obj

return objs

except botocore.exceptions.ClientError as e:
ecode = e.response['Error']['Code']
print(ecode)
120 changes: 120 additions & 0 deletions services/apigateway/apigateway.reporter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"ExecutionLogging": {
"category": "S",
"^description": "API Gateway REST or WebSocket API stages should have relevant logs enabled. API Gateway REST and WebSocket API execution logging provides detailed records of requests made to API Gateway REST and WebSocket API stages. The stages include API integration backend responses, Lambda authorizer responses, and the requestId for AWS integration endpoints.",
"shortDesc": "Enable execution logging",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Set up CloudWatch API logging using the API Gateway console]<https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html#set-up-access-logging-using-console>"
]
},
"EncryptionInTransit": {
"category": "S",
"^description": "API Gateway REST API stages should be configured with SSL certificates to allow backend systems to authenticate that requests originate from API Gateway.",
"shortDesc": "Enable SSL certificates",
"criticality": "M",
"downtime": 0,
"slowness": -1,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Generate and configure an SSL certificate for backend authentication]<https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-client-side-ssl-authentication.html>"
]
},
"XRayTracing": {
"category": "S",
"^description": "X-Ray active tracing enables a more rapid response to performance changes in the underlying infrastructure. Changes in performance could result in a lack of availability of the API. X-Ray active tracing provides real-time metrics of user requests that flow through your API Gateway REST API operations and connected services.",
"shortDesc": "Enable AWS X-Ray tracing",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Amazon API Gateway active tracing support for AWS X-Ray]<https://docs.aws.amazon.com/xray/latest/devguide/xray-services-apigateway.html>"
]
},
"WAFWACL": {
"category": "S",
"^description": "AWS WAF is a web application firewall that helps protect web applications and APIs from attacks. It enables you to configure an ACL, which is a set of rules that allow, block, or count web requests based on customizable web security rules and conditions that you define. Ensure that your API Gateway stage is associated with an AWS WAF web ACL to help protect it from malicious attacks.",
"shortDesc": "Associale a WAF Web ACL",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 1,
"ref": [
"[API Gateway should be associated with a WAF Web ACL]<https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-aws-waf.html>"
]
},
"EncryptionAtRest": {
"category": "S",
"^description": "Encrypting data at rest reduces the risk of data stored on disk being accessed by a user not authenticated to AWS. It adds another set of access controls to limit unauthorized users ability access the data. For example, API permissions are required to decrypt the data before it can be read. API Gateway REST API caches should be encrypted at rest for an added layer of security.",
"shortDesc": "Encrypt cache data",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Configuring encryption at rest for API Gateway cache data]<https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#api-gateway-caching-encryption>"
]
},
"AuthorizationType": {
"category": "S",
"^description": "API Gateway V2 WebSocket and HTTP routes should specify an authorization type. Specifying an authorization type ensures that access to the API is controlled and restricted to authorized users or processes.",
"shortDesc": "Specify an authorization type",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 0,
"needFullTest": 1,
"ref": [
"[Configuring authorization for API Gateway V2 WebSocket APIs]<https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-authorization.html>",
"[Configuring authorization for API Gateway V2 HTTP APIs]<https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-auth-providers.html>"
]
},
"AccessLogging": {
"category": "S",
"^description": "API Gateway access logs provide detailed information about who has accessed your API and how the caller accessed the API. These logs are useful for applications such as security and access audits and forensics investigation. Enable these access logs to analyze traffic patterns and to troubleshoot issues.",
"shortDesc": "Enable access logging",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Configuring access logging for API Gateway V2]<https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-logging.html>"
]
},
"MinTLSVersion": {
"category": "S",
"^description": "API Gateway REST API domains should use a security policy that specifies a minimum TLS protocol version of TLSv1.2. Using a minimum TLS version of 1.2 helps ensure that secure communication is established between the client and the API Gateway.",
"shortDesc": "API Gateway REST API domains should use a security policy with a minimum TLS version of TLSv1.2",
"criticality": "M",
"downtime": 0,
"slowness": 0,
"additionalCost": 1,
"needFullTest": 0,
"ref": [
"[Configuring a minimum TLS version for API Gateway REST API domains]<https://docs.aws.amazon.com/apigateway/latest/developerguide/security-policy.html>"
]
},
"IdleAPIGateway": {
"category": "O",
"^description": "Info only: {$COUNT} APIGateway(s) is not deployed",
"shortDesc": "Deploy/delete APIGateway",
"criticality": "I",
"downtime": 0,
"slowness": 0,
"additionalCost": 0,
"needFullTest": 0,
"ref":[
"[Setting up a stage using the API Gateway console]<https://docs.aws.amazon.com/apigateway/latest/developerguide/stages.html>"
]
}
}
40 changes: 40 additions & 0 deletions services/apigateway/drivers/ApiGatewayCommon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import boto3
import botocore
import constants as _C

from services.Service import Service
from services.Evaluator import Evaluator

class ApiGatewayCommon(Evaluator):

def __init__(self, api, apiClient):
super().__init__()
self.apiClient = apiClient
self.api = api
return

def _checkStage(self):
resp = self.apiClient.get_stages(
ApiId = self.api['ApiId'],
)
items = resp['Items']
for stage in items:

if self.api['ProtocolType'] == 'WEBSOCKET':
if stage['DefaultRouteSettings']['LoggingLevel'] != 'INFO' or 'ERROR':
self.results['ExecutionLogging'] = [-1, "Stage name: " + stage['StageName']]
try:
accesslogs = stage['AccessLogSettings']
except KeyError:
self.results['AccessLogging'] = [-1, "Stage name: " + stage['StageName']]
return

def _checkRoute(self):
resp = self.apiClient.get_routes(
ApiId = self.api['ApiId'],
)
items = resp['Items']
for route in items:
if route['AuthorizationType'] == 'NONE':
self.results['AuthorizationType'] = [-1, "Route key: " + route['RouteKey']]
return
51 changes: 51 additions & 0 deletions services/apigateway/drivers/ApiGatewayRest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import boto3
import botocore
import constants as _C
import json

from services.Service import Service
from services.Evaluator import Evaluator

class ApiGatewayRest(Evaluator):

def __init__(self, api, apiClient):
super().__init__()
self.apiClient = apiClient
self.api = api
return

def _checkStage(self):
resp = self.apiClient.get_stages(
restApiId = self.api['id'],
)
item = resp['item']
if item == []:
self.results['IdleAPIGateway'] = [-1, "No stages found"]
return
for stage in item:
if stage['methodSettings'] == []:
self.results['ExecutionLogging'] = [-1, "Stage name: " + stage['stageName']]
self.results['EncryptionAtRest'] = [-1, "Stage name: " + stage['stageName']]

for k, json in stage['methodSettings'].items():
for key, value in json.items():
if key == 'loggingLevel' and value != 'INFO' or 'ERROR':
self.results['ExecutionLogging'] = [-1, "Stage name: " + stage['stageName']]
if key == 'cachingEnabled' and value is True:
if key == 'cacheDataEncrypted' and value is False:
self.results['EncryptionAtRest'] = [-1, "Stage name: " + stage['stageName']]

try:
certid = stage['clientCertificateId']
except KeyError:
self.results['EncryptionInTransit'] = [-1, "Stage name: " + stage['stageName']]

if not stage['tracingEnabled']:
self.results['XRayTracing'] = [-1, "Stage name: " + stage['stageName']]

try:
wacl = stage['webAclArn']
except KeyError:
self.results['WAFWACL'] = [-1, "Stage name: " + stage['stageName']]

return
18 changes: 0 additions & 18 deletions services/redshift/Redshift.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,12 @@
from services.Service import Service
from services.redshift.drivers.RedshiftCluster import RedshiftCluster

###### TO DO #####
## Import required service module below
## Example
## from services.ec2.drivers.Ec2Instance import Ec2Instance


###### TO DO #####
## Replace ServiceName with
## getResources and advise method is default method that must have
## Feel free to develop method to support your checks
class Redshift(Service):
def __init__(self, region):
super().__init__(region)
ssBoto = self.ssBoto
self.rsClient = ssBoto.client('redshift', config=self.bConfig)

###### TO DO #####
## Initiate clients required for the check
## Example
## self.rdsClient = ssBoto.client('rds', config=self.bConfig)
self.redshifts = []
return

Expand Down Expand Up @@ -60,10 +46,6 @@ def getClusters(self, Marker=None):
def advise(self):
objs = {}

###### TO DO #####
## call getResources method
## loop through the resources and run the checks in drivers
## Example
self.getClusterResources()
for cluster in self.redshifts:
print('... (Redshift) inspecting ' + cluster['ClusterIdentifier'])
Expand Down
20 changes: 2 additions & 18 deletions services/redshift/drivers/RedshiftCluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,8 @@

from services.Evaluator import Evaluator

###### TO DO #####
## Import modules that needed for this driver
## Example
## from services.ec2.drivers.Ec2SecGroup import Ec2SecGroup

###### TO DO #####
## Replace ServiceDriver with

class RedshiftCluster(Evaluator):

###### TO DO #####
## Replace resource variable to meaningful name
## Modify based on your need
def __init__(self, cluster, rsClient):
super().__init__()
self.init()
Expand All @@ -26,20 +15,15 @@ def __init__(self, cluster, rsClient):
# print(self.cluster)
return

###### TO DO #####
## Change the method name to meaningful name
## Check methods name must follow _check[Description]
def _checkPubliclyAcessible(self):
# resp = self.rsClient.describe_clusters(
# ClusterIdentifier=self.cluster['ClusterIdentifier']
# )

# check if publicly accessible
if self.cluster['PubliclyAccessible']:
self.results['PubliclyAccessible'] = [-1, "Redshift cluster is publicly accessible"]

# check if automated snapshot is enabled
try:
if self.cluster['AutomatedSnapshotRetentionPeriod'] < 7:
print(self.cluster['AutomatedSnapshotRetentionPeriod'])
self.results['AutomaticSnapshots'] = [-1, "Automatic snapshot retention is < 7 days"]

except Exception as e:
Expand Down
Loading

0 comments on commit 858449d

Please sign in to comment.