AWSTemplateFormatVersion: "2010-09-09"
Description: Infrastructure for the registry extensions CICD pipeline

Parameters:

  Env:
    Type: String
    Description: The environment, alpha, beta, or prod. In a sandbox these are all in one account, but the actual deployment is to three different accounts.
    AllowedValues: ["alpha", "beta", "prod"]

  PrefixLower:
    Type: String
    Description: The extension prefix lowercase, for example, awscommunity.

  BetaAccountId:
    Type: String
    Description: AccountId for the beta account, which pushes builds to the prod source bucket 

  ProdAccountId:
    Type: String
    Description: Account ID for prod, required to share the KMS key so beta can deploy builds to the prod source bucket

  NotificationEmail:
    Type: String
    Description: Email address for pipeline notifications

Conditions:

  IsBeta: !Equals
    - !Ref Env
    - beta

  IsProd: !Equals
    - !Ref Env
    - prod

Resources:

  ArtifactBucket:
    Type: AWS::S3::Bucket
    Metadata:
      Comment: CodePipeline artifacts
    Properties:
      BucketName: !Sub "cep-${PrefixLower}-${Env}-${AWS::AccountId}-artifacts"

  ArtifactBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Condition: IsBeta
    Metadata:
      Comment: Allows the beta account to use an assumed role in the prod account to drop builds into the prod account
    Properties:
      Bucket: !Ref ArtifactBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: BetaProdCrossAccount
            Effect: Allow
            Principal:
              AWS: 
                - !Sub "arn:aws:iam::${ProdAccountId}:root"
            Action: 
              - s3:Put*
              - s3:Get*
              - s3:List*
            Resource: 
              - !Sub "arn:aws:s3:::cep-${PrefixLower}-${Env}-${AWS::AccountId}-artifacts"
              - !Sub "arn:aws:s3:::cep-${PrefixLower}-${Env}-${AWS::AccountId}-artifacts/*" 

  FastlyParameterPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Statement:
        - Action:
            - secretsmanager:GetSecretValue
          Effect: Allow
          Resource: 
            - !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:cep-${PrefixLower}-*"
        - Action:
            - ssm:GetParameter
            - ssm:GetParameters
          Effect: Allow
          Resource: 
            - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/cep-${PrefixLower}-*"
        Version: '2012-10-17'

  FastlyServicesDomainBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyServicesBackendBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyServicesHealthcheckBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyServicesServiceBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyDictionaryDictionaryBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyDictionaryDictionaryItemBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyLoggingS3BuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy
       
  FastlyLoggingSplunkBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyServicesDomainBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-services-domain"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyServicesDomainBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyServicesBackendBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-services-backend"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyServicesBackendBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyServicesHealthcheckBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-services-healthcheck"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyServicesHealthcheckBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyServicesServiceBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-services-service"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
      ServiceRole: !GetAtt FastlyServicesServiceBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyDictionaryDictionaryBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-dictionary-dictionary"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyDictionaryDictionaryBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyDictionaryDictionaryItemBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-dictionary-dictionaryitem"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
        - Name: FASTLY_DICTIONARY_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-dictionary-id"
      ServiceRole: !GetAtt FastlyDictionaryDictionaryItemBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyLoggingS3BuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-logging-s3"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyLoggingS3BuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyLoggingSplunkBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-logging-splunk"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: RESOURCE_PATH
          Type: PLAINTEXT
          Value: "placeholder-for-path-to-resource"
        - Name: FASTLY_SERVICE_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-service-id"
        - Name: FASTLY_VERSION_ID
          Type: PARAMETER_STORE
          Value: "cep-fastly-version-id"
      ServiceRole: !GetAtt FastlyLoggingSplunkBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"


  FastlyTlsCertificateBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyTlsCertificateBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-tls-certificate"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: RESOURCE_PATH
            Type: PLAINTEXT
            Value: "Fastly-Tls-Certificate"
          - Name: FASTLY_TLS_CERTIFICATE
            Type: PARAMETER_STORE
            Value: "cep-fastly-tls-certificate"
      ServiceRole: !GetAtt FastlyTlsCertificateBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyTlsDomainBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyTlsDomainBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-tls-domain"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: RESOURCE_PATH
            Type: PLAINTEXT
            Value: "Fastly-Tls-Domain"
          - Name: FASTLY_TLS_CERT_ID
            Type: PARAMETER_STORE
            Value: "cep-fastly-tls-cert-id"
          - Name: FASTLY_TLS_DOMAIN_ID
            Type: PARAMETER_STORE
            Value: "cep-fastly-tls-domain-id"
          - Name: FASTLY_TLS_CONFIG_ID
            Type: PARAMETER_STORE
            Value: "cep-fastly-tls-config-id"
      ServiceRole: !GetAtt FastlyTlsDomainBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  FastlyTlsPrivateKeysBuildProjectRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: '2012-10-17'
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub "cep-${Env}-common-build-project-policy"
        - !Ref FastlyParameterPolicy

  FastlyTlsPrivateKeysBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Sub "${PrefixLower}-${Env}-${PrefixLower}-tls-privatekeys"
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_LARGE
        Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/cep-cicd:latest"
        ImagePullCredentialsType: SERVICE_ROLE
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
          - Name: RESOURCE_PATH
            Type: PLAINTEXT
            Value: "Fastly-Tls-PrivateKeys"
          - Name: FASTLY_PRIVATE_KEY
            Type: PARAMETER_STORE
            Value: "cep-fastly-tls-privatekey"
      ServiceRole: !GetAtt FastlyTlsPrivateKeysBuildProjectRole.Arn
      Source:
        Type: CODEPIPELINE
        BuildSpec: !Sub "${Env}-buildspec.yml"

  SourceBucket:
    Type: AWS::S3::Bucket
    Metadata:
      Comment: The name is important here since it gets constructed by the webhook handler and CodeBuild job to drop the build into the correct bucket. We only use a one webhook for AwsCommunity and 3rd parties.
    Properties:
      BucketName: !Sub "cep-source-${AWS::AccountId}-${Env}-${PrefixLower}"
      VersioningConfiguration: 
        Status: Enabled

  PipelineRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "cep-${PrefixLower}-${Env}-pipeline-role"
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
        Version: '2012-10-17'
      Policies:
        - PolicyName: "inline-pipeline-policy" 
          PolicyDocument:
            Statement:
              - Action: "sts:AssumeRole"
                Effect: Allow
                Resource:
                  - !Sub "arn:aws:iam::${ProdAccountId}:role/${PrefixLower}-registry-extensions-publish-role"
              - Action:
                  - s3:GetObject*
                  - s3:GetBucket*
                  - s3:List*
                  - s3:DeleteObject*
                  - s3:PutObject*
                  - s3:Abort*
                Effect: Allow
                Resource:
                  - !GetAtt ArtifactBucket.Arn
                  - !Join
                    - ''
                    - - !GetAtt ArtifactBucket.Arn
                      - /*
                  - !GetAtt SourceBucket.Arn
                  - !Join
                    - ''
                    - - !GetAtt SourceBucket.Arn
                      - /*
              - Action:
                  - codebuild:StartBuild
                  - codebuild:BatchGetBuilds
                Effect: Allow
                Resource: 
                  - !GetAtt FastlyServicesDomainBuildProject.Arn
                  - !GetAtt FastlyServicesBackendBuildProject.Arn
                  - !GetAtt FastlyServicesHealthcheckBuildProject.Arn
                  - !GetAtt FastlyServicesServiceBuildProject.Arn
                  - !GetAtt FastlyDictionaryDictionaryBuildProject.Arn
                  - !GetAtt FastlyDictionaryDictionaryItemBuildProject.Arn
                  - !GetAtt FastlyLoggingS3BuildProject.Arn
                  - !GetAtt FastlyLoggingSplunkBuildProject.Arn
                  - !GetAtt FastlyTlsCertificateBuildProject.Arn
                  - !GetAtt FastlyTlsDomainBuildProject.Arn
                  - !GetAtt FastlyTlsPrivateKeysBuildProject.Arn
              - Action:
                  - kms:*
                Effect: Allow
                Resource: "*"
              - Action:
                  - sns:Publish
                Effect: Allow
                Resource: !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${PrefixLower}-${Env}-pipeline-topic"

  PipelineKey:
    Type: AWS::KMS::Key
    Metadata: 
      Comment: Required for cross account deployment from beta CodePipeline to the prod bucket
    Condition: IsBeta
    DeletionPolicy: Delete
    UpdateReplacePolicy: Delete
    Properties: 
      Description: This key is used by the CEP beta build process to deploy builds to the prod bucket
      KeyPolicy: 
        Statement:
          - Action: 
              - kms:Create*
              - kms:Describe*
              - kms:Enable*
              - kms:List*
              - kms:Put*
              - kms:Update*
              - kms:Revoke*
              - kms:Disable*
              - kms:Get*
              - kms:Delete*
              - kms:ScheduleKeyDeletion
              - kms:CancelKeyDeletion
              - kms:GenerateDataKey
              - kms:TagResource
              - kms:UntagResource
            Effect: Allow
            Principal: 
              AWS: 
                - !Sub "arn:aws:iam::${ProdAccountId}:root"
                - !Sub "arn:aws:iam::${AWS::AccountId}:role/Admin"
            Resource: "*"
          - Action: 
              - kms:Encrypt
              - kms:Decrypt
              - kms:ReEncrypt
              - kms:GenerateDataKey*
              - kms:DescribeKey
            Effect: Allow
            Principal: 
              AWS: 
                - !GetAtt PipelineRole.Arn
                - !Sub "arn:aws:iam::${ProdAccountId}:root"
                - !GetAtt FastlyServicesDomainBuildProjectRole.Arn
                - !GetAtt FastlyServicesBackendBuildProjectRole.Arn
                - !GetAtt FastlyServicesHealthcheckBuildProjectRole.Arn
                - !GetAtt FastlyServicesServiceBuildProjectRole.Arn
                - !GetAtt FastlyDictionaryDictionaryBuildProjectRole.Arn
                - !GetAtt FastlyDictionaryDictionaryItemBuildProjectRole.Arn
                - !GetAtt FastlyLoggingS3BuildProjectRole.Arn
                - !GetAtt FastlyLoggingSplunkBuildProjectRole.Arn
                - !GetAtt FastlyTlsCertificateBuildProjectRole.Arn
                - !GetAtt FastlyTlsPrivateKeysBuildProjectRole.Arn
                - !GetAtt FastlyTlsDomainBuildProjectRole.Arn
            Resource: "*"
      MultiRegion: true

  PipelineKeyAlias:
    Type: AWS::KMS::Alias
    Condition: IsBeta
    Properties:
      AliasName: !Sub "alias/cep-${PrefixLower}-pipeline-publish-key"
      TargetKeyId: !Ref PipelineKey

  WaitForPipelineRole:
    Type: Custom::Delay
    DependsOn: PipelineRole
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      SecondsToSleep: 10

  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    DependsOn: WaitForPipelineRole
    Metadata:
      Comment: This pipeline runs integ tests on all extensions, then drops the build into the prod account for publishing
    Properties:
      Name: !Sub "cep-${Env}-${PrefixLower}"
      RoleArn: !GetAtt PipelineRole.Arn
      ArtifactStore: !If
        - IsBeta
        - Type: S3
          Location: !Ref ArtifactBucket
          EncryptionKey:
            Id: !Ref PipelineKey
            Type: KMS
        - Type: S3
          Location: !Ref ArtifactBucket
          EncryptionKey: !Ref AWS::NoValue
      Stages:
        - Name: Source
          Actions:
            - Name: S3Source
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: S3
                Version: 1
              Configuration: 
                S3Bucket: !Ref SourceBucket
                S3ObjectKey: "source.zip" 
                PollForSourceChanges: true
              OutputArtifacts:
                - Name: extensions-source 
        - Name: FastlyResourceBuilds
          Actions:
            - Name: FastlyServicesDomain
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyServicesDomainBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Services-Domain"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyServicesBackend
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyServicesBackendBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Services-Backend"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyServicesHealthcheck
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyServicesHealthcheckBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Services-Healthcheck"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyServicesService
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyServicesServiceBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Services-Service"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyDictionaryDictionary
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyDictionaryDictionaryBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Dictionary-Dictionary"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyDictionaryDictionaryItem
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyDictionaryDictionaryItemBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Dictionary-DictionaryItem"
                    }
                  ]
              RunOrder: 2
            - Name: FastlyLoggingS3
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyLoggingS3BuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Logging-S3"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyLoggingSplunk
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyLoggingSplunkBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Logging-Splunk"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyTlsCertificate
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyTlsCertificateBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Tls-Certificate"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyTlsDomain
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyTlsDomainBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Tls-Domain"
                    }
                  ]
              RunOrder: 1
            - Name: FastlyTlsPrivateKeys
              InputArtifacts:
                - Name: extensions-source
              ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: 1
              Configuration:
                ProjectName: !Ref FastlyTlsPrivateKeysBuildProject
                EnvironmentVariables: |-
                  [
                    {
                      "name": "RESOURCE_PATH",
                      "type": "PLAINTEXT",
                      "value": "Fastly-Tls-PrivateKeys"
                    }
                  ]
              RunOrder: 1
        - !If
          - IsBeta
          - Name: CopyBuildToProd
            Actions:
              - Name: Copy
                RoleArn: !Sub "arn:aws:iam::${ProdAccountId}:role/${PrefixLower}-registry-extensions-publish-role"
                InputArtifacts: 
                  - Name: extensions-source
                ActionTypeId:
                  Category: Deploy
                  Owner: AWS
                  Provider: S3
                  Version: 1
                Configuration:
                  BucketName: !Sub "cep-source-${ProdAccountId}-prod-${PrefixLower}"
                  Extract: false
                  ObjectKey: source.zip
                  KMSEncryptionKeyARN: !GetAtt PipelineKey.Arn
          - !Ref AWS::NoValue

  PublishBuildBucketRole:
    Type: AWS::IAM::Role
    Condition: IsBeta
    Metadata:
      Comment: Allows the beta account to put builds into the prod bucket
    Properties:
      RoleName: !Sub "cep-${PrefixLower}-publish-role"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - s3.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      Policies:
        -
          PolicyName: put-builds
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action: s3:PutObject
                Resource: 
                  - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}"
                  - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}/*"

  PipelineTopic:
    Type: AWS::SNS::Topic
    Metadata:
      Comment: Topic for pipeline notifications
    DependsOn: Pipeline
    Properties:
      TopicName: !Sub "${PrefixLower}-${Env}-pipeline-topic"
      Subscription:
        - Endpoint: !Ref NotificationEmail 
          Protocol: email

  WaitForPipeline:
    Type: Custom::Delay
    DependsOn: 
      - Pipeline
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      SecondsToSleep: 10

  WaitForTopic:
    Type: Custom::Delay
    DependsOn: 
      - PipelineTopic
      - PipelineTopicPolicy
    Properties:
      ServiceToken: !GetAtt DelayFunction.Arn
      SecondsToSleep: 10

  PipelineTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Id: MyTopicPolicy
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - events.amazonaws.com
          Action: sns:Publish
          Resource: !Ref PipelineTopic
      Topics:
      - !Ref PipelineTopic

  PipelineEventRole:
    Type: AWS::IAM::Role
    Metadata:
      Comment: Allows the event rule to push to the topic
    Properties:
      RoleName: !Sub "cep-${Env}-${PrefixLower}-pipeline-event-role"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      Policies:
        -
          PolicyName: put-events
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action: sns:Publish
                Resource: !Ref PipelineTopic

  PipelineEventRule:
    Type: AWS::Events::Rule
    DependsOn: WaitForTopic
    Properties:
      Description: Watch for pipeline success and failure
      EventPattern: 
        source:
          - aws.codepipeline
        detail-type:
          - CodePipeline Pipeline Execution State Change
        detail:
          pipeline: 
            - !Ref Pipeline
          state:
            - SUCCEEDED
            - FAILED
      Name: !Sub "cep-${PrefixLower}-${Env}-pipelines"
      Targets:
        - Arn: !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${PrefixLower}-${Env}-pipeline-topic"
          Id: pipeline-topic-target
          InputTransformer:
            InputTemplate: '"The pipeline <pipeline> from account <account> has <state> at <at>."'
            InputPathsMap:
              pipeline: "$.detail.pipeline"
              state: "$.detail.state"
              at: "$.time"
              account: "$.account"

# Prod account resources

  PublishBuildBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Condition: IsProd
    Metadata:
      Comment: Allows the beta account to drop builds into the prod account.
    Properties:
      Bucket: !Ref SourceBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: BetaAccountPut
            Effect: Allow
            Principal:
              AWS: 
                - !Sub "arn:aws:iam::${BetaAccountId}:root"
                - !GetAtt PublishCrossAccountRole.Arn
            Action: s3:PutObject
            Resource: 
              - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}"
              - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}/*"

  PublishCrossAccountRole:
    Type: AWS::IAM::Role
    Condition: IsProd
    Metadata:
      Comment: Assumed by codepipeline in the beta account to access the prod source bucket
    Properties:
      RoleName: !Sub "${PrefixLower}-registry-extensions-publish-role"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              AWS:
                - !Sub "arn:aws:iam::${BetaAccountId}:root"
            Action: sts:AssumeRole
      Path: /
      Policies:
        -
          PolicyName: cross-account-pipeline-deploy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action:
                  - s3:Get*
                  - s3:List*
                  - s3:Put*
                Effect: Allow
                Resource:
                  - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}"
                  - !Sub "arn:aws:s3:::cep-source-${ProdAccountId}-prod-${PrefixLower}/*"
                  - !Sub "arn:aws:s3:::cep-${PrefixLower}-beta-${BetaAccountId}-artifacts"
                  - !Sub "arn:aws:s3:::cep-${PrefixLower}-beta-${BetaAccountId}-artifacts/*"
              - Action: 
                  - kms:Encrypt
                  - kms:Decrypt
                  - kms:ReEncrypt
                  - kms:GenerateDataKey*
                  - kms:DescribeKey
                Effect: Allow
                Resource: 
                  - !Sub "arn:aws:kms:${AWS::Region}:${BetaAccountId}:key/*"
              
# Delay Function to solve race conditions where the resource is not actually ready

  DelayFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: "lambda-logs"
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource:
                  - "arn:aws:logs:*:*:*"

  DelayFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: delay.handler
      Timeout: 120
      Role: !GetAtt DelayFunctionRole.Arn
      Runtime: python3.7
      Code: delay.py 
      MemorySize: 1024