diff --git a/HOWTO.md b/HOWTO.md index aca0e2e4a7..26b9802dec 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -53,7 +53,7 @@ packaged template that can be readily deployed to CloudFormation. $ aws cloudformation package \ --template-file /path_to_template/template.yaml \ --s3-bucket bucket-name \ - --s3-prefix appname/branchname/version + --s3-prefix appname/branchname/version \ --output-template-file packaged-template.yaml ``` @@ -63,7 +63,7 @@ Or using the aws-sam-cli $ sam package \ --template-file /path_to_template/template.yaml \ --s3-bucket bucket-name \ - --s3-prefix appname/branchname/version + --s3-prefix appname/branchname/version \ --output-template-file packaged-template.yaml ``` @@ -104,7 +104,7 @@ Or using aws-sam-cli ```bash $ sam deploy \ --template-file /path_to_template/packaged-template.yaml \ - --stack-name my-new-stack + --stack-name my-new-stack \ --capabilities CAPABILITY_IAM ``` diff --git a/LICENSE b/LICENSE index 8dada3edaf..6474801f62 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/docs/cloudformation_compatibility.rst b/docs/cloudformation_compatibility.rst index 9118c33955..a89430e705 100644 --- a/docs/cloudformation_compatibility.rst +++ b/docs/cloudformation_compatibility.rst @@ -125,6 +125,9 @@ Schedule ======================== ================================== ======================== Schedule All Input All +Name All +Description All +Enabled All ======================== ================================== ======================== CloudWatchEvent diff --git a/docs/safe_lambda_deployments.rst b/docs/safe_lambda_deployments.rst index 539d124242..6f0b741270 100644 --- a/docs/safe_lambda_deployments.rst +++ b/docs/safe_lambda_deployments.rst @@ -93,7 +93,7 @@ resource: Type: AWS::Serverless::Function Properties: Handler: index.handler - Runtime: nodejs6.10 + Runtime: nodejs8.10 AutoPublishAlias: live DeploymentPreference: Type: Linear10PercentEvery10Minutes @@ -162,8 +162,8 @@ resource: - Effect: "Allow" Action: - "lambda:InvokeFunction" - Resource: !Ref MyLambdaFunction.Version - Runtime: nodejs6.10 + Resource: !GetAtt MyLambdaFunction.Arn + Runtime: nodejs8.10 FunctionName: 'CodeDeployHook_preTrafficHook' DeploymentPreference: Enabled: false @@ -286,7 +286,7 @@ Hooks are extremely powerful because: - Effect: "Allow" Action: - "lambda:InvokeFunction" - Resource: !Ref MyLambdaFunction.Version + Resource: !GetAtt MyLambdaFunction.Arn Checkout the lambda_safe_deployments_ folder for an example for how to create SAM template that contains a hook function. diff --git a/examples/2016-10-31/api_aws_iam_auth/template.yaml b/examples/2016-10-31/api_aws_iam_auth/template.yaml index 935e45c71b..56551333de 100644 --- a/examples/2016-10-31/api_aws_iam_auth/template.yaml +++ b/examples/2016-10-31/api_aws_iam_auth/template.yaml @@ -8,7 +8,7 @@ Resources: StageName: Prod Auth: DefaultAuthorizer: AWS_IAM - InvokeRole: CALLER_CREDENTIALS + InvokeRole: CALLER_CREDENTIALS # default, can specify other role or NONE MyFunction: Type: AWS::Serverless::Function diff --git a/examples/2016-10-31/api_cognito_auth/package.json b/examples/2016-10-31/api_cognito_auth/package.json index 997222c19a..6bd1d43b3a 100644 --- a/examples/2016-10-31/api_cognito_auth/package.json +++ b/examples/2016-10-31/api_cognito_auth/package.json @@ -19,12 +19,12 @@ "configure-cognito-user-pool": "npm run set-cognito-user-pool-id && npm run set-cognito-user-pool-client-id && npm run set-api-id && npm run set-api-url && npm run update-user-pool-client && npm run create-user-pool-domain", "set-cognito-user-pool-id": "npm config set COGNITO_USER_POOL_ID $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`CognitoUserPoolId`].OutputValue' --output text)", "set-cognito-user-pool-client-id": "npm config set COGNITO_USER_POOL_CLIENT_ID $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`CognitoUserPoolClientId`].OutputValue' --output text)", - "set-api-url": "npm config set API_URL $(aws cloudformation describe-stacks --stack-name sam-example-api-cognito-auth --query 'Stacks[].Outputs[?OutputKey==`ApiUrl`].OutputValue' --output text)", - "set-api-id": "npm config set API_ID $(aws cloudformation describe-stacks --stack-name sam-example-api-cognito-auth --query 'Stacks[].Outputs[?OutputKey==`ApiId`].OutputValue' --output text)", + "set-api-url": "npm config set API_URL $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`ApiUrl`].OutputValue' --output text)", + "set-api-id": "npm config set API_ID $(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`ApiId`].OutputValue' --output text)", "update-user-pool-client": "aws cognito-idp update-user-pool-client --user-pool-id $(npm config get COGNITO_USER_POOL_ID) --client-id $(npm config get COGNITO_USER_POOL_CLIENT_ID) --supported-identity-providers COGNITO --callback-urls \"[\\\"$(npm config get API_URL)\\\"]\" --allowed-o-auth-flows code implicit --allowed-o-auth-scopes openid email --allowed-o-auth-flows-user-pool-client", "create-user-pool-domain": "aws cognito-idp create-user-pool-domain --domain $(npm config get API_ID) --user-pool-id $(npm config get COGNITO_USER_POOL_ID)", - "open-signup-page": "open \"https://$(npm config get API_ID).auth.us-east-1.amazoncognito.com/signup?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"", - "open-login-page": "open \"https://$(npm config get API_ID).auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"", + "open-signup-page": "open \"https://$(npm config get API_ID).auth.$(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`Region`].OutputValue' --output text).amazoncognito.com/signup?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"", + "open-login-page": "open \"https://$(npm config get API_ID).auth.$(aws cloudformation describe-stacks --stack-name $(npm config get STACK_NAME) --query 'Stacks[].Outputs[?OutputKey==`Region`].OutputValue' --output text).amazoncognito.com/login?response_type=code&client_id=$(npm config get COGNITO_USER_POOL_CLIENT_ID)&redirect_uri=$(npm config get API_URL)\"", "open-api-ui": "open \"$(npm config get API_URL)\"" } } diff --git a/examples/2016-10-31/api_cognito_auth/template.yaml b/examples/2016-10-31/api_cognito_auth/template.yaml index b1dc1dacc3..0b1042f344 100644 --- a/examples/2016-10-31/api_cognito_auth/template.yaml +++ b/examples/2016-10-31/api_cognito_auth/template.yaml @@ -140,6 +140,10 @@ Resources: # UserPool: !Ref MyCognitoUserPool Outputs: + Region: + Description: "Region" + Value: !Ref AWS::Region + ApiId: Description: "API ID" Value: !Ref MyApi diff --git a/examples/2016-10-31/api_resource_policy/README.md b/examples/2016-10-31/api_resource_policy/README.md new file mode 100644 index 0000000000..7222c12908 --- /dev/null +++ b/examples/2016-10-31/api_resource_policy/README.md @@ -0,0 +1,11 @@ +# Api Resource Policy Event Source Example + +Example SAM template for adding Custom Resource Policy to Api. + +## Running the example + +```bash +# Replace YOUR_S3_ARTIFACTS_BUCKET +aws cloudformation package --template-file template.yaml --output-template-file cfn-transformed-template.yaml --s3-bucket YOUR_S3_ARTIFACTS_BUCKET +aws cloudformation deploy --template-file ./cfn-transformed-template.yaml --stack-name example-resource-policy --capabilities CAPABILITY_IAM +``` diff --git a/examples/2016-10-31/api_resource_policy/template.yaml b/examples/2016-10-31/api_resource_policy/template.yaml new file mode 100644 index 0000000000..ae8361477a --- /dev/null +++ b/examples/2016-10-31/api_resource_policy/template.yaml @@ -0,0 +1,37 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Globals: + Api: + Auth: + ResourcePolicy: + CustomStatements: [{ + "Effect": "Allow", + "Principal": "*", + "Action": "execute-api:Invoke", + "Resource": "execute-api:*/*/*", + "Condition": { + "IpAddress": { + "aws:SourceIp": "1.2.3.4" + } + } + }] +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get diff --git a/examples/2016-10-31/lambda_safe_deployments/template.yaml b/examples/2016-10-31/lambda_safe_deployments/template.yaml index 211158fbca..49c31e7c7a 100644 --- a/examples/2016-10-31/lambda_safe_deployments/template.yaml +++ b/examples/2016-10-31/lambda_safe_deployments/template.yaml @@ -34,7 +34,7 @@ Resources: - Effect: "Allow" Action: - "lambda:InvokeFunction" - Resource: !Ref safeTest.Version + Resource: !GetAtt safeTest.Arn Runtime: nodejs8.10 FunctionName: 'CodeDeployHook_preTrafficHook' DeploymentPreference: diff --git a/examples/apps/api-gateway-multiple-origin-cors/package-lock.json b/examples/apps/api-gateway-multiple-origin-cors/package-lock.json index 9287383682..3a6a0fc546 100644 --- a/examples/apps/api-gateway-multiple-origin-cors/package-lock.json +++ b/examples/apps/api-gateway-multiple-origin-cors/package-lock.json @@ -3151,9 +3151,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz", + "integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA==", "dev": true }, "lodash.sortby": { diff --git a/examples/apps/api-gateway-multiple-origin-cors/package.json b/examples/apps/api-gateway-multiple-origin-cors/package.json index e2c80cd073..d87477c793 100644 --- a/examples/apps/api-gateway-multiple-origin-cors/package.json +++ b/examples/apps/api-gateway-multiple-origin-cors/package.json @@ -9,7 +9,7 @@ "author": "", "devDependencies": { "jest": "^23.1.0", - "lodash": ">=4.17.11", + "lodash": ">=4.17.13", "merge": ">=1.2.1" }, "jest": { diff --git a/examples/apps/microservice-http-endpoint-python3/lambda_function.py b/examples/apps/microservice-http-endpoint-python3/lambda_function.py index 838fd389d0..b00a29872e 100644 --- a/examples/apps/microservice-http-endpoint-python3/lambda_function.py +++ b/examples/apps/microservice-http-endpoint-python3/lambda_function.py @@ -33,7 +33,7 @@ def lambda_handler(event, context): operations = { 'DELETE': lambda dynamo, x: dynamo.delete_item(TableName=table_name, **x), - 'GET': lambda dynamo, x: dynamo.scan(TableName=table_name, **x) if x else dynamo.scan(TableName=table_name), + 'GET': lambda dynamo, x: dynamo.scan(TableName=table_name, **x) if x else dynamo.scan(TableName=table_name), 'POST': lambda dynamo, x: dynamo.put_item(TableName=table_name, **x), 'PUT': lambda dynamo, x: dynamo.update_item(TableName=table_name, **x), } diff --git a/requirements/dev.txt b/requirements/dev.txt index 1fe5d9f99e..35279a22a7 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -3,15 +3,15 @@ flake8>=3.3.0 tox>=2.2.1 pytest-cov>=2.4.0 pylint>=1.7.2,<2.0 -pyyaml>=4.2b1 +pyyaml>=5.1 # Test requirements pytest>=3.0.7 -py>=1.4.33 mock>=2.0.0 parameterized>=0.6.1 + +# Requirements for examples requests>=2.20.0 -cfn-lint>=0.18.1 # CLI requirements docopt>=0.6.2 diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index f43a2786d7..e4f2ad49d9 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = '1.13.2' +__version__ = '1.14.0' diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 9095ae8d09..b9e02d538a 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -13,6 +13,7 @@ from samtranslator.model.intrinsics import is_instrinsic, fnSub from samtranslator.model.lambda_ import LambdaPermission from samtranslator.translator.arn_generator import ArnGenerator +from samtranslator.model.tags.resource_tagging import get_tag_list _CORS_WILDCARD = "'*'" CorsProperties = namedtuple("_CorsProperties", ["AllowMethods", "AllowHeaders", "AllowOrigin", "MaxAge", @@ -21,8 +22,9 @@ CorsProperties.__new__.__defaults__ = (None, None, _CORS_WILDCARD, None, False) AuthProperties = namedtuple("_AuthProperties", - ["Authorizers", "DefaultAuthorizer", "InvokeRole", "AddDefaultAuthorizerToCorsPreflight"]) -AuthProperties.__new__.__defaults__ = (None, None, None, True) + ["Authorizers", "DefaultAuthorizer", "InvokeRole", "AddDefaultAuthorizerToCorsPreflight", + "ApiKeyRequired", "ResourcePolicy"]) +AuthProperties.__new__.__defaults__ = (None, None, None, True, None, None) GatewayResponseProperties = ["ResponseParameters", "ResponseTemplates", "StatusCode"] @@ -30,7 +32,7 @@ class ApiGenerator(object): def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variables, depends_on, - definition_body, definition_uri, name, stage_name, endpoint_configuration=None, + definition_body, definition_uri, name, stage_name, tags=None, endpoint_configuration=None, method_settings=None, binary_media=None, minimum_compression_size=None, cors=None, auth=None, gateway_responses=None, access_log_setting=None, canary_setting=None, tracing_enabled=None, resource_attributes=None, passthrough_resource_attributes=None, @@ -46,6 +48,7 @@ def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variab :param definition_uri: URI to API definition :param name: Name of the API Gateway resource :param stage_name: Name of the Stage + :param tags: Stage Tags :param access_log_setting: Whether to send access logs and where for Stage :param canary_setting: Canary Setting for Stage :param tracing_enabled: Whether active tracing with X-ray is enabled @@ -62,6 +65,7 @@ def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variab self.definition_uri = definition_uri self.name = name self.stage_name = stage_name + self.tags = tags self.endpoint_configuration = endpoint_configuration self.method_settings = method_settings self.binary_media = binary_media @@ -75,6 +79,7 @@ def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variab self.resource_attributes = resource_attributes self.passthrough_resource_attributes = passthrough_resource_attributes self.open_api_version = open_api_version + self.remove_extra_stage = open_api_version self.models = models def _construct_rest_api(self): @@ -115,6 +120,8 @@ def _construct_rest_api(self): if self.definition_uri: rest_api.BodyS3Location = self._construct_body_s3_dict() elif self.definition_body: + # # Post Process OpenApi Auth Settings + self.definition_body = self._openapi_postprocess(self.definition_body) rest_api.Body = self.definition_body if self.name: @@ -152,7 +159,7 @@ def _construct_body_s3_dict(self): body_s3['Version'] = s3_pointer['Version'] return body_s3 - def _construct_deployment(self, rest_api, open_api_version): + def _construct_deployment(self, rest_api): """Constructs and returns the ApiGateway Deployment. :param model.apigateway.ApiGatewayRestApi rest_api: the RestApi for this Deployment @@ -162,7 +169,7 @@ def _construct_deployment(self, rest_api, open_api_version): deployment = ApiGatewayDeployment(self.logical_id + 'Deployment', attributes=self.passthrough_resource_attributes) deployment.RestApiId = rest_api.get_runtime_attr('rest_api_id') - if not self.open_api_version: + if not self.remove_extra_stage: deployment.StageName = 'Stage' return deployment @@ -193,7 +200,10 @@ def _construct_stage(self, deployment, swagger): stage.TracingEnabled = self.tracing_enabled if swagger is not None: - deployment.make_auto_deployable(stage, self.open_api_version, swagger) + deployment.make_auto_deployable(stage, self.remove_extra_stage, swagger) + + if self.tags is not None: + stage.Tags = get_tag_list(self.tags) return stage @@ -205,7 +215,7 @@ def to_cloudformation(self): """ rest_api = self._construct_rest_api() - deployment = self._construct_deployment(rest_api, self.open_api_version) + deployment = self._construct_deployment(rest_api) swagger = None if rest_api.Body is not None: @@ -308,11 +318,16 @@ def _add_auth(self): authorizers = self._get_authorizers(auth_properties.Authorizers, auth_properties.DefaultAuthorizer) if authorizers: - swagger_editor.add_authorizers(authorizers) + swagger_editor.add_authorizers_security_definitions(authorizers) self._set_default_authorizer(swagger_editor, authorizers, auth_properties.DefaultAuthorizer, auth_properties.AddDefaultAuthorizerToCorsPreflight) - # Assign the Swagger back to template + if auth_properties.ApiKeyRequired: + swagger_editor.add_apikey_security_definition() + self._set_default_apikey_required(swagger_editor) + + if auth_properties.ResourcePolicy: + swagger_editor.add_resource_policy(auth_properties.ResourcePolicy) self.definition_body = self._openapi_postprocess(swagger_editor.swagger) @@ -506,6 +521,10 @@ def _set_default_authorizer(self, swagger_editor, authorizers, default_authorize swagger_editor.set_path_default_authorizer(path, default_authorizer, authorizers=authorizers, add_default_auth_to_preflight=add_default_auth_to_preflight) + def _set_default_apikey_required(self, swagger_editor): + for path in swagger_editor.iter_on_path(): + swagger_editor.set_path_default_apikey_required(path) + def _set_endpoint_configuration(self, rest_api, value): """ Sets endpoint configuration property of AWS::ApiGateway::RestApi resource diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index ab761811a5..e2cc90095a 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -2,7 +2,7 @@ from samtranslator.model import PropertyType, Resource from samtranslator.model.exceptions import InvalidResourceException -from samtranslator.model.types import is_type, one_of, is_str +from samtranslator.model.types import is_type, one_of, is_str, list_of from samtranslator.model.intrinsics import ref, fnSub from samtranslator.translator import logical_id_generator from samtranslator.translator.arn_generator import ArnGenerator @@ -40,6 +40,7 @@ class ApiGatewayStage(Resource): 'Description': PropertyType(False, is_str()), 'RestApiId': PropertyType(True, is_str()), 'StageName': PropertyType(True, one_of(is_str(), is_type(dict))), + 'Tags': PropertyType(False, list_of(is_type(dict))), 'TracingEnabled': PropertyType(False, is_type(bool)), 'Variables': PropertyType(False, is_type(dict)), "MethodSettings": PropertyType(False, is_type(list)) diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index 14217806fb..d70c7bb37f 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -72,14 +72,17 @@ class Schedule(PushEventSource): principal = 'events.amazonaws.com' property_types = { 'Schedule': PropertyType(True, is_str()), - 'Input': PropertyType(False, is_str()) + 'Input': PropertyType(False, is_str()), + 'Enabled': PropertyType(False, is_type(bool)), + 'Name': PropertyType(False, is_str()), + 'Description': PropertyType(False, is_str()) } def to_cloudformation(self, **kwargs): """Returns the CloudWatch Events Rule and Lambda Permission to which this Schedule event source corresponds. :param dict kwargs: no existing resources need to be modified - :returns: a list of vanilla CloudFormation Resources, to which this pull event expands + :returns: a list of vanilla CloudFormation Resources, to which this Schedule event expands :rtype: list """ function = kwargs.get('function') @@ -93,6 +96,10 @@ def to_cloudformation(self, **kwargs): resources.append(events_rule) events_rule.ScheduleExpression = self.Schedule + if self.Enabled is not None: + events_rule.State = "ENABLED" if self.Enabled else "DISABLED" + events_rule.Name = self.Name + events_rule.Description = self.Description events_rule.Targets = [self._construct_target(function)] source_arn = events_rule.get_runtime_attr("arn") @@ -123,9 +130,9 @@ class CloudWatchEvent(PushEventSource): resource_type = 'CloudWatchEvent' principal = 'events.amazonaws.com' property_types = { - 'Pattern': PropertyType(False, is_type(dict)), - 'Input': PropertyType(False, is_str()), - 'InputPath': PropertyType(False, is_str()) + 'Pattern': PropertyType(False, is_type(dict)), + 'Input': PropertyType(False, is_str()), + 'InputPath': PropertyType(False, is_str()) } def to_cloudformation(self, **kwargs): @@ -133,7 +140,7 @@ def to_cloudformation(self, **kwargs): corresponds. :param dict kwargs: no existing resources need to be modified - :returns: a list of vanilla CloudFormation Resources, to which this pull event expands + :returns: a list of vanilla CloudFormation Resources, to which this CloudWatch Events event expands :rtype: list """ function = kwargs.get('function') @@ -344,6 +351,7 @@ class SNS(PushEventSource): principal = 'sns.amazonaws.com' property_types = { 'Topic': PropertyType(True, is_str()), + 'Region': PropertyType(False, is_str()), 'FilterPolicy': PropertyType(False, dict_of(is_str(), list_of(one_of(is_str(), is_type(dict))))) } @@ -360,13 +368,15 @@ def to_cloudformation(self, **kwargs): raise TypeError("Missing required keyword argument: function") return [self._construct_permission(function, source_arn=self.Topic), - self._inject_subscription(function, self.Topic, self.FilterPolicy)] + self._inject_subscription(function, self.Topic, self.Region, self.FilterPolicy)] - def _inject_subscription(self, function, topic, filterPolicy): + def _inject_subscription(self, function, topic, region, filterPolicy): subscription = SNSSubscription(self.logical_id) subscription.Protocol = 'lambda' subscription.Endpoint = function.get_runtime_attr("arn") subscription.TopicArn = topic + if region is not None: + subscription.Region = region if CONDITION in function.resource_attributes: subscription.set_resource_attribute(CONDITION, function.resource_attributes[CONDITION]) @@ -492,7 +502,7 @@ 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 = path.replace('{proxy+}', '*') + path = re.sub(r'{([a-zA-Z0-9._-]+|proxy\+)}', '*', path) method = '*' if self.Method.lower() == 'any' else self.Method.upper() api_id = self.RestApiId @@ -536,9 +546,9 @@ def _add_swagger_integration(self, api, function): if self.Auth: method_authorizer = self.Auth.get('Authorizer') + api_auth = api.get('Auth') if method_authorizer: - api_auth = api.get('Auth') api_authorizers = api_auth and api_auth.get('Authorizers') if method_authorizer != 'AWS_IAM': @@ -563,6 +573,16 @@ def _add_swagger_integration(self, api, function): 'is only a valid value when a DefaultAuthorizer on the API is specified.'.format( method=self.Method, path=self.Path)) + apikey_required_setting = self.Auth.get('ApiKeyRequired') + apikey_required_setting_is_false = apikey_required_setting is not None and not apikey_required_setting + if apikey_required_setting_is_false and not api_auth.get('ApiKeyRequired'): + raise InvalidEventException( + self.relative_id, + 'Unable to set ApiKeyRequired [False] on API method [{method}] for path [{path}] ' + 'because the related API does not specify any ApiKeyRequired.'.format( + method=self.Method, path=self.Path)) + + if method_authorizer or apikey_required_setting is not None: editor.add_auth_to_method(api=api, path=self.Path, method_name=self.Method, auth=self.Auth) if self.RequestModel: diff --git a/samtranslator/model/function_policies.py b/samtranslator/model/function_policies.py index c62e94d19d..843366e388 100644 --- a/samtranslator/model/function_policies.py +++ b/samtranslator/model/function_policies.py @@ -3,7 +3,8 @@ from six import string_types -from samtranslator.model.intrinsics import is_instrinsic +from samtranslator.model.intrinsics import is_instrinsic, is_intrinsic_if, is_intrinsic_no_value +from samtranslator.model.exceptions import InvalidTemplateException PolicyEntry = namedtuple("PolicyEntry", "data type") @@ -114,8 +115,16 @@ def _get_type(self, policy): # Must handle intrinsic functions. Policy could be a primitive type or an intrinsic function - # Managed policies are either string or an intrinsic function that resolves to a string - if isinstance(policy, string_types) or is_instrinsic(policy): + # Managed policies are of type string + if isinstance(policy, string_types): + return PolicyTypes.MANAGED_POLICY + + # Handle the special case for 'if' intrinsic function + if is_intrinsic_if(policy): + return self._get_type_from_intrinsic_if(policy) + + # Intrinsic functions are treated as managed policies by default + if is_instrinsic(policy): return PolicyTypes.MANAGED_POLICY # Policy statement is a dictionary with the key "Statement" in it @@ -143,6 +152,36 @@ def _is_policy_template(self, policy): len(policy) == 1 and \ self._policy_template_processor.has(list(policy.keys())[0]) is True + def _get_type_from_intrinsic_if(self, policy): + """ + Returns the type of the given policy assuming that it is an intrinsic if function + + :param policy: Input value to get type from + :return: PolicyTypes: Type of the given policy. PolicyTypes.UNKNOWN, if type could not be inferred + """ + intrinsic_if_value = policy["Fn::If"] + + if not len(intrinsic_if_value) == 3: + raise InvalidTemplateException("Fn::If requires 3 arguments") + + if_data = intrinsic_if_value[1] + else_data = intrinsic_if_value[2] + + if_data_type = self._get_type(if_data) + else_data_type = self._get_type(else_data) + + if if_data_type == else_data_type: + return if_data_type + + if is_intrinsic_no_value(if_data): + return else_data_type + + if is_intrinsic_no_value(else_data): + return if_data_type + + raise InvalidTemplateException("Different policy types within the same Fn::If statement is unsupported. " + "Separate different policy types into different Fn::If statements") + class PolicyTypes(Enum): """ diff --git a/samtranslator/model/intrinsics.py b/samtranslator/model/intrinsics.py index 720540b90e..11edd9dabf 100644 --- a/samtranslator/model/intrinsics.py +++ b/samtranslator/model/intrinsics.py @@ -138,3 +138,35 @@ def is_instrinsic(input): return key == "Ref" or key == "Condition" or key.startswith("Fn::") return False + + +def is_intrinsic_if(input): + """ + Is the given input an intrinsic if? Intrinsic function 'if' is a dictionary with single + key - if + + :param input: Input value to check if it is an intrinsic if + :return: True, if yes + """ + + if not is_instrinsic(input): + return False + + key = list(input.keys())[0] + return key == "Fn::If" + + +def is_intrinsic_no_value(input): + """ + Is the given input an intrinsic Ref: AWS::NoValue? Intrinsic function is a dictionary with single + key - Ref and value - AWS::NoValue + + :param input: Input value to check if it is an intrinsic if + :return: True, if yes + """ + + if not is_instrinsic(input): + return False + + key = list(input.keys())[0] + return key == "Ref" and input["Ref"] == "AWS::NoValue" diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 64890b715a..91285a97f7 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -22,6 +22,7 @@ from samtranslator.model.types import dict_of, is_str, is_type, list_of, one_of, any_type from samtranslator.translator import logical_id_generator from samtranslator.translator.arn_generator import ArnGenerator +from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value class SamFunction(SamResourceMacro): @@ -212,10 +213,34 @@ def _construct_role(self, managed_policy_map): if policy_entry.type is PolicyTypes.POLICY_STATEMENT: - policy_documents.append({ - 'PolicyName': execution_role.logical_id + 'Policy' + str(index), - 'PolicyDocument': policy_entry.data - }) + if is_intrinsic_if(policy_entry.data): + + intrinsic_if = policy_entry.data + then_statement = intrinsic_if["Fn::If"][1] + else_statement = intrinsic_if["Fn::If"][2] + + if not is_intrinsic_no_value(then_statement): + then_statement = { + 'PolicyName': execution_role.logical_id + 'Policy' + str(index), + 'PolicyDocument': then_statement + } + intrinsic_if["Fn::If"][1] = then_statement + + if not is_intrinsic_no_value(else_statement): + else_statement = { + 'PolicyName': execution_role.logical_id + 'Policy' + str(index), + 'PolicyDocument': else_statement + } + intrinsic_if["Fn::If"][2] = else_statement + + policy_documents.append(intrinsic_if) + + else: + policy_documents.append({ + 'PolicyName': execution_role.logical_id + 'Policy' + str(index), + 'PolicyDocument': policy_entry.data + }) + elif policy_entry.type is PolicyTypes.MANAGED_POLICY: # There are three options: @@ -440,6 +465,7 @@ class SamApi(SamResourceMacro): 'Name': PropertyType(False, one_of(is_str(), is_type(dict))), 'StageName': PropertyType(True, one_of(is_str(), is_type(dict))), + 'Tags': PropertyType(False, is_type(dict)), 'DefinitionBody': PropertyType(False, is_type(dict)), 'DefinitionUri': PropertyType(False, one_of(is_str(), is_type(dict))), 'CacheClusterEnabled': PropertyType(False, is_type(bool)), @@ -486,6 +512,7 @@ def to_cloudformation(self, **kwargs): self.DefinitionUri, self.Name, self.StageName, + tags=self.Tags, endpoint_configuration=self.EndpointConfiguration, method_settings=self.MethodSettings, binary_media=self.BinaryMediaTypes, @@ -535,6 +562,11 @@ def _construct_dynamodb_table(self): dynamodb_table = DynamoDBTable(self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes) if self.PrimaryKey: + if 'Name' not in self.PrimaryKey or 'Type' not in self.PrimaryKey: + raise InvalidResourceException( + self.logical_id, + '\'PrimaryKey\' is missing required Property \'Name\' or \'Type\'.' + ) primary_key = { 'AttributeName': self.PrimaryKey['Name'], 'AttributeType': self._convert_attribute_type(self.PrimaryKey['Type']) diff --git a/samtranslator/model/sns.py b/samtranslator/model/sns.py index 7bfb1b94a6..4b4290b946 100644 --- a/samtranslator/model/sns.py +++ b/samtranslator/model/sns.py @@ -8,5 +8,6 @@ class SNSSubscription(Resource): 'Endpoint': PropertyType(True, is_str()), 'Protocol': PropertyType(True, is_str()), 'TopicArn': PropertyType(True, is_str()), + 'Region': PropertyType(False, is_str()), 'FilterPolicy': PropertyType(False, is_type(dict)) } diff --git a/samtranslator/plugins/application/serverless_app_plugin.py b/samtranslator/plugins/application/serverless_app_plugin.py index ac419d9baf..5058b98d7f 100644 --- a/samtranslator/plugins/application/serverless_app_plugin.py +++ b/samtranslator/plugins/application/serverless_app_plugin.py @@ -132,6 +132,7 @@ def _can_process_application(self, app): return (self.LOCATION_KEY in app.properties and isinstance(app.properties[self.LOCATION_KEY], dict) and self.APPLICATION_ID_KEY in app.properties[self.LOCATION_KEY] and + app.properties[self.LOCATION_KEY][self.APPLICATION_ID_KEY] is not None and self.SEMANTIC_VERSION_KEY in app.properties[self.LOCATION_KEY]) def _handle_get_application_request(self, app_id, semver, key, logical_id): diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index f6b860bdc6..1e9f1f63f8 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -44,7 +44,7 @@ class Globals(object): # StageName: Because StageName cannot be overridden for Implicit APIs because of the current plugin # architecture SamResourceType.Api.value: [ - 'Auth', + "Auth", "Name", "DefinitionUri", "CacheClusterEnabled", diff --git a/samtranslator/plugins/policies/policy_templates_plugin.py b/samtranslator/plugins/policies/policy_templates_plugin.py index 9ae515ff2c..50aded6478 100644 --- a/samtranslator/plugins/policies/policy_templates_plugin.py +++ b/samtranslator/plugins/policies/policy_templates_plugin.py @@ -2,6 +2,7 @@ from samtranslator.model.function_policies import FunctionPolicies, PolicyTypes from samtranslator.model.exceptions import InvalidResourceException from samtranslator.policy_template_processor.exceptions import InsufficientParameterValues, InvalidParameterValues +from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value class PolicyTemplatesForFunctionPlugin(BasePlugin): @@ -55,28 +56,60 @@ def on_before_transform_resource(self, logical_id, resource_type, resource_prope result.append(policy_entry.data) continue - # We are processing policy templates. We know they have a particular structure: - # {"templateName": { parameter_values_dict }} - template_data = policy_entry.data - template_name = list(template_data.keys())[0] - template_parameters = list(template_data.values())[0] - - try: - - # 'convert' will return a list of policy statements - result.append(self._policy_template_processor.convert(template_name, template_parameters)) + if is_intrinsic_if(policy_entry.data): + # If policy is an intrinsic if, we need to process each sub-statement separately + processed_intrinsic_if = self._process_intrinsic_if_policy_template(logical_id, policy_entry) + result.append(processed_intrinsic_if) + continue - except InsufficientParameterValues as ex: - # Exception's message will give lot of specific details - raise InvalidResourceException(logical_id, str(ex)) - except InvalidParameterValues: - raise InvalidResourceException(logical_id, - "Must specify valid parameter values for policy template '{}'" - .format(template_name)) + converted_policy = self._process_policy_template(logical_id, policy_entry.data) + result.append(converted_policy) # Save the modified policies list to the input resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result + def _process_intrinsic_if_policy_template(self, logical_id, policy_entry): + intrinsic_if = policy_entry.data + then_statement = intrinsic_if["Fn::If"][1] + else_statement = intrinsic_if["Fn::If"][2] + + processed_then_statement = then_statement \ + if is_intrinsic_no_value(then_statement) \ + else self._process_policy_template(logical_id, then_statement) + + processed_else_statement = else_statement \ + if is_intrinsic_no_value(else_statement) \ + else self._process_policy_template(logical_id, else_statement) + + processed_intrinsic_if = { + "Fn::If": [ + policy_entry.data["Fn::If"][0], + processed_then_statement, + processed_else_statement + ] + } + + return processed_intrinsic_if + + def _process_policy_template(self, logical_id, template_data): + + # We are processing policy templates. We know they have a particular structure: + # {"templateName": { parameter_values_dict }} + template_name = list(template_data.keys())[0] + template_parameters = list(template_data.values())[0] + try: + + # 'convert' will return a list of policy statements + return self._policy_template_processor.convert(template_name, template_parameters) + + except InsufficientParameterValues as ex: + # Exception's message will give lot of specific details + raise InvalidResourceException(logical_id, str(ex)) + except InvalidParameterValues: + raise InvalidResourceException(logical_id, + "Must specify valid parameter values for policy template '{}'" + .format(template_name)) + def _is_supported(self, resource_type): """ Is this resource supported by this plugin? diff --git a/samtranslator/policy_templates_data/policy_templates.json b/samtranslator/policy_templates_data/policy_templates.json index f15dc1308d..4b3dc28e69 100644 --- a/samtranslator/policy_templates_data/policy_templates.json +++ b/samtranslator/policy_templates_data/policy_templates.json @@ -246,7 +246,7 @@ } }, "ElasticsearchHttpPostPolicy": { - "Description": "Gives POST permissions to Elasticsearch", + "Description": "Gives POST and PUT permissions to Elasticsearch", "Parameters": { "DomainName": { "Description": "Name of Domain" @@ -257,7 +257,8 @@ { "Effect": "Allow", "Action": [ - "es:ESHttpPost" + "es:ESHttpPost", + "es:ESHttpPut" ], "Resource": { "Fn::Sub": [ @@ -1051,9 +1052,7 @@ "RekognitionFacesPolicy": { "Description": "Gives permission to compare and detect faces and labels", "Parameters": { - "CollectionId": { - "Description": "ID of the collection" - } + }, "Definition": { "Statement": [ @@ -1063,16 +1062,7 @@ "rekognition:CompareFaces", "rekognition:DetectFaces" ], - "Resource": { - "Fn::Sub": [ - "arn:${AWS::Partition}:rekognition:${AWS::Region}:${AWS::AccountId}:collection/${collectionId}", - { - "collectionId": { - "Ref": "CollectionId" - } - } - ] - } + "Resource": "*" } ] } diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index a1fecb3444..61f753dc81 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -21,6 +21,7 @@ class SwaggerEditor(object): _X_APIGW_BINARY_MEDIA_TYPES = 'x-amazon-apigateway-binary-media-types' _CONDITIONAL_IF = "Fn::If" _X_APIGW_GATEWAY_RESPONSES = 'x-amazon-apigateway-gateway-responses' + _X_APIGW_POLICY = 'x-amazon-apigateway-policy' _X_ANY_METHOD = 'x-amazon-apigateway-any-method' def __init__(self, doc): @@ -39,6 +40,7 @@ def __init__(self, doc): self.paths = self._doc["paths"] self.security_definitions = self._doc.get("securityDefinitions", {}) self.gateway_responses = self._doc.get(self._X_APIGW_GATEWAY_RESPONSES, {}) + self.resource_policy = self._doc.get(self._X_APIGW_POLICY, {}) self.definitions = self._doc.get('definitions', {}) def get_path(self, path): @@ -161,19 +163,27 @@ def add_lambda_integration(self, path, method, integration_uri, path_dict = self.get_path(path) path_dict[method][self._X_APIGW_INTEGRATION] = { - 'type': 'aws_proxy', - 'httpMethod': 'POST', - 'uri': integration_uri + 'type': 'aws_proxy', + 'httpMethod': 'POST', + 'uri': integration_uri } method_auth_config = method_auth_config or {} api_auth_config = api_auth_config or {} if method_auth_config.get('Authorizer') == 'AWS_IAM' \ or api_auth_config.get('DefaultAuthorizer') == 'AWS_IAM' and not method_auth_config: - self.paths[path][method][self._X_APIGW_INTEGRATION]['credentials'] = self._generate_integration_credentials( - method_invoke_role=method_auth_config.get('InvokeRole'), - api_invoke_role=api_auth_config.get('InvokeRole') + method_invoke_role = method_auth_config.get('InvokeRole') + if not method_invoke_role and 'InvokeRole' in method_auth_config: + method_invoke_role = 'NONE' + api_invoke_role = api_auth_config.get('InvokeRole') + if not api_invoke_role and 'InvokeRole' in api_auth_config: + api_invoke_role = 'NONE' + credentials = self._generate_integration_credentials( + method_invoke_role=method_invoke_role, + api_invoke_role=api_invoke_role ) + if credentials and credentials != 'NONE': + self.paths[path][method][self._X_APIGW_INTEGRATION]['credentials'] = credentials # If 'responses' key is *not* present, add it with an empty dict as value path_dict[method].setdefault('responses', {}) @@ -391,7 +401,7 @@ def _make_cors_allowed_methods_for_path(self, path): # Allow-Methods is comma separated string return ','.join(allow_methods) - def add_authorizers(self, authorizers): + def add_authorizers_security_definitions(self, authorizers): """ Add Authorizer definitions to the securityDefinitions part of Swagger. @@ -402,11 +412,56 @@ def add_authorizers(self, authorizers): for authorizer_name, authorizer in authorizers.items(): self.security_definitions[authorizer_name] = authorizer.generate_swagger() + def add_awsiam_security_definition(self): + """ + Adds AWS_IAM definition to the securityDefinitions part of Swagger. + Note: this method is idempotent + """ + + aws_iam_security_definition = { + 'AWS_IAM': { + 'x-amazon-apigateway-authtype': 'awsSigv4', + 'type': 'apiKey', + 'name': 'Authorization', + 'in': 'header' + } + } + + self.security_definitions = self.security_definitions or {} + + # Only add the security definition if it doesn't exist. This helps ensure + # that we minimize changes to the swagger in the case of user defined swagger + if 'AWS_IAM' not in self.security_definitions: + self.security_definitions.update(aws_iam_security_definition) + + def add_apikey_security_definition(self): + """ + Adds api_key definition to the securityDefinitions part of Swagger. + Note: this method is idempotent + """ + + api_key_security_definition = { + 'api_key': { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + + self.security_definitions = self.security_definitions or {} + + # Only add the security definition if it doesn't exist. This helps ensure + # that we minimize changes to the swagger in the case of user defined swagger + if 'api_key' not in self.security_definitions: + self.security_definitions.update(api_key_security_definition) + def set_path_default_authorizer(self, path, default_authorizer, authorizers, add_default_auth_to_preflight=True): """ - Sets the DefaultAuthorizer for each method on this path. The DefaultAuthorizer won't be set if an Authorizer - was defined at the Function/Path/Method level + Adds the default_authorizer to the security block for each method on this path unless an Authorizer + was defined at the Function/Path/Method level. This is intended to be used to set the + authorizer security restriction for all api methods based upon the default configured in the + Serverless API. :param string path: Path name :param string default_authorizer: Name of the authorizer to use as the default. Must be a key in the @@ -418,35 +473,169 @@ def set_path_default_authorizer(self, path, default_authorizer, authorizers, for method_name, method in self.get_path(path).items(): normalized_method_name = self._normalize_method_name(method_name) + # Excluding paramters section if normalized_method_name == "parameters": continue if add_default_auth_to_preflight or normalized_method_name != "options": - self.set_method_authorizer(path, method_name, default_authorizer, authorizers, - default_authorizer=default_authorizer, is_default=True) + normalized_method_name = self._normalize_method_name(method_name) + # It is possible that the method could have two definitions in a Fn::If block. + for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + + # If no integration given, then we don't need to process this definition (could be AWS::NoValue) + if not self.method_definition_has_integration(method_definition): + continue + existing_security = method_definition.get('security', []) + authorizer_list = ['AWS_IAM'] + if authorizers: + authorizer_list.extend(authorizers.keys()) + authorizer_names = set(authorizer_list) + existing_non_authorizer_security = [] + existing_authorizer_security = [] + + # Split existing security into Authorizers and everything else + # (e.g. sigv4 (AWS_IAM), api_key (API Key/Usage Plans), NONE (marker for ignoring default)) + # We want to ensure only a single Authorizer security entry exists while keeping everything else + for security in existing_security: + if authorizer_names.isdisjoint(security.keys()): + existing_non_authorizer_security.append(security) + else: + existing_authorizer_security.append(security) + + none_idx = -1 + authorizer_security = [] + + # Check for an existing Authorizer before applying the default. It would be simpler + # if instead we applied the DefaultAuthorizer first and then simply + # overwrote it if necessary, however, the order in which things get + # applied (Function Api Events first; then Api Resource) complicates it. + # Check if Function/Path/Method specified 'NONE' for Authorizer + for idx, security in enumerate(existing_non_authorizer_security): + is_none = any(key == 'NONE' for key in security.keys()) + + if is_none: + none_idx = idx + break + + # NONE was found; remove it and don't add the DefaultAuthorizer + if none_idx > -1: + del existing_non_authorizer_security[none_idx] + + # Existing Authorizer found (defined at Function/Path/Method); use that instead of default + elif existing_authorizer_security: + authorizer_security = existing_authorizer_security + + # No existing Authorizer found; use default + else: + security_dict = {} + security_dict[default_authorizer] = [] + authorizer_security = [security_dict] + + security = existing_non_authorizer_security + authorizer_security + + if security: + method_definition['security'] = security + + # The first element of the method_definition['security'] should be AWS_IAM + # because authorizer_list = ['AWS_IAM'] is hardcoded above + if 'AWS_IAM' in method_definition['security'][0]: + self.add_awsiam_security_definition() + + def set_path_default_apikey_required(self, path): + """ + Add the ApiKey security as required for each method on this path unless ApiKeyRequired + was defined at the Function/Path/Method level. This is intended to be used to set the + apikey security restriction for all api methods based upon the default configured in the + Serverless API. + + :param string path: Path name + """ + + for method_name, _ in self.get_path(path).items(): + # Excluding paramters section + if method_name == "parameters": + continue + + normalized_method_name = self._normalize_method_name(method_name) + # It is possible that the method could have two definitions in a Fn::If block. + for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + + # If no integration given, then we don't need to process this definition (could be AWS::NoValue) + if not self.method_definition_has_integration(method_definition): + continue + + existing_security = method_definition.get('security', []) + apikey_security_names = set(['api_key', 'api_key_false']) + existing_non_apikey_security = [] + existing_apikey_security = [] + apikey_security = [] + + # Split existing security into ApiKey and everything else + # (e.g. sigv4 (AWS_IAM), authorizers, NONE (marker for ignoring default authorizer)) + # We want to ensure only a single ApiKey security entry exists while keeping everything else + for security in existing_security: + if apikey_security_names.isdisjoint(security.keys()): + existing_non_apikey_security.append(security) + else: + existing_apikey_security.append(security) + + # Check for an existing method level ApiKey setting before applying the default. It would be simpler + # if instead we applied the default first and then simply + # overwrote it if necessary, however, the order in which things get + # applied (Function Api Events first; then Api Resource) complicates it. + # Check if Function/Path/Method specified 'False' for ApiKeyRequired + apikeyfalse_idx = -1 + for idx, security in enumerate(existing_apikey_security): + is_none = any(key == 'api_key_false' for key in security.keys()) + + if is_none: + apikeyfalse_idx = idx + break + + # api_key_false was found; remove it and don't add default api_key security setting + if apikeyfalse_idx > -1: + del existing_apikey_security[apikeyfalse_idx] + + # No existing ApiKey setting found or it's already set to the default + else: + security_dict = {} + security_dict['api_key'] = [] + apikey_security = [security_dict] + + security = existing_non_apikey_security + apikey_security + + if security != existing_security: + method_definition['security'] = security def add_auth_to_method(self, path, method_name, auth, api): """ - Adds auth settings for this path/method. Auth settings currently consist solely of Authorizers - but this method will eventually include setting other auth settings such as API Key, - Resource Policy, etc. + Adds auth settings for this path/method. Auth settings currently consist of Authorizers and ApiKeyRequired + but this method will eventually include setting other auth settings such as Resource Policy, etc. + This is used to configure the security for individual functions. :param string path: Path name :param string method_name: Method name - :param dict auth: Auth configuration such as Authorizers, ApiKey, ResourcePolicy (only Authorizers supported - currently) + :param dict auth: Auth configuration such as Authorizers, ApiKeyRequired, ResourcePolicy :param dict api: Reference to the related Api's properties as defined in the template. """ method_authorizer = auth and auth.get('Authorizer') if method_authorizer: - api_auth = api.get('Auth') - api_authorizers = api_auth and api_auth.get('Authorizers') - default_authorizer = api_auth and api_auth.get('DefaultAuthorizer') + self._set_method_authorizer(path, method_name, method_authorizer) - self.set_method_authorizer(path, method_name, method_authorizer, api_authorizers, default_authorizer) + method_apikey_required = auth and auth.get('ApiKeyRequired') + if method_apikey_required is not None: + self._set_method_apikey_handling(path, method_name, method_apikey_required) - def set_method_authorizer(self, path, method_name, authorizer_name, authorizers, default_authorizer, - is_default=False): + def _set_method_authorizer(self, path, method_name, authorizer_name): + """ + Adds the authorizer_name to the security block for each method on this path. + This is used to configure the authorizer for individual functions. + + :param string path: Path name + :param string method_name: Method name + :param string authorizer_name: Name of the authorizer to use. Must be a key in the + authorizers param. + """ normalized_method_name = self._normalize_method_name(method_name) # It is possible that the method could have two definitions in a Fn::If block. for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): @@ -454,82 +643,63 @@ def set_method_authorizer(self, path, method_name, authorizer_name, authorizers, # If no integration given, then we don't need to process this definition (could be AWS::NoValue) if not self.method_definition_has_integration(method_definition): continue + existing_security = method_definition.get('security', []) - # TEST: [{'sigv4': []}, {'api_key': []}]) - authorizer_list = ['AWS_IAM'] - if authorizers: - authorizer_list.extend(authorizers.keys()) - authorizer_names = set(authorizer_list) - existing_non_authorizer_security = [] - existing_authorizer_security = [] - - # Split existing security into Authorizers and everything else - # (e.g. sigv4 (AWS_IAM), api_key (API Key/Usage Plans), NONE (marker for ignoring default)) - # We want to ensure only a single Authorizer security entry exists while keeping everything else - for security in existing_security: - if authorizer_names.isdisjoint(security.keys()): - existing_non_authorizer_security.append(security) - else: - existing_authorizer_security.append(security) - none_idx = -1 - authorizer_security = [] + security_dict = {} + security_dict[authorizer_name] = [] + authorizer_security = [security_dict] - # If this is the Api-level DefaultAuthorizer we need to check for an - # existing Authorizer before applying the default. It would be simpler - # if instead we applied the DefaultAuthorizer first and then simply - # overwrote it if necessary, however, the order in which things get - # applied (Function Api Events first; then Api Resource) complicates it. - if is_default: - # Check if Function/Path/Method specified 'NONE' for Authorizer - for idx, security in enumerate(existing_non_authorizer_security): - is_none = any(key == 'NONE' for key in security.keys()) + # This assumes there are no autorizers already configured in the existing security block + security = existing_security + authorizer_security - if is_none: - none_idx = idx - break + if security: + method_definition['security'] = security - # NONE was found; remove it and don't add the DefaultAuthorizer - if none_idx > -1: - del existing_non_authorizer_security[none_idx] + # The first element of the method_definition['security'] should be AWS_IAM + # because authorizer_list = ['AWS_IAM'] is hardcoded above + if 'AWS_IAM' in method_definition['security'][0]: + self.add_awsiam_security_definition() - # Existing Authorizer found (defined at Function/Path/Method); use that instead of default - elif existing_authorizer_security: - authorizer_security = existing_authorizer_security + def _set_method_apikey_handling(self, path, method_name, apikey_required): + """ + Adds the apikey setting to the security block for each method on this path. + This is used to configure the authorizer for individual functions. - # No existing Authorizer found; use default - else: - security_dict = {} - security_dict[authorizer_name] = [] - authorizer_security = [security_dict] + :param string path: Path name + :param string method_name: Method name + :param bool apikey_required: Whether the apikey security is required + """ + normalized_method_name = self._normalize_method_name(method_name) + # It is possible that the method could have two definitions in a Fn::If block. + for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + + # If no integration given, then we don't need to process this definition (could be AWS::NoValue) + if not self.method_definition_has_integration(method_definition): + continue + + existing_security = method_definition.get('security', []) - # This is a Function/Path/Method level Authorizer; simply set it + if apikey_required: + # We want to enable apikey required security + security_dict = {} + security_dict['api_key'] = [] + apikey_security = [security_dict] + self.add_apikey_security_definition() else: + # The method explicitly does NOT require apikey and there is an API default + # so let's add a marker 'api_key_false' so that we don't incorrectly override + # with the api default security_dict = {} - security_dict[authorizer_name] = [] - authorizer_security = [security_dict] + security_dict['api_key_false'] = [] + apikey_security = [security_dict] - security = existing_non_authorizer_security + authorizer_security + # This assumes there are no autorizers already configured in the existing security block + security = existing_security + apikey_security - if security: + if security != existing_security: method_definition['security'] = security - # The first element of the method_definition['security'] should be AWS_IAM - # because authorizer_list = ['AWS_IAM'] is hardcoded above - if 'AWS_IAM' in method_definition['security'][0]: - aws_iam_security_definition = { - 'AWS_IAM': { - 'x-amazon-apigateway-authtype': 'awsSigv4', - 'type': 'apiKey', - 'name': 'Authorization', - 'in': 'header' - } - } - if not self.security_definitions: - self.security_definitions = aws_iam_security_definition - elif 'AWS_IAM' not in self.security_definitions: - self.security_definitions.update(aws_iam_security_definition) - def add_request_model_to_method(self, path, method_name, request_model): """ Adds request model body parameter for this path/method. @@ -619,6 +789,37 @@ def add_models(self, models): self.definitions[model_name.lower()] = schema + def add_resource_policy(self, resource_policy): + """ + Add resource policy definition to Swagger. + + :param dict resource_policy: Dictionary of resource_policy statements which gets translated + :return: + """ + if resource_policy is None: + return + + custom_statements = resource_policy.get('CustomStatements') + + if custom_statements is not None: + if not isinstance(custom_statements, list): + custom_statements = [custom_statements] + + self.resource_policy['Version'] = '2012-10-17' + if self.resource_policy.get('Statement') is None: + self.resource_policy['Statement'] = custom_statements + else: + statement = self.resource_policy['Statement'] + if isinstance(statement, list): + statement.extend(custom_statements) + else: + statement = [statement] + statement.extend(custom_statements) + + self.resource_policy['Statement'] = statement + + self._doc[self._X_APIGW_POLICY] = self.resource_policy + @property def swagger(self): """ diff --git a/samtranslator/validator/sam_schema/schema.json b/samtranslator/validator/sam_schema/schema.json index 8fa499b9e2..082c633d13 100644 --- a/samtranslator/validator/sam_schema/schema.json +++ b/samtranslator/validator/sam_schema/schema.json @@ -632,6 +632,9 @@ "Topic": { "type": "string" }, + "Region": { + "type": "string" + }, "FilterPolicy": { "type": "object" } @@ -649,7 +652,16 @@ }, "Schedule": { "type": "string" - } + }, + "Name": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Enabled": { + "type": "boolean" + } }, "required": [ "Schedule" diff --git a/tests/model/eventsources/test_api_event_source.py b/tests/model/eventsources/test_api_event_source.py index df240b6fad..92d946bf39 100644 --- a/tests/model/eventsources/test_api_event_source.py +++ b/tests/model/eventsources/test_api_event_source.py @@ -51,6 +51,36 @@ def test_get_permission_with_trailing_slash(self): self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo") + @patch("boto3.session.Session.region_name", "eu-west-2") + def test_get_permission_with_path_parameter(self): + self.api_event_source.Path = "/foo/{userId}/bar" + cfn = self.api_event_source.to_cloudformation(function=self.func, explicit_api={}) + + perm = cfn[0] + self.assertIsInstance(perm, LambdaPermission) + + try: + arn = self._extract_path_from_arn("{}PermissionTest".format(self.logical_id), perm) + except AttributeError: + self.fail("Permission class isn't valid") + + self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo/*/bar") + + @patch("boto3.session.Session.region_name", "eu-west-2") + def test_get_permission_with_proxy_resource(self): + self.api_event_source.Path = "/foo/{proxy+}" + cfn = self.api_event_source.to_cloudformation(function=self.func, explicit_api={}) + + perm = cfn[0] + self.assertIsInstance(perm, LambdaPermission) + + try: + arn = self._extract_path_from_arn("{}PermissionTest".format(self.logical_id), perm) + except AttributeError: + self.fail("Permission class isn't valid") + + self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo/*") + @patch("boto3.session.Session.region_name", "eu-west-2") def test_get_permission_with_just_slash(self): self.api_event_source.Path = "/" diff --git a/tests/model/eventsources/test_sns_event_source.py b/tests/model/eventsources/test_sns_event_source.py index efedec6cac..434aca9486 100644 --- a/tests/model/eventsources/test_sns_event_source.py +++ b/tests/model/eventsources/test_sns_event_source.py @@ -31,8 +31,21 @@ def test_to_cloudformation_returns_permission_and_subscription_resources(self): self.assertEqual(subscription.TopicArn, 'arn:aws:sns:MyTopic') self.assertEqual(subscription.Protocol, 'lambda') self.assertEqual(subscription.Endpoint, 'arn:aws:lambda:mock') + self.assertIsNone(subscription.Region) self.assertIsNone(subscription.FilterPolicy) + def test_to_cloudformation_passes_the_region(self): + region = 'us-west-2' + self.sns_event_source.Region = region + + resources = self.sns_event_source.to_cloudformation( + function=self.function) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[1].resource_type, + 'AWS::SNS::Subscription') + subscription = resources[1] + self.assertEqual(subscription.Region, region) + def test_to_cloudformation_passes_the_filter_policy(self): filterPolicy = { 'attribute1': ['value1'], diff --git a/tests/model/test_function_policies.py b/tests/model/test_function_policies.py index 371ea70b18..a0a82b4bd9 100644 --- a/tests/model/test_function_policies.py +++ b/tests/model/test_function_policies.py @@ -2,6 +2,8 @@ from unittest import TestCase from samtranslator.model.function_policies import FunctionPolicies, PolicyTypes, PolicyEntry +from samtranslator.model.exceptions import InvalidTemplateException +from samtranslator.model.intrinsics import is_intrinsic_if, is_intrinsic_no_value class TestFunctionPolicies(TestCase): @@ -333,3 +335,138 @@ def test_is_policy_template_must_return_false_without_the_processor(self): self.assertFalse(function_policies_obj._is_policy_template(policy)) self.policy_template_processor_mock.has.assert_not_called() + + def test_is_intrinsic_if_must_return_true_for_if(self): + policy = { + "Fn::If": "some value" + } + + self.assertTrue(is_intrinsic_if(policy)) + + def test_is_intrinsic_if_must_return_false_for_others(self): + too_many_keys = { + "Fn::If": "some value", + "Fn::And": "other value" + } + + not_if = { + "Fn::Or": "some value" + } + + self.assertFalse(is_intrinsic_if(too_many_keys)) + self.assertFalse(is_intrinsic_if(not_if)) + self.assertFalse(is_intrinsic_if(None)) + + def test_is_intrinsic_no_value_must_return_true_for_no_value(self): + policy = { + "Ref": "AWS::NoValue" + } + + self.assertTrue(is_intrinsic_no_value(policy)) + + def test_is_intrinsic_no_value_must_return_false_for_other_value(self): + bad_key = { + "sRefs": "AWS::NoValue" + } + + bad_value = { + "Ref": "SWA::NoValue" + } + + too_many_keys = { + "Ref": "AWS::NoValue", + "feR": "SWA::NoValue" + } + + self.assertFalse(is_intrinsic_no_value(bad_key)) + self.assertFalse(is_intrinsic_no_value(bad_value)) + self.assertFalse(is_intrinsic_no_value(None)) + self.assertFalse(is_intrinsic_no_value(too_many_keys)) + + def test_get_type_with_intrinsic_if_must_return_managed_policy_type(self): + managed_policy = { + "Fn::If": ["SomeCondition", "some managed policy arn", "other managed policy arn"] + } + + no_value_if = { + "Fn::If": ["SomeCondition", {"Ref": "AWS::NoValue"}, "other managed policy arn"] + } + + no_value_else = { + "Fn::If": ["SomeCondition", "other managed policy arn", {"Ref": "AWS::NoValue"}] + } + + expected_managed_policy = PolicyTypes.MANAGED_POLICY + + self.assertTrue(expected_managed_policy, self.function_policies._get_type(managed_policy)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_return_policy_statement_type(self): + policy_statement = { + "Fn::If": ["SomeCondition", {"Statement": "then statement"}, {"Statement": "else statement"}] + } + + no_value_if = { + "Fn::If": ["SomeCondition", {"Ref": "AWS::NoValue"}, {"Statement": "else statement"}] + } + + no_value_else = { + "Fn::If": ["SomeCondition", {"Statement": "then statement"}, {"Ref": "AWS::NoValue"}] + } + expected_managed_policy = PolicyTypes.POLICY_STATEMENT + + self.assertTrue(expected_managed_policy, self.function_policies._get_type(policy_statement)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, self.function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_return_policy_template_type(self): + policy_template = { + "Fn::If": [ "SomeCondition", + {"template_name_one": { "Param1": "foo"}}, + {"template_name_one": { "Param1": "foo"}} + ] + } + no_value_if = { + "Fn::If": [ "SomeCondition", + {"Ref": "AWS::NoValue"}, + {"template_name_one": { "Param1": "foo"}} + ] + } + no_value_else = { + "Fn::If": [ "SomeCondition", + {"template_name_one": { "Param1": "foo"}}, + {"Ref": "AWS::NoValue"} + ] + } + + expected_managed_policy = PolicyTypes.POLICY_TEMPLATE + self.policy_template_processor_mock.has.return_value = True + function_policies = FunctionPolicies({}, self.policy_template_processor_mock) + + self.assertTrue(expected_managed_policy, function_policies._get_type(policy_template)) + self.assertTrue(expected_managed_policy, function_policies._get_type(no_value_if)) + self.assertTrue(expected_managed_policy, function_policies._get_type(no_value_else)) + + def test_get_type_with_intrinsic_if_must_raise_exception_for_bad_policy(self): + policy_too_few_values = { + "Fn::If": ["condition", "then"] + } + + policy_too_many_values = { + "Fn::If": ["condition", "then", "else", "extra"] + } + + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_too_few_values) + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_too_many_values) + + def test_get_type_with_intrinsic_if_must_raise_exception_for_different_policy_types(self): + policy_one = { + "Fn::If": ["condition", "then", {"Statement": "else"}] + } + policy_two = { + "Fn::If": ["condition", {"Statement": "then"}, "else"] + } + + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_one) + self.assertRaises(InvalidTemplateException, self.function_policies._get_type, policy_two) \ No newline at end of file diff --git a/tests/model/test_sam_resources.py b/tests/model/test_sam_resources.py index ff59a063e7..a2129d1eb7 100644 --- a/tests/model/test_sam_resources.py +++ b/tests/model/test_sam_resources.py @@ -7,6 +7,7 @@ from samtranslator.model.lambda_ import LambdaFunction, LambdaVersion from samtranslator.model.apigateway import ApiGatewayRestApi from samtranslator.model.apigateway import ApiGatewayDeployment +from samtranslator.model.apigateway import ApiGatewayStage from samtranslator.model.sam_resources import SamFunction from samtranslator.model.sam_resources import SamApi @@ -121,3 +122,38 @@ def test_with_swagger_no_stage(self): self.assertEqual(deployment.__len__(), 1) self.assertEqual(deployment[0].StageName, "Stage") + +class TestApiTags(TestCase): + kwargs = { + 'intrinsics_resolver': IntrinsicsResolver({}), + 'event_resources': [], + 'managed_policy_map': { + "foo": "bar" + } + } + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_no_tags(self): + api = SamApi("foo") + api.Tags = {} + + resources = api.to_cloudformation(**self.kwargs) + deployment = [x for x in resources if isinstance(x, ApiGatewayStage)] + + self.assertEqual(deployment.__len__(), 1) + self.assertEqual(deployment[0].Tags, []) + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_tags(self): + api = SamApi("foo") + api.Tags = { + 'MyKey': 'MyValue' + } + + resources = api.to_cloudformation(**self.kwargs) + deployment = [x for x in resources if isinstance(x, ApiGatewayStage)] + + self.assertEqual(deployment.__len__(), 1) + self.assertEqual(deployment[0].Tags, [ + {'Key': 'MyKey', 'Value': 'MyValue'} + ]) diff --git a/tests/swagger/test_swagger.py b/tests/swagger/test_swagger.py index e3771e87bf..907e091cb8 100644 --- a/tests/swagger/test_swagger.py +++ b/tests/swagger/test_swagger.py @@ -131,6 +131,7 @@ def test_must_not_fail_on_bad_path(self): self.assertTrue(self.editor.has_path("badpath")) self.assertFalse(self.editor.has_path("badpath", "somemethod")) + class TestSwaggerEditor_has_integration(TestCase): def setUp(self): @@ -725,6 +726,7 @@ def test_allow_credentials_is_skipped_with_false_value(self): actual = options_config[_X_INTEGRATION]["responses"]["default"]["responseParameters"] self.assertEqual(expected, actual) + class TestSwaggerEditor_make_cors_allowed_methods_for_path(TestCase): def setUp(self): @@ -1112,4 +1114,120 @@ def test_must_add_body_parameter_to_method_openapi_required_true(self): } } - self.assertEqual(expected, editor.swagger['paths']['/foo']['get']['requestBody']) \ No newline at end of file + self.assertEqual(expected, editor.swagger['paths']['/foo']['get']['requestBody']) + +class TestSwaggerEditor_add_auth(TestCase): + + def setUp(self): + + self.original_swagger = { + "swagger": "2.0", + "paths": { + "/foo": { + "get": { + _X_INTEGRATION: { + "a": "b" + } + }, + "post":{ + _X_INTEGRATION: { + "a": "b" + } + } + }, + "/bar": { + "get": { + _X_INTEGRATION: { + "a": "b" + } + } + }, + } + } + + self.editor = SwaggerEditor(self.original_swagger) + + def test_add_apikey_security_definition_is_added(self): + expected = { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + + self.editor.add_apikey_security_definition() + self.assertIn('securityDefinitions', self.editor.swagger) + self.assertIn('api_key', self.editor.swagger["securityDefinitions"]) + self.assertEqual(expected, self.editor.swagger["securityDefinitions"]['api_key']) + + def test_must_add_default_apikey_to_all_paths(self): + expected = [{ + "api_key": [] + }] + path = "/foo" + + + self.editor.set_path_default_apikey_required(path) + methods = self.editor.swagger["paths"][path] + for method in methods: + self.assertEqual(expected, methods[method]["security"]) + + def test_add_default_apikey_to_all_paths_correctly_handles_method_level_settings(self): + self.original_swagger = { + "swagger": "2.0", + "paths": { + "/foo": { + "apikeyfalse": { + _X_INTEGRATION: { + "a": "b" + }, + "security":[ + {"api_key_false":[]} + ] + }, + "apikeytrue": { + _X_INTEGRATION: { + "a": "b" + }, + "security":[ + {"api_key":[]} + ] + }, + "apikeydefault":{ + _X_INTEGRATION: { + "a": "b" + } + } + }, + } + } + + self.editor = SwaggerEditor(self.original_swagger) + api_key_exists = [{ + "api_key": [] + }] + path = "/foo" + + self.editor.set_path_default_apikey_required(path) + self.assertEqual([], self.editor.swagger["paths"][path]['apikeyfalse']["security"]) + self.assertEqual(api_key_exists, self.editor.swagger["paths"][path]['apikeytrue']["security"]) + self.assertEqual(api_key_exists, self.editor.swagger["paths"][path]['apikeydefault']["security"]) + + def test_set_method_apikey_handling_apikeyrequired_false(self): + expected = [{ + "api_key_false": [] + }] + path = "/bar" + method = "get" + + self.editor._set_method_apikey_handling(path, method, False) + self.assertEqual(expected, self.editor.swagger["paths"][path][method]["security"]) + + def test_set_method_apikey_handling_apikeyrequired_true(self): + expected = [{ + "api_key": [] + }] + path = "/bar" + method = "get" + + self.editor._set_method_apikey_handling(path, method, True) + self.assertEqual(expected, self.editor.swagger["paths"][path][method]["security"]) diff --git a/tests/translator/input/all_policy_templates.yaml b/tests/translator/input/all_policy_templates.yaml index 2cca6996f8..b6d97bd814 100644 --- a/tests/translator/input/all_policy_templates.yaml +++ b/tests/translator/input/all_policy_templates.yaml @@ -98,8 +98,7 @@ Resources: - CloudWatchDashboardPolicy: {} - - RekognitionFacesPolicy: - CollectionId: collection + - RekognitionFacesPolicy: {} - RekognitionLabelsPolicy: {} diff --git a/tests/translator/input/api_with_apikey_default_override.yaml b/tests/translator/input/api_with_apikey_default_override.yaml new file mode 100644 index 0000000000..53a94e3b62 --- /dev/null +++ b/tests/translator/input/api_with_apikey_default_override.yaml @@ -0,0 +1,51 @@ +Resources: + MyApiWithAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + ApiKeyRequired: true + + MyFunctionWithApiKeyRequiredDefault: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredDefault: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyDefault + Method: get + MyFunctionWithApiKeyRequiredTrue: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredTrue: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyTrue + Method: get + Auth: + ApiKeyRequired: true + MyFunctionWithApiKeyRequiredFalse: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredFalse: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyFalse + Method: get + Auth: + ApiKeyRequired: false diff --git a/tests/translator/input/api_with_apikey_required.yaml b/tests/translator/input/api_with_apikey_required.yaml new file mode 100644 index 0000000000..e5c562c916 --- /dev/null +++ b/tests/translator/input/api_with_apikey_required.yaml @@ -0,0 +1,21 @@ +Resources: + MyApiWithoutAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + + MyFunctionWithApiKeyRequired: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequired: + Type: Api + Properties: + RestApiId: !Ref MyApiWithoutAuth + Path: /ApiKeyRequiredTrue + Method: get + Auth: + ApiKeyRequired: true diff --git a/tests/translator/input/api_with_apikey_required_openapi_3.yaml b/tests/translator/input/api_with_apikey_required_openapi_3.yaml new file mode 100644 index 0000000000..95d7727c58 --- /dev/null +++ b/tests/translator/input/api_with_apikey_required_openapi_3.yaml @@ -0,0 +1,22 @@ +Resources: + MyApiWithoutAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + OpenApiVersion: '3.0.1' + + MyFunctionWithApiKeyRequired: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequired: + Type: Api + Properties: + RestApiId: !Ref MyApiWithoutAuth + Path: /ApiKeyRequiredTrue + Method: get + Auth: + ApiKeyRequired: true diff --git a/tests/translator/input/api_with_auth_all_maximum.yaml b/tests/translator/input/api_with_auth_all_maximum.yaml index 89c94fdc7e..e3dbd397b3 100644 --- a/tests/translator/input/api_with_auth_all_maximum.yaml +++ b/tests/translator/input/api_with_auth_all_maximum.yaml @@ -5,6 +5,7 @@ Resources: StageName: Prod Auth: DefaultAuthorizer: MyCognitoAuth + ApiKeyRequired: true Authorizers: MyCognitoAuth: UserPoolArn: arn:aws:1 diff --git a/tests/translator/input/api_with_auth_all_maximum_openapi_3.yaml b/tests/translator/input/api_with_auth_all_maximum_openapi_3.yaml index 8cab3cd48c..bb236464fe 100644 --- a/tests/translator/input/api_with_auth_all_maximum_openapi_3.yaml +++ b/tests/translator/input/api_with_auth_all_maximum_openapi_3.yaml @@ -6,6 +6,7 @@ Resources: OpenApiVersion: '3.0.1' Auth: DefaultAuthorizer: MyCognitoAuth + ApiKeyRequired: true Authorizers: MyCognitoAuth: UserPoolArn: arn:aws:1 diff --git a/tests/translator/input/api_with_aws_iam_auth_overrides.yaml b/tests/translator/input/api_with_aws_iam_auth_overrides.yaml index f9cd47765a..5ce61f7924 100644 --- a/tests/translator/input/api_with_aws_iam_auth_overrides.yaml +++ b/tests/translator/input/api_with_aws_iam_auth_overrides.yaml @@ -1,4 +1,11 @@ Resources: + MyApiWithAwsIamAuthNoCallerCredentials: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: AWS_IAM + InvokeRole: NONE MyApiWithAwsIamAuth: Type: "AWS::Serverless::Api" Properties: @@ -84,3 +91,64 @@ Resources: Auth: Authorizer: AWS_IAM InvokeRole: arn:aws:iam::456::role/something-else + MyFunctionNONEInvokeRole: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Method: get + Path: /MyFunctionNONEInvokeRole + Auth: + Authorizer: AWS_IAM + InvokeRole: NONE + MyFunctionNullInvokeRole: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Method: get + Path: /MyFunctionNullInvokeRole + Auth: + Authorizer: AWS_IAM + InvokeRole: null + MyFunctionCallerCredentialsOverride: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuthNoCallerCredentials + Method: get + Path: / + Auth: + Authorizer: AWS_IAM + InvokeRole: CALLER_CREDENTIALS + MyFunctionNoCallerCredentials: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuthNoCallerCredentials + Method: post + Path: / diff --git a/tests/translator/input/api_with_path_parameters.yaml b/tests/translator/input/api_with_path_parameters.yaml new file mode 100644 index 0000000000..4e1b751051 --- /dev/null +++ b/tests/translator/input/api_with_path_parameters.yaml @@ -0,0 +1,20 @@ +Resources: + HtmlFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: HtmlApi + Path: /{prameter}/resources + Method: get + + HtmlApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: s3://sam-demo-bucket/webpage_swagger.json diff --git a/tests/translator/input/api_with_resource_policy.yaml b/tests/translator/input/api_with_resource_policy.yaml new file mode 100644 index 0000000000..dac884c579 --- /dev/null +++ b/tests/translator/input/api_with_resource_policy.yaml @@ -0,0 +1,12 @@ +Resources: + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + Auth: + ResourcePolicy: + CustomStatements: { + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + } + \ No newline at end of file diff --git a/tests/translator/input/api_with_resource_policy_global.yaml b/tests/translator/input/api_with_resource_policy_global.yaml new file mode 100644 index 0000000000..6585beb05b --- /dev/null +++ b/tests/translator/input/api_with_resource_policy_global.yaml @@ -0,0 +1,38 @@ +Globals: + Api: + Auth: + ResourcePolicy: + CustomStatements: [{ + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + }, + { + Action: 'execute-api:blah', + Resource: ['execute-api:/*/*/*'] + }] + +Resources: + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionBody: { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + } + } \ No newline at end of file diff --git a/tests/translator/input/api_with_resource_policy_global_implicit.yaml b/tests/translator/input/api_with_resource_policy_global_implicit.yaml new file mode 100644 index 0000000000..5ec9536e4b --- /dev/null +++ b/tests/translator/input/api_with_resource_policy_global_implicit.yaml @@ -0,0 +1,26 @@ +Globals: + Api: + Auth: + ResourcePolicy: + CustomStatements: [{ + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + }, + { + Action: 'execute-api:blah', + Resource: ['execute-api:/*/*/*'] + }] +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + Events: + AddItem: + Type: Api + Properties: + Path: /add + Method: post + diff --git a/tests/translator/input/api_with_stage_tags.yaml b/tests/translator/input/api_with_stage_tags.yaml new file mode 100644 index 0000000000..83473e1163 --- /dev/null +++ b/tests/translator/input/api_with_stage_tags.yaml @@ -0,0 +1,16 @@ +Parameters: + TagValueParam: + Type: String + Default: value + +Resources: + MyApiWithStageTags: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Tags: + TagKey1: TagValue1 + TagKey2: "" + TagKey3: + Ref: TagValueParam + TagKey4: "123" diff --git a/tests/translator/input/cloudwatchevent_schedule_properties.yaml b/tests/translator/input/cloudwatchevent_schedule_properties.yaml new file mode 100644 index 0000000000..72a6120347 --- /dev/null +++ b/tests/translator/input/cloudwatchevent_schedule_properties.yaml @@ -0,0 +1,30 @@ +Resources: + ScheduledFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO + Handler: hello.handler + Runtime: python2.7 + Events: + Schedule: + Type: Schedule + Properties: + Schedule: 'rate(1 minute)' + Name: test-schedule + Description: Test Schedule + Enabled: True + + TriggeredFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO + Handler: hello.handler + Runtime: python2.7 + Events: + OnTerminate: + Type: CloudWatchEvent + Properties: + Pattern: + detail: + state: + - terminated diff --git a/tests/translator/input/error_null_application_id.yaml b/tests/translator/input/error_null_application_id.yaml new file mode 100644 index 0000000000..3985e3782c --- /dev/null +++ b/tests/translator/input/error_null_application_id.yaml @@ -0,0 +1,7 @@ +Resources: + Application: + Type: AWS::Serverless::Application + Properties: + Location: + ApplicationId: null + SemanticVersion: 1.0.0 diff --git a/tests/translator/input/error_table_primary_key_missing_name.yaml b/tests/translator/input/error_table_primary_key_missing_name.yaml new file mode 100644 index 0000000000..af257bc02f --- /dev/null +++ b/tests/translator/input/error_table_primary_key_missing_name.yaml @@ -0,0 +1,7 @@ +Resources: + Table: + Type: AWS::Serverless::SimpleTable + Properties: + PrimaryKey: + Id: id + Type: String diff --git a/tests/translator/input/error_table_primary_key_missing_type.yaml b/tests/translator/input/error_table_primary_key_missing_type.yaml new file mode 100644 index 0000000000..3ff377e3b4 --- /dev/null +++ b/tests/translator/input/error_table_primary_key_missing_type.yaml @@ -0,0 +1,6 @@ +Resources: + Table: + Type: AWS::Serverless::SimpleTable + Properties: + PrimaryKey: + Name: id diff --git a/tests/translator/input/function_with_conditional_managed_policy.yaml b/tests/translator/input/function_with_conditional_managed_policy.yaml new file mode 100644 index 0000000000..6bfed9d071 --- /dev/null +++ b/tests/translator/input/function_with_conditional_managed_policy.yaml @@ -0,0 +1,17 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + - !Sub arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess \ No newline at end of file diff --git a/tests/translator/input/function_with_conditional_managed_policy_and_ref_no_value.yaml b/tests/translator/input/function_with_conditional_managed_policy_and_ref_no_value.yaml new file mode 100644 index 0000000000..62f9528016 --- /dev/null +++ b/tests/translator/input/function_with_conditional_managed_policy_and_ref_no_value.yaml @@ -0,0 +1,17 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + - !Ref "AWS::NoValue" \ No newline at end of file diff --git a/tests/translator/input/function_with_conditional_policy_template.yaml b/tests/translator/input/function_with_conditional_policy_template.yaml new file mode 100644 index 0000000000..4b7a0b8fe9 --- /dev/null +++ b/tests/translator/input/function_with_conditional_policy_template.yaml @@ -0,0 +1,19 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: "Dummy Secret Arn" + - AWSSecretsManagerRotationPolicy: + FunctionName: "Dummy Function Name" \ No newline at end of file diff --git a/tests/translator/input/function_with_conditional_policy_template_and_ref_no_value.yaml b/tests/translator/input/function_with_conditional_policy_template_and_ref_no_value.yaml new file mode 100644 index 0000000000..432b4db2ab --- /dev/null +++ b/tests/translator/input/function_with_conditional_policy_template_and_ref_no_value.yaml @@ -0,0 +1,18 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: "Dummy Secret Arn" + - !Ref "AWS::NoValue" \ No newline at end of file diff --git a/tests/translator/input/function_with_sns_event_source_all_parameters.yaml b/tests/translator/input/function_with_sns_event_source_all_parameters.yaml index a745b2f9c8..65711e7330 100644 --- a/tests/translator/input/function_with_sns_event_source_all_parameters.yaml +++ b/tests/translator/input/function_with_sns_event_source_all_parameters.yaml @@ -11,6 +11,7 @@ Resources: Type: SNS Properties: Topic: topicArn + Region: region FilterPolicy: store: - example_corp diff --git a/tests/translator/input/globals_for_api.yaml b/tests/translator/input/globals_for_api.yaml index 5d3a956322..92aca3703e 100644 --- a/tests/translator/input/globals_for_api.yaml +++ b/tests/translator/input/globals_for_api.yaml @@ -8,6 +8,7 @@ Globals: Authorizers: MyCognitoAuth: UserPoolArn: !GetAtt MyUserPool.Arn + ApiKeyRequired: true Variables: SomeVar: Value diff --git a/tests/translator/input/implicit_api_with_auth_and_conditions_max.yaml b/tests/translator/input/implicit_api_with_auth_and_conditions_max.yaml index 61d2751a21..3c0ac05049 100644 --- a/tests/translator/input/implicit_api_with_auth_and_conditions_max.yaml +++ b/tests/translator/input/implicit_api_with_auth_and_conditions_max.yaml @@ -161,4 +161,6 @@ Resources: Type: Api Properties: Path: /users - Method: put \ No newline at end of file + Method: put + Auth: + ApiKeyRequired: true \ No newline at end of file diff --git a/tests/translator/output/all_policy_templates.json b/tests/translator/output/all_policy_templates.json index 4488918b0f..9690d5bc6e 100644 --- a/tests/translator/output/all_policy_templates.json +++ b/tests/translator/output/all_policy_templates.json @@ -208,7 +208,8 @@ "Statement": [ { "Action": [ - "es:ESHttpPost" + "es:ESHttpPost", + "es:ESHttpPut" ], "Resource": { "Fn::Sub": [ @@ -809,14 +810,7 @@ "rekognition:CompareFaces", "rekognition:DetectFaces" ], - "Resource": { - "Fn::Sub": [ - "arn:${AWS::Partition}:rekognition:${AWS::Region}:${AWS::AccountId}:collection/${collectionId}", - { - "collectionId": "collection" - } - ] - }, + "Resource": "*", "Effect": "Allow" } ] diff --git a/tests/translator/output/api_with_apikey_default_override.json b/tests/translator/output/api_with_apikey_default_override.json new file mode 100644 index 0000000000..03f6db829a --- /dev/null +++ b/tests/translator/output/api_with_apikey_default_override.json @@ -0,0 +1,363 @@ +{ + "Resources": { + "MyApiWithAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAuthDeployment054e605502" + }, + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrue": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredTrueRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefault": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredDefaultRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyApiWithAuthDeployment054e605502": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "Description": "RestApi deployment id: 054e60550295973114b1bc4384d00c8b641ea20f", + "StageName": "Stage" + } + }, + "MyFunctionWithApiKeyRequiredFalse": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredFalseRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredFalseRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyFalse": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredFalse.Arn}/invocations" + } + }, + "security": [], + "responses": {} + } + }, + "/ApiKeyTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredTrue.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + }, + "/ApiKeyDefault": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredDefault.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + } + } + } + } \ No newline at end of file diff --git a/tests/translator/output/api_with_apikey_required.json b/tests/translator/output/api_with_apikey_required.json new file mode 100644 index 0000000000..b864a2dcc8 --- /dev/null +++ b/tests/translator/output/api_with_apikey_required.json @@ -0,0 +1,155 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeployment3ab9d13134" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApiWithoutAuthDeployment3ab9d13134": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: 3ab9d13134bf550e275a303c6987801dfb7f9d7b", + "StageName": "Stage" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/api_with_apikey_required_openapi_3.json b/tests/translator/output/api_with_apikey_required_openapi_3.json new file mode 100644 index 0000000000..cc53ba7465 --- /dev/null +++ b/tests/translator/output/api_with_apikey_required_openapi_3.json @@ -0,0 +1,156 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuthDeployment8770e31c42": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: 8770e31c425e4cc01e67db6627300b459720eff9" + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeployment8770e31c42" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/api_with_auth_all_maximum.json b/tests/translator/output/api_with_auth_all_maximum.json index 61b4a6b398..3701420314 100644 --- a/tests/translator/output/api_with_auth_all_maximum.json +++ b/tests/translator/output/api_with_auth_all_maximum.json @@ -1,39 +1,41 @@ { "Resources": { "MyFunction": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, - "Handler": "index.handler", + }, "Role": { "Fn::GetAtt": [ - "MyFunctionRole", + "MyFunctionRole", "Arn" ] - }, - "Runtime": "nodejs8.10", - "Tags": [{ - "Value": "SAM", - "Key": "lambda:createdBy" - }] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -41,16 +43,16 @@ ] } } - }, + }, "MyApiMyLambdaRequestAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -59,20 +61,20 @@ ] } } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -80,20 +82,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -101,20 +103,20 @@ ] } } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -122,20 +124,20 @@ ] } } - }, + }, "MyFunctionWithNoAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -143,210 +145,242 @@ ] } } - }, + }, "MyFunctionRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [{ - "Action": [ - "sts:AssumeRole" - ], - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } } - }] + ] } } - }, + }, "MyApi": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { "/": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "NONE": [] - }], + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], "responses": {} } - }, + }, "/users": { "put": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuth": [] - }], + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "post": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuthMultipleUserPools": [] - }], + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "patch": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaTokenAuthNoneFunctionInvokeRole": [] - }], + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "delete": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaRequestAuth": [] - }], + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 0, + "type": "token", + "authorizerResultTtlInSeconds": 0, "authorizerUri": { "Fn::Sub": [ - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] } - }, + }, "x-amazon-apigateway-authtype": "custom" - }, + }, "MyCognitoAuthMultipleUserPools": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader2", + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", + "identityValidationExpression": "myauthvalidationexpression2", "providerARNs": [ - "arn:aws:2", + "arn:aws:2", "arn:aws:3" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, - "MyLambdaTokenAuth": { - "in": "header", - "type": "apiKey", - "name": "MyCustomAuthHeader", + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, "x-amazon-apigateway-authtype": "custom" - }, - "MyLambdaRequestAuth": { - "in": "header", - "type": "apiKey", - "name": "Unused", + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } } } - }, + }, "MyApiMyLambdaTokenAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -355,20 +389,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -376,20 +410,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -397,30 +431,20 @@ ] } } - }, - "MyApiDeployment22f365e69f": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi" - }, - "Description": "RestApi deployment id: 22f365e69fd10c36975a60c0b715eb1340f4b5e6", - "StageName": "Stage" - } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -428,16 +452,26 @@ ] } } - }, + }, + "MyApiDeployment0cec4886a5": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 0cec4886a504a36373a7cbd8952ec7aa9643bfbd", + "StageName": "Stage" + } + }, "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -446,32 +480,32 @@ ] } } - }, + }, "MyApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiDeployment22f365e69f" - }, + "Ref": "MyApiDeployment0cec4886a5" + }, "RestApiId": { "Ref": "MyApi" - }, + }, "StageName": "Prod" } - }, + }, "MyFunctionWithNoAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -479,20 +513,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } diff --git a/tests/translator/output/api_with_auth_all_maximum_openapi_3.json b/tests/translator/output/api_with_auth_all_maximum_openapi_3.json index 33b914c849..ef0435efa2 100644 --- a/tests/translator/output/api_with_auth_all_maximum_openapi_3.json +++ b/tests/translator/output/api_with_auth_all_maximum_openapi_3.json @@ -104,15 +104,6 @@ } } }, - "MyApiDeployment7d5eb3f14f": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi" - }, - "Description": "RestApi deployment id: 7d5eb3f14f891b4276d48b764348b944dcaf2918" - } - }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -202,6 +193,9 @@ "security": [ { "NONE": [] + }, + { + "api_key": [] } ], "responses": {} @@ -219,6 +213,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -234,6 +231,9 @@ "security": [ { "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] } ], "responses": {} @@ -249,6 +249,9 @@ "security": [ { "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] } ], "responses": {} @@ -264,6 +267,9 @@ "security": [ { "MyLambdaRequestAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -273,19 +279,6 @@ "openapi": "3.0.1", "components": { "securitySchemes": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { "in": "header", "type": "apiKey", @@ -318,13 +311,14 @@ }, "x-amazon-apigateway-authtype": "cognito_user_pools" }, - "MyLambdaTokenAuth": { + "MyLambdaRequestAuth": { "in": "header", "type": "apiKey", - "name": "MyCustomAuthHeader", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -333,19 +327,30 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" }, "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaRequestAuth": { + "MyCognitoAuth": { "in": "header", "type": "apiKey", - "name": "Unused", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -354,9 +359,15 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } } @@ -462,16 +473,13 @@ } } }, - "MyApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "MyApiDeployment98ad824f7d": { + "Type": "AWS::ApiGateway::Deployment", "Properties": { - "DeploymentId": { - "Ref": "MyApiDeployment7d5eb3f14f" - }, "RestApiId": { "Ref": "MyApi" }, - "StageName": "Prod" + "Description": "RestApi deployment id: 98ad824f7db83981e747e44ba34d318c7fa410c8" } }, "MyFunctionWithNoAuthorizerPermissionProd": { @@ -495,6 +503,18 @@ } } }, + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment98ad824f7d" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": "Prod" + } + }, "MyFunctionWithDefaultAuthorizerPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -517,4 +537,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/api_with_aws_iam_auth_overrides.json b/tests/translator/output/api_with_aws_iam_auth_overrides.json index 6ca104082e..c1906a4f37 100644 --- a/tests/translator/output/api_with_aws_iam_auth_overrides.json +++ b/tests/translator/output/api_with_aws_iam_auth_overrides.json @@ -1,77 +1,142 @@ { "Resources": { "MyFunctionCustomInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionCustomInvokeRoleRole", + "MyFunctionCustomInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, "MyFunctionNoneAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionNoneAuthRole", + "MyFunctionNoneAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, + "MyFunctionNullInvokeRole": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNullInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionNullInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNullInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyApiWithAwsIamAuthProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiWithAwsIamAuthDeployment8a32fb1652" - }, + "Ref": "MyApiWithAwsIamAuthDeployment3bec5f30f2" + }, "RestApiId": { "Ref": "MyApiWithAwsIamAuth" - }, + }, "StageName": "Prod" } - }, + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionCallerCredentialsOverride" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionWithoutAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -81,20 +146,20 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -102,20 +167,20 @@ ] } } - }, - "MyFunctionWithoutAuthAPI2PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionMyCognitoAuthAPI1PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionWithoutAuth" - }, + "Ref": "MyFunctionMyCognitoAuth" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -123,30 +188,98 @@ ] } } - }, - "MyApiWithAwsIamAuthDeployment8a32fb1652": { - "Type": "AWS::ApiGateway::Deployment", + }, + "MyApiWithAwsIamAuthNoCallerCredentials": { + "Type": "AWS::ApiGateway::RestApi", "Properties": { - "RestApiId": { - "Ref": "MyApiWithAwsIamAuth" - }, - "Description": "RestApi deployment id: 8a32fb165218ee858b16980eed421b4f38d18f00", - "StageName": "Stage" + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoCallerCredentials.Arn}/invocations" + } + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCallerCredentialsOverride.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "AWS_IAM": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + } } - }, + }, + "MyFunctionWithoutAuthAPI2PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithoutAuth" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuthAPI1PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionMyCognitoAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -154,65 +287,154 @@ ] } } - }, + }, + "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionDefaultInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionMyCognitoAuthRole", + "MyFunctionMyCognitoAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleRole": { + "Type": "AWS::IAM::Role", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionDefaultInvokeRole" - }, + "Ref": "MyFunctionNoCallerCredentials" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", { - "__Stage__": "Prod", + "__Stage__": "*", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionNONEInvokeRole": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNONEInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNoCallerCredentials" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionNoneAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -222,21 +444,21 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -246,20 +468,20 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionDefaultInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -267,64 +489,107 @@ ] } } - }, - "MyFunctionWithoutAuthAPI2PermissionTest": { - "Type": "AWS::Lambda::Permission", + }, + "MyApiWithAwsIamAuthDeployment3bec5f30f2": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuth" + }, + "Description": "RestApi deployment id: 3bec5f30f275272b5feee10af30f848d1ce4400d", + "StageName": "Stage" + } + }, + "MyApiWithAwsIamAuthNoCallerCredentialsDeployment38c75afec1": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "Description": "RestApi deployment id: 38c75afec1f32ff6e177b0f49a2b9e86958f594e", + "StageName": "Stage" + } + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionWithoutAuth" - }, + "Ref": "MyFunctionCallerCredentialsOverride" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "Prod", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionCallerCredentialsOverride": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionCallerCredentialsOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionWithoutAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionWithoutAuthRole", + "MyFunctionWithoutAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionMyCognitoAuthAPI1PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionMyCognitoAuth" - }, + "Ref": "MyFunctionNullInvokeRole" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -332,21 +597,111 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, "MyFunctionDefaultInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithoutAuthAPI2PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithoutAuth" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionCallerCredentialsOverrideRole": { + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -356,21 +711,42 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -380,20 +756,32 @@ ] } } - }, + }, + "MyApiWithAwsIamAuthNoCallerCredentialsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentialsDeployment38c75afec1" + }, + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "StageName": "Prod" + } + }, "MyFunctionCustomInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -401,43 +789,66 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionDefaultInvokeRoleRole", + "MyFunctionDefaultInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, + "MyFunctionNoCallerCredentials": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNoCallerCredentialsRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionNoneAuthAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -445,144 +856,178 @@ ] } } - }, + }, "MyApiWithAwsIamAuth": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { - "/MyFunctionDefaultInvokeRole": { + "/MyFunctionWithoutAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" - }, - "credentials": "arn:aws:iam::*:user/*" - }, + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" + }, + "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionWithoutAuth": { + }, + "/MyFunctionNONEInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" - }, - "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" - }, + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNONEInvokeRole.Arn}/invocations" + } + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionNoneAuth": { + }, + "/MyFunctionMyCognitoAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" } - }, + }, "security": [ { - "NONE": [] + "MyCognitoAuth": [] } - ], + ], "responses": {} } - }, - "/MyFunctionMyCognitoAuth": { + }, + "/MyFunctionDefaultInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" - } - }, + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, "security": [ { - "MyCognitoAuth": [] + "AWS_IAM": [] } - ], + ], "responses": {} } - }, + }, "/MyFunctionCustomInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCustomInvokeRole.Arn}/invocations" - }, + }, "credentials": "arn:aws:iam::456::role/something-else" - }, + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + }, + "/MyFunctionNullInvokeRole": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNullInvokeRole.Arn}/invocations" + } + }, "security": [ { "AWS_IAM": [] } - ], + ], + "responses": {} + } + }, + "/MyFunctionNoneAuth": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + } + }, + "security": [ + { + "NONE": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { "providerARNs": [ "arn:aws:cognito-idp:xxxxxxxxx" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, + }, "AWS_IAM": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authtype": "awsSigv4" } } } } - }, + }, "MyFunctionNoneAuthAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -590,6 +1035,30 @@ ] } } + }, + "MyFunctionNONEInvokeRoleRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } } } } diff --git a/tests/translator/output/api_with_openapi_definition_body_no_flag.json b/tests/translator/output/api_with_openapi_definition_body_no_flag.json index 02ab6e4891..273a6e2d4a 100644 --- a/tests/translator/output/api_with_openapi_definition_body_no_flag.json +++ b/tests/translator/output/api_with_openapi_definition_body_no_flag.json @@ -47,6 +47,16 @@ } } }, + "ExplicitApiDeployment9252467a1e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 9252467a1edc49ba35cb258640f5e3734cc9fab1", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -68,15 +78,6 @@ } } }, - "ExplicitApiDeployment63a10e26af": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: 63a10e26af7194aefd61ead891c470ed75ce20be" - } - }, "ExplicitApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -172,7 +173,7 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeployment63a10e26af" + "Ref": "ExplicitApiDeployment9252467a1e" } } }, @@ -272,4 +273,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/api_with_path_parameters.json b/tests/translator/output/api_with_path_parameters.json new file mode 100644 index 0000000000..e9c4f7e149 --- /dev/null +++ b/tests/translator/output/api_with_path_parameters.json @@ -0,0 +1,120 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/api_with_resource_policy.json b/tests/translator/output/api_with_resource_policy.json new file mode 100644 index 0000000000..ec4ca14cc9 --- /dev/null +++ b/tests/translator/output/api_with_resource_policy.json @@ -0,0 +1,52 @@ +{ + "Resources": { + "ExplicitApiDeploymente11dac9531": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: e11dac9531e1328d9249c42ac3e40044b4159d60", + "StageName": "Stage" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymente11dac9531" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + } + } + } + } + } \ No newline at end of file diff --git a/tests/translator/output/api_with_resource_policy_global.json b/tests/translator/output/api_with_resource_policy_global.json new file mode 100644 index 0000000000..87ddea1469 --- /dev/null +++ b/tests/translator/output/api_with_resource_policy_global.json @@ -0,0 +1,65 @@ +{ + "Resources": { + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment8d22456d58" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiDeployment8d22456d58": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 8d22456d5883ad51c72f5d9be988d14f0a41182e", + "StageName": "Stage" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/api_with_resource_policy_global_implicit.json b/tests/translator/output/api_with_resource_policy_global_implicit.json new file mode 100644 index 0000000000..9be861c977 --- /dev/null +++ b/tests/translator/output/api_with_resource_policy_global_implicit.json @@ -0,0 +1,160 @@ +{ + "Resources": { + "MinimalFunctionAddItemPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment1ecad21e32" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment1ecad21e32": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 1ecad21e325b9a3167fd5c2d6399ef59ccab0df9", + "StageName": "Stage" + } + }, + "MinimalFunctionAddItemPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MinimalFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + } + } + } + } +} diff --git a/tests/translator/output/api_with_stage_tags.json b/tests/translator/output/api_with_stage_tags.json new file mode 100644 index 0000000000..702a6b1815 --- /dev/null +++ b/tests/translator/output/api_with_stage_tags.json @@ -0,0 +1,67 @@ +{ + "Parameters": { + "TagValueParam": { + "Default": "value", + "Type": "String" + } + }, + "Resources": { + "MyApiWithStageTagsDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "StageName": "Stage" + } + }, + "MyApiWithStageTags": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + } + } + }, + "MyApiWithStageTagsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithStageTagsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "StageName": "Prod", + "Tags": [ + { + "Value": "TagValue1", + "Key": "TagKey1" + }, + { + "Value": "", + "Key": "TagKey2" + }, + { + "Value": { + "Ref": "TagValueParam" + }, + "Key": "TagKey3" + }, + { + "Value": "123", + "Key": "TagKey4" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/all_policy_templates.json b/tests/translator/output/aws-cn/all_policy_templates.json index 0bf9d32254..6b8be0e273 100644 --- a/tests/translator/output/aws-cn/all_policy_templates.json +++ b/tests/translator/output/aws-cn/all_policy_templates.json @@ -207,7 +207,8 @@ "Statement": [ { "Action": [ - "es:ESHttpPost" + "es:ESHttpPost", + "es:ESHttpPut" ], "Resource": { "Fn::Sub": [ @@ -808,14 +809,7 @@ "rekognition:CompareFaces", "rekognition:DetectFaces" ], - "Resource": { - "Fn::Sub": [ - "arn:${AWS::Partition}:rekognition:${AWS::Region}:${AWS::AccountId}:collection/${collectionId}", - { - "collectionId": "collection" - } - ] - }, + "Resource": "*", "Effect": "Allow" } ] diff --git a/tests/translator/output/aws-cn/api_with_apikey_default_override.json b/tests/translator/output/aws-cn/api_with_apikey_default_override.json new file mode 100644 index 0000000000..31e38efe95 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_apikey_default_override.json @@ -0,0 +1,371 @@ +{ + "Resources": { + "MyApiWithAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAuthDeployment12e3363002" + }, + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrue": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredTrueRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefault": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredDefaultRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyApiWithAuthDeployment12e3363002": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "Description": "RestApi deployment id: 12e33630022574b70be75950554db06d81af114d", + "StageName": "Stage" + } + }, + "MyFunctionWithApiKeyRequiredFalse": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredFalseRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredFalseRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyFalse": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredFalse.Arn}/invocations" + } + }, + "security": [], + "responses": {} + } + }, + "/ApiKeyTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredTrue.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + }, + "/ApiKeyDefault": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredDefault.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_apikey_required.json b/tests/translator/output/aws-cn/api_with_apikey_required.json new file mode 100644 index 0000000000..65a966df63 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_apikey_required.json @@ -0,0 +1,163 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuthDeploymentcc6d6fc40a": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: cc6d6fc40a37188fe0115a039b24e397dc149478", + "StageName": "Stage" + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeploymentcc6d6fc40a" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_apikey_required_openapi_3.json b/tests/translator/output/aws-cn/api_with_apikey_required_openapi_3.json new file mode 100644 index 0000000000..15f1809328 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_apikey_required_openapi_3.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuthDeployment44fb9ac597": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: 44fb9ac5971a18de67dd843c5c069f07726ad36c" + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeployment44fb9ac597" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_auth_all_maximum.json b/tests/translator/output/aws-cn/api_with_auth_all_maximum.json index 781c9b8bef..b74a6965e7 100644 --- a/tests/translator/output/aws-cn/api_with_auth_all_maximum.json +++ b/tests/translator/output/aws-cn/api_with_auth_all_maximum.json @@ -1,39 +1,41 @@ { "Resources": { "MyFunction": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, - "Handler": "index.handler", + }, "Role": { "Fn::GetAtt": [ - "MyFunctionRole", + "MyFunctionRole", "Arn" ] - }, - "Runtime": "nodejs8.10", - "Tags": [{ - "Value": "SAM", - "Key": "lambda:createdBy" - }] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -41,16 +43,16 @@ ] } } - }, + }, "MyApiMyLambdaRequestAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -59,20 +61,20 @@ ] } } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -80,20 +82,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -101,30 +103,20 @@ ] } } - }, - "MyApiDeployment8401165542": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi" - }, - "Description": "RestApi deployment id: 8401165542e94cea0086026b427b10c966b84f1d", - "StageName": "Stage" - } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -132,20 +124,20 @@ ] } } - }, + }, "MyFunctionWithNoAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -153,218 +145,250 @@ ] } } - }, + }, "MyFunctionRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [{ - "Action": [ - "sts:AssumeRole" - ], - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } } - }] + ] } } - }, + }, "MyApi": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { "/": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "NONE": [] - }], + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], "responses": {} } - }, + }, "/users": { "put": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuth": [] - }], + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "post": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuthMultipleUserPools": [] - }], + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "patch": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaTokenAuthNoneFunctionInvokeRole": [] - }], + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "delete": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaRequestAuth": [] - }], + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 0, + "type": "token", + "authorizerResultTtlInSeconds": 0, "authorizerUri": { "Fn::Sub": [ - "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] } - }, + }, "x-amazon-apigateway-authtype": "custom" - }, + }, "MyCognitoAuthMultipleUserPools": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader2", + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", + "identityValidationExpression": "myauthvalidationexpression2", "providerARNs": [ - "arn:aws:2", + "arn:aws:2", "arn:aws:3" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, - "MyLambdaTokenAuth": { - "in": "header", - "type": "apiKey", - "name": "MyCustomAuthHeader", + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ - "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, "x-amazon-apigateway-authtype": "custom" - }, - "MyLambdaRequestAuth": { - "in": "header", - "type": "apiKey", - "name": "Unused", + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ - "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } - }, + }, "EndpointConfiguration": { "Types": [ "REGIONAL" ] - }, + }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" } } - }, + }, "MyApiMyLambdaTokenAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -373,20 +397,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -394,20 +418,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -415,20 +439,20 @@ ] } } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -436,16 +460,16 @@ ] } } - }, + }, "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -454,32 +478,42 @@ ] } } - }, + }, + "MyApiDeployment2b4f028142": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 2b4f028142eb38900e00f362b76751032ac4e464", + "StageName": "Stage" + } + }, "MyApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiDeployment8401165542" - }, + "Ref": "MyApiDeployment2b4f028142" + }, "RestApiId": { "Ref": "MyApi" - }, + }, "StageName": "Prod" } - }, + }, "MyFunctionWithNoAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -487,20 +521,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } diff --git a/tests/translator/output/aws-cn/api_with_auth_all_maximum_openapi_3.json b/tests/translator/output/aws-cn/api_with_auth_all_maximum_openapi_3.json index 669c8a73ea..448bc5f722 100644 --- a/tests/translator/output/aws-cn/api_with_auth_all_maximum_openapi_3.json +++ b/tests/translator/output/aws-cn/api_with_auth_all_maximum_openapi_3.json @@ -193,6 +193,9 @@ "security": [ { "NONE": [] + }, + { + "api_key": [] } ], "responses": {} @@ -210,6 +213,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -225,6 +231,9 @@ "security": [ { "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] } ], "responses": {} @@ -240,6 +249,9 @@ "security": [ { "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] } ], "responses": {} @@ -255,6 +267,9 @@ "security": [ { "MyLambdaRequestAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -264,19 +279,6 @@ "openapi": "3.0.1", "components": { "securitySchemes": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { "in": "header", "type": "apiKey", @@ -309,13 +311,14 @@ }, "x-amazon-apigateway-authtype": "cognito_user_pools" }, - "MyLambdaTokenAuth": { + "MyLambdaRequestAuth": { "in": "header", "type": "apiKey", - "name": "MyCustomAuthHeader", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -324,19 +327,30 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" }, "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaRequestAuth": { + "MyCognitoAuth": { "in": "header", "type": "apiKey", - "name": "Unused", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -345,9 +359,15 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } } @@ -443,6 +463,15 @@ } } }, + "MyApiDeploymentcc3ee70601": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: cc3ee706016a512ef6fe9e3608b7b637fd4c7abd" + } + }, "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -461,20 +490,11 @@ } } }, - "MyApiDeployment046c8986a5": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi" - }, - "Description": "RestApi deployment id: 046c8986a58a325ce5b92a3fe24ea15bef68aced" - } - }, "MyApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiDeployment046c8986a5" + "Ref": "MyApiDeploymentcc3ee70601" }, "RestApiId": { "Ref": "MyApi" @@ -525,4 +545,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-cn/api_with_aws_iam_auth_overrides.json b/tests/translator/output/aws-cn/api_with_aws_iam_auth_overrides.json index 49f1e90a40..ea4ab32eed 100644 --- a/tests/translator/output/aws-cn/api_with_aws_iam_auth_overrides.json +++ b/tests/translator/output/aws-cn/api_with_aws_iam_auth_overrides.json @@ -1,77 +1,152 @@ { "Resources": { "MyFunctionCustomInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionCustomInvokeRoleRole", + "MyFunctionCustomInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, "MyFunctionNoneAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionNoneAuthRole", + "MyFunctionNoneAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, + "MyFunctionNullInvokeRole": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNullInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionNullInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNullInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyApiWithAwsIamAuthProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiWithAwsIamAuthDeploymented0a631915" - }, + "Ref": "MyApiWithAwsIamAuthDeployment4253f994cd" + }, "RestApiId": { "Ref": "MyApiWithAwsIamAuth" - }, + }, "StageName": "Prod" } - }, + }, + "MyApiWithAwsIamAuthDeployment4253f994cd": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuth" + }, + "Description": "RestApi deployment id: 4253f994cdaf14767907decd5cb875cbafc08704", + "StageName": "Stage" + } + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionCallerCredentialsOverride" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionWithoutAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -81,20 +156,20 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -102,20 +177,116 @@ ] } } - }, + }, + "MyFunctionMyCognitoAuthAPI1PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionMyCognitoAuth" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyApiWithAwsIamAuthNoCallerCredentialsDeployment07ee28f86e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "Description": "RestApi deployment id: 07ee28f86edc705d064d88266db4dea8f5c305b1", + "StageName": "Stage" + } + }, + "MyApiWithAwsIamAuthNoCallerCredentials": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoCallerCredentials.Arn}/invocations" + } + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCallerCredentialsOverride.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "AWS_IAM": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, "MyFunctionWithoutAuthAPI2PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionWithoutAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -123,20 +294,20 @@ ] } } - }, + }, "MyFunctionMyCognitoAuthAPI1PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionMyCognitoAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -144,75 +315,154 @@ ] } } - }, - "MyApiWithAwsIamAuthDeploymented0a631915": { - "Type": "AWS::ApiGateway::Deployment", + }, + "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "RestApiId": { - "Ref": "MyApiWithAwsIamAuth" - }, - "Description": "RestApi deployment id: ed0a631915dc4df4436f471e81cd69beb6f89603", - "StageName": "Stage" + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionDefaultInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } } - }, + }, "MyFunctionMyCognitoAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionMyCognitoAuthRole", + "MyFunctionMyCognitoAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionDefaultInvokeRole" - }, + "Ref": "MyFunctionNoCallerCredentials" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", { - "__Stage__": "Prod", + "__Stage__": "*", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionNONEInvokeRole": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNONEInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNoCallerCredentials" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionNoneAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -222,21 +472,21 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -246,20 +496,20 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionDefaultInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -267,64 +517,87 @@ ] } } - }, - "MyFunctionWithoutAuthAPI2PermissionTest": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionWithoutAuth" - }, + "Ref": "MyFunctionCallerCredentialsOverride" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "Prod", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionCallerCredentialsOverride": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionCallerCredentialsOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionWithoutAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionWithoutAuthRole", + "MyFunctionWithoutAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionMyCognitoAuthAPI1PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionMyCognitoAuth" - }, + "Ref": "MyFunctionNullInvokeRole" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -332,21 +605,111 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, "MyFunctionDefaultInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithoutAuthAPI2PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithoutAuth" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionCallerCredentialsOverrideRole": { + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -356,21 +719,42 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -380,20 +764,32 @@ ] } } - }, + }, + "MyApiWithAwsIamAuthNoCallerCredentialsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentialsDeployment07ee28f86e" + }, + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "StageName": "Prod" + } + }, "MyFunctionCustomInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -401,43 +797,66 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionDefaultInvokeRoleRole", + "MyFunctionDefaultInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, + "MyFunctionNoCallerCredentials": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNoCallerCredentialsRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionNoneAuthAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -445,152 +864,186 @@ ] } } - }, + }, "MyApiWithAwsIamAuth": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { - "/MyFunctionDefaultInvokeRole": { + "/MyFunctionWithoutAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" - }, - "credentials": "arn:aws:iam::*:user/*" - }, + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" + }, + "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionWithoutAuth": { + }, + "/MyFunctionNONEInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" - }, - "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" - }, + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNONEInvokeRole.Arn}/invocations" + } + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionNoneAuth": { + }, + "/MyFunctionMyCognitoAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" } - }, + }, "security": [ { - "NONE": [] + "MyCognitoAuth": [] } - ], + ], "responses": {} } - }, - "/MyFunctionMyCognitoAuth": { + }, + "/MyFunctionDefaultInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" - } - }, + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, "security": [ { - "MyCognitoAuth": [] + "AWS_IAM": [] } - ], + ], "responses": {} } - }, + }, "/MyFunctionCustomInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCustomInvokeRole.Arn}/invocations" - }, + }, "credentials": "arn:aws:iam::456::role/something-else" - }, + }, "security": [ { "AWS_IAM": [] } - ], + ], + "responses": {} + } + }, + "/MyFunctionNullInvokeRole": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNullInvokeRole.Arn}/invocations" + } + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + }, + "/MyFunctionNoneAuth": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + } + }, + "security": [ + { + "NONE": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { "providerARNs": [ "arn:aws:cognito-idp:xxxxxxxxx" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, + }, "AWS_IAM": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authtype": "awsSigv4" } } - }, + }, "EndpointConfiguration": { "Types": [ "REGIONAL" ] - }, + }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" } } - }, + }, "MyFunctionNoneAuthAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -598,6 +1051,30 @@ ] } } + }, + "MyFunctionNONEInvokeRoleRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } } } } diff --git a/tests/translator/output/aws-cn/api_with_openapi_definition_body_no_flag.json b/tests/translator/output/aws-cn/api_with_openapi_definition_body_no_flag.json index 815e57e930..29180a0bcf 100644 --- a/tests/translator/output/aws-cn/api_with_openapi_definition_body_no_flag.json +++ b/tests/translator/output/aws-cn/api_with_openapi_definition_body_no_flag.json @@ -47,6 +47,16 @@ } } }, + "ExplicitApiDeployment9252467a1e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 9252467a1edc49ba35cb258640f5e3734cc9fab1", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -68,15 +78,6 @@ } } }, - "ExplicitApiDeployment63a10e26af": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: 63a10e26af7194aefd61ead891c470ed75ce20be" - } - }, "ExplicitApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -180,7 +181,7 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeployment63a10e26af" + "Ref": "ExplicitApiDeployment9252467a1e" } } }, @@ -288,4 +289,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-cn/api_with_path_parameters.json b/tests/translator/output/aws-cn/api_with_path_parameters.json new file mode 100644 index 0000000000..f8914fdb13 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_path_parameters.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_resource_policy.json b/tests/translator/output/aws-cn/api_with_resource_policy.json new file mode 100644 index 0000000000..52961cf666 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_resource_policy.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "ExplicitApiDeploymente11dac9531": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: e11dac9531e1328d9249c42ac3e40044b4159d60", + "StageName": "Stage" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymente11dac9531" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_resource_policy_global.json b/tests/translator/output/aws-cn/api_with_resource_policy_global.json new file mode 100644 index 0000000000..2a34a70ce6 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_resource_policy_global.json @@ -0,0 +1,73 @@ +{ + "Resources": { + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment8d22456d58" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiDeployment8d22456d58": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 8d22456d5883ad51c72f5d9be988d14f0a41182e", + "StageName": "Stage" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_resource_policy_global_implicit.json b/tests/translator/output/aws-cn/api_with_resource_policy_global_implicit.json new file mode 100644 index 0000000000..c912f4dcc4 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_resource_policy_global_implicit.json @@ -0,0 +1,168 @@ +{ + "Resources": { + "MinimalFunctionAddItemPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment0ff9f5a989" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment0ff9f5a989": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 0ff9f5a9899528e1cb050311c49f15a88071a275", + "StageName": "Stage" + } + }, + "MinimalFunctionAddItemPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MinimalFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_stage_tags.json b/tests/translator/output/aws-cn/api_with_stage_tags.json new file mode 100644 index 0000000000..1e99128862 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_stage_tags.json @@ -0,0 +1,75 @@ +{ + "Parameters": { + "TagValueParam": { + "Default": "value", + "Type": "String" + } + }, + "Resources": { + "MyApiWithStageTagsDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "StageName": "Stage" + } + }, + "MyApiWithStageTags": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithStageTagsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithStageTagsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "StageName": "Prod", + "Tags": [ + { + "Value": "TagValue1", + "Key": "TagKey1" + }, + { + "Value": "", + "Key": "TagKey2" + }, + { + "Value": { + "Ref": "TagValueParam" + }, + "Key": "TagKey3" + }, + { + "Value": "123", + "Key": "TagKey4" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/cloudwatchevent.json b/tests/translator/output/aws-cn/cloudwatchevent.json index e7b0bd8f3f..64003f5575 100644 --- a/tests/translator/output/aws-cn/cloudwatchevent.json +++ b/tests/translator/output/aws-cn/cloudwatchevent.json @@ -154,7 +154,7 @@ "ScheduledFunctionSchedule": { "Type": "AWS::Events::Rule", "Properties": { - "ScheduleExpression": "rate(1 minute)", + "ScheduleExpression": "rate(1 minute)", "Targets": [ { "Id": "ScheduledFunctionScheduleLambdaTarget", @@ -169,4 +169,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-cn/cloudwatchevent_schedule_properties.json b/tests/translator/output/aws-cn/cloudwatchevent_schedule_properties.json new file mode 100644 index 0000000000..c947e4bc21 --- /dev/null +++ b/tests/translator/output/aws-cn/cloudwatchevent_schedule_properties.json @@ -0,0 +1,175 @@ +{ + "Resources": { + "ScheduledFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "TriggeredFunctionOnTerminatePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "TriggeredFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "TriggeredFunctionOnTerminate", + "Arn" + ] + } + } + }, + "ScheduledFunctionSchedulePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "ScheduledFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "ScheduledFunctionSchedule", + "Arn" + ] + } + } + }, + "ScheduledFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ScheduledFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionOnTerminate": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "Id": "TriggeredFunctionOnTerminateLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "TriggeredFunction", + "Arn" + ] + } + } + ] + } + }, + "TriggeredFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "TriggeredFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ScheduledFunctionSchedule": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Name": "test-schedule", + "Description": "Test Schedule", + "State": "ENABLED", + "Targets": [ + { + "Id": "ScheduledFunctionScheduleLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "ScheduledFunction", + "Arn" + ] + } + } + ] + } + } + } +} diff --git a/tests/translator/output/aws-cn/function_with_conditional_managed_policy.json b/tests/translator/output/aws-cn/function_with_conditional_managed_policy.json new file mode 100644 index 0000000000..f014353300 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_conditional_managed_policy.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/function_with_conditional_managed_policy_and_ref_no_value.json b/tests/translator/output/aws-cn/function_with_conditional_managed_policy_and_ref_no_value.json new file mode 100644 index 0000000000..bcd345bf35 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_conditional_managed_policy_and_ref_no_value.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/function_with_conditional_policy_template.json b/tests/translator/output/aws-cn/function_with_conditional_policy_template.json new file mode 100644 index 0000000000..6cb4ad3aae --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_conditional_policy_template.json @@ -0,0 +1,126 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue", + "secretsmanager:PutSecretValue", + "secretsmanager:UpdateSecretVersionStage" + ], + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*" + }, + "Effect": "Allow", + "Condition": { + "StringEquals": { + "secretsmanager:resource/AllowRotationLambdaArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}", + { + "functionName": "Dummy Function Name" + } + ] + } + } + } + }, + { + "Action": [ + "secretsmanager:GetRandomPassword" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + } + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/function_with_conditional_policy_template_and_ref_no_value.json b/tests/translator/output/aws-cn/function_with_conditional_policy_template_and_ref_no_value.json new file mode 100644 index 0000000000..39be617ed1 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_conditional_policy_template_and_ref_no_value.json @@ -0,0 +1,91 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/function_with_sns_event_source_all_parameters.json b/tests/translator/output/aws-cn/function_with_sns_event_source_all_parameters.json index 2a2072b9b2..cac15164c9 100644 --- a/tests/translator/output/aws-cn/function_with_sns_event_source_all_parameters.json +++ b/tests/translator/output/aws-cn/function_with_sns_event_source_all_parameters.json @@ -33,7 +33,8 @@ ] }, "Protocol": "lambda", - "TopicArn": "topicArn" + "TopicArn": "topicArn", + "Region": "region" } }, "MyAwesomeFunctionNotificationTopicPermission": { diff --git a/tests/translator/output/aws-cn/globals_for_api.json b/tests/translator/output/aws-cn/globals_for_api.json index bcfdd57cad..8bd110f3fc 100644 --- a/tests/translator/output/aws-cn/globals_for_api.json +++ b/tests/translator/output/aws-cn/globals_for_api.json @@ -91,6 +91,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -115,6 +118,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, @@ -142,20 +150,10 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ServerlessRestApiDeploymente1212668e0" + "Ref": "ServerlessRestApiDeploymentf6c326a165" } } }, - "ServerlessRestApiDeploymente1212668e0": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: e1212668e096994ab32167666f5a877bd6ac5fad", - "StageName": "Stage" - } - }, "ExplicitApiSomeStageStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -169,10 +167,30 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeploymentd5fa0145e9" + "Ref": "ExplicitApiDeployment43e01e673d" } } }, + "ServerlessRestApiDeploymentf6c326a165": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: f6c326a1656cc9fbb0106cc645598d88575554eb", + "StageName": "Stage" + } + }, + "ExplicitApiDeployment43e01e673d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 43e01e673d7acbd09e4c38ff78dd6ddaf2ed1d55", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -194,16 +212,6 @@ } } }, - "ExplicitApiDeploymentd5fa0145e9": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: d5fa0145e9e6393911d32967e66fd7091d605483", - "StageName": "Stage" - } - }, "MyUserPool": { "Type": "AWS::Cognito::UserPool", "Properties": { @@ -248,6 +256,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -272,6 +283,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, diff --git a/tests/translator/output/aws-cn/implicit_api_with_auth_and_conditions_max.json b/tests/translator/output/aws-cn/implicit_api_with_auth_and_conditions_max.json index 1ffd2bd98b..2ced69491d 100644 --- a/tests/translator/output/aws-cn/implicit_api_with_auth_and_conditions_max.json +++ b/tests/translator/output/aws-cn/implicit_api_with_auth_and_conditions_max.json @@ -223,7 +223,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment13185ed4f8" + "Ref": "ServerlessRestApiDeployment6b0de9dc9a" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -594,17 +594,6 @@ }, "Condition": "FunctionCondition" }, - "ServerlessRestApiDeployment13185ed4f8": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 13185ed4f830a9731f30c8561a781a0f560748c1", - "StageName": "Stage" - }, - "Condition": "ServerlessRestApiCondition" - }, "MyFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { @@ -652,6 +641,17 @@ }, "Condition": "FunctionCondition5" }, + "ServerlessRestApiDeployment6b0de9dc9a": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 6b0de9dc9a2450a248988d39c61e2ee23b257724", + "StageName": "Stage" + }, + "Condition": "ServerlessRestApiCondition" + }, "MyFunction3WithLambdaTokenAuthorizerPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -772,6 +772,9 @@ } }, "security": [ + { + "api_key": [] + }, { "MyCognitoAuth": [] } @@ -916,26 +919,37 @@ }, "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { + "MyLambdaTokenAuthNoneFunctionInvokeRole": { "in": "header", "type": "apiKey", - "name": "MyAuthorizationHeader", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" + "type": "token", + "authorizerResultTtlInSeconds": 0, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + } }, - "x-amazon-apigateway-authtype": "cognito_user_pools" + "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaTokenAuthNoneFunctionInvokeRole": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaRequestAuth": { "in": "header", "type": "apiKey", - "name": "Authorization", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", + "type": "request", "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -943,19 +957,19 @@ "__FunctionArn__": "arn:aws" } ] - } + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" }, "x-amazon-apigateway-authtype": "custom" }, - "MyCognitoAuthMultipleUserPools": { + "MyCognitoAuth": { "in": "header", "type": "apiKey", - "name": "MyAuthorizationHeader2", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", + "identityValidationExpression": "myauthvalidationexpression", "providerARNs": [ - "arn:aws:2", - "arn:aws:3" + "arn:aws:1" ], "type": "cognito_user_pools" }, @@ -981,25 +995,19 @@ }, "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaRequestAuth": { + "MyCognitoAuthMultipleUserPools": { "in": "header", "type": "apiKey", - "name": "Unused", + "name": "MyAuthorizationHeader2", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", - "authorizerUri": { - "Fn::Sub": [ - "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", - { - "__FunctionArn__": "arn:aws" - } - ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" }, - "x-amazon-apigateway-authtype": "custom" + "x-amazon-apigateway-authtype": "cognito_user_pools" } } }, @@ -1037,4 +1045,4 @@ "Condition": "FunctionCondition2" } } -} +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/all_policy_templates.json b/tests/translator/output/aws-us-gov/all_policy_templates.json index 9e8386268d..87621eb9dc 100644 --- a/tests/translator/output/aws-us-gov/all_policy_templates.json +++ b/tests/translator/output/aws-us-gov/all_policy_templates.json @@ -207,7 +207,8 @@ "Statement": [ { "Action": [ - "es:ESHttpPost" + "es:ESHttpPost", + "es:ESHttpPut" ], "Resource": { "Fn::Sub": [ @@ -808,14 +809,7 @@ "rekognition:CompareFaces", "rekognition:DetectFaces" ], - "Resource": { - "Fn::Sub": [ - "arn:${AWS::Partition}:rekognition:${AWS::Region}:${AWS::AccountId}:collection/${collectionId}", - { - "collectionId": "collection" - } - ] - }, + "Resource": "*", "Effect": "Allow" } ] diff --git a/tests/translator/output/aws-us-gov/api_with_apikey_default_override.json b/tests/translator/output/aws-us-gov/api_with_apikey_default_override.json new file mode 100644 index 0000000000..a508c0e137 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_apikey_default_override.json @@ -0,0 +1,371 @@ +{ + "Resources": { + "MyApiWithAuthDeployment084855ab6d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "Description": "RestApi deployment id: 084855ab6d04ef5b762ac75de403810cd5f0c166", + "StageName": "Stage" + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalseMyApiWithApiKeyRequiredFalsePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredFalse" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyFalse", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyApiWithAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAuthDeployment084855ab6d" + }, + "RestApiId": { + "Ref": "MyApiWithAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredTrue": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredTrueRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefault": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredDefaultRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredFalse": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredFalseRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionWithApiKeyRequiredFalseRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredDefaultMyApiWithApiKeyRequiredDefaultPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredDefault" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyDefault", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueMyApiWithApiKeyRequiredTruePermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequiredTrue" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredTrueRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyApiWithAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyFalse": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredFalse.Arn}/invocations" + } + }, + "security": [], + "responses": {} + } + }, + "/ApiKeyTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredTrue.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + }, + "/ApiKeyDefault": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequiredDefault.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_apikey_required.json b/tests/translator/output/aws-us-gov/api_with_apikey_required.json new file mode 100644 index 0000000000..0d7f930765 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_apikey_required.json @@ -0,0 +1,163 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeployment1f6bf4c0d5" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApiWithoutAuthDeployment1f6bf4c0d5": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: 1f6bf4c0d5babf513c5623a65931134211ad3d0b", + "StageName": "Stage" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_apikey_required_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_apikey_required_openapi_3.json new file mode 100644 index 0000000000..80dfe87167 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_apikey_required_openapi_3.json @@ -0,0 +1,164 @@ +{ + "Resources": { + "MyFunctionWithApiKeyRequiredRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyApiWithoutAuthDeployment36e0aae784": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "Description": "RestApi deployment id: 36e0aae784b2c12681164079395d2d416638051f" + } + }, + "MyApiWithoutAuth": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/ApiKeyRequiredTrue": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithApiKeyRequired.Arn}/invocations" + } + }, + "security": [ + { + "api_key": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0.1", + "components": { + "securitySchemes": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithoutAuthProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithoutAuthDeployment36e0aae784" + }, + "RestApiId": { + "Ref": "MyApiWithoutAuth" + }, + "StageName": "Prod" + } + }, + "MyFunctionWithApiKeyRequiredMyApiWithApiKeyRequiredPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithApiKeyRequired" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/ApiKeyRequiredTrue", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithoutAuth" + } + } + ] + } + } + }, + "MyFunctionWithApiKeyRequired": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionWithApiKeyRequiredRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_auth_all_maximum.json b/tests/translator/output/aws-us-gov/api_with_auth_all_maximum.json index 7faead9d31..589b9fd953 100644 --- a/tests/translator/output/aws-us-gov/api_with_auth_all_maximum.json +++ b/tests/translator/output/aws-us-gov/api_with_auth_all_maximum.json @@ -1,39 +1,41 @@ { "Resources": { "MyFunction": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, - "Handler": "index.handler", + }, "Role": { "Fn::GetAtt": [ - "MyFunctionRole", + "MyFunctionRole", "Arn" ] - }, - "Runtime": "nodejs8.10", - "Tags": [{ - "Value": "SAM", - "Key": "lambda:createdBy" - }] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -41,16 +43,16 @@ ] } } - }, + }, "MyApiMyLambdaRequestAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -59,20 +61,20 @@ ] } } - }, + }, "MyFunctionWithLambdaTokenAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -80,20 +82,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -101,20 +103,20 @@ ] } } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -122,20 +124,20 @@ ] } } - }, + }, "MyFunctionWithNoAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -143,218 +145,260 @@ ] } } - }, + }, + "MyApiDeployment7939ed72e3": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 7939ed72e39cf5e3c86aaa365a531790a1d244e6", + "StageName": "Stage" + } + }, "MyFunctionRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [{ - "Action": [ - "sts:AssumeRole" - ], - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } } - }] + ] } } - }, + }, "MyApi": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { "/": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "NONE": [] - }], + }, + "security": [ + { + "NONE": [] + }, + { + "api_key": [] + } + ], "responses": {} } - }, + }, "/users": { "put": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuth": [] - }], + }, + "security": [ + { + "MyCognitoAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "post": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyCognitoAuthMultipleUserPools": [] - }], + }, + "security": [ + { + "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "patch": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaTokenAuthNoneFunctionInvokeRole": [] - }], + }, + "security": [ + { + "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] + } + ], "responses": {} - }, + }, "delete": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" } - }, - "security": [{ - "MyLambdaRequestAuth": [] - }], + }, + "security": [ + { + "MyLambdaRequestAuth": [] + }, + { + "api_key": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 0, + "type": "token", + "authorizerResultTtlInSeconds": 0, "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] } - }, + }, "x-amazon-apigateway-authtype": "custom" - }, + }, "MyCognitoAuthMultipleUserPools": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader2", + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", + "identityValidationExpression": "myauthvalidationexpression2", "providerARNs": [ - "arn:aws:2", + "arn:aws:2", "arn:aws:3" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, - "MyLambdaTokenAuth": { - "in": "header", - "type": "apiKey", - "name": "MyCustomAuthHeader", + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, "x-amazon-apigateway-authtype": "custom" - }, - "MyLambdaRequestAuth": { - "in": "header", - "type": "apiKey", - "name": "Unused", + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } - }, + }, "EndpointConfiguration": { "Types": [ "REGIONAL" ] - }, + }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" } } - }, + }, "MyApiMyLambdaTokenAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -363,20 +407,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -384,20 +428,20 @@ ] } } - }, + }, "MyFunctionWithLambdaRequestAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -405,30 +449,20 @@ ] } } - }, - "MyApiDeploymentf9e0be23dc": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "MyApi" - }, - "Description": "RestApi deployment id: f9e0be23dccfaabdc2729c4d2221a3eeaa8e87db", - "StageName": "Stage" - } - }, + }, "MyFunctionWithCognitoMultipleUserPoolsAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApi" } @@ -436,16 +470,16 @@ ] } } - }, + }, "MyApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "MyApi" @@ -454,32 +488,32 @@ ] } } - }, + }, "MyApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiDeploymentf9e0be23dc" - }, + "Ref": "MyApiDeployment7939ed72e3" + }, "RestApiId": { "Ref": "MyApi" - }, + }, "StageName": "Prod" } - }, + }, "MyFunctionWithNoAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } @@ -487,20 +521,20 @@ ] } } - }, + }, "MyFunctionWithDefaultAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApi" } diff --git a/tests/translator/output/aws-us-gov/api_with_auth_all_maximum_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_auth_all_maximum_openapi_3.json index da3eefd416..2e13d4e481 100644 --- a/tests/translator/output/aws-us-gov/api_with_auth_all_maximum_openapi_3.json +++ b/tests/translator/output/aws-us-gov/api_with_auth_all_maximum_openapi_3.json @@ -170,6 +170,15 @@ } } }, + "MyApiDeployment57e8e73ac5": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 57e8e73ac5d3dea833fbbfb4d0d67328fb198a35" + } + }, "MyApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -193,6 +202,9 @@ "security": [ { "NONE": [] + }, + { + "api_key": [] } ], "responses": {} @@ -210,6 +222,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -225,6 +240,9 @@ "security": [ { "MyCognitoAuthMultipleUserPools": [] + }, + { + "api_key": [] } ], "responses": {} @@ -240,6 +258,9 @@ "security": [ { "MyLambdaTokenAuthNoneFunctionInvokeRole": [] + }, + { + "api_key": [] } ], "responses": {} @@ -255,6 +276,9 @@ "security": [ { "MyLambdaRequestAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -264,19 +288,6 @@ "openapi": "3.0.1", "components": { "securitySchemes": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { "in": "header", "type": "apiKey", @@ -309,13 +320,14 @@ }, "x-amazon-apigateway-authtype": "cognito_user_pools" }, - "MyLambdaTokenAuth": { + "MyLambdaRequestAuth": { "in": "header", "type": "apiKey", - "name": "MyCustomAuthHeader", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -324,19 +336,30 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" }, "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaRequestAuth": { + "MyCognitoAuth": { "in": "header", "type": "apiKey", - "name": "Unused", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -345,9 +368,15 @@ } ] }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" }, "x-amazon-apigateway-authtype": "custom" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } } @@ -461,13 +490,16 @@ } } }, - "MyApiDeployment1340211fad": { - "Type": "AWS::ApiGateway::Deployment", + "MyApiProdStage": { + "Type": "AWS::ApiGateway::Stage", "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment57e8e73ac5" + }, "RestApiId": { "Ref": "MyApi" }, - "Description": "RestApi deployment id: 1340211fad54a37a0ad8ff3740ecdf6a48107e28" + "StageName": "Prod" } }, "MyFunctionWithNoAuthorizerPermissionProd": { @@ -491,18 +523,6 @@ } } }, - "MyApiProdStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "MyApiDeployment1340211fad" - }, - "RestApiId": { - "Ref": "MyApi" - }, - "StageName": "Prod" - } - }, "MyFunctionWithDefaultAuthorizerPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -525,4 +545,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/api_with_aws_iam_auth_overrides.json b/tests/translator/output/aws-us-gov/api_with_aws_iam_auth_overrides.json index cf8d219509..77cc8a3298 100644 --- a/tests/translator/output/aws-us-gov/api_with_aws_iam_auth_overrides.json +++ b/tests/translator/output/aws-us-gov/api_with_aws_iam_auth_overrides.json @@ -1,87 +1,142 @@ { "Resources": { "MyFunctionCustomInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionCustomInvokeRoleRole", + "MyFunctionCustomInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, "MyFunctionNoneAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionNoneAuthRole", + "MyFunctionNoneAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyApiWithAwsIamAuthDeploymentd6dd2d1504": { - "Type": "AWS::ApiGateway::Deployment", + }, + "MyFunctionNullInvokeRole": { + "Type": "AWS::Lambda::Function", "Properties": { - "RestApiId": { - "Ref": "MyApiWithAwsIamAuth" - }, - "Description": "RestApi deployment id: d6dd2d1504ea960bdb50055b256d9292aa565e4b", - "StageName": "Stage" + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNullInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] } - }, + }, + "MyFunctionNullInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNullInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyApiWithAwsIamAuthProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "MyApiWithAwsIamAuthDeploymentd6dd2d1504" - }, + "Ref": "MyApiWithAwsIamAuthDeploymentc7d4214444" + }, "RestApiId": { "Ref": "MyApiWithAwsIamAuth" - }, + }, "StageName": "Prod" } - }, + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionCallerCredentialsOverride" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionWithoutAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -91,20 +146,41 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionMyCognitoAuthAPI1PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionMyCognitoAuth" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -112,20 +188,95 @@ ] } } - }, + }, + "MyApiWithAwsIamAuthDeploymentc7d4214444": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuth" + }, + "Description": "RestApi deployment id: c7d4214444b325ee43f7a16744a5a74d01b268b2", + "StageName": "Stage" + } + }, + "MyApiWithAwsIamAuthNoCallerCredentials": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoCallerCredentials.Arn}/invocations" + } + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCallerCredentialsOverride.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + } + }, + "swagger": "2.0", + "securityDefinitions": { + "AWS_IAM": { + "in": "header", + "type": "apiKey", + "name": "Authorization", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, "MyFunctionWithoutAuthAPI2PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionWithoutAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -133,20 +284,20 @@ ] } } - }, + }, "MyFunctionMyCognitoAuthAPI1PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionMyCognitoAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -154,65 +305,154 @@ ] } } - }, + }, + "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionDefaultInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionMyCognitoAuthRole", + "MyFunctionMyCognitoAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionDefaultInvokeRoleAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionDefaultInvokeRole" - }, + "Ref": "MyFunctionNoCallerCredentials" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", { - "__Stage__": "Prod", + "__Stage__": "*", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionNONEInvokeRole": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNONEInvokeRoleRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyFunctionNoCallerCredentialsAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNoCallerCredentials" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + } + } + ] + } + } + }, "MyFunctionNoneAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -222,21 +462,21 @@ ] } } - }, + }, "MyFunctionCustomInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -246,20 +486,20 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionDefaultInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionDefaultInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -267,64 +507,87 @@ ] } } - }, - "MyFunctionWithoutAuthAPI2PermissionTest": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionCallerCredentialsOverrideAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionWithoutAuth" - }, + "Ref": "MyFunctionCallerCredentialsOverride" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "Prod", "__ApiId__": { - "Ref": "MyApiWithAwsIamAuth" + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" } } ] } } - }, + }, + "MyFunctionCallerCredentialsOverride": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionCallerCredentialsOverrideRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionWithoutAuth": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionWithoutAuthRole", + "MyFunctionWithoutAuthRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, - "MyFunctionMyCognitoAuthAPI1PermissionProd": { - "Type": "AWS::Lambda::Permission", + }, + "MyFunctionNullInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { - "Ref": "MyFunctionMyCognitoAuth" - }, + "Ref": "MyFunctionNullInvokeRole" + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionMyCognitoAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNullInvokeRole", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -332,21 +595,111 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionNoCallerCredentialsRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, "MyFunctionDefaultInvokeRoleRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MyFunctionWithoutAuthAPI2PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionWithoutAuth" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionWithoutAuth", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, + "MyFunctionCallerCredentialsOverrideRole": { + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -356,21 +709,42 @@ ] } } - }, + }, + "MyFunctionNONEInvokeRoleAPI3PermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MyFunctionNONEInvokeRole" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNONEInvokeRole", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApiWithAwsIamAuth" + } + } + ] + } + } + }, "MyFunctionMyCognitoAuthRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -380,20 +754,32 @@ ] } } - }, + }, + "MyApiWithAwsIamAuthNoCallerCredentialsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentialsDeployment673da6c5e9" + }, + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "StageName": "Prod" + } + }, "MyFunctionCustomInvokeRoleAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionCustomInvokeRole" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionCustomInvokeRole", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -401,43 +787,66 @@ ] } } - }, + }, "MyFunctionDefaultInvokeRole": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "bucket", + "S3Bucket": "bucket", "S3Key": "key" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionDefaultInvokeRoleRole", + "MyFunctionDefaultInvokeRoleRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] } - }, + }, + "MyFunctionNoCallerCredentials": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "bucket", + "S3Key": "key" + }, + "Role": { + "Fn::GetAtt": [ + "MyFunctionNoCallerCredentialsRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, "MyFunctionNoneAuthAPI3PermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -445,152 +854,186 @@ ] } } - }, + }, "MyApiWithAwsIamAuth": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { - "/MyFunctionDefaultInvokeRole": { + "/MyFunctionWithoutAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" - }, - "credentials": "arn:aws:iam::*:user/*" - }, + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" + }, + "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionWithoutAuth": { + }, + "/MyFunctionNONEInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionWithoutAuth.Arn}/invocations" - }, - "credentials": "arn:aws:iam::123:role/AUTH_AWS_IAM" - }, + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNONEInvokeRole.Arn}/invocations" + } + }, "security": [ { "AWS_IAM": [] } - ], + ], "responses": {} } - }, - "/MyFunctionNoneAuth": { + }, + "/MyFunctionMyCognitoAuth": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" } - }, + }, "security": [ { - "NONE": [] + "MyCognitoAuth": [] } - ], + ], "responses": {} } - }, - "/MyFunctionMyCognitoAuth": { + }, + "/MyFunctionDefaultInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { - "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionMyCognitoAuth.Arn}/invocations" - } - }, + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionDefaultInvokeRole.Arn}/invocations" + }, + "credentials": "arn:aws:iam::*:user/*" + }, "security": [ { - "MyCognitoAuth": [] + "AWS_IAM": [] } - ], + ], "responses": {} } - }, + }, "/MyFunctionCustomInvokeRole": { "get": { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionCustomInvokeRole.Arn}/invocations" - }, + }, "credentials": "arn:aws:iam::456::role/something-else" - }, + }, + "security": [ + { + "AWS_IAM": [] + } + ], + "responses": {} + } + }, + "/MyFunctionNullInvokeRole": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNullInvokeRole.Arn}/invocations" + } + }, "security": [ { "AWS_IAM": [] } - ], + ], + "responses": {} + } + }, + "/MyFunctionNoneAuth": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunctionNoneAuth.Arn}/invocations" + } + }, + "security": [ + { + "NONE": [] + } + ], "responses": {} } } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { "providerARNs": [ "arn:aws:cognito-idp:xxxxxxxxx" - ], + ], "type": "cognito_user_pools" - }, + }, "x-amazon-apigateway-authtype": "cognito_user_pools" - }, + }, "AWS_IAM": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authtype": "awsSigv4" } } - }, + }, "EndpointConfiguration": { "Types": [ "REGIONAL" ] - }, + }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" } } - }, + }, "MyFunctionNoneAuthAPI3PermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunctionNoneAuth" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/MyFunctionNoneAuth", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "MyApiWithAwsIamAuth" } @@ -598,6 +1041,40 @@ ] } } + }, + "MyApiWithAwsIamAuthNoCallerCredentialsDeployment673da6c5e9": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithAwsIamAuthNoCallerCredentials" + }, + "Description": "RestApi deployment id: 673da6c5e9481163e7b1cbf6d5604eb84cf64fd0", + "StageName": "Stage" + } + }, + "MyFunctionNONEInvokeRoleRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } } } } diff --git a/tests/translator/output/aws-us-gov/api_with_openapi_definition_body_no_flag.json b/tests/translator/output/aws-us-gov/api_with_openapi_definition_body_no_flag.json index f9513c92fe..976fac88b4 100644 --- a/tests/translator/output/aws-us-gov/api_with_openapi_definition_body_no_flag.json +++ b/tests/translator/output/aws-us-gov/api_with_openapi_definition_body_no_flag.json @@ -47,6 +47,16 @@ } } }, + "ExplicitApiDeployment9252467a1e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 9252467a1edc49ba35cb258640f5e3734cc9fab1", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -68,15 +78,6 @@ } } }, - "ExplicitApiDeployment63a10e26af": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: 63a10e26af7194aefd61ead891c470ed75ce20be" - } - }, "ExplicitApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -170,7 +171,7 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeployment63a10e26af" + "Ref": "ExplicitApiDeployment9252467a1e" } } }, @@ -288,4 +289,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/api_with_path_parameters.json b/tests/translator/output/aws-us-gov/api_with_path_parameters.json new file mode 100644 index 0000000000..390e6c87e8 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_path_parameters.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_resource_policy.json b/tests/translator/output/aws-us-gov/api_with_resource_policy.json new file mode 100644 index 0000000000..52961cf666 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_resource_policy.json @@ -0,0 +1,60 @@ +{ + "Resources": { + "ExplicitApiDeploymente11dac9531": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: e11dac9531e1328d9249c42ac3e40044b4159d60", + "StageName": "Stage" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymente11dac9531" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_resource_policy_global.json b/tests/translator/output/aws-us-gov/api_with_resource_policy_global.json new file mode 100644 index 0000000000..e74f826487 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_resource_policy_global.json @@ -0,0 +1,73 @@ +{ + "Resources": { + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment8d22456d58" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiDeployment8d22456d58": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 8d22456d5883ad51c72f5d9be988d14f0a41182e", + "StageName": "Stage" + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + }, + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} diff --git a/tests/translator/output/aws-us-gov/api_with_resource_policy_global_implicit.json b/tests/translator/output/aws-us-gov/api_with_resource_policy_global_implicit.json new file mode 100644 index 0000000000..c06c2188c8 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_resource_policy_global_implicit.json @@ -0,0 +1,168 @@ +{ + "Resources": { + "MinimalFunctionAddItemPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "MinimalFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "MinimalFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "hello.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Role": { + "Fn::GetAtt": [ + "MinimalFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment9558094c1e" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "MinimalFunctionAddItemPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "MinimalFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/add", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MinimalFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Resource": [ + "execute-api:/*/*/*" + ] + }, + { + "Action": "execute-api:blah", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ] + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ServerlessRestApiDeployment9558094c1e": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 9558094c1ecacce5e02be40fdb03356118d9ccac", + "StageName": "Stage" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_stage_tags.json b/tests/translator/output/aws-us-gov/api_with_stage_tags.json new file mode 100644 index 0000000000..1e99128862 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_stage_tags.json @@ -0,0 +1,75 @@ +{ + "Parameters": { + "TagValueParam": { + "Default": "value", + "Type": "String" + } + }, + "Resources": { + "MyApiWithStageTagsDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "StageName": "Stage" + } + }, + "MyApiWithStageTags": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "MyApiWithStageTagsProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiWithStageTagsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "MyApiWithStageTags" + }, + "StageName": "Prod", + "Tags": [ + { + "Value": "TagValue1", + "Key": "TagKey1" + }, + { + "Value": "", + "Key": "TagKey2" + }, + { + "Value": { + "Ref": "TagValueParam" + }, + "Key": "TagKey3" + }, + { + "Value": "123", + "Key": "TagKey4" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/cloudwatchevent.json b/tests/translator/output/aws-us-gov/cloudwatchevent.json index cec52175ae..75979c84b6 100644 --- a/tests/translator/output/aws-us-gov/cloudwatchevent.json +++ b/tests/translator/output/aws-us-gov/cloudwatchevent.json @@ -154,7 +154,7 @@ "ScheduledFunctionSchedule": { "Type": "AWS::Events::Rule", "Properties": { - "ScheduleExpression": "rate(1 minute)", + "ScheduleExpression": "rate(1 minute)", "Targets": [ { "Id": "ScheduledFunctionScheduleLambdaTarget", @@ -169,4 +169,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/cloudwatchevent_schedule_properties.json b/tests/translator/output/aws-us-gov/cloudwatchevent_schedule_properties.json new file mode 100644 index 0000000000..3913b5c724 --- /dev/null +++ b/tests/translator/output/aws-us-gov/cloudwatchevent_schedule_properties.json @@ -0,0 +1,175 @@ +{ + "Resources": { + "ScheduledFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "TriggeredFunctionOnTerminatePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "TriggeredFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "TriggeredFunctionOnTerminate", + "Arn" + ] + } + } + }, + "ScheduledFunctionSchedulePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "ScheduledFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "ScheduledFunctionSchedule", + "Arn" + ] + } + } + }, + "ScheduledFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ScheduledFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionOnTerminate": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "Id": "TriggeredFunctionOnTerminateLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "TriggeredFunction", + "Arn" + ] + } + } + ] + } + }, + "TriggeredFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "TriggeredFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ScheduledFunctionSchedule": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Name": "test-schedule", + "Description": "Test Schedule", + "State": "ENABLED", + "Targets": [ + { + "Id": "ScheduledFunctionScheduleLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "ScheduledFunction", + "Arn" + ] + } + } + ] + } + } + } +} diff --git a/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy.json b/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy.json new file mode 100644 index 0000000000..859c85a8a1 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy_and_ref_no_value.json b/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy_and_ref_no_value.json new file mode 100644 index 0000000000..ddcf43ff1a --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_conditional_managed_policy_and_ref_no_value.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_conditional_policy_template.json b/tests/translator/output/aws-us-gov/function_with_conditional_policy_template.json new file mode 100644 index 0000000000..7a9e12b898 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_conditional_policy_template.json @@ -0,0 +1,126 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue", + "secretsmanager:PutSecretValue", + "secretsmanager:UpdateSecretVersionStage" + ], + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*" + }, + "Effect": "Allow", + "Condition": { + "StringEquals": { + "secretsmanager:resource/AllowRotationLambdaArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}", + { + "functionName": "Dummy Function Name" + } + ] + } + } + } + }, + { + "Action": [ + "secretsmanager:GetRandomPassword" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + } + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_conditional_policy_template_and_ref_no_value.json b/tests/translator/output/aws-us-gov/function_with_conditional_policy_template_and_ref_no_value.json new file mode 100644 index 0000000000..f3d43297cb --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_conditional_policy_template_and_ref_no_value.json @@ -0,0 +1,91 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_sns_event_source_all_parameters.json b/tests/translator/output/aws-us-gov/function_with_sns_event_source_all_parameters.json index 4e682d5be2..5ebf5d48e6 100644 --- a/tests/translator/output/aws-us-gov/function_with_sns_event_source_all_parameters.json +++ b/tests/translator/output/aws-us-gov/function_with_sns_event_source_all_parameters.json @@ -33,7 +33,8 @@ ] }, "Protocol": "lambda", - "TopicArn": "topicArn" + "TopicArn": "topicArn", + "Region": "region" } }, "MyAwesomeFunctionNotificationTopicPermission": { diff --git a/tests/translator/output/aws-us-gov/globals_for_api.json b/tests/translator/output/aws-us-gov/globals_for_api.json index 138c62aedb..42b4008f31 100644 --- a/tests/translator/output/aws-us-gov/globals_for_api.json +++ b/tests/translator/output/aws-us-gov/globals_for_api.json @@ -91,6 +91,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -115,6 +118,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, @@ -142,7 +150,7 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentc969c99f9d" + "Ref": "ServerlessRestApiDeployment6fd1928d9b" } } }, @@ -159,10 +167,20 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeploymentd5fa0145e9" + "Ref": "ExplicitApiDeployment43e01e673d" } } }, + "ExplicitApiDeployment43e01e673d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 43e01e673d7acbd09e4c38ff78dd6ddaf2ed1d55", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -184,23 +202,13 @@ } } }, - "ServerlessRestApiDeploymentc969c99f9d": { + "ServerlessRestApiDeployment6fd1928d9b": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: c969c99f9d6b6921dff605a206e8989bdb7d1bc7", - "StageName": "Stage" - } - }, - "ExplicitApiDeploymentd5fa0145e9": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: d5fa0145e9e6393911d32967e66fd7091d605483", + "Description": "RestApi deployment id: 6fd1928d9b9ad3c711a371e1337306458029f8bd", "StageName": "Stage" } }, @@ -248,6 +256,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -272,6 +283,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, diff --git a/tests/translator/output/aws-us-gov/implicit_api_with_auth_and_conditions_max.json b/tests/translator/output/aws-us-gov/implicit_api_with_auth_and_conditions_max.json index ee12134b50..c29ef0c3b5 100644 --- a/tests/translator/output/aws-us-gov/implicit_api_with_auth_and_conditions_max.json +++ b/tests/translator/output/aws-us-gov/implicit_api_with_auth_and_conditions_max.json @@ -4,259 +4,248 @@ "Fn::Or": [ { "Condition": "FunctionCondition" - }, + }, { "Condition": "FunctionCondition2" - }, + }, { "Condition": "FunctionCondition3" - }, + }, { "Condition": "FunctionCondition4" - }, + }, { "Condition": "FunctionCondition5" - }, + }, { "Condition": "FunctionCondition6" } ] - }, + }, "FunctionCondition6": { "Fn::Equals": [ - true, + true, false ] - }, + }, "FunctionCondition5": { "Fn::Equals": [ - true, + true, false ] - }, + }, "FunctionCondition4": { "Fn::Equals": [ - true, + true, false ] - }, + }, "FunctionCondition3": { "Fn::Equals": [ - true, + true, false ] - }, + }, "FunctionCondition2": { "Fn::Equals": [ - true, + true, false ] - }, + }, "ServerlessRestApiSLASHusersPathCondition": { "Fn::Or": [ { "Condition": "FunctionCondition2" - }, + }, { "Condition": "FunctionCondition3" - }, + }, { "Condition": "FunctionCondition4" - }, + }, { "Condition": "FunctionCondition5" - }, + }, { "Condition": "FunctionCondition6" } ] - }, + }, "FunctionCondition": { "Fn::Equals": [ - true, + true, false ] } - }, + }, "Resources": { "MyFunction4WithLambdaTokenAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction4" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition4" - }, + }, "MyFunction4": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunction4Role", + "MyFunction4Role", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition4" - }, + }, "MyFunction6": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunction6Role", + "MyFunction6Role", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition6" - }, - "ServerlessRestApiDeploymentc06acce7cc": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: c06acce7cc8764dcad4cb4a7c74b2d0b43310c00", - "StageName": "Stage" - }, - "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunction2WithCognitoMultipleUserPoolsAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction2" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition2" - }, + }, "MyFunction3": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunction3Role", + "MyFunction3Role", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition3" - }, + }, "MyFunction2": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunction2Role", + "MyFunction2Role", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition2" - }, + }, "ServerlessRestApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentc06acce7cc" - }, + "Ref": "ServerlessRestApiDeployment91a6380656" + }, "RestApiId": { "Ref": "ServerlessRestApi" - }, + }, "StageName": "Prod" - }, + }, "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunction5Role": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -265,23 +254,23 @@ } ] } - }, + }, "Condition": "FunctionCondition5" - }, + }, "MyFunction2Role": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -290,23 +279,23 @@ } ] } - }, + }, "Condition": "FunctionCondition2" - }, + }, "MyFunction4Role": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -315,69 +304,69 @@ } ] } - }, + }, "Condition": "FunctionCondition4" - }, + }, "MyFunction3WithLambdaTokenAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction3" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition3" - }, + }, "MyFunction5": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunction5Role", + "MyFunction5Role", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition5" - }, + }, "MyFunction6Role": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -386,18 +375,18 @@ } ] } - }, + }, "Condition": "FunctionCondition6" - }, + }, "ServerlessRestApiMyLambdaTokenAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "ServerlessRestApi" @@ -405,67 +394,67 @@ } ] } - }, + }, "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunctionWithNoAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition" - }, + }, "MyFunction6WithDefaultAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction6" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition6" - }, + }, "MyFunction3Role": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -474,64 +463,64 @@ } ] } - }, + }, "Condition": "FunctionCondition3" - }, + }, "MyFunction": { - "Type": "AWS::Lambda::Function", + "Type": "AWS::Lambda::Function", "Properties": { - "Handler": "index.handler", + "Handler": "index.handler", "Code": { - "S3Bucket": "sam-demo-bucket", + "S3Bucket": "sam-demo-bucket", "S3Key": "thumbnails.zip" - }, + }, "Role": { "Fn::GetAtt": [ - "MyFunctionRole", + "MyFunctionRole", "Arn" ] - }, - "Runtime": "nodejs8.10", + }, + "Runtime": "nodejs8.10", "Tags": [ { - "Value": "SAM", + "Value": "SAM", "Key": "lambda:createdBy" } ] - }, + }, "Condition": "FunctionCondition" - }, + }, "MyFunction4WithLambdaTokenAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction4" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PATCH/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition4" - }, + }, "ServerlessRestApiMyLambdaRequestAuthAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "ServerlessRestApi" @@ -539,40 +528,40 @@ } ] } - }, + }, "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunction5WithLambdaRequestAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction5" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition5" - }, + }, "ServerlessRestApiMyLambdaTokenAuthNoneFunctionInvokeRoleAuthorizerPermission": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": "arn:aws", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": "arn:aws", "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/authorizers/*", { "__ApiId__": { "Ref": "ServerlessRestApi" @@ -580,45 +569,45 @@ } ] } - }, + }, "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunctionWithNoAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition" - }, + }, "MyFunctionRole": { - "Type": "AWS::IAM::Role", + "Type": "AWS::IAM::Role", "Properties": { "ManagedPolicyArns": [ "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], + ], "AssumeRolePolicyDocument": { - "Version": "2012-10-17", + "Version": "2012-10-17", "Statement": [ { "Action": [ "sts:AssumeRole" - ], - "Effect": "Allow", + ], + "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" @@ -627,414 +616,433 @@ } ] } - }, + }, "Condition": "FunctionCondition" - }, + }, "MyFunction5WithLambdaRequestAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction5" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/DELETE/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition5" - }, + }, + "ServerlessRestApiDeployment91a6380656": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 91a63806562bbe4a3ad1c14c2444bc7d8d27397c", + "StageName": "Stage" + }, + "Condition": "ServerlessRestApiCondition" + }, "MyFunction3WithLambdaTokenAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction3" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition3" - }, + }, "MyFunction6WithDefaultAuthorizerPermissionProd": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction6" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/PUT/users", { - "__Stage__": "Prod", + "__Stage__": "Prod", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition6" - }, + }, "ServerlessRestApi": { - "Type": "AWS::ApiGateway::RestApi", + "Type": "AWS::ApiGateway::RestApi", "Properties": { "Body": { "info": { - "version": "1.0", + "version": "1.0", "title": { "Ref": "AWS::StackName" } - }, + }, "paths": { "/": { "Fn::If": [ - "FunctionCondition", + "FunctionCondition", { "get": { "Fn::If": [ - "FunctionCondition", + "FunctionCondition", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition", + "FunctionCondition", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ { "NONE": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, { "Ref": "AWS::NoValue" } ] - }, + }, "/users": { "Fn::If": [ - "ServerlessRestApiSLASHusersPathCondition", + "ServerlessRestApiSLASHusersPathCondition", { "put": { "Fn::If": [ - "FunctionCondition6", + "FunctionCondition6", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition6", + "FunctionCondition6", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction6.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ + { + "api_key": [] + }, { "MyCognitoAuth": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] - }, + }, "patch": { "Fn::If": [ - "FunctionCondition4", + "FunctionCondition4", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition4", + "FunctionCondition4", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction4.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ { "MyLambdaTokenAuthNoneFunctionInvokeRole": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] - }, + }, "post": { "Fn::If": [ - "FunctionCondition2", + "FunctionCondition2", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition2", + "FunctionCondition2", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction2.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ { "MyCognitoAuthMultipleUserPools": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] - }, + }, "get": { "Fn::If": [ - "FunctionCondition3", + "FunctionCondition3", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition3", + "FunctionCondition3", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction3.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ { "MyLambdaTokenAuth": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] - }, + }, "delete": { "Fn::If": [ - "FunctionCondition5", + "FunctionCondition5", { "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", + "httpMethod": "POST", + "type": "aws_proxy", "uri": { "Fn::If": [ - "FunctionCondition5", + "FunctionCondition5", { "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction5.Arn}/invocations" - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, "security": [ { "MyLambdaRequestAuth": [] } - ], + ], "responses": {} - }, + }, { "Ref": "AWS::NoValue" } ] } - }, + }, { "Ref": "AWS::NoValue" } ] } - }, - "swagger": "2.0", + }, + "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, "MyLambdaTokenAuthNoneFunctionInvokeRole": { - "in": "header", - "type": "apiKey", - "name": "Authorization", + "in": "header", + "type": "apiKey", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 0, + "type": "token", + "authorizerResultTtlInSeconds": 0, "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] } - }, + }, "x-amazon-apigateway-authtype": "custom" - }, - "MyCognitoAuthMultipleUserPools": { - "in": "header", - "type": "apiKey", - "name": "MyAuthorizationHeader2", - "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", - "providerARNs": [ - "arn:aws:2", - "arn:aws:3" - ], - "type": "cognito_user_pools" - }, - "x-amazon-apigateway-authtype": "cognito_user_pools" - }, - "MyLambdaTokenAuth": { - "in": "header", - "type": "apiKey", - "name": "MyCustomAuthHeader", + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaRequestAuth": { + "in": "header", + "type": "apiKey", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", - "authorizerResultTtlInSeconds": 20, + "type": "request", + "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", - "identityValidationExpression": "mycustomauthexpression" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + }, "x-amazon-apigateway-authtype": "custom" - }, - "MyLambdaRequestAuth": { - "in": "header", - "type": "apiKey", - "name": "Unused", + }, + "MyCognitoAuth": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", + "identityValidationExpression": "myauthvalidationexpression", + "providerARNs": [ + "arn:aws:1" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "MyLambdaTokenAuth": { + "in": "header", + "type": "apiKey", + "name": "MyCustomAuthHeader", + "x-amazon-apigateway-authorizer": { + "type": "token", + "authorizerResultTtlInSeconds": 20, "authorizerUri": { "Fn::Sub": [ - "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": "arn:aws" } ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" - }, + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access", + "identityValidationExpression": "mycustomauthexpression" + }, "x-amazon-apigateway-authtype": "custom" + }, + "MyCognitoAuthMultipleUserPools": { + "in": "header", + "type": "apiKey", + "name": "MyAuthorizationHeader2", + "x-amazon-apigateway-authorizer": { + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" + }, + "x-amazon-apigateway-authtype": "cognito_user_pools" } } - }, + }, "EndpointConfiguration": { "Types": [ "REGIONAL" ] - }, + }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" } - }, + }, "Condition": "ServerlessRestApiCondition" - }, + }, "MyFunction2WithCognitoMultipleUserPoolsAuthorizerPermissionTest": { - "Type": "AWS::Lambda::Permission", + "Type": "AWS::Lambda::Permission", "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", "FunctionName": { "Ref": "MyFunction2" - }, + }, "SourceArn": { "Fn::Sub": [ - "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/users", { - "__Stage__": "*", + "__Stage__": "*", "__ApiId__": { "Ref": "ServerlessRestApi" } } ] } - }, + }, "Condition": "FunctionCondition2" } } -} +} \ No newline at end of file diff --git a/tests/translator/output/cloudwatchevent.json b/tests/translator/output/cloudwatchevent.json index afe566a039..53b58bb37c 100644 --- a/tests/translator/output/cloudwatchevent.json +++ b/tests/translator/output/cloudwatchevent.json @@ -154,7 +154,7 @@ "ScheduledFunctionSchedule": { "Type": "AWS::Events::Rule", "Properties": { - "ScheduleExpression": "rate(1 minute)", + "ScheduleExpression": "rate(1 minute)", "Targets": [ { "Id": "ScheduledFunctionScheduleLambdaTarget", @@ -169,4 +169,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/cloudwatchevent_schedule_properties.json b/tests/translator/output/cloudwatchevent_schedule_properties.json new file mode 100644 index 0000000000..5737fa5e69 --- /dev/null +++ b/tests/translator/output/cloudwatchevent_schedule_properties.json @@ -0,0 +1,175 @@ +{ + "Resources": { + "ScheduledFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "TriggeredFunctionOnTerminatePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "TriggeredFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "TriggeredFunctionOnTerminate", + "Arn" + ] + } + } + }, + "ScheduledFunctionSchedulePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "events.amazonaws.com", + "FunctionName": { + "Ref": "ScheduledFunction" + }, + "SourceArn": { + "Fn::GetAtt": [ + "ScheduledFunctionSchedule", + "Arn" + ] + } + } + }, + "ScheduledFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "ScheduledFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionOnTerminate": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "detail": { + "state": [ + "terminated" + ] + } + }, + "Targets": [ + { + "Id": "TriggeredFunctionOnTerminateLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "TriggeredFunction", + "Arn" + ] + } + } + ] + } + }, + "TriggeredFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip", + "S3ObjectVersion": "3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO" + }, + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "TriggeredFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "TriggeredFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ScheduledFunctionSchedule": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "Name": "test-schedule", + "Description": "Test Schedule", + "State": "ENABLED", + "Targets": [ + { + "Id": "ScheduledFunctionScheduleLambdaTarget", + "Arn": { + "Fn::GetAtt": [ + "ScheduledFunction", + "Arn" + ] + } + } + ] + } + } + } +} diff --git a/tests/translator/output/error_null_application_id.json b/tests/translator/output/error_null_application_id.json new file mode 100644 index 0000000000..579a684c8f --- /dev/null +++ b/tests/translator/output/error_null_application_id.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [Application] is invalid. Property 'ApplicationId' cannot be blank." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [Application] is invalid. Property 'ApplicationId' cannot be blank." +} \ No newline at end of file diff --git a/tests/translator/output/error_table_primary_key_missing_name.json b/tests/translator/output/error_table_primary_key_missing_name.json new file mode 100644 index 0000000000..de5a712c21 --- /dev/null +++ b/tests/translator/output/error_table_primary_key_missing_name.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [Table] is invalid. 'PrimaryKey' is missing required Property 'Name' or 'Type'." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [Table] is invalid. 'PrimaryKey' is missing required Property 'Name' or 'Type'." +} \ No newline at end of file diff --git a/tests/translator/output/error_table_primary_key_missing_type.json b/tests/translator/output/error_table_primary_key_missing_type.json new file mode 100644 index 0000000000..de5a712c21 --- /dev/null +++ b/tests/translator/output/error_table_primary_key_missing_type.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [Table] is invalid. 'PrimaryKey' is missing required Property 'Name' or 'Type'." + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [Table] is invalid. 'PrimaryKey' is missing required Property 'Name' or 'Type'." +} \ No newline at end of file diff --git a/tests/translator/output/function_with_conditional_managed_policy.json b/tests/translator/output/function_with_conditional_managed_policy.json new file mode 100644 index 0000000000..a7aacc2839 --- /dev/null +++ b/tests/translator/output/function_with_conditional_managed_policy.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/function_with_conditional_managed_policy_and_ref_no_value.json b/tests/translator/output/function_with_conditional_managed_policy_and_ref_no_value.json new file mode 100644 index 0000000000..056fd49c55 --- /dev/null +++ b/tests/translator/output/function_with_conditional_managed_policy_and_ref_no_value.json @@ -0,0 +1,71 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + { + "Fn::If": [ + "DummyCondition", + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess" + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/function_with_conditional_policy_template.json b/tests/translator/output/function_with_conditional_policy_template.json new file mode 100644 index 0000000000..dd145ce751 --- /dev/null +++ b/tests/translator/output/function_with_conditional_policy_template.json @@ -0,0 +1,126 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue", + "secretsmanager:PutSecretValue", + "secretsmanager:UpdateSecretVersionStage" + ], + "Resource": { + "Fn::Sub": "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*" + }, + "Effect": "Allow", + "Condition": { + "StringEquals": { + "secretsmanager:resource/AllowRotationLambdaArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}", + { + "functionName": "Dummy Function Name" + } + ] + } + } + } + }, + { + "Action": [ + "secretsmanager:GetRandomPassword" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + } + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/function_with_conditional_policy_template_and_ref_no_value.json b/tests/translator/output/function_with_conditional_policy_template_and_ref_no_value.json new file mode 100644 index 0000000000..2d6b987c25 --- /dev/null +++ b/tests/translator/output/function_with_conditional_policy_template_and_ref_no_value.json @@ -0,0 +1,91 @@ +{ + "Conditions": { + "DummyCondition": { + "Fn::Equals": [ + "", + "" + ] + } + }, + "Resources": { + "FunctionWithConditionalPolicy": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "hello.zip" + }, + "Description": "A function that has Fn::If in the policies property", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Handler": "hello.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionWithConditionalPolicyRole", + "Arn" + ] + }, + "Runtime": "python2.7" + } + }, + "FunctionWithConditionalPolicyRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Policies": [ + { + "Fn::If": [ + "DummyCondition", + { + "PolicyName": "FunctionWithConditionalPolicyRolePolicy0", + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:GetSecretValue" + ], + "Resource": { + "Fn::Sub": [ + "${secretArn}", + { + "secretArn": "Dummy Secret Arn" + } + ] + }, + "Effect": "Allow" + } + ] + } + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/function_with_sns_event_source_all_parameters.json b/tests/translator/output/function_with_sns_event_source_all_parameters.json index fb74655888..698eb00559 100644 --- a/tests/translator/output/function_with_sns_event_source_all_parameters.json +++ b/tests/translator/output/function_with_sns_event_source_all_parameters.json @@ -33,7 +33,8 @@ ] }, "Protocol": "lambda", - "TopicArn": "topicArn" + "TopicArn": "topicArn", + "Region": "region" } }, "MyAwesomeFunctionNotificationTopicPermission": { diff --git a/tests/translator/output/globals_for_api.json b/tests/translator/output/globals_for_api.json index 13abe41971..23bbf1472d 100644 --- a/tests/translator/output/globals_for_api.json +++ b/tests/translator/output/globals_for_api.json @@ -68,6 +68,16 @@ } } }, + "ServerlessRestApiDeploymentaa32438b68": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: aa32438b68e05d3771a975585dfbc7b012672b55", + "StageName": "Stage" + } + }, "ExplicitApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -91,6 +101,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -115,6 +128,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, @@ -134,20 +152,10 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentdb4b9da82a" + "Ref": "ServerlessRestApiDeploymentaa32438b68" } } }, - "ServerlessRestApiDeploymentdb4b9da82a": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: db4b9da82adc6031fcd32bf3a4954485464fc009", - "StageName": "Stage" - } - }, "ExplicitApiSomeStageStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -161,10 +169,20 @@ }, "CacheClusterEnabled": true, "DeploymentId": { - "Ref": "ExplicitApiDeploymentd5fa0145e9" + "Ref": "ExplicitApiDeployment43e01e673d" } } }, + "ExplicitApiDeployment43e01e673d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 43e01e673d7acbd09e4c38ff78dd6ddaf2ed1d55", + "StageName": "Stage" + } + }, "ImplicitApiFunctionGetHtmlPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -186,16 +204,6 @@ } } }, - "ExplicitApiDeploymentd5fa0145e9": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: d5fa0145e9e6393911d32967e66fd7091d605483", - "StageName": "Stage" - } - }, "MyUserPool": { "Type": "AWS::Cognito::UserPool", "Properties": { @@ -240,6 +248,9 @@ "security": [ { "MyCognitoAuth": [] + }, + { + "api_key": [] } ], "responses": {} @@ -264,6 +275,11 @@ "type": "cognito_user_pools" }, "x-amazon-apigateway-authtype": "cognito_user_pools" + }, + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" } } }, diff --git a/tests/translator/output/implicit_api_with_auth_and_conditions_max.json b/tests/translator/output/implicit_api_with_auth_and_conditions_max.json index a3e2433541..28dc23d353 100644 --- a/tests/translator/output/implicit_api_with_auth_and_conditions_max.json +++ b/tests/translator/output/implicit_api_with_auth_and_conditions_max.json @@ -223,7 +223,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeploymente09cc405ab" + "Ref": "ServerlessRestApiDeploymentcbc79073ff" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -282,6 +282,17 @@ }, "Condition": "FunctionCondition2" }, + "ServerlessRestApiDeploymentcbc79073ff": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: cbc79073ff900d53c3f67ea223640210914a672c", + "StageName": "Stage" + }, + "Condition": "ServerlessRestApiCondition" + }, "MyFunction4Role": { "Type": "AWS::IAM::Role", "Properties": { @@ -685,17 +696,6 @@ }, "Condition": "FunctionCondition6" }, - "ServerlessRestApiDeploymente09cc405ab": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: e09cc405abe09a0afb9e5f0cb2e94cfba98767d5", - "StageName": "Stage" - }, - "Condition": "ServerlessRestApiCondition" - }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -772,6 +772,9 @@ } }, "security": [ + { + "api_key": [] + }, { "MyCognitoAuth": [] } @@ -916,26 +919,37 @@ }, "swagger": "2.0", "securityDefinitions": { - "MyCognitoAuth": { + "MyLambdaTokenAuthNoneFunctionInvokeRole": { "in": "header", "type": "apiKey", - "name": "MyAuthorizationHeader", + "name": "Authorization", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression", - "providerARNs": [ - "arn:aws:1" - ], - "type": "cognito_user_pools" + "type": "token", + "authorizerResultTtlInSeconds": 0, + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": "arn:aws" + } + ] + } }, - "x-amazon-apigateway-authtype": "cognito_user_pools" + "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaTokenAuthNoneFunctionInvokeRole": { + "api_key": { + "type": "apiKey", + "name": "x-api-key", + "in": "header" + }, + "MyLambdaRequestAuth": { "in": "header", "type": "apiKey", - "name": "Authorization", + "name": "Unused", "x-amazon-apigateway-authorizer": { - "type": "token", + "type": "request", "authorizerResultTtlInSeconds": 0, + "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", "authorizerUri": { "Fn::Sub": [ "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", @@ -943,19 +957,19 @@ "__FunctionArn__": "arn:aws" } ] - } + }, + "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" }, "x-amazon-apigateway-authtype": "custom" }, - "MyCognitoAuthMultipleUserPools": { + "MyCognitoAuth": { "in": "header", "type": "apiKey", - "name": "MyAuthorizationHeader2", + "name": "MyAuthorizationHeader", "x-amazon-apigateway-authorizer": { - "identityValidationExpression": "myauthvalidationexpression2", + "identityValidationExpression": "myauthvalidationexpression", "providerARNs": [ - "arn:aws:2", - "arn:aws:3" + "arn:aws:1" ], "type": "cognito_user_pools" }, @@ -981,25 +995,19 @@ }, "x-amazon-apigateway-authtype": "custom" }, - "MyLambdaRequestAuth": { + "MyCognitoAuthMultipleUserPools": { "in": "header", "type": "apiKey", - "name": "Unused", + "name": "MyAuthorizationHeader2", "x-amazon-apigateway-authorizer": { - "type": "request", - "authorizerResultTtlInSeconds": 0, - "identitySource": "method.request.header.Authorization1, method.request.querystring.Authorization2, stageVariables.Authorization3, context.Authorization4", - "authorizerUri": { - "Fn::Sub": [ - "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", - { - "__FunctionArn__": "arn:aws" - } - ] - }, - "authorizerCredentials": "arn:aws:iam::123456789012:role/S3Access" + "identityValidationExpression": "myauthvalidationexpression2", + "providerARNs": [ + "arn:aws:2", + "arn:aws:3" + ], + "type": "cognito_user_pools" }, - "x-amazon-apigateway-authtype": "custom" + "x-amazon-apigateway-authtype": "cognito_user_pools" } } } @@ -1029,4 +1037,4 @@ "Condition": "FunctionCondition2" } } -} +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 89402cfbfd..532578da30 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -1,6 +1,4 @@ import json -import cfnlint.core -from cfnlint import Runner import itertools import os.path import hashlib @@ -36,21 +34,6 @@ INPUT_FOLDER = os.path.join(BASE_PATH, 'input') OUTPUT_FOLDER = os.path.join(BASE_PATH, 'output') -LINT_IGNORE_WARNINGS = [ - 'W2001', # unused parameters. Sometimes, SAM uses parameters and removes the param reference from the output template, but the parameter stays in the parameters section. - 'W1001', # Ref/GetAtt with conditions. This incorrectly flags resources since it can't map conditions fully. - 'E3001', # Check for resource availability in a region. - 'W7001', # Check if mappings are used. Serverless::Application uses mappings, the output CFN doesn't use them anymore. - 'W1020', # Sub isn't needed if it doesn't have a variable defined. SAM leaves `!Sub` in even if it tries to resolve variables. - 'E2531', # we don't care if a runtime has been deprecated in our tests. - 'E3038', # Serverless resources- test for invalid resources. -] - -LINT_IGNORE_TESTS = [ - 'function_with_resource_refs', # Tests functionality of the translator in ways that result in improper GetAtt calls on CFN resources. - 'api_with_canary_setting', # Has stage variable overrides for nonexistent stage variables. -] - def deep_sort_lists(value): """ @@ -162,6 +145,7 @@ class TestTranslatorEndToEnd(TestCase): 'application_with_intrinsics', 'basic_layer', 'cloudwatchevent', + 'cloudwatchevent_schedule_properties', 'cloudwatch_logs_with_ref', 'cloudwatchlog', 'streams', @@ -201,6 +185,10 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_canary_setting', 'api_with_xray_tracing', 'api_request_model', + 'api_with_stage_tags', + 'api_with_resource_policy', + 'api_with_resource_policy_global', + 'api_with_resource_policy_global_implicit', 's3', 's3_create_remove', 's3_existing_lambda_notification_configuration', @@ -243,6 +231,10 @@ class TestTranslatorEndToEnd(TestCase): 'function_with_permissions_boundary', 'function_with_policy_templates', 'function_with_sns_event_source_all_parameters', + 'function_with_conditional_managed_policy', + 'function_with_conditional_managed_policy_and_ref_no_value', + 'function_with_conditional_policy_template', + 'function_with_conditional_policy_template_and_ref_no_value', 'global_handle_path_level_parameter', 'globals_for_function', 'globals_for_api', @@ -260,6 +252,9 @@ class TestTranslatorEndToEnd(TestCase): 'implicit_and_explicit_api_with_conditions', 'api_with_cors_and_conditions_no_definitionbody', 'api_with_auth_and_conditions_all_max', + 'api_with_apikey_default_override', + 'api_with_apikey_required', + 'api_with_path_parameters', ], [ ("aws", "ap-southeast-1"), @@ -296,29 +291,12 @@ def test_transform_success(self, testcase, partition_with_region): print(json.dumps(output_fragment, indent=2)) - # Run cfn-lint on translator test output files. - rules = cfnlint.core.get_rules([], LINT_IGNORE_WARNINGS, []) - # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: self._update_logical_id_hash(expected) self._update_logical_id_hash(output_fragment) - output_template = cfnlint.decode.cfn_json.load(expected_filepath) - else: # deprecation warning catching in py2 - import warnings - with warnings.catch_warnings(): - warnings.filterwarnings("ignore",category=DeprecationWarning) - output_template = cfnlint.decode.cfn_json.load(expected_filepath) - runner = cfnlint.Runner(rules, expected_filepath, output_template, [region]) - matches = [] - - # Only run linter on normal/gov partitions. It errors on china regions - if testcase not in LINT_IGNORE_TESTS and partition != 'aws-cn': - matches = runner.run() - print('cfn-lint ({}): {}'.format(expected_filepath, matches)) assert deep_sort_lists(output_fragment) == deep_sort_lists(expected) - assert len(matches) == 0 @parameterized.expand( itertools.product([ @@ -331,7 +309,8 @@ def test_transform_success(self, testcase, partition_with_region): 'api_with_auth_all_minimum_openapi', 'api_with_swagger_and_openapi_with_auth', 'api_with_openapi_definition_body_no_flag', - 'api_request_model_openapi_3' + 'api_request_model_openapi_3', + 'api_with_apikey_required_openapi_3' ], [ ("aws", "ap-southeast-1"), @@ -368,29 +347,12 @@ def test_transform_success_openapi3(self, testcase, partition_with_region): print(json.dumps(output_fragment, indent=2)) - # Run cfn-lint on translator test output files. - rules = cfnlint.core.get_rules([], LINT_IGNORE_WARNINGS, []) - # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: self._update_logical_id_hash(expected) self._update_logical_id_hash(output_fragment) - output_template = cfnlint.decode.cfn_json.load(expected_filepath) - else: # deprecation warning catching in py2 - import warnings - with warnings.catch_warnings(): - warnings.filterwarnings("ignore",category=DeprecationWarning) - output_template = cfnlint.decode.cfn_json.load(expected_filepath) - runner = cfnlint.Runner(rules, expected_filepath, output_template, [region]) - matches = [] - - # Only run linter on normal/gov partitions. It errors on china regions - if testcase not in LINT_IGNORE_TESTS and partition != 'aws-cn': - matches = runner.run() - print('cfn-lint ({}): {}'.format(expected_filepath, matches)) assert deep_sort_lists(output_fragment) == deep_sort_lists(expected) - assert len(matches) == 0 def _update_logical_id_hash(self, resources): """ @@ -500,8 +462,11 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw 'error_missing_startingposition', 'error_missing_stream', 'error_multiple_resource_errors', + 'error_null_application_id', 'error_s3_not_in_template', 'error_table_invalid_attributetype', + 'error_table_primary_key_missing_name', + 'error_table_primary_key_missing_type', 'error_invalid_resource_parameters', 'error_reserved_sam_tag', 'existing_event_logical_id', diff --git a/versions/2016-10-31.md b/versions/2016-10-31.md index 9493abadee..6078ab8366 100644 --- a/versions/2016-10-31.md +++ b/versions/2016-10-31.md @@ -196,7 +196,7 @@ Events: PhotoUpload: Type: S3 Properties: - Bucket: my-photo-bucket + Bucket: my-photo-bucket # bucket must be created in the same template Tags: AppNameTag: ThumbnailApp DepartmentNameTag: ThumbnailDepartment @@ -221,12 +221,13 @@ DefinitionBody | `JSON or YAML Object` | Swagger specification that describes yo CacheClusterEnabled | `boolean` | Indicates whether cache clustering is enabled for the stage. CacheClusterSize | `string` | The stage's cache cluster size. Variables | Map of `string` to `string` | A map (string to string map) that defines the stage variables, where the variable name is the key and the variable value is the value. Variable names are limited to alphanumeric characters. Values must match the following regular expression: `[A-Za-z0-9._~:/?#&=,-]+`. -MethodSettings | [CloudFormation MethodSettings property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-stage-methodsetting.html) | Configures all settings for API stage including Logging, Metrics, CacheTTL, Throttling. This value is passed through to CloudFormation. So any values supported by CloudFormation ``MethodSettings`` property can be used here. +MethodSettings | [CloudFormation MethodSettings property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apitgateway-stage-methodsetting.html) | Configures all settings for API stage including Logging, Metrics, CacheTTL, Throttling. This value is passed through to CloudFormation. So any values supported by CloudFormation ``MethodSettings`` property can be used here. +Tags | Map of `string` to `string` | A map (string to string) that specifies the tags to be added to this API Stage. Keys and values are limited to alphanumeric characters. EndpointConfiguration | `string` | Specify the type of endpoint for API endpoint. Value is either `REGIONAL`, `EDGE`, or `PRIVATE`. BinaryMediaTypes | List of `string` | List of MIME types that your API could return. Use this to enable binary support for APIs. Use `~1` instead of `/` in the mime types (See examples in [template.yaml](../examples/2016-10-31/implicit_api_settings/template.yaml)). MinimumCompressionSize | `int` | Allow compression of response bodies based on client's Accept-Encoding header. Compression is triggered when response body size is greater than or equal to your configured threshold. The maximum body size threshold is 10 MB (10,485,760 Bytes). The following compression types are supported: gzip, deflate, and identity. Cors | `string` or [Cors Configuration](#cors-configuration) | Enable CORS for all your APIs. Specify the domain to allow as a string or specify a dictionary with additional [Cors Configuration](#cors-configuration). NOTE: Cors requires SAM to modify your Swagger definition. Hence it works only inline swagger defined with `DefinitionBody`. -Auth | [API Auth Object](#api-auth-object) | Auth configuration for this API. Define Lambda and Cognito `Authorizers` and specify a `DefaultAuthorizer` for this API. +Auth | [API Auth Object](#api-auth-object) | Auth configuration for this API. Define Lambda and Cognito `Authorizers` and specify a `DefaultAuthorizer` for this API. Can specify default ApiKey restriction using `ApiKeyRequired`. GatewayResponses | Map of [Gateway Response Type](https://docs.aws.amazon.com/apigateway/api-reference/resource/gateway-response/) to [Gateway Response Object](#gateway-response-object) | Configures Gateway Reponses for an API. Gateway Responses are responses returned by API Gateway, either directly or through the use of Lambda Authorizers. Keys for this object are passed through to Api Gateway, so any value supported by `GatewayResponse.responseType` is supported here. AccessLogSetting | [CloudFormation AccessLogSetting property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-stage-accesslogsetting.html) | Configures Access Log Setting for a stage. This value is passed through to CloudFormation, so any value supported by `AccessLogSetting` is supported here. CanarySetting | [CloudFormation CanarySetting property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-stage-canarysetting.html) | Configure a Canary Setting to a Stage of a regular deployment. This value is passed through to Cloudformation, so any value supported by `CanarySetting` is supported here. @@ -408,7 +409,7 @@ NOTE: To specify an S3 bucket as an event source for a Lambda function, both res ```yaml Type: S3 Properties: - Bucket: my-photo-bucket + Bucket: my-photo-bucket # bucket must be created in the same template Events: s3:ObjectCreated:* Filter: S3Key: @@ -426,6 +427,7 @@ The object describing an event source with type `SNS`. Property Name | Type | Description ---|:---:|--- Topic | `string` | **Required.** Topic ARN. +Region | `string` | Region. FilterPolicy | [Amazon SNS filter policy](https://docs.aws.amazon.com/sns/latest/dg/message-filtering.html) | Policy assigned to the topic subscription in order to receive only a subset of the messages. ##### Example: SNS event source object @@ -526,7 +528,7 @@ Property Name | Type | Description Path | `string` | **Required.** Uri path for which this function is invoked. MUST start with `/`. Method | `string` | **Required.** HTTP method for which this function is invoked. RestApiId | `string` | Identifier of a RestApi resource which MUST contain an operation with the given path and method. Typically, this is set to [reference](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) an `AWS::Serverless::Api` resource defined in this template. If not defined, a default `AWS::Serverless::Api` resource is created using a generated Swagger document contains a union of all paths and methods defined by `Api` events defined in this template that do not specify a RestApiId. -Auth | [Function Auth Object](#function-auth-object) | Auth configuration for this specific Api+Path+Method. Useful for overriding the API's `DefaultAuthorizer` or setting auth config on an individual path when no `DefaultAuthorizer` is specified. +Auth | [Function Auth Object](#function-auth-object) | Auth configuration for this specific Api+Path+Method. Useful for overriding the API's `DefaultAuthorizer` setting auth config on an individual path when no `DefaultAuthorizer` is specified or overriding the default `ApiKeyRequired' setting. RequestModel | [Function Request Model Object](#function-request-model-object) | Request model configuration for this specific Api+Path+Method. ##### Example: Api event source object @@ -548,6 +550,9 @@ Property Name | Type | Description ---|:---:|--- Schedule | `string` | **Required.** Schedule expression, which MUST follow the [schedule expression syntax rules](http://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html). Input | `string` | JSON-formatted string to pass to the function as the event body. +Name | `string` | A name for the Schedule. If you don't specify a name, a unique name will be generated. +Description | `string` | Description of Schedule. +Enabled | `boolean` | Indicated whether the Schedule is enabled. ##### Example: Schedule event source object @@ -555,6 +560,9 @@ Input | `string` | JSON-formatted string to pass to the function as the event bo Type: Schedule Properties: Schedule: rate(5 minutes) + Name: my-schedule + Description: Example schedule + Enabled: True ``` #### CloudWatchEvent @@ -656,7 +664,7 @@ The object describing the source of events which trigger the function. Property Name | Type | Description ---|:---:|--- -Type | `string` | **Required.** Event type. Event source types include '[S3](#s3), '[Api](#api)', '[SNS](#sns)', '[Kinesis](#kinesis)', '[DynamoDB](#dynamodb)'. For more information about all types, see [Event source types](#event-source-types). +Type | `string` | **Required.** Event type. Event source types include '[S3](#s3), '[SNS](#sns)', '[Kinesis](#kinesis)', '[DynamoDB](#dynamodb)', '[SQS](#sqs)', '[Api](#api)', '[Schedule](#schedule)', '[CloudWatchEvent](#cloudwatchevent)', '[CloudWatchLogs](#cloudwatchlogs)', '[IoTRule](#iotrule)', '[AlexaSkill](#alexaskill)'. For more information about the types, see [Event source types](#event-source-types). Properties | * | **Required.** Object describing properties of this event mapping. Must conform to the defined `Type`. For more information about all types, see [Event source types](#event-source-types). ##### Example: Event source object @@ -664,7 +672,7 @@ Properties | * | **Required.** Object describing properties of this event mappin ```yaml Type: S3 Properties: - Bucket: my-photo-bucket + Bucket: my-photo-bucket # bucket must be created in the same template ``` ```yaml @@ -781,11 +789,18 @@ Cors: #### API Auth Object -Configure Auth on APIs. Define Lambda and Cognito `Authorizers` and specify a `DefaultAuthorizer`. If you use IAM permission, only specify `AWS_IAM` to a `DefaultAuthorizer`. For more information, see the documentation on [Lambda Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) and [Amazon Cognito User Pool Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html) and [IAM Permissions](https://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html). +Configure Auth on APIs. + +**Authorizers:** +Define Lambda and Cognito `Authorizers` and specify a `DefaultAuthorizer`. If you use IAM permission, only specify `AWS_IAM` to a `DefaultAuthorizer`. For more information, see the documentation on [Lambda Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) and [Amazon Cognito User Pool Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html) and [IAM Permissions](https://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html). ```yaml Auth: + ApiKeyRequired: true # OPTIONAL DefaultAuthorizer: MyCognitoAuth # OPTIONAL, if you use IAM permissions, specify AWS_IAM. + # For AWS_IAM: + # DefaultAuthorizer: AWS_IAM + # InvokeRole: NONE # CALLER_CREDENTIALS by default unless overridden Authorizers: MyCognitoAuth: UserPoolArn: !GetAtt MyCognitoUserPool.Arn # Can also accept an array @@ -819,6 +834,15 @@ Auth: ReauthorizeEvery: 0 # OPTIONAL; Service Default: 300 ``` +**ApiKey:** +Configure ApiKey restriction for all methods and paths on an API. This setting can be overriden on individual `AWS::Serverless::Function` using the [Function Auth Object](#function-auth-object). Typically this would be used to require ApiKey on all methods and then override it on select methods that you want to be public. + +```yaml +Auth: + ApiKeyRequired: true +``` + + #### Function Auth Object Configure Auth for a specific Api+Path+Method. @@ -835,6 +859,20 @@ Auth: Authorizer: 'NONE' ``` +Require api keys for a specific Api+Path+Method. + +```yaml +Auth: + ApiKeyRequired: true +``` + +If you have specified `ApiKeyRequired: true` globally on the API and want to make a specific Function public, override with the following: + +```yaml +Auth: + ApiKeyRequired: false +``` + #### Function Request Model Object Configure Request Model for a specific Api+Path+Method.