def _get_permission(self, resources_to_link, stage, suffix): # It turns out that APIGW doesn't like trailing slashes in paths (#665) # and removes as a part of their behaviour, but this isn't documented. # The regex removes the tailing slash to ensure the permission works as intended path = re.sub(r'^(.+)/$', r'\1', self.Path) if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") path = re.sub(r'{([a-zA-Z0-9._-]+|proxy\+)}', '*', path) method = '*' if self.Method.lower() == 'any' else self.Method.upper() api_id = self.RestApiId # RestApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = '${__ApiId__}/' + '${__Stage__}/' + method + path partition = ArnGenerator.get_partition_name() source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), { "__ApiId__": api_id, "__Stage__": stage }) return self._construct_permission(resources_to_link['function'], source_arn=source_arn, suffix=suffix)
def to_cloudformation(self, **kwargs): function = kwargs.get('function') if not function: raise TypeError("Missing required keyword argument: function") resources = [] resource = 'rule/${RuleName}' partition = ArnGenerator.get_partition_name() source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service='iot', resource=resource), {'RuleName': ref(self.logical_id)}) source_account = fnSub('${AWS::AccountId}') resources.append( self._construct_permission(function, source_arn=source_arn, source_account=source_account)) resources.append(self._construct_iot_rule(function)) return resources
def _get_permission(self, authorizer_name, authorizer_lambda_function_arn): """Constructs and returns the Lambda Permission resource allowing the Authorizer to invoke the function. :returns: the permission resource :rtype: model.lambda_.LambdaPermission """ rest_api = ApiGatewayRestApi(self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes) api_id = rest_api.get_runtime_attr("rest_api_id") partition = ArnGenerator.get_partition_name() resource = "${__ApiId__}/authorizers/*" source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service="execute-api", resource=resource), {"__ApiId__": api_id}, ) lambda_permission = LambdaPermission( self.logical_id + authorizer_name + "AuthorizerPermission", attributes=self.passthrough_resource_attributes ) lambda_permission.Action = "lambda:InvokeFunction" lambda_permission.FunctionName = authorizer_lambda_function_arn lambda_permission.Principal = "apigateway.amazonaws.com" lambda_permission.SourceArn = source_arn return lambda_permission
def generate_swagger(self): authorizer_type = self._get_type() APIGATEWAY_AUTHORIZER_KEY = "x-amazon-apigateway-authorizer" swagger = { "type": "apiKey", "name": self._get_swagger_header_name(), "in": "header", "x-amazon-apigateway-authtype": self._get_swagger_authtype(), } if authorizer_type == "COGNITO_USER_POOLS": swagger[APIGATEWAY_AUTHORIZER_KEY] = { "type": self._get_swagger_authorizer_type(), "providerARNs": self._get_user_pool_arn_array(), } elif authorizer_type == "LAMBDA": swagger[APIGATEWAY_AUTHORIZER_KEY] = { "type": self._get_swagger_authorizer_type() } partition = ArnGenerator.get_partition_name() resource = "lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations" authorizer_uri = fnSub( ArnGenerator.generate_arn(partition=partition, service="apigateway", resource=resource, include_account_id=False), {"__FunctionArn__": self.function_arn}, ) swagger[APIGATEWAY_AUTHORIZER_KEY][ "authorizerUri"] = authorizer_uri reauthorize_every = self._get_reauthorize_every() function_invoke_role = self._get_function_invoke_role() if reauthorize_every is not None: swagger[APIGATEWAY_AUTHORIZER_KEY][ "authorizerResultTtlInSeconds"] = reauthorize_every if function_invoke_role: swagger[APIGATEWAY_AUTHORIZER_KEY][ "authorizerCredentials"] = function_invoke_role if self._get_function_payload_type() == "REQUEST": swagger[APIGATEWAY_AUTHORIZER_KEY][ "identitySource"] = self._get_identity_source() # Authorizer Validation Expression is only allowed on COGNITO_USER_POOLS and LAMBDA_TOKEN is_lambda_token_authorizer = authorizer_type == "LAMBDA" and self._get_function_payload_type( ) == "TOKEN" if authorizer_type == "COGNITO_USER_POOLS" or is_lambda_token_authorizer: identity_validation_expression = self._get_identity_validation_expression( ) if identity_validation_expression: swagger[APIGATEWAY_AUTHORIZER_KEY][ "identityValidationExpression"] = identity_validation_expression return swagger
def _get_permission(self, authorizer_name, authorizer_lambda_function_arn): """Constructs and returns the Lambda Permission resource allowing the Authorizer to invoke the function. :returns: the permission resource :rtype: model.lambda_.LambdaPermission """ rest_api = ApiGatewayRestApi(self.logical_id, depends_on=self.depends_on) api_id = rest_api.get_runtime_attr('rest_api_id') partition = ArnGenerator.get_partition_name() resource = '${__ApiId__}/authorizers/*' source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), {"__ApiId__": api_id}) lambda_permission = LambdaPermission(self.logical_id + authorizer_name + 'AuthorizerPermission') lambda_permission.Action = 'lambda:invokeFunction' lambda_permission.FunctionName = authorizer_lambda_function_arn lambda_permission.Principal = 'apigateway.amazonaws.com' lambda_permission.SourceArn = source_arn return lambda_permission
def get_source_arn(self): resource = "log-group:${__LogGroupName__}:*" partition = ArnGenerator.get_partition_name() return fnSub( ArnGenerator.generate_arn(partition=partition, service="logs", resource=resource), {"__LogGroupName__": self.LogGroupName}, )
def generate_swagger(self): authorizer_type = self._get_type() APIGATEWAY_AUTHORIZER_KEY = 'x-amazon-apigateway-authorizer' swagger = { "type": "apiKey", "name": self._get_swagger_header_name(), "in": "header", "x-amazon-apigateway-authtype": self._get_swagger_authtype(), "x-amazon-apigateway-authorizer": { "type": self._get_swagger_authorizer_type() } } if authorizer_type == 'COGNITO_USER_POOLS': swagger[APIGATEWAY_AUTHORIZER_KEY][ 'providerARNs'] = self._get_user_pool_arn_array() elif authorizer_type == 'LAMBDA': partition = ArnGenerator.get_partition_name() resource = 'lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations' authorizer_uri = fnSub( ArnGenerator.generate_arn(partition=partition, service='apigateway', resource=resource, include_account_id=False), {'__FunctionArn__': self.function_arn}) swagger[APIGATEWAY_AUTHORIZER_KEY][ 'authorizerUri'] = authorizer_uri reauthorize_every = self._get_reauthorize_every() function_invoke_role = self._get_function_invoke_role() if reauthorize_every is not None: swagger[APIGATEWAY_AUTHORIZER_KEY][ 'authorizerResultTtlInSeconds'] = reauthorize_every if function_invoke_role: swagger[APIGATEWAY_AUTHORIZER_KEY][ 'authorizerCredentials'] = function_invoke_role if self._get_function_payload_type() == 'REQUEST': swagger[APIGATEWAY_AUTHORIZER_KEY][ 'identitySource'] = self._get_identity_source() # Authorizer Validation Expression is only allowed on COGNITO_USER_POOLS and LAMBDA_TOKEN is_lambda_token_authorizer = authorizer_type == 'LAMBDA' and self._get_function_payload_type( ) == 'TOKEN' if authorizer_type == 'COGNITO_USER_POOLS' or is_lambda_token_authorizer: identity_validation_expression = self._get_identity_validation_expression( ) if identity_validation_expression: swagger[APIGATEWAY_AUTHORIZER_KEY][ 'identityValidationExpression'] = identity_validation_expression return swagger
def generate_swagger(self): authorizer_type = self._get_type() APIGATEWAY_AUTHORIZER_KEY = 'x-amazon-apigateway-authorizer' swagger = { "type": "apiKey", "name": self._get_swagger_header_name(), "in": "header", "x-amazon-apigateway-authtype": self._get_swagger_authtype() } if authorizer_type == 'COGNITO_USER_POOLS': swagger[APIGATEWAY_AUTHORIZER_KEY] = { 'type': self._get_swagger_authorizer_type(), 'providerARNs': self._get_user_pool_arn_array() } elif authorizer_type == 'LAMBDA': swagger[APIGATEWAY_AUTHORIZER_KEY] = { 'type': self._get_swagger_authorizer_type() } partition = ArnGenerator.get_partition_name() resource = 'lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations' authorizer_uri = fnSub(ArnGenerator.generate_arn(partition=partition, service='apigateway', resource=resource, include_account_id=False), {'__FunctionArn__': self.function_arn}) swagger[APIGATEWAY_AUTHORIZER_KEY]['authorizerUri'] = authorizer_uri reauthorize_every = self._get_reauthorize_every() function_invoke_role = self._get_function_invoke_role() if reauthorize_every is not None: swagger[APIGATEWAY_AUTHORIZER_KEY]['authorizerResultTtlInSeconds'] = reauthorize_every if function_invoke_role: swagger[APIGATEWAY_AUTHORIZER_KEY]['authorizerCredentials'] = function_invoke_role if self._get_function_payload_type() == 'REQUEST': swagger[APIGATEWAY_AUTHORIZER_KEY]['identitySource'] = self._get_identity_source() # Authorizer Validation Expression is only allowed on COGNITO_USER_POOLS and LAMBDA_TOKEN is_lambda_token_authorizer = authorizer_type == 'LAMBDA' and self._get_function_payload_type() == 'TOKEN' if authorizer_type == 'COGNITO_USER_POOLS' or is_lambda_token_authorizer: identity_validation_expression = self._get_identity_validation_expression() if identity_validation_expression: swagger[APIGATEWAY_AUTHORIZER_KEY]['identityValidationExpression'] = identity_validation_expression return swagger
def _get_permission(self, resources_to_link, stage, suffix): if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") path = self.Path.replace('{proxy+}', '*') api_id = self.RestApiId # RestApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = '${__ApiId__}/' + '${__Stage__}/' + self.Method.upper() + path partition = ArnGenerator.get_partition_name() source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), {"__ApiId__": api_id, "__Stage__": stage}) return self._construct_permission(resources_to_link['function'], source_arn=source_arn, suffix=suffix)
def _get_permission(self, resources_to_link, stage, suffix): if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") path = self.Path.replace('{proxy+}', '*') method = '*' if self.Method.lower() == 'any' else self.Method.upper() api_id = self.RestApiId # RestApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = '${__ApiId__}/' + '${__Stage__}/' + method + path partition = ArnGenerator.get_partition_name() source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), {"__ApiId__": api_id, "__Stage__": stage}) return self._construct_permission(resources_to_link['function'], source_arn=source_arn, suffix=suffix)
def _get_permission(self, resources_to_link, stage): # It turns out that APIGW doesn't like trailing slashes in paths (#665) # and removes as a part of their behaviour, but this isn't documented. # The regex removes the tailing slash to ensure the permission works as intended path = re.sub(r"^(.+)/$", r"\1", self.Path) editor = None if resources_to_link["explicit_api"].get("DefinitionBody"): try: editor = OpenApiEditor(resources_to_link["explicit_api"].get("DefinitionBody")) except ValueError as e: api_logical_id = self.ApiId.get("Ref") if isinstance(self.ApiId, dict) else self.ApiId raise InvalidResourceException(api_logical_id, e) # If this is using the new $default path, keep path blank and add a * permission if path == OpenApiEditor._DEFAULT_PATH: path = "" elif editor and resources_to_link.get("function").logical_id == editor.get_integration_function_logical_id( OpenApiEditor._DEFAULT_PATH, OpenApiEditor._X_ANY_METHOD ): # Case where default exists for this function, and so the permissions for that will apply here as well # This can save us several CFN resources (not duplicating permissions) return else: path = OpenApiEditor.get_path_without_trailing_slash(path) # Handle case where Method is already the ANY ApiGateway extension if self.Method.lower() == "any" or self.Method.lower() == OpenApiEditor._X_ANY_METHOD: method = "*" else: method = self.Method.upper() api_id = self.ApiId # ApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = "${__ApiId__}/" + "${__Stage__}/" + method + path source_arn = fnSub( ArnGenerator.generate_arn(partition="${AWS::Partition}", service="execute-api", resource=resource), {"__ApiId__": api_id, "__Stage__": stage}, ) return self._construct_permission(resources_to_link["function"], source_arn=source_arn)
def to_cloudformation(self, **kwargs): function = kwargs.get('function') if not function: raise TypeError("Missing required keyword argument: function") resources = [] resource = 'rule/${RuleName}' partition = ArnGenerator.get_partition_name() source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='iot', resource=resource), {'RuleName': ref(self.logical_id)}) source_account = fnSub('${AWS::AccountId}') resources.append(self._construct_permission(function, source_arn=source_arn, source_account=source_account)) resources.append(self._construct_iot_rule(function)) return resources
def _get_permission(self, resources_to_link, stage, suffix): # It turns out that APIGW doesn't like trailing slashes in paths (#665) # and removes as a part of their behaviour, but this isn't documented. # The regex removes the tailing slash to ensure the permission works as intended path = re.sub(r'^(.+)/$', r'\1', self.Path) if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") path = path.replace('{proxy+}', '*') method = '*' if self.Method.lower() == 'any' else self.Method.upper() api_id = self.RestApiId # RestApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = '${__ApiId__}/' + '${__Stage__}/' + method + path partition = ArnGenerator.get_partition_name() source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), {"__ApiId__": api_id, "__Stage__": stage}) return self._construct_permission(resources_to_link['function'], source_arn=source_arn, suffix=suffix)
def _get_permission(self, authorizer_name, authorizer_lambda_function_arn): """Constructs and returns the Lambda Permission resource allowing the Authorizer to invoke the function. :returns: the permission resource :rtype: model.lambda_.LambdaPermission """ rest_api = ApiGatewayRestApi(self.logical_id, depends_on=self.depends_on) api_id = rest_api.get_runtime_attr('rest_api_id') partition = ArnGenerator.get_partition_name() resource = '${__ApiId__}/authorizers/*' source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='execute-api', resource=resource), {"__ApiId__": api_id}) lambda_permission = LambdaPermission(self.logical_id + authorizer_name + 'AuthorizerPermission') lambda_permission.Action = 'lambda:invokeFunction' lambda_permission.FunctionName = authorizer_lambda_function_arn lambda_permission.Principal = 'apigateway.amazonaws.com' lambda_permission.SourceArn = source_arn return lambda_permission
def _get_permission(self, resources_to_link, stage, suffix): # It turns out that APIGW doesn't like trailing slashes in paths (#665) # and removes as a part of their behaviour, but this isn't documented. # The regex removes the tailing slash to ensure the permission works as intended path = re.sub(r"^(.+)/$", r"\1", self.Path) if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") path = SwaggerEditor.get_path_without_trailing_slash(path) method = "*" if self.Method.lower() == "any" else self.Method.upper() api_id = self.RestApiId # RestApiId can be a simple string or intrinsic function like !Ref. Using Fn::Sub will handle both cases resource = "${__ApiId__}/" + "${__Stage__}/" + method + path partition = ArnGenerator.get_partition_name() source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service="execute-api", resource=resource), {"__ApiId__": api_id, "__Stage__": stage}, ) return self._construct_permission(resources_to_link["function"], source_arn=source_arn, suffix=suffix)
def generate_openapi(self): """ Generates OAS for the securitySchemes section """ authorizer_type = self._get_auth_type() if authorizer_type == "JWT": openapi = {"type": "oauth2"} openapi[APIGATEWAY_AUTHORIZER_KEY] = { "jwtConfiguration": self.jwt_configuration, "identitySource": self.id_source, "type": "jwt", } if authorizer_type == "REQUEST": openapi = { "type": "apiKey", "name": "Unused", "in": "header", } openapi[APIGATEWAY_AUTHORIZER_KEY] = {"type": "request"} # Generate the lambda arn partition = ArnGenerator.get_partition_name() resource = "lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations" authorizer_uri = fnSub( ArnGenerator.generate_arn(partition=partition, service="apigateway", resource=resource, include_account_id=False), {"__FunctionArn__": self.function_arn}, ) openapi[APIGATEWAY_AUTHORIZER_KEY][ "authorizerUri"] = authorizer_uri # Set authorizerCredentials if present function_invoke_role = self._get_function_invoke_role() if function_invoke_role: openapi[APIGATEWAY_AUTHORIZER_KEY][ "authorizerCredentials"] = function_invoke_role # Set authorizerResultTtlInSeconds if present reauthorize_every = self._get_reauthorize_every() if reauthorize_every is not None: openapi[APIGATEWAY_AUTHORIZER_KEY][ "authorizerResultTtlInSeconds"] = reauthorize_every # Set identitySource if present if self.identity: openapi[APIGATEWAY_AUTHORIZER_KEY][ "identitySource"] = self._get_identity_source() # Set authorizerPayloadFormatVersion. It's a required parameter openapi[APIGATEWAY_AUTHORIZER_KEY][ "authorizerPayloadFormatVersion"] = self.authorizer_payload_format_version # Set authorizerPayloadFormatVersion. It's a required parameter if self.enable_simple_responses: openapi[APIGATEWAY_AUTHORIZER_KEY][ "enableSimpleResponses"] = self.enable_simple_responses return openapi
def get_source_arn(self): resource = "log-group:${__LogGroupName__}:*" partition = ArnGenerator.get_partition_name() return fnSub(ArnGenerator.generate_arn(partition=partition, service='logs', resource=resource), {'__LogGroupName__': self.LogGroupName})