SpeedPizzaのインフラ

# インフラ
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73237/d7b9e841-0815-ba98-e2af-144af6baaeb5.png)

## Frontend(SSR)
CloudFront → ApiGateway → Lambda(nuxt)

### deploy
- CloudFormation
- CodePipeline
- ServerlessFramework

![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73237/441330a9-96c1-734b-937a-668c3377f0cc.png)

```yaml:template.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: serverless framework deploy pipeline example
Parameters:
  ServiceName:
    Description: serverless framework deploy pipeline example
    Type: String
    Default: serverless-deploy-example
  Env:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - prod
  GithubOwner:
    Type: String
    Description: The github owner or org name of the repository.
  GithubRepoName:
    Type: String
    Description: The name of the github repository.
  GithubRepoSecretId:
    Type: String
    Default: speed_pizza/GithubRepoAccess
    Description: The name/ID of the SecretsManager secret that contains the personal access token for the github repo.
  GithubRepoSecretJSONKey:
    Type: String
    Default: OAuthToken
    Description: The name of the JSON key in the SecretsManager secret that contains the personal access token for the github repo.

Mappings:
  EnvParams:
    dev:
      GitBranchName: develop
    prod:
      GitBranchName: main

Resources:
  # ビルド成果物を格納するS3バケット
  ArtifactsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${ServiceName}-artifacts-${Env}
      LifecycleConfiguration:
        Rules:
          - Id: DeleteRule
            Status: Enabled
            ExpirationInDays: 7
  # CodeBuild
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub ${ServiceName}-${Env}
      Artifacts:
        Type: CODEPIPELINE
      Source:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/standard:3.0
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: DEPLOY_ENV
            Value: !Sub ${Env}
      ServiceRole: !GetAtt CodeBuildServiceRole.Arn
  # CodeBuildのIAMロール
  CodeBuildServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:
        !Sub ${ServiceName}-CodeBuildServiceRole-${Env}
      Policies:
        - PolicyName: !Sub ${ServiceName}-CodeBuild-ServiceRolePolicy-${Env}
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - logs:DeleteLogGroup
                  - logs:DescribeLogGroups
                Resource:
                  - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}-${Env}:*
                  - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group:/aws/lambda/*
                  - !Sub arn:aws:logs:ap-northeast-1:${AWS::AccountId}:log-group::log-stream:*
                Effect: Allow
              - Action:
                  - codebuild:CreateReportGroup
                  - codebuild:CreateReport
                  - codebuild:UpdateReport
                  - codebuild:BatchPutTestCases
                Resource:
                  - !Sub arn:aws:codebuild:ap-northeast-1:${AWS::AccountId}:project/${ServiceName}-${Env}
                Effect: Allow
              - Action:
                  - s3:CreateBucket
                  - s3:DeleteBucket
                  - s3:PutBucket
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
                  - s3:PutObject
                  - s3:ListBucket
                  - s3:SetBucketEncryption
                  - s3:GetEncryptionConfiguration
                  - s3:PutEncryptionConfiguration
                  - s3:PutBucketPolicy
                  - s3:PutBucketCORS
                  - s3:DeleteBucketPolicy
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - cloudformation:DescribeStackEvents
                  - cloudformation:DescribeStackResources
                  - cloudformation:DescribeStackResource
                  - cloudformation:DescribeStacks
                  - cloudformation:ValidateTemplate
                  - cloudformation:CreateStack
                  - cloudformation:UpdateStack
                  - cloudformation:DeleteStack
                  - cloudformation:ListStackResources
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - iam:CreateRole
                  - iam:DeleteRole
                  - iam:DeleteRolePolicy
                  - iam:PutRolePolicy
                  - iam:GetRole
                  - iam:PassRole
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - apigateway:*
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - lambda:UpdateFunctionCode
                  - lambda:GetFunction
                  - lambda:GetFunctionConfiguration
                  - lambda:CreateFunction
                  - lambda:DeleteFunction
                  - lambda:ListVersionsByFunction
                  - lambda:PublishVersion
                  - lambda:AddPermission
                  - lambda:UpdateFunctionConfiguration
                  - lambda:CreateAlias
                  - lambda:DeleteAlias
                  - lambda:PutProvisionedConcurrencyConfig
                  - lambda:GetProvisionedConcurrencyConfig
                  - lambda:RemovePermission
                  - lambda:UpdateAlias
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - cloudfront:CreateCloudFrontOriginAccessIdentity
                  - cloudfront:DeleteCloudFrontOriginAccessIdentity
                  - cloudfront:GetCloudFrontOriginAccessIdentity
                  - cloudfront:GetCloudFrontOriginAccessIdentityConfig
                  - cloudfront:ListCloudFrontOriginAccessIdentities
                  - cloudfront:UpdateCloudFrontOriginAccessIdentity
                Resource:
                  - '*'
                Effect: Allow
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
  # CodePipeline
  CodePipelineProject:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Name: !Sub ${ServiceName}-${Env}
      RoleArn: !GetAtt CodePipelineServiceRole.Arn
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: ThirdParty
                Version: 1
                Provider: GitHub
              OutputArtifacts:
                - Name: SourceArtifact
              # デプロイもとのCodeCommitのリポジトリとブランチ
              Configuration:
                Owner:
                  !Ref GithubOwner
                Repo:
                  !Ref GithubRepoName
                OAuthToken:
                  !Join
                  - ''
                  - - 'resolve:secretsmanager:'
                    - !Ref GithubRepoSecretId
                    - 'SecretString:'
                    - !Ref GithubRepoSecretJSONKey
                Branch: !FindInMap [EnvParams, !Ref 'Env', GitBranchName]
                PollForSourceChanges: true
              RunOrder: 1
        - Name: Build
          Actions:
            - Name: BuildAction
              InputArtifacts:
                - Name: SourceArtifact
              OutputArtifacts:
                - Name: BuildArtifact
              ActionTypeId:
                Category: Build
                Owner: AWS
                Version: 1
                Provider: CodeBuild
              Configuration:
                ProjectName:
                  !Ref CodeBuildProject
              RunOrder: 2
      ArtifactStore:
        Type: S3
        Location:
          !Ref ArtifactsBucket
    # CodePipelineのIAMロール
  CodePipelineServiceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${ServiceName}-CodePipelineServiceRole-${Env}
      Policies:
        - PolicyName: !Sub ${ServiceName}-CodePipelineServiceRolePolicy-${Env}
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Action:
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:GetBucketVersioning
                  - s3:PutObject
                Resource:
                  - arn:aws:s3:::codepipeline*
                Effect: Allow
              - Action:
                  - codecommit:CancelUploadArchive
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:UploadArchive
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - codebuild:BatchGetBuilds
                  - codebuild:StartBuild
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - codedeploy:CreateDeployment
                  - codedeploy:GetApplication
                  - codedeploy:GetApplicationRevision
                  - codedeploy:GetDeployment
                  - codedeploy:GetDeploymentConfig
                  - codedeploy:RegisterApplicationRevision
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - codestar-connections:UseConnection
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - s3:*
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - cloudfront:CreateCloudFrontOriginAccessIdentity
                Resource:
                  - '*'
                Effect: Allow
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codepipeline.amazonaws.com
            Action:
              - sts:AssumeRole

```
```yaml:buildspec.yaml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 12
    commands:
      - cd speed_pizza
      - npm install
      - cd $CODEBUILD_SRC_DIR
  build:
    commands:
      - cd speed_pizza
      - npm run build:${DEPLOY_ENV}
      - npm run deploy:${DEPLOY_ENV}
      - cd $CODEBUILD_SRC_DIR

```

```yaml:serverless.yml
service: speed-pizza-${opt:stage}

plugins:
  - serverless-s3-sync
  - serverless-apigw-binary
  - serverless-dotenv-plugin
package:
  individually: true
  excludeDevDependencies: true

provider:
  name: aws
  lambdaHashingVersion: 20201221
  runtime: nodejs12.x
  stage: ${opt:stage}
  region: ap-northeast-1
  apiKeys:
    - ${self:custom.apiKey.${self:provider.stage}}

custom:
  #######################################
  # Unique ID included in resource names.
  # Replace it with a random value for every first distribution.
  # https://www.random.org/strings/?num=1&len=6&digits=on&loweralpha=on&unique=on&format=html&rnd=new
  stackId: SpeedPizza-${opt:stage}
  #######################################
  env:
    stg: development
    prod: production

  apiKey:
    stg: UECpdNb9TM2dcBQd2nZi2rXhUYfu9Fks
    prod: UkuLUDnSZR5eBAnUATchpH6KJGQkNuwE

  buckets:
    ASSETS_BUCKET_NAME: ${self:service}-assets
    STATIC_BUCKET_NAME: ${self:service}-static
  s3Sync:
    - bucketName: ${self:custom.buckets.ASSETS_BUCKET_NAME}
      bucketPrefix: _nuxt/
      localDir: .nuxt/dist/client
    - bucketName: ${self:custom.buckets.STATIC_BUCKET_NAME}
      localDir: src/static
  apigwBinary:
    types:
      - '*/*'

functions:
  renderer:
    name: ${self:service}-${self:custom.stackId}-${self:provider.stage}-renderer
    handler: server/lambda.handler
    memorySize: 512
    timeout: 30
    environment:
      NODE_ENV: ${self:custom.env.${self:provider.stage}}
    package:
      include:
        - .nuxt/**
        - server/**
        - node_modules/autoprefixer/**
      exclude:
        - .**
        - .**/*
        - src/**
        - test/*
        - README.md
        - package.json
        - package-lock.json
        - test/*
        - node_modules/babel**/**
        - node_modules/caniuse-db/**
        - node_modules/prettier/**
        - node_modules/yargs/**
        - node_modules/xxhashjs/**
        - node_modules/jschardet/**
        - node_modules/**/*.md
        - node_modules/**/bin/**
        - node_modules/typescript/**
    events:
      - http:
          path: /
          method: any
          private: true
      - http:
          path: /{proxy+}
          method: any
          private: true

resources:
  Resources:
    ClientAssetsBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.buckets.ASSETS_BUCKET_NAME}
    ClientAssetsBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket:
          Ref: ClientAssetsBucket
        PolicyDocument:
          Version: '2012-10-17'
          Statement: [
            {
              Action: [ 's3:GetObject' ],
              Effect: 'Allow',
              Resource: {
                Fn::Join: [ '', [ 'arn:aws:s3:::', { Ref: 'ClientAssetsBucket' }, '/*' ] ],
              },
              Principal: '*'
            }
          ]
    ClientStaticBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.buckets.STATIC_BUCKET_NAME}
    ClientStaticBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket:
          Ref: ClientStaticBucket
        PolicyDocument:
          Version: '2012-10-17'
          Statement: [
            {
              Action: [ 's3:GetObject' ],
              Effect: 'Allow',
              Resource: {
                Fn::Join: [ '', [ 'arn:aws:s3:::', { Ref: 'ClientStaticBucket' }, '/*' ] ],
              },
              Principal: '*'
            },
          ]
```

## Backend
CloudFront → ApiGateway → Lambda(chalice)

### deploy
- CloudFormation
- CodePipeline
- Chalice

![Untitled Diagram (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73237/c618d6f1-d0af-8227-1236-ce148f15a027.png)

```json:pipeline.json
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "ApplicationName": {
      "Default": "SpeedPizzaApi",
      "Type": "String",
      "Description": "Enter the name of your application"
    },
    "CodeBuildImage": {
      "Default": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
      "Type": "String",
      "Description": "Name of codebuild image to use."
    },
    "GithubOwner": {
      "Type": "String",
      "Description": "The github owner or org name of the repository."
    },
    "GithubRepoName": {
      "Type": "String",
      "Description": "The name of the github repository."
    },
    "GithubRepoSecretId": {
      "Type": "String",
      "Default": "speed_pizza/GithubRepoAccess",
      "Description": "The name/ID of the SecretsManager secret that contains the personal access token for the github repo."
    },
    "GithubRepoSecretJSONKey": {
      "Type": "String",
      "Default": "OAuthToken",
      "Description": "The name of the JSON key in the SecretsManager secret that contains the personal access token for the github repo."
    },
    "Env": {
      "Description": "System Environment",
      "AllowedValues": [
        "stg",
        "prod"
      ],
      "Type": "String"
    }
  },
  "Conditions": {
    "IsProduction": {
      "Fn::Equals": [
        {
          "Ref": "Env"
        },
        "prod"
      ]
    },
    "IsStaging": {
      "Fn::Equals": [
        {
          "Ref": "Env"
        },
        "stg"
      ]
    }
  },
  "Mappings": {
    "EnvParams": {
      "stg": {
        "TableName": "pizza-stg",
        "OgpBucketName": "speed-pizza-stg",
        "ApplicationBucketName": "speed-pizza-application-bucket-stg",
        "GitBranchName": "stg",
        "ArtifactBucketName": "speed-pizza-artifact-bucket-store-stg",
        "LambdaRoleName": "SpeedPizzaStg"
      },
      "prod": {
        "TableName": "pizza",
        "OgpBucketName": "speed-pizza-prod",
        "ApplicationBucketName": "speed-pizza-application-bucket-prod",
        "GitBranchName": "main",
        "ArtifactBucketName": "speed-pizza-artifact-bucket-store-prod",
        "LambdaRoleName": "SpeedPizzaProd"
      }
    }
  },
  "Resources": {
    "ApplicationTable": {
      "Type": "AWS::DynamoDB::Table",
      "Properties": {
        "TableName": {
          "Fn::FindInMap": [
            "EnvParams",
            {
              "Ref": "Env"
            },
            "TableName"
          ]
        },
        "AttributeDefinitions": [
          {
            "AttributeName": "id",
            "AttributeType": "S"
          },
          {
            "AttributeName": "created_year",
            "AttributeType": "N"
          },
          {
            "AttributeName": "created_at",
            "AttributeType": "S"
          }
        ],
        "KeySchema": [
          {
            "AttributeName": "id",
            "KeyType": "HASH"
          }
        ],
        "GlobalSecondaryIndexes": [
          {
            "IndexName": "created_at_index",
            "KeySchema": [
              {
                "AttributeName": "created_year",
                "KeyType": "HASH"
              },
              {
                "AttributeName": "created_at",
                "KeyType": "RANGE"
              }
            ],
            "Projection": {
              "ProjectionType": "ALL"
            }
          }
        ],
        "BillingMode": "PAY_PER_REQUEST"
      }
    },
    "OgpBucket": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": {
          "Fn::FindInMap": [
            "EnvParams",
            {
              "Ref": "Env"
            },
            "OgpBucketName"
          ]
        }
      }
    },
    "ApplicationBucket": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": {
          "Fn::FindInMap": [
            "EnvParams",
            {
              "Ref": "Env"
            },
            "ApplicationBucketName"
          ]
        }
      }
    },
    "CodeBuildRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  {
                    "Fn::Sub": "codebuild.${AWS::URLSuffix}"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    "CodeBuildPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "CodeBuildPolicy",
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Resource": "*",
              "Effect": "Allow"
            },
            {
              "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:PutObject"
              ],
              "Resource": "arn:*:s3:::*",
              "Effect": "Allow"
            }
          ]
        },
        "Roles": [
          {
            "Ref": "CodeBuildRole"
          }
        ]
      }
    },
    "AppPackageBuild": {
      "Type": "AWS::CodeBuild::Project",
      "Properties": {
        "Artifacts": {
          "Type": "CODEPIPELINE"
        },
        "Environment": {
          "ComputeType": "BUILD_GENERAL1_SMALL",
          "Image": {
            "Ref": "CodeBuildImage"
          },
          "Type": "LINUX_CONTAINER",
          "EnvironmentVariables": [
            {
              "Name": "APP_S3_BUCKET",
              "Value": {
                "Ref": "ApplicationBucket"
              }
            },
            {
              "Name": "Env",
              "Type": "PLAINTEXT",
              "Value": {
                "Ref": "Env"
              }
            },
            {
              "Name": "Arn",
              "Type": "PLAINTEXT",
              "Value": {
                "Fn::GetAtt": [
                  "LambdaRole",
                  "Arn"
                ]
              }
            }
          ]
        },
        "Name": {
          "Fn::Sub": "${ApplicationName}Build"
        },
        "ServiceRole": {
          "Fn::GetAtt": "CodeBuildRole.Arn"
        },
        "Source": {
          "Type": "CODEPIPELINE"
        }
      }
    },
    "AppPipeline": {
      "Type": "AWS::CodePipeline::Pipeline",
      "Properties": {
        "Name": {
          "Fn::Sub": "${ApplicationName}Pipeline"
        },
        "ArtifactStore": {
          "Type": "S3",
          "Location": {
            "Ref": "ArtifactBucketStore"
          }
        },
        "RoleArn": {
          "Fn::GetAtt": "CodePipelineRole.Arn"
        },
        "Stages": [
          {
            "Name": "Source",
            "Actions": [
              {
                "Name": "Source",
                "ActionTypeId": {
                  "Category": "Source",
                  "Owner": "ThirdParty",
                  "Version": "1",
                  "Provider": "GitHub"
                },
                "RunOrder": 1,
                "OutputArtifacts": [
                  {
                    "Name": "SourceRepo"
                  }
                ],
                "Configuration": {
                  "Owner": {
                    "Ref": "GithubOwner"
                  },
                  "Repo": {
                    "Ref": "GithubRepoName"
                  },
                  "OAuthToken": {
                    "Fn::Join": [
                      "",
                      [
                        "{{resolve:secretsmanager:",
                        {
                          "Ref": "GithubRepoSecretId"
                        },
                        ":SecretString:",
                        {
                          "Ref": "GithubRepoSecretJSONKey"
                        },
                        "}}"
                      ]
                    ]
                  },
                  "Branch": {
                    "Fn::FindInMap": [
                      "EnvParams",
                      {
                        "Ref": "Env"
                      },
                      "GitBranchName"
                    ]
                  },
                  "PollForSourceChanges": true
                }
              }
            ]
          },
          {
            "Name": "Build",
            "Actions": [
              {
                "InputArtifacts": [
                  {
                    "Name": "SourceRepo"
                  }
                ],
                "Name": "CodeBuild",
                "ActionTypeId": {
                  "Category": "Build",
                  "Owner": "AWS",
                  "Version": "1",
                  "Provider": "CodeBuild"
                },
                "OutputArtifacts": [
                  {
                    "Name": "CompiledCFNTemplate"
                  }
                ],
                "Configuration": {
                  "ProjectName": {
                    "Ref": "AppPackageBuild"
                  }
                },
                "RunOrder": 1
              }
            ]
          },
          {
            "Name": "Deploy",
            "Actions": [
              {
                "ActionTypeId": {
                  "Category": "Deploy",
                  "Owner": "AWS",
                  "Version": "1",
                  "Provider": "CloudFormation"
                },
                "InputArtifacts": [
                  {
                    "Name": "CompiledCFNTemplate"
                  }
                ],
                "Name": "CreateBetaChangeSet",
                "Configuration": {
                  "ActionMode": "CHANGE_SET_REPLACE",
                  "ChangeSetName": {
                    "Fn::Sub": "${ApplicationName}ChangeSet"
                  },
                  "RoleArn": {
                    "Fn::GetAtt": "CFNDeployRole.Arn"
                  },
                  "Capabilities": "CAPABILITY_NAMED_IAM",
                  "StackName": {
                    "Fn::Sub": "${ApplicationName}Deploy"
                  },
                  "TemplatePath": "CompiledCFNTemplate::transformed.yaml"
                },
                "RunOrder": 1
              },
              {
                "RunOrder": 2,
                "ActionTypeId": {
                  "Category": "Deploy",
                  "Owner": "AWS",
                  "Version": "1",
                  "Provider": "CloudFormation"
                },
                "Configuration": {
                  "StackName": {
                    "Fn::Sub": "${ApplicationName}Deploy"
                  },
                  "ActionMode": "CHANGE_SET_EXECUTE",
                  "ChangeSetName": {
                    "Fn::Sub": "${ApplicationName}ChangeSet"
                  },
                  "OutputFileName": "StackOutputs.json"
                },
                "Name": "ExecuteChangeSet",
                "OutputArtifacts": [
                  {
                    "Name": "AppDeploymentValues"
                  }
                ]
              }
            ]
          }
        ]
      }
    },
    "ArtifactBucketStore": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": {
          "Fn::FindInMap": [
            "EnvParams",
            {
              "Ref": "Env"
            },
            "ArtifactBucketName"
          ]
        },
        "VersioningConfiguration": {
          "Status": "Enabled"
        }
      }
    },
    "LambdaRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::FindInMap": [
            "EnvParams",
            {
              "Ref": "Env"
            },
            "LambdaRoleName"
          ]
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  {
                    "Fn::Sub": "lambda.${AWS::URLSuffix}"
                  }
                ]
              }
            }
          ]
        },
        "Policies": [
          {
            "PolicyName": "DefaultPolicy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                  ],
                  "Resource": "arn:*:logs:*:*:*",
                  "Effect": "Allow"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "dynamodb:List*",
                    "dynamodb:DescribeReservedCapacity*",
                    "dynamodb:DescribeLimits",
                    "dynamodb:DescribeTimeToLive",
                    "dynamodb:CreateTable"
                  ],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "dynamodb:BatchGet*",
                    "dynamodb:DescribeStream",
                    "dynamodb:DescribeTable",
                    "dynamodb:Get*",
                    "dynamodb:Query",
                    "dynamodb:Scan",
                    "dynamodb:BatchWrite*",
                    "dynamodb:CreateTable",
                    "dynamodb:Delete*",
                    "dynamodb:Update*",
                    "dynamodb:PutItem"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": [
                        "arn:aws:dynamodb:*:*:table/${TableName}",
                        {
                          "TableName": {
                            "Fn::FindInMap": [
                              "EnvParams",
                              {
                                "Ref": "Env"
                              },
                              "TableName"
                            ]
                          }
                        }
                      ]
                    },
                    {
                      "Fn::Sub": [
                        "arn:aws:dynamodb:*:*:table/${TableName}/index/*",
                        {
                          "TableName": {
                            "Fn::FindInMap": [
                              "EnvParams",
                              {
                                "Ref": "Env"
                              },
                              "TableName"
                            ]
                          }
                        }
                      ]
                    }
                  ]
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "s3:ListBucket"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": [
                        "arn:aws:s3:::${OgpBucketName}",
                        {
                          "OgpBucketName": {
                            "Fn::FindInMap": [
                              "EnvParams",
                              {
                                "Ref": "Env"
                              },
                              "OgpBucketName"
                            ]
                          }
                        }
                      ]
                    }
                  ]
                },
                {
                  "Effect": "Allow",
                  "Action": "s3:*Object",
                  "Resource": [
                    {
                      "Fn::Sub": [
                        "arn:aws:s3:::${OgpBucketName}/*",
                        {
                          "OgpBucketName": {
                            "Fn::FindInMap": [
                              "EnvParams",
                              {
                                "Ref": "Env"
                              },
                              "OgpBucketName"
                            ]
                          }
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "CodePipelineRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "Policies": [
          {
            "PolicyName": "DefaultPolicy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": [
                    "s3:GetObject",
                    "s3:GetObjectVersion",
                    "s3:GetBucketVersioning",
                    "s3:CreateBucket",
                    "s3:PutObject",
                    "s3:PutBucketVersioning"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "codecommit:CancelUploadArchive",
                    "codecommit:GetBranch",
                    "codecommit:GetCommit",
                    "codecommit:GetUploadArchiveStatus",
                    "codecommit:UploadArchive"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "cloudwatch:*",
                    "iam:PassRole"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "lambda:InvokeFunction",
                    "lambda:ListFunctions"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "cloudformation:CreateStack",
                    "cloudformation:DeleteStack",
                    "cloudformation:DescribeStacks",
                    "cloudformation:UpdateStack",
                    "cloudformation:CreateChangeSet",
                    "cloudformation:DeleteChangeSet",
                    "cloudformation:DescribeChangeSet",
                    "cloudformation:ExecuteChangeSet",
                    "cloudformation:SetStackPolicy",
                    "cloudformation:ValidateTemplate",
                    "iam:PassRole"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                },
                {
                  "Action": [
                    "codebuild:BatchGetBuilds",
                    "codebuild:StartBuild"
                  ],
                  "Resource": "*",
                  "Effect": "Allow"
                }
              ]
            }
          }
        ],
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  {
                    "Fn::Sub": "codepipeline.${AWS::URLSuffix}"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    "CFNDeployRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "Policies": [
          {
            "PolicyName": "DeployAccess",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Action": "*",
                  "Resource": "*",
                  "Effect": "Allow"
                }
              ]
            }
          }
        ],
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sts:AssumeRole"
              ],
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  {
                    "Fn::Sub": "cloudformation.${AWS::URLSuffix}"
                  }
                ]
              }
            }
          ]
        }
      }
    }
  },
  "Outputs": {
    "S3ApplicationBucket": {
      "Value": {
        "Ref": "ApplicationBucket"
      }
    },
    "CodeBuildRoleArn": {
      "Value": {
        "Fn::GetAtt": "CodeBuildRole.Arn"
      }
    },
    "S3PipelineBucket": {
      "Value": {
        "Ref": "ArtifactBucketStore"
      }
    },
    "CodePipelineRoleArn": {
      "Value": {
        "Fn::GetAtt": "CodePipelineRole.Arn"
      }
    },
    "CFNDeployRoleArn": {
      "Value": {
        "Fn::GetAtt": "CFNDeployRole.Arn"
      }
    }
  }
}
```
```yaml:buildspec.yaml
artifacts:
  files:
  - transformed.yaml
  type: zip
phases:
  build:
    commands:
    - cd src/speed_pizza
    - sed -i -e "s@<ARN>@$Arn@g" .chalice/config.json
    - chalice package --stage ${Env} /tmp/packaged
    - cd $CODEBUILD_SRC_DIR
    - aws cloudformation package --template-file /tmp/packaged/sam.json --s3-bucket
      ${APP_S3_BUCKET} --output-template-file transformed.yaml
  install:
    commands:
    - cd src/speed_pizza
    - pip install -r requirements.txt
    - cd $CODEBUILD_SRC_DIR
    runtime-versions:
      python: '3.7'
version: '0.2'

```
```json:config.json
{
  "version": "2.0",
  "app_name": "speed_pizza",
  "stages": {
    "prod": {
      "api_gateway_stage": "api",
      "manage_iam_role": false,
      "iam_role_arn": "<ARN>",
      "lambda_memory_size": 512,
      "lambda_timeout": 900,
      "environment_variables": {
        "DYNAMODB_TABLE": "pizza",
        "S3_BUCKET_NAME": "speed-pizza-prod",
        "LOG_LEVEL": "ERROR",
        "LOCAL": "false",
        "CLOUD_FRONT_URL": "https://s-pizza.ninja/"
      }
    },
    "stg": {
      "api_gateway_stage": "api",
      "manage_iam_role": false,
      "iam_role_arn": "<ARN>",
      "lambda_memory_size": 512,
      "lambda_timeout": 900,
      "environment_variables": {
        "DYNAMODB_TABLE": "pizza-stg",
        "S3_BUCKET_NAME": "speed-pizza-stg",
        "LOG_LEVEL": "DEBUG",
        "LOCAL": "false",
        "CLOUD_FRONT_URL": "https://stg.s-pizza.ninja/"
      }
    },
    "dev": {
      "api_gateway_stage": "dev",
      "environment_variables": {
        "DYNAMODB_TABLE": "pizza",
        "S3_BUCKET_NAME": "minio-s-pizza-dev",
        "LOG_LEVEL": "DEBUG",
        "LOCAL": "true"
      }
    }
  }
}
```

## Frontend(Static)
```
/data/* - 3d models
/_nuxt/* - static nuxt source and image and css
/ogp/* - ogp images
```