Skip to content

Commit

Permalink
feat: Add APIGW V2 Lambda Authorizer mapping and linking (#5625)
Browse files Browse the repository at this point in the history
* Added V2 Authorizer property mapping

* make format

* Link a V2 Authorizer to a Lambda Function

* Link V2 Authorizers to V2 Api

* Added missing lines to include new resource in testing suite

* Removed max diff pytest option
  • Loading branch information
lucashuy authored Jul 27, 2023
1 parent 6c4d7cf commit 6b9366e
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 2 deletions.
28 changes: 28 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,34 @@ class GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException(Local
"""


class OneGatewayV2AuthorizerToLambdaFunctionLinkingLimitationException(OneResourceLinkingLimitationException):
"""
Exception specific for Gateway V2 Authorizer linking to more than one Lambda Function
"""


class GatewayV2AuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException(
LocalVariablesLinkingLimitationException
):
"""
Exception specific for Gateway V2 Authorizer linking to Lambda Function using locals.
"""


class OneGatewayV2AuthorizerToGatewayV2ApiLinkingLimitationException(OneResourceLinkingLimitationException):
"""
Exception specific for Gateway V2 Authorizer linking to more than one Gateway V2 API
"""


class GatewayV2AuthorizerToGatewayV2ApiLocalVariablesLinkingLimitationException(
LocalVariablesLinkingLimitationException
):
"""
Exception specific for Gateway V2 Authorizer linking to Gateway V2 API using locals.
"""


class OneGatewayV2ApiToLambdaFunctionLinkingLimitationException(OneResourceLinkingLimitationException):
"""
Exception specific for Gateway V2 API linking to more than one Lambda Function
Expand Down
15 changes: 15 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/property_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from samcli.lib.utils.resources import AWS_APIGATEWAY_RESTAPI as CFN_AWS_APIGATEWAY_RESTAPI
from samcli.lib.utils.resources import AWS_APIGATEWAY_STAGE as CFN_AWS_APIGATEWAY_STAGE
from samcli.lib.utils.resources import AWS_APIGATEWAY_V2_API as CFN_AWS_APIGATEWAY_V2_API
from samcli.lib.utils.resources import AWS_APIGATEWAY_V2_AUTHORIZER as CFN_AWS_APIGATEWAY_V2_AUTHORIZER
from samcli.lib.utils.resources import AWS_APIGATEWAY_V2_INTEGRATION as CFN_AWS_APIGATEWAY_V2_INTEGRATION
from samcli.lib.utils.resources import AWS_APIGATEWAY_V2_ROUTE as CFN_AWS_APIGATEWAY_V2_ROUTE
from samcli.lib.utils.resources import AWS_APIGATEWAY_V2_STAGE as CFN_AWS_APIGATEWAY_V2_STAGE
Expand All @@ -49,6 +50,7 @@
TF_AWS_API_GATEWAY_V2_ROUTE = "aws_apigatewayv2_route"
TF_AWS_API_GATEWAY_V2_STAGE = "aws_apigatewayv2_stage"
TF_AWS_API_GATEWAY_V2_INTEGRATION = "aws_apigatewayv2_integration"
TF_AWS_API_GATEWAY_V2_AUTHORIZER = "aws_apigatewayv2_authorizer"


def _build_code_property(tf_properties: dict, resource: TFResource) -> Any:
Expand Down Expand Up @@ -412,6 +414,16 @@ def _add_property(cfn_prop, tf_prop):
"PayloadFormatVersion": _get_property_extractor("payload_format_version"),
}

AWS_API_GATEWAY_V2_AUTHORIZER_PROPERTY_BUILDER_MAPPING: PropertyBuilderMapping = {
"ApiId": _get_property_extractor("api_id"),
"AuthorizerType": _get_property_extractor("authorizer_type"),
"AuthorizerUri": _get_property_extractor("authorizer_uri"),
"Name": _get_property_extractor("name"),
"AuthorizerPayloadFormatVersion": _get_property_extractor("authorizer_payload_format_version"),
"IdentitySource": _get_property_extractor("identity_sources"),
"EnableSimpleResponses": _get_property_extractor("enable_simple_responses"),
}

RESOURCE_TRANSLATOR_MAPPING: Dict[str, ResourceTranslator] = {
TF_AWS_LAMBDA_FUNCTION: ResourceTranslator(CFN_AWS_LAMBDA_FUNCTION, AWS_LAMBDA_FUNCTION_PROPERTY_BUILDER_MAPPING),
TF_AWS_LAMBDA_LAYER_VERSION: ResourceTranslator(
Expand Down Expand Up @@ -450,4 +462,7 @@ def _add_property(cfn_prop, tf_prop):
TF_AWS_API_GATEWAY_V2_INTEGRATION: ResourceTranslator(
CFN_AWS_APIGATEWAY_V2_INTEGRATION, AWS_API_GATEWAY_V2_INTEGRATION_PROPERTY_BUILDER_MAPPING
),
TF_AWS_API_GATEWAY_V2_AUTHORIZER: ResourceTranslator(
CFN_AWS_APIGATEWAY_V2_AUTHORIZER, AWS_API_GATEWAY_V2_AUTHORIZER_PROPERTY_BUILDER_MAPPING
),
}
77 changes: 77 additions & 0 deletions samcli/hook_packages/terraform/hooks/prepare/resource_linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
GatewayResourceToApiGatewayMethodLocalVariablesLinkingLimitationException,
GatewayResourceToGatewayRestApiLocalVariablesLinkingLimitationException,
GatewayV2ApiToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayV2AuthorizerToGatewayV2ApiLocalVariablesLinkingLimitationException,
GatewayV2AuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayV2IntegrationToGatewayV2ApiLocalVariablesLinkingLimitationException,
GatewayV2IntegrationToLambdaFunctionLocalVariablesLinkingLimitationException,
GatewayV2RouteToGatewayV2ApiLocalVariablesLinkingLimitationException,
Expand All @@ -33,6 +35,8 @@
OneGatewayResourceToApiGatewayMethodLinkingLimitationException,
OneGatewayResourceToRestApiLinkingLimitationException,
OneGatewayV2ApiToLambdaFunctionLinkingLimitationException,
OneGatewayV2AuthorizerToGatewayV2ApiLinkingLimitationException,
OneGatewayV2AuthorizerToLambdaFunctionLinkingLimitationException,
OneGatewayV2IntegrationToGatewayV2ApiLinkingLimitationException,
OneGatewayV2IntegrationToLambdaFunctionLinkingLimitationException,
OneGatewayV2RouteToGatewayV2ApiLinkingLimitationException,
Expand Down Expand Up @@ -2008,6 +2012,79 @@ def _link_gateway_v2_route_to_api(
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_v2_authorizer_to_lambda_function(
authorizer_config_resources: Dict[str, TFResource],
authorizer_cfn_resources: Dict[str, List],
lamda_function_resources: Dict[str, Dict],
) -> None:
"""
Iterate through all the resources and link the corresponding V2 Authorizer to each Lambda Function
Parameters
----------
authorizer_config_resources: Dict[str, TFResource]
Dictionary of configuration Authorizer resources
authorizer_cfn_resources: Dict[str, List]
Dictionary containing resolved configuration address of CFN Authorizer resources
lamda_function_resources: Dict[str, Dict]
Dictionary of Terraform Lambda Function resources (not configuration resources). The dictionary's key is the
calculated logical id for each resource
"""
exceptions = ResourcePairExceptions(
multiple_resource_linking_exception=OneGatewayV2AuthorizerToLambdaFunctionLinkingLimitationException,
local_variable_linking_exception=GatewayV2AuthorizerToLambdaFunctionLocalVariablesLinkingLimitationException,
)
resource_linking_pair = ResourceLinkingPair(
source_resource_cfn_resource=authorizer_cfn_resources,
source_resource_tf_config=authorizer_config_resources,
destination_resource_tf=lamda_function_resources,
tf_destination_attribute_name="invoke_arn",
terraform_link_field_name="authorizer_uri",
cfn_link_field_name="AuthorizerUri",
terraform_resource_type_prefix=LAMBDA_FUNCTION_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=_link_gateway_authorizer_to_lambda_function_call_back,
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_v2_authorizer_to_api(
v2_authorizer_config_resources: Dict[str, TFResource],
v2_authorizer_config_address_cfn_resources_map: Dict[str, List],
api_resources: Dict[str, Dict],
) -> None:
"""
Iterate through all the resources and link the corresponding
Gateway V2 Authorizer resources to each Gateway V2 Api
Parameters
----------
v2_authorizer_config_resources: Dict[str, TFResource]
Dictionary of configuration Gateway V2 Authorizers
v2_authorizer_config_address_cfn_resources_map: Dict[str, List]
Dictionary containing resolved configuration addresses matched up to the cfn Gateway V2 Authorizer
api_resources: Dict[str, Dict]
Dictionary of all Terraform Gateway V2 Api resources (not configuration resources).
The dictionary's key is the calculated logical id for each resource.
"""
exceptions = ResourcePairExceptions(
multiple_resource_linking_exception=OneGatewayV2AuthorizerToGatewayV2ApiLinkingLimitationException,
local_variable_linking_exception=GatewayV2AuthorizerToGatewayV2ApiLocalVariablesLinkingLimitationException,
)
resource_linking_pair = ResourceLinkingPair(
source_resource_cfn_resource=v2_authorizer_config_address_cfn_resources_map,
source_resource_tf_config=v2_authorizer_config_resources,
destination_resource_tf=api_resources,
tf_destination_attribute_name="id",
terraform_link_field_name="api_id",
cfn_link_field_name="ApiId",
terraform_resource_type_prefix=API_GATEWAY_V2_API_RESOURCE_ADDRESS_PREFIX,
cfn_resource_update_call_back_function=_link_gateway_v2_resource_to_api_callback,
linking_exceptions=exceptions,
)
ResourceLinker(resource_linking_pair).link_resources()


def _link_gateway_v2_api_to_function_callback(
gateway_v2_api_cfn_resource: Dict, referenced_function_resource_values: List[ReferenceType]
) -> None:
Expand Down
11 changes: 10 additions & 1 deletion samcli/hook_packages/terraform/hooks/prepare/resources/apigw.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,22 @@ def __init__(self):

class ApiGatewayV2IntegrationProperties(ResourceProperties):
"""
Contains the collection logic of the required properties for linking the aws_api_gateway_v2_authorizer resources.
Contains the collection logic of the required properties for linking the aws_api_gateway_v2_integration resources.
"""

def __init__(self):
super(ApiGatewayV2IntegrationProperties, self).__init__()


class ApiGatewayV2AuthorizerProperties(ResourceProperties):
"""
Contains the collection logic of the required properties for linking the aws_api_gateway_v2_authorizer resources.
"""

def __init__(self):
super(ApiGatewayV2AuthorizerProperties, self).__init__()


class ApiGatewayV2StageProperties(ResourceProperties):
"""
Contains the collection logic of the required properties for linking the aws_api_gateway_v2_stage resources.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
TF_AWS_API_GATEWAY_REST_API,
TF_AWS_API_GATEWAY_STAGE,
TF_AWS_API_GATEWAY_V2_API,
TF_AWS_API_GATEWAY_V2_AUTHORIZER,
TF_AWS_API_GATEWAY_V2_INTEGRATION,
TF_AWS_API_GATEWAY_V2_ROUTE,
TF_AWS_API_GATEWAY_V2_STAGE,
Expand All @@ -29,6 +30,8 @@
_link_gateway_resources_to_gateway_rest_apis,
_link_gateway_stage_to_rest_api,
_link_gateway_v2_api_to_function,
_link_gateway_v2_authorizer_to_api,
_link_gateway_v2_authorizer_to_lambda_function,
_link_gateway_v2_integration_to_api,
_link_gateway_v2_integration_to_lambda_function,
_link_gateway_v2_route_to_api,
Expand Down Expand Up @@ -120,6 +123,16 @@
dest=TF_AWS_API_GATEWAY_V2_API,
linking_func=_link_gateway_v2_route_to_api,
),
LinkingPairCaller(
source=TF_AWS_API_GATEWAY_V2_AUTHORIZER,
dest=TF_AWS_LAMBDA_FUNCTION,
linking_func=_link_gateway_v2_authorizer_to_lambda_function,
),
LinkingPairCaller(
source=TF_AWS_API_GATEWAY_V2_AUTHORIZER,
dest=TF_AWS_API_GATEWAY_V2_API,
linking_func=_link_gateway_v2_authorizer_to_api,
),
LinkingPairCaller(
source=TF_AWS_API_GATEWAY_V2_API,
dest=TF_AWS_LAMBDA_FUNCTION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
TF_AWS_API_GATEWAY_REST_API,
TF_AWS_API_GATEWAY_STAGE,
TF_AWS_API_GATEWAY_V2_API,
TF_AWS_API_GATEWAY_V2_AUTHORIZER,
TF_AWS_API_GATEWAY_V2_INTEGRATION,
TF_AWS_API_GATEWAY_V2_ROUTE,
TF_AWS_API_GATEWAY_V2_STAGE,
Expand All @@ -23,6 +24,7 @@
ApiGatewayRestApiProperties,
ApiGatewayStageProperties,
ApiGatewayV2ApiProperties,
ApiGatewayV2AuthorizerProperties,
ApiGatewayV2IntegrationProperties,
ApiGatewayV2RouteProperties,
ApiGatewayV2StageProperties,
Expand Down Expand Up @@ -60,5 +62,6 @@ def get_resource_property_mapping() -> Dict[str, ResourceProperties]:
TF_AWS_API_GATEWAY_V2_ROUTE: ApiGatewayV2RouteProperties(),
TF_AWS_API_GATEWAY_V2_INTEGRATION: ApiGatewayV2IntegrationProperties(),
TF_AWS_API_GATEWAY_V2_API: ApiGatewayV2ApiProperties(),
TF_AWS_API_GATEWAY_V2_AUTHORIZER: ApiGatewayV2AuthorizerProperties(),
TF_AWS_API_GATEWAY_V2_STAGE: ApiGatewayV2StageProperties(),
}
43 changes: 42 additions & 1 deletion tests/unit/hook_packages/terraform/hooks/prepare/prepare_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from samcli.hook_packages.terraform.hooks.prepare.translate import AWS_PROVIDER_NAME, NULL_RESOURCE_PROVIDER_NAME
from samcli.lib.utils.resources import (
AWS_APIGATEWAY_V2_AUTHORIZER,
AWS_LAMBDA_FUNCTION as CFN_AWS_LAMBDA_FUNCTION,
AWS_LAMBDA_LAYERVERSION,
AWS_APIGATEWAY_RESOURCE,
Expand Down Expand Up @@ -61,6 +62,7 @@ def setUp(self) -> None:
self.apigwv2_route_name = "my_apigwv2_route"
self.apigwv2_stage_name = "my_apigwv2_stage"
self.apigwv2_integration_name = "my_apigwv2_integration"
self.apigwv2_authorizer_name = "my_authorizer_v2"

self.tf_function_common_properties: dict = {
"function_name": self.zip_function_name,
Expand Down Expand Up @@ -941,6 +943,44 @@ def setUp(self) -> None:
"Metadata": {"SamResourceId": f"aws_apigatewayv2_integration.{self.apigwv2_integration_name}"},
}

self.tf_apigwv2_authorizer_common_attributes: dict = {
"type": "aws_apigatewayv2_authorizer",
"provider_name": AWS_PROVIDER_NAME,
}

self.tf_apigwv2_authorizer_properties: dict = {
"api_id": "aws_apigatewayv2_api.my_api.id",
"authorizer_type": "REQUEST",
"authorizer_uri": "aws_lambda_function.authorizerv2.invoke_arn",
"name": self.apigwv2_authorizer_name,
"authorizer_payload_format_version": "2.0",
"identity_sources": ["$request.header.hello"],
"enable_simple_responses": False,
}

self.expected_cfn_apigwv2_authorizer_properties: dict = {
"ApiId": "aws_apigatewayv2_api.my_api.id",
"AuthorizerType": "REQUEST",
"AuthorizerUri": "aws_lambda_function.authorizerv2.invoke_arn",
"Name": self.apigwv2_authorizer_name,
"AuthorizerPayloadFormatVersion": "2.0",
"IdentitySource": ["$request.header.hello"],
"EnableSimpleResponses": False,
}

self.tf_apigwv2_authorizer_resource: dict = {
**self.tf_apigwv2_authorizer_common_attributes,
"values": self.tf_apigwv2_authorizer_properties,
"address": f"aws_apigatewayv2_authorizer.{self.apigwv2_authorizer_name}",
"name": self.apigwv2_authorizer_name,
}

self.expected_cfn_apigwv2_authorizer: dict = {
"Type": AWS_APIGATEWAY_V2_AUTHORIZER,
"Properties": self.expected_cfn_apigwv2_authorizer_properties,
"Metadata": {"SamResourceId": f"aws_apigatewayv2_authorizer.{self.apigwv2_authorizer_name}"},
}

self.tf_json_with_root_module_only: dict = {
"planned_values": {
"root_module": {
Expand All @@ -961,6 +1001,7 @@ def setUp(self) -> None:
self.tf_apigwv2_route_resource,
self.tf_apigwv2_stage_resource,
self.tf_apigwv2_integration_resource,
self.tf_apigwv2_authorizer_resource,
]
}
}
Expand All @@ -982,9 +1023,9 @@ def setUp(self) -> None:
f"AwsApigatewayv2RouteMyApigwv2Route{self.mock_logical_id_hash}": self.expected_cfn_apigwv2_route,
f"AwsApigatewayv2StageMyApigwv2Stage{self.mock_logical_id_hash}": self.expected_cfn_apigwv2_stage,
f"AwsApigatewayv2IntegrationMyApigwv2Integration{self.mock_logical_id_hash}": self.expected_cfn_apigwv2_integration,
f"AwsApigatewayv2AuthorizerMyAuthorizerV2{self.mock_logical_id_hash}": self.expected_cfn_apigwv2_authorizer,
},
}

self.tf_json_with_root_module_with_sam_metadata_resources: dict = {
"planned_values": {
"root_module": {
Expand Down
Loading

0 comments on commit 6b9366e

Please sign in to comment.