AWSTemplateFormatVersion: '2010-09-09' Description: This creates resources in one account. Parameters: NetworkFabricType: Type: String AllowedValues: - NONE - TRANSIT_GATEWAY Description: Select if you want Refactor Spaces to provision a network bridge (Transit Gateway) to establish cross account/VPC network connectivity. Default: NONE Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.2.0.0/16 Tags: - Key: Name Value: VpcForRefactorSpaces PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 0, !GetAZs '' ] CidrBlock: 10.2.1.0/24 MapPublicIpOnLaunch: false Tags: - Key: Name Value: Refactor Spaces Private Subnet (AZ1) PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 1, !GetAZs '' ] CidrBlock: 10.2.2.0/24 MapPublicIpOnLaunch: false Tags: - Key: Name Value: Refactor Spaces Private Subnet (AZ2) PrivateSubnet3: # Creates a subnet in the VPC Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [ 2, !GetAZs '' ] CidrBlock: 10.2.3.0/24 MapPublicIpOnLaunch: false Tags: - Key: Name Value: Refactor Spaces Private Subnet (AZ3) RefactorSpacesTestEnvironment: Type: AWS::RefactorSpaces::Environment DeletionPolicy: Delete Properties: Name: EnvWithMultiAccountServices NetworkFabricType: !Ref NetworkFabricType Description: "This is a test environment" TestApplication: Type: AWS::RefactorSpaces::Application DeletionPolicy: Delete DependsOn: - PrivateSubnet1 - PrivateSubnet2 Properties: Name: proxytest EnvironmentIdentifier: !Ref RefactorSpacesTestEnvironment VpcId: !Ref VPC ProxyType: API_GATEWAY ApiGatewayProxy: EndpointType: "REGIONAL" StageName: "admintest" AdminAccountService: Type: AWS::RefactorSpaces::Service DeletionPolicy: Delete Properties: Name: AdminAccountService EnvironmentIdentifier: !Ref RefactorSpacesTestEnvironment ApplicationIdentifier: !GetAtt TestApplication.ApplicationIdentifier EndpointType: URL VpcId: !Ref VPC UrlEndpoint: Url: "http://aws.amazon.com" RefactorSpacesDefaultRoute: Type: AWS::RefactorSpaces::Route Properties: RouteType: "DEFAULT" EnvironmentIdentifier: !Ref RefactorSpacesTestEnvironment ApplicationIdentifier: !GetAtt TestApplication.ApplicationIdentifier ServiceIdentifier: !GetAtt AdminAccountService.ServiceIdentifier DefaultRoute: ActivationState: ACTIVE RefactorSpacesURIRoute: Type: AWS::RefactorSpaces::Route DependsOn: 'RefactorSpacesDefaultRoute' Properties: RouteType: "URI_PATH" EnvironmentIdentifier: !Ref RefactorSpacesTestEnvironment ApplicationIdentifier: !GetAtt TestApplication.ApplicationIdentifier ServiceIdentifier: !GetAtt AdminAccountService.ServiceIdentifier UriPathRoute: SourcePath: "/cfn-created-route" ActivationState: ACTIVE Methods: [ "GET" ] CloudWatchLogsRoleForAPI: #Creates an IAM role which grants API Gateway permission to read and write logs to CloudWatch for your account Type: AWS::IAM::Role Properties: RoleName: API-Role-For-Logging-To-CloudWatch AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: apigateway.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs SetRoleforAPICloudWatchLogs: #Specifies the IAM role (created above) that API Gateway will use to write API logs to CloudWatch Logs Type: 'AWS::ApiGateway::Account' DependsOn: 'CloudWatchLogsRoleForAPI' Properties: CloudWatchRoleArn: !GetAtt - CloudWatchLogsRoleForAPI - Arn CloudWatchLogsLogGroup: # Creates Log Group for CloudWatch API Access Logs Type: AWS::Logs::LogGroup Properties: LogGroupName: myapiaccesslogs ApiGatewayStageLogging: # Custom resource to enable access logging for the API Gateway stage. The lambda function specified in ServiceToken is invoked whenever the custom resource is created, updated, or deleted. Type: AWS::CloudFormation::CustomResource Properties: #These values will be passed to the Lambda function ServiceToken: !GetAtt MyLambdaFunction.Arn RestApiId: !GetAtt TestApplication.ApiGatewayId StageName: !GetAtt TestApplication.StageName LoggingLevel: 'INFO' #Specifies the logging level. Possible values: OFF, ERROR, or INFO MetricsEnabled: true #Specifies whether Amazon CloudWatch metrics are enabled for this method. Possible values: true, false LoggingArn: #Specifies the Arn of the CloudWatch logs group that was created. The select and split are needed to format the arn correctly. Fn::Select: - 0 - Fn::Split: - ":*" - !GetAtt CloudWatchLogsLogGroup.Arn LogFormat: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "user": "$context.identity.user", "method": "$context.httpMethod", "path": "$context.resourcePath", "status": "$context.status", "latency": "$context.latency", "integrationError": "$context.integrationErrorMessage" }' #Specifies the format of the access logs MyLambdaFunction: #Lambda function which updates the Refactor Spaces API stage to enable execution and access logging Type: AWS::Lambda::Function DependsOn: 'RefactorSpacesURIRoute' Properties: Code: ZipFile: | import json import boto3 import cfnresponse import botocore.exceptions def lambda_handler(event, context): api_gateway = boto3.client('apigateway') stage_name = event['ResourceProperties']['StageName'] logging_level = event['ResourceProperties']['LoggingLevel'] metrics_enabled = event['ResourceProperties']['MetricsEnabled'] rest_api_id = event['ResourceProperties']['RestApiId'] logging_arn = event['ResourceProperties']['LoggingArn'] log_format = event['ResourceProperties']['LogFormat'] try: response = api_gateway.update_stage( restApiId=rest_api_id, stageName=stage_name, patchOperations=[ { 'op': 'replace', 'path': '/accessLogSettings/destinationArn', 'value': logging_arn }, { 'op': 'replace', 'path': '/accessLogSettings/format', 'value': log_format }, { 'op': 'replace', 'path': '/*/*/metrics/enabled', 'value': metrics_enabled }, { 'op': 'replace', 'path': '/*/*/logging/loglevel', 'value': logging_level } ] ) except botocore.exceptions.ClientError as e: print(e.response['Error']['Message']) cfnresponse.send(event, context, cfnresponse.FAILED, responseData={"message": "Update stage failed"}) else: cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={"message": "Update stage succeeded"}) Handler: index.lambda_handler Role: !GetAtt MyLambdaExecutionRole.Arn Runtime: python3.8 Timeout: 120 MyLambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: AccessAPIGateway PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - apigateway:PATCH Resource: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${TestApplication.ApiGatewayId}/stages/${TestApplication.StageName}"