Parameters:
  UserBasedAuth:
    Description: If checked, Zerve will create an IAM user and store its' credentials,
      instead of using a more secure AssumeRole-based flow.
    AllowedValues:
    - true
    - false
    Type: String
    Default: false
  Organization:
    Type: String
    Description: ID of your organization in Zerve app
  ApiKey:
    Type: String
    Description: Zerve API key of a user with organization admin permissions. If you
      have not created one yet, visit https://app.zerve.ai/settings/developer-api
  CanvasBucket:
    Type: String
    Description: Prefix for name of the S3 bucket. Bucket name will be this prefix
      concatenated with organization ID.
    Default: zerve-bucket
  ApplyCommonTags:
    Description: If checked, all resources created by this stack will be tagged with
      common zerve tags
    AllowedValues:
    - true
    - false
    Type: String
    Default: true
  PermissionsBoundaryArn:
    Type: String
    Description: "ARN of the IAM policy to attach as the permissions boundary to all\
      \ IAM roles created by this stack.\n"
    Default: ''
  DomainName:
    Type: String
    Description: "Domain name to use for public endpoints (Sagemaker Endpoint layer,\
      \ API Deployment layer, Hosted Apps).\nThose features may not be available if\
      \ domain name is not provided.\nExample: foo.zerve.cloud\n"
    ConstraintDescription: Must be a valid domain name.
    AllowedPattern: ^$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?){2,}$
    Default: ''
  HostedZoneID:
    Type: String
    Description: "Existing hosted zone ID in this AWS account that corresponds to\
      \ the DomainName.\nHosted zone will be created if this is not provided.\nIf\
      \ DomainName is not a subdomain of `.zerve.cloud`, this must be provided and\
      \ delegation from the parent domain must be set up before deploying this stack.\n"
    Default: ''
  Env:
    Type: String
    Description: Deployment environment
    Default: prod
    AllowedValues:
    - dev
    - prod
  AssetServiceUrl:
    Type: String
    Default: https://asset.api.zerve.ai
    Description: "The URL of the Zerve Asset service without a trailing slash. A lambda\
      \ in the stack will\ntalk back to the Zerve application using this URL in order\
      \ to synchronize data.\nWith this parameter missing or configured incorrectly\
      \ Zerve will not be able\nto execute code in the provided AWS account.\n"
  VpcId:
    Type: String
    Description: ID of an existing VPC in this account. VPC will be created if this
      is not provided.
    Default: ''
  PublicSubnets:
    Type: CommaDelimitedList
    Description: 'IDs of at least two existing public subnets from different AZs within
      the specified VPC. Required if VPC is provided. Example: subnet-1234,subnet-5678'
    Default: ''
  PrivateSubnets:
    Type: CommaDelimitedList
    Description: 'IDs of at least two existing private subnets from different AZs
      within the specified VPC. Required if VPC is provided. Example: subnet-1234,subnet-5678'
    Default: ''
Conditions:
  CreateVpc:
    Fn::Equals:
    - Ref: VpcId
    - ''
  SkipHostedZoneIam:
    Fn::Equals:
    - Ref: DomainName
    - ''
  CreateHostedZone:
    Fn::And:
    - Fn::Equals:
      - Ref: HostedZoneID
      - ''
    - Fn::Not:
      - Fn::Equals:
        - Ref: DomainName
        - ''
  CreateUser:
    Fn::Equals:
    - Ref: UserBasedAuth
    - 'true'
  CreateFargateApiDeploymentsInfra:
    Fn::Not:
    - Fn::Equals:
      - Ref: DomainName
      - ''
  CreateApiProxy:
    Fn::Not:
    - Fn::Equals:
      - Ref: DomainName
      - ''
  CreateSagemakerProxy:
    Fn::Not:
    - Fn::Equals:
      - Ref: DomainName
      - ''
  IsDev:
    Fn::Equals:
    - Ref: Env
    - dev
  ApplyTags:
    Fn::Equals:
    - Ref: ApplyCommonTags
    - 'true'
  AttachPermissionsBoundary:
    Fn::Not:
    - Fn::Equals:
      - Ref: PermissionsBoundaryArn
      - ''
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: General
      Parameters:
      - UserBasedAuth
      - Organization
      - ApiKey
      - CanvasBucket
      - ApplyCommonTags
    - Label:
        default: IAM
      Parameters:
      - PermissionsBoundaryArn
    - Label:
        default: DNS
      Parameters:
      - DomainName
      - HostedZoneID
    - Label:
        default: Networking - VPC
      Parameters:
      - VpcId
      - PublicSubnets
      - PrivateSubnets
    - Label:
        default: Dev-only parameters
      Parameters:
      - Env
      - AssetServiceUrl
    ParameterLabels:
      UserBasedAuth:
        default: '[not recommended] Enable user-based auth?'
      Organization:
        default: Zerve organization ID
      ApiKey:
        default: Zerve API key
      CanvasBucket:
        default: Bucket name
      ApplyCommonTags:
        default: Apply common tags
      PermissionsBoundaryArn:
        default: '[optional] Permissions boundary'
      DomainName:
        default: '[optional] Domain name'
      HostedZoneID:
        default: '[optional] Hosted zone ID'
      Env:
        default: Environment
      AssetServiceUrl:
        default: Asset service URL
      VpcId:
        default: '[optional] Existing VPC'
      PublicSubnets:
        default: '[optional] Existing public subnets'
      PrivateSubnets:
        default: '[optional] Existing private subnets'
  CommonTags:
    Fn::If:
    - ApplyTags
    - - Key: zerve:owned
        Value: 'true'
      - Key: zerve:environment
        Value:
          Ref: Env
    - Ref: AWS::NoValue
Resources:
  ZerveRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            AWS:
            - arn:aws:iam::851228104600:role/zerve-machine-role
            - Fn::If:
              - CreateUser
              - Fn::GetAtt:
                - ZerveUser
                - Arn
              - Ref: AWS::NoValue
            - Fn::If:
              - IsDev
              - '851228104600'
              - Ref: AWS::NoValue
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              sts:ExternalId:
                Ref: Organization
      Policies:
      - PolicyName: zerve-read-logs
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Action:
            - logs:GetLogEvents
            - logs:DescribeLogStreams
            - logs:FilterLogEvents
            - logs:StartLiveTail
            - logs:StartQuery
            - logs:GetQueryResults
            - logs:GetLogRecord
            Resource:
            - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/zerve*
          - Effect: Allow
            Action:
            - logs:StopLiveTail
            - logs:StopQuery
            Resource: '*'
      ManagedPolicyArns:
      - Ref: ZerveStateBucketReadWritePolicy
      - Ref: ZerveECRPullPolicy
      - Ref: ZerveImageManagementPolicy
      - Ref: ZerveFargateManagementPolicy
      - Ref: ZerveLambdaManagementPolicy
      - Ref: ZerveSagemakerManagementPolicy
      - Ref: ZerveCloudFormationPolicy
      - Ref: ZerveApiBuilderPolicy
      - Ref: ZerveBedrockInvokeModelPolicy
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveUser:
    Type: AWS::IAM::User
    Condition: CreateUser
    Properties:
      UserName: zerve
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveUserAccessKey:
    Type: AWS::IAM::AccessKey
    Condition: CreateUser
    Properties:
      Serial: 1
      Status: Active
      UserName: zerve
    DependsOn: ZerveUser
  ZerveNetworking:
    Type: AWS::CloudFormation::Stack
    Condition: CreateVpc
    Properties:
      TemplateURL: https://s3.eu-west-1.amazonaws.com/zerve-deployment-templates/e62506cebcac4ae3cec8b66bd82ec9e1.template
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveHostedZone:
    Type: AWS::Route53::HostedZone
    Condition: CreateHostedZone
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Properties:
      HostedZoneTags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
      Name:
        Ref: DomainName
  ZerveDeployCallbackLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-deploy-callback-lambda-execution-role
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveDeployCallbackLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: zerve-deploy-callback-lambda
      Timeout: 30
      Runtime: python3.12
      Handler: index.lambda_handler
      Role:
        Fn::GetAtt:
        - ZerveDeployCallbackLambdaExecutionRole
        - Arn
      Layers:
      - Fn::Sub: arn:aws:lambda:${AWS::Region}:770693421928:layer:Klayers-p312-requests:13
      VpcConfig:
        SecurityGroupIds:
        - Ref: DeployCallbackSecurityGroup
        SubnetIds:
        - Fn::If:
          - CreateVpc
          - Fn::GetAtt:
            - ZerveNetworking
            - Outputs.PrivateSubnet1
          - Fn::Select:
            - 0
            - Ref: PrivateSubnets
        - Fn::If:
          - CreateVpc
          - Fn::GetAtt:
            - ZerveNetworking
            - Outputs.PrivateSubnet2
          - Fn::Select:
            - 1
            - Ref: PrivateSubnets
      Code:
        ZipFile: "import cfnresponse\nimport requests\nimport traceback\n\nresponse_data\
          \ = {}\n\ndef lambda_handler(event, context):\n    try:\n        inputs\
          \ = event[\"ResourceProperties\"]\n\n        if event['RequestType'] in\
          \ ('Create', 'Update'):\n            if inputs[\"Send\"] == \"false\":\n\
          \                return cfnresponse.send(event, context, cfnresponse.SUCCESS,\
          \ {}, \"dummy\")\n            res = requests.request(\n                method=inputs[\"\
          Method\"],\n                url=inputs[\"Url\"],\n                json=inputs[\"\
          Data\"],\n                headers=inputs[\"Headers\"],\n            )\n\
          \            print(f'Status code: {res.status_code}')\n            if res.ok:\n\
          \                return cfnresponse.send(event, context, cfnresponse.SUCCESS,\
          \ {}, \"dummy\")\n\n            reason = f\"{res.status_code} {res.reason}:\
          \ {res.text}\"\n            return cfnresponse.send(event, context, cfnresponse.FAILED,\
          \ {}, \"dummy\", reason=reason)\n\n        if event['RequestType'] == 'Delete':\n\
          \            print(\"Received Deletion Request\")\n            return cfnresponse.send(event,\
          \ context, cfnresponse.SUCCESS, {}, \"dummy\")\n    except Exception as\
          \ e:\n        traceback.print_exc()\n        cfnresponse.send(event, context,\
          \ cfnresponse.FAILED, {}, \"dummy\", reason=str(e))\n"
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveDeployCallback:
    Type: Custom::ZerveDeployCallback
    Properties:
      ServiceToken:
        Fn::GetAtt:
        - ZerveDeployCallbackLambda
        - Arn
      Data:
        cloud_provider: aws
        organisation_id:
          Ref: Organization
        credentials:
          access_key_id:
            Fn::If:
            - CreateUser
            - Ref: ZerveUserAccessKey
            - Ref: AWS::NoValue
          secret_access_key:
            Fn::If:
            - CreateUser
            - Fn::GetAtt:
              - ZerveUserAccessKey
              - SecretAccessKey
            - Ref: AWS::NoValue
          account_id:
            Ref: AWS::AccountId
          role_arn:
            Fn::GetAtt:
            - ZerveRole
            - Arn
          region:
            Ref: AWS::Region
          s3_bucket_name:
            Ref: ZerveStateBucket
          vpc_id:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.VPC
            - Ref: VpcId
          subnet_id:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.PrivateSubnet1
            - Fn::Select:
              - 0
              - Ref: PrivateSubnets
          subnet_id_2:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.PrivateSubnet2
            - Fn::Select:
              - 1
              - Ref: PrivateSubnets
          security_group_id:
            Ref: CanvasBlockSecurityGroup
          nat_gateway_ip_address:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.NatGateway1EIP
            - dummy
          public_subnet_id_1:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.PublicSubnet1
            - Fn::Select:
              - 0
              - Ref: PublicSubnets
          public_subnet_id_2:
            Fn::If:
            - CreateVpc
            - Fn::GetAtt:
              - ZerveNetworking
              - Outputs.PublicSubnet2
            - Fn::Select:
              - 1
              - Ref: PublicSubnets
          public_security_group_id:
            Ref: PublicLBSecurityGroup
          app_security_group_id:
            Ref: EcsHostedAppSecurityGroup
          hosted_zone:
            id:
              Fn::If:
              - CreateHostedZone
              - Ref: ZerveHostedZone
              - Ref: HostedZoneID
            name:
              Ref: DomainName
          service_discovery_namespace_id:
            Fn::If:
            - CreateFargateApiDeploymentsInfra
            - Ref: ServiceDiscoveryNamespace
            - Ref: AWS::NoValue
          vpc_link_id:
            Fn::If:
            - CreateFargateApiDeploymentsInfra
            - Ref: VpcLink
            - Ref: AWS::NoValue
          ecs_api_service_security_group_id:
            Fn::If:
            - CreateFargateApiDeploymentsInfra
            - Ref: EcsApiServiceSecurityGroup
            - Ref: AWS::NoValue
      Headers:
        x-api-key:
          Ref: ApiKey
      Url:
        Fn::Sub: ${AssetServiceUrl}/cloud-credentials/${Organization}
      Method: POST
      Send: 'true'
      Version: '20240801'
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveApiProxy:
    Type: AWS::CloudFormation::Stack
    Condition: CreateApiProxy
    DependsOn:
    - ZerveDeployCallback
    Properties:
      TemplateURL: https://s3.eu-west-1.amazonaws.com/zerve-deployment-templates/f2e2520deddcb67480544b1fb0ea48d8.template
      Parameters:
        DomainName:
          Ref: DomainName
        HostedZoneId:
          Fn::If:
          - CreateHostedZone
          - Ref: ZerveHostedZone
          - Ref: HostedZoneID
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveSagemakerProxy:
    Type: AWS::CloudFormation::Stack
    Condition: CreateSagemakerProxy
    DependsOn:
    - ZerveDeployCallback
    Properties:
      TemplateURL: https://s3.eu-west-1.amazonaws.com/zerve-deployment-templates/6f922f1a934f7c9dca541a1db4adc406.template
      Parameters:
        DomainName:
          Ref: DomainName
        HostedZoneId:
          Fn::If:
          - CreateHostedZone
          - Ref: ZerveHostedZone
          - Ref: HostedZoneID
        PermissionsBoundaryArn:
          Ref: PermissionsBoundaryArn
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveStateBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Fn::Sub: ${CanvasBucket}-${Organization}
      CorsConfiguration:
        CorsRules:
        - AllowedHeaders:
          - '*'
          AllowedMethods:
          - GET
          - PUT
          - POST
          AllowedOrigins:
          - Fn::If:
            - IsDev
            - http://localhost:8080
            - https://app.zerve.ai
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveLogsPushPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Allow pushing logs to cloudwatch
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
          - logs:CreateLogGroup
          - logs:CreateLogStream
          - logs:PutLogEvents
          Resource: '*'
  ZerveECRPullPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Allow pulling zerve images
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Resource: '*'
          Action:
          - ecr:GetAuthorizationToken
        - Effect: Allow
          Resource:
          - Fn::Sub: arn:aws:ecr:${AWS::Region}:851228104600:repository/zerve*
          - Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/zerve*
          Action:
          - ecr:DescribeImages
          - ecr:BatchGetImage
          - ecr:GetDownloadUrlForLayer
          - ecr:BatchCheckLayerAvailability
  ZerveStateBucketReadWritePolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Allow access to canvas state bucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action:
          - s3:PutObject
          - s3:PutObjectAcl
          - s3:GetObject
          - s3:GetObjectAcl
          - s3:DeleteObject
          - s3:ListBucket
          - s3:ListBucketMultipartUploads
          - s3:AbortMultipartUpload
          - s3:ListMultipartUploadParts
          Resource:
          - Fn::GetAtt:
            - ZerveStateBucket
            - Arn
          - Fn::Sub: ${ZerveStateBucket.Arn}/*
  ZerveStateBucketCanvasScopedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Allow access to a specific canvas in a state bucket based on a
        principal tag
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: s3:ListBucket
          Resource:
            Fn::GetAtt:
            - ZerveStateBucket
            - Arn
          Condition:
            StringLike:
              s3:prefix: canvases/${aws:PrincipalTag/zerve:canvas-id}/*
        - Effect: Deny
          Action: s3:ListBucket
          Resource:
            Fn::GetAtt:
            - ZerveStateBucket
            - Arn
          Condition:
            StringNotLike:
              s3:prefix: canvases/${aws:PrincipalTag/zerve:canvas-id}/*
        - Effect: Allow
          Action:
          - s3-object-lambda:Get*
          - s3:GetObject
          - s3:PutObject
          - s3:PutObjectAcl
          - s3:DeleteObject
          - s3:DeleteObjectVersion
          Resource:
          - Fn::Sub: ${ZerveStateBucket.Arn}/canvases/${!aws:PrincipalTag/zerve:canvas-id}
          - Fn::Sub: ${ZerveStateBucket.Arn}/canvases/${!aws:PrincipalTag/zerve:canvas-id}/*
  ZerveCloudFormationPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Sid: cloudFormationAllstacks
          Resource: '*'
          Action:
          - cloudformation:ListStacks
          - cloudformation:ValidateTemplate
          - cloudformation:CreateChangeSet
        - Effect: Allow
          Sid: cloudFormationChangeSet
          Resource:
            Fn::Sub: arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/zerve-*
          Action:
          - cloudformation:CreateStack
          - cloudformation:DescribeStacks
          - cloudformation:UpdateStack
          - cloudformation:DescribeStackEvents
          - cloudformation:DeleteStack
          - cloudformation:ExecuteChangeSet
          - cloudformation:DescribeChangeSet
          - cloudformation:ContinueUpdateRollback
          - cloudformation:TagResource
          - cloudformation:UntagResource
  ZerveImageManagementPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to manage executor images builds
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Resource: '*'
          Action:
          - codebuild:ListProjects
        - Effect: Allow
          Sid: InvokeCodeBuild
          Resource:
            Fn::Sub: arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/zerve-*
          Action:
          - codebuild:StartBuild
          - codebuild:StopBuild
          - codebuild:BatchGetBuilds
          - codebuild:CreateProject
          - codebuild:UpdateProject
          - codebuild:DeleteProject
        - Effect: Allow
          Sid: GetBuildLogs
          Resource:
          - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/zerve-*
          - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${ZerveImageBuild.Outputs.LogGroupName}*
          Action:
          - logs:GetLogEvents
          - logs:DescribeLogStreams
          - logs:FilterLogEvents
        - Effect: Allow
          Sid: CreateRepo
          Resource:
            Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/zerve*
          Action:
          - ecr:CreateRepository
          - ecr:TagResource
          - ecr:UntagResource
        - Effect: Allow
          Sid: DescribeImages
          Resource:
            Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/zerve*
          Action:
          - ecr:DescribeImages
        - Effect: Allow
          Sid: PassCodebuildServiceRole
          Resource:
          - Fn::GetAtt:
            - ZerveCodeBuildRole
            - Arn
          - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/${ZerveImageBuild.Outputs.BuildRoleName}
          Action:
          - iam:PassRole
          Condition:
            StringEqualsIfExists:
              iam:PassedToService: codebuild.amazonaws.com
  ZerveFargateManagementPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to manage fargate executors
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action:
          - ecs:ListClusters
          - ecs:DescribeTaskDefinition
          - ecs:RegisterTaskDefinition
          - ecs:DeregisterTaskDefinition
          - ecs:ListTaskDefinitions
          Resource: '*'
        - Effect: Allow
          Action:
          - ec2:DescribeSubnets
          - ec2:DescribeInternetGateways
          - ec2:DescribeVpcs
          - ec2:DescribeAccountAttributes
          - ec2:DescribeSecurityGroups
          - ec2:DescribeSecurityGroupRules
          - ec2:DescribeTags
          - ec2:GetSecurityGroupsForVpc
          Resource: '*'
        - Effect: Allow
          Action:
          - ecs:DescribeTasks
          - ecs:RunTask
          - ecs:StopTask
          - ecs:ListTasks
          - ecs:ListServices
          - ecs:CreateService
          - ecs:UpdateService
          - ecs:DescribeServices
          - ecs:DeleteService
          Resource: '*'
          Condition:
            ArnLike:
              ecs:cluster:
                Fn::Sub: arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/zerve-*
        - Effect: Allow
          Resource:
            Fn::Sub: arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:cluster/zerve-*
          Action:
          - ecs:CreateCluster
          - ecs:UpdateCluster
          - ecs:UpdateClusterSettings
          - ecs:DescribeClusters
          - ecs:DeleteCluster
        - Effect: Allow
          Resource:
          - Fn::Sub: arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*/zerve*
          Action:
          - ecs:TagResource
          - ecs:UntagResource
        - Effect: Allow
          Action:
          - elasticloadbalancing:DescribeLoadBalancers
          - elasticloadbalancing:DescribeTargetGroups
          - elasticloadbalancing:DescribeListeners
          Resource: '*'
        - Effect: Allow
          Action:
          - elasticloadbalancing:CreateLoadBalancer
          - elasticloadbalancing:ModifyLoadBalancerAttributes
          - elasticloadbalancing:DeleteLoadBalancer
          - elasticloadbalancing:CreateListener
          - elasticloadbalancing:ModifyListener
          - elasticloadbalancing:DeleteListener
          - elasticloadbalancing:CreateTargetGroup
          - elasticloadbalancing:ModifyTargetGroup
          - elasticloadbalancing:DeleteTargetGroup
          - elasticloadbalancing:CreateRule
          - elasticloadbalancing:ModifyRule
          - elasticloadbalancing:DeleteRule
          - elasticloadbalancing:AddTags
          - elasticloadbalancing:RemoveTags
          Resource:
          - Fn::Sub: arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:loadbalancer/app/zerve-*
          - Fn::Sub: arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:listener/app/zerve-*
          - Fn::Sub: arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:listener-rule/app/zerve-*
          - Fn::Sub: arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:targetgroup/zerve-*
        - Effect: Allow
          Resource:
          - Fn::GetAtt:
            - ZerveFargateRole
            - Arn
          - Fn::GetAtt:
            - ZerveFargateTaskExecutionRole
            - Arn
          Action:
          - iam:PassRole
          Condition:
            StringEquals:
              iam:PassedToService: ecs-tasks.amazonaws.com
        - Effect: Allow
          Action:
          - iam:CreateServiceLinkedRole
          Resource:
          - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS
        - Effect: Allow
          Resource:
          - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/app/zerve-*
          - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/fargate/zerve-*
          Action:
          - logs:DescribeLogStreams
          - logs:GetLogEvents
          - logs:FilterLogEvents
  ZerveLambdaManagementPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to manage lambda executors
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Resource:
            Fn::Sub: arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:zerve-*
          Action:
          - lambda:GetFunction
          - lambda:CreateFunction
          - lambda:DeleteFunction
          - lambda:UpdateFunctionCode
          - lambda:ListTags
          - lambda:InvokeFunction
          - lambda:TagResource
          - lambda:UntagResource
          - lambda:AddPermission
          - lambda:RemovePermission
          - lambda:UpdateFunctionConfiguration
        - Effect: Allow
          Resource:
          - Fn::GetAtt:
            - ZerveLambdaExecutionRole
            - Arn
          - Fn::GetAtt:
            - ApiLambdaRole
            - Arn
          Action:
          - iam:PassRole
          Condition:
            StringEquals:
              iam:PassedToService: lambda.amazonaws.com
        - Effect: Allow
          Resource: '*'
          Action:
          - ec2:DescribeVpcs
          - ec2:DescribeSubnets
          - ec2:DescribeSecurityGroups
        - Effect: Allow
          Sid: ManageClientEcrRepoPolicies
          Resource:
            Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/zerve*
          Action:
          - ecr:GetRepositoryPolicy
          - ecr:SetRepositoryPolicy
        - Effect: Allow
          Resource:
            Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/zerve-*
          Action:
          - logs:DescribeLogStreams
          - logs:GetLogEvents
          - logs:FilterLogEvents
  ZerveSagemakerManagementPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to manage sagemaker executors
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Sid: sagemakerTrainingJobs
          Resource:
            Fn::Sub: arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:training-job/zerve-*
          Action:
          - sagemaker:AddTags
          - sagemaker:ListTags
          - sagemaker:DeleteTags
          - sagemaker:CreateTrainingJob
          - sagemaker:StopTrainingJob
          - sagemaker:DescribeTrainingJob
          - sagemaker:UpdateTrainingJob
          - sagemaker:ListTrainingJobs
        - Effect: Allow
          Action:
          - sagemaker:AddTags
          - sagemaker:ListTags
          - sagemaker:DeleteTags
          - sagemaker:DescribeModel
          - sagemaker:CreateModel
          - sagemaker:DeleteModel
          Resource:
            Fn::Sub: arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:model/zerve-*
        - Effect: Allow
          Action:
          - sagemaker:AddTags
          - sagemaker:ListTags
          - sagemaker:DeleteTags
          - sagemaker:DescribeEndpoint
          - sagemaker:CreateEndpoint
          - sagemaker:UpdateEndpoint
          - sagemaker:DeleteEndpoint
          - sagemaker:InvokeEndpoint
          Resource:
          - Fn::Sub: arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint/zerve-*
          - Fn::Sub: arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint-config/zerve-*
        - Effect: Allow
          Action:
          - sagemaker:AddTags
          - sagemaker:ListTags
          - sagemaker:DeleteTags
          - sagemaker:CreateEndpointConfig
          - sagemaker:DeleteEndpointConfig
          - sagemaker:DescribeEndpointConfig
          Resource:
            Fn::Sub: arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint-config/zerve-*
        - Effect: Allow
          Resource:
            Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/sagemaker/Endpoints/zerve-*
          Action:
          - logs:DescribeLogStreams
          - logs:GetLogEvents
          - logs:FilterLogEvents
        - Effect: Allow
          Resource:
          - Fn::GetAtt:
            - ZerveSagemakerRole
            - Arn
          Action:
          - iam:PassRole
          Condition:
            StringEquals:
              iam:PassedToService: sagemaker.amazonaws.com
  ZerveBedrockInvokeModelPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to invoke bedrock models
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
          - bedrock:InvokeModel
          Resource: '*'
  ZerveCodeBuildRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-code-build-role
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      Description: Service role for CodeBuild to build executor images
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - codebuild.amazonaws.com
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              aws:sourceAccount:
                Ref: AWS::AccountId
      ManagedPolicyArns:
      - Ref: ZerveECRPullPolicy
      - Ref: ZerveLogsPushPolicy
      Policies:
      - PolicyName: zerve-code-build-role-policy
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Sid: StateBucketRead
            Resource:
            - Fn::GetAtt:
              - ZerveStateBucket
              - Arn
            - Fn::Sub: ${ZerveStateBucket.Arn}/*
            Action:
            - s3:GetObject
            - s3:GetObjectVersion
            - s3:GetBucketLocation
          - Effect: Allow
            Sid: EcrPush
            Resource:
              Fn::Sub: arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/zerve*
            Action:
            - ecr:UploadLayerPart
            - ecr:InitiateLayerUpload
            - ecr:CompleteLayerUpload
            - ecr:PutImage
            - ecr:BatchCheckLayerAvailability
            - ecr:TagResource
            - ecr:UntagResource
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveApiBuilderPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: Permissions needed for Zerve to manage API deployments
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Resource:
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/restapis*
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/domainnames/*.zerve.cloud/*
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/domainnames/*.zerve.cloud
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/tags/*
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/apis*
          Action:
          - apigateway:PUT
          - apigateway:POST
          - apigateway:GET
          - apigateway:DELETE
          - apigateway:PATCH
          Condition:
            StringLikeIfExists:
              apigateway:Resource/ApiName: zerve-*
              apigateway:Request/ApiName: zerve-*
        - Effect: Allow
          Resource:
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/domainnames
          Action:
          - apigateway:POST
        - Effect: Allow
          Action:
          - route53:GetChangeRequest
          - route53:GetChange
          Resource: '*'
        - Fn::If:
          - SkipHostedZoneIam
          - Ref: AWS::NoValue
          - Effect: Allow
            Action:
            - route53:GetHostedZone
            - route53:ListResourceRecordSets
            - route53:ChangeResourceRecordSets
            Resource:
              Fn::If:
              - CreateHostedZone
              - Fn::Sub: arn:aws:route53:::hostedzone/${ZerveHostedZone.Id}
              - Fn::Sub: arn:aws:route53:::hostedzone/${HostedZoneID}
        - Effect: Allow
          Action:
          - acm:RequestCertificate
          Resource: '*'
          Condition:
            ForAllValues:StringLike:
              acm:DomainNames:
              - '*.zerve.cloud'
        - Effect: Allow
          Action:
          - acm:DescribeCertificate
          - acm:DeleteCertificate
          - acm:AddTagsToCertificate
          - acm:RemoveTagsFromCertificate
          - acm:ListTagsForCertificate
          Resource: '*'
        - Effect: Allow
          Action:
          - iam:CreateServiceLinkedRole
          Resource:
          - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ops.apigateway.amazonaws.com/AWSServiceRoleForAPIGateway
          - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/aws-service-role/elasticloadbalancing.amazonaws.com/AWSServiceRoleForElasticLoadBalancing
        - Effect: Allow
          Action:
          - servicediscovery:CreateService
          - servicediscovery:GetOperation
          - servicediscovery:GetService
          - servicediscovery:TagResource
          - servicediscovery:DeleteService
          Resource: '*'
        - Effect: Allow
          Action:
          - apigateway:TagResource
          Resource:
          - Fn::Sub: arn:aws:apigateway:${AWS::Region}::/apis/*
  ZerveFargateRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-fargate-role
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      Description: Task role for fargate tasks that run code from Zerve canvas blocks
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ecs-tasks.amazonaws.com
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              aws:SourceAccount:
                Ref: AWS::AccountId
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveFargateTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-fargate-task-execution-role
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      Description: Task execution role for fargate tasks that run code from Zerve
        canvas blocks
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ecs-tasks.amazonaws.com
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              aws:SourceAccount:
                Ref: AWS::AccountId
      ManagedPolicyArns:
      - Ref: ZerveLogsPushPolicy
      - Ref: ZerveECRPullPolicy
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-lambda-execution-role
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
          Condition:
            StringEquals:
              aws:sourceAccount:
                Ref: AWS::AccountId
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveExecutorAssumeRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-executor-assume-role
      Description: Role used internally by Zerve executors' runtime to manage block
        state on S3
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Principal:
            AWS:
            - Fn::GetAtt:
              - ZerveRole
              - Arn
          Action:
          - sts:AssumeRole
          - sts:TagSession
          Condition:
            StringLike:
              aws:RequestTag/zerve:canvas-id: '*'
            ForAnyValue:StringEquals:
              sts:TransitiveTagKeys:
              - zerve:canvas-id
        - Effect: Allow
          Principal:
            AWS:
            - Ref: AWS::AccountId
          Action:
          - sts:AssumeRole
          - sts:TagSession
          Condition:
            StringLike:
              aws:RequestTag/zerve:canvas-id: '*'
            ForAnyValue:StringEquals:
              sts:TransitiveTagKeys:
              - zerve:canvas-id
            ArnEquals:
              aws:PrincipalArn:
              - Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/zerve-executor-assume-role
      Policies:
      - PolicyName: allow-self-assume
        PolicyDocument:
          Version: 2012-10-17
          Statement:
          - Effect: Allow
            Resource:
              Fn::Sub: arn:aws:iam::${AWS::AccountId}:role/zerve-executor-assume-role
            Action:
            - sts:AssumeRole
            - sts:TagSession
      ManagedPolicyArns:
      - Ref: ZerveStateBucketCanvasScopedPolicy
      - Ref: ZerveBedrockInvokeModelPolicy
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ApiLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: zerve-api-lambda-role
      Description: Role for lambdas that run code from Zerve API-builder blocks
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Action: sts:AssumeRole
          Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Condition:
            StringEquals:
              aws:sourceAccount:
                Ref: AWS::AccountId
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveSagemakerRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: sagemaker
      Description: Role for sagemaker jobs that run code from Zerve canvas GPU-powered
        blocks
      PermissionsBoundary:
        Fn::If:
        - AttachPermissionsBoundary
        - Ref: PermissionsBoundaryArn
        - Ref: AWS::NoValue
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
        - Action: sts:AssumeRole
          Effect: Allow
          Principal:
            Service: sagemaker.amazonaws.com
          Condition:
            StringEquals:
              aws:sourceAccount:
                Ref: AWS::AccountId
      ManagedPolicyArns:
      - Ref: ZerveECRPullPolicy
      - Ref: ZerveLogsPushPolicy
      - Ref: ZerveStateBucketReadWritePolicy
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ZerveImageBuild:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.eu-west-1.amazonaws.com/zerve-deployment-templates/2fbc87e2a0451e966aaa9e3e6d82b927.template
      Parameters:
        Bucket:
          Ref: ZerveStateBucket
        OIDCProviderArn: ''
        PermissionsBoundaryArn:
          Ref: PermissionsBoundaryArn
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  ServiceDiscoveryNamespace:
    Type: AWS::ServiceDiscovery::PrivateDnsNamespace
    Condition: CreateFargateApiDeploymentsInfra
    Properties:
      Name: zerve-ecs-api
      Vpc:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  VpcLink:
    Type: AWS::ApiGatewayV2::VpcLink
    Condition: CreateFargateApiDeploymentsInfra
    Properties:
      Name: zerve-ecs-api-vpc-link
      SubnetIds:
        Fn::If:
        - CreateVpc
        - Fn::Split:
          - ','
          - Fn::GetAtt:
            - ZerveNetworking
            - Outputs.PrivateSubnets
        - Ref: PrivateSubnets
      SecurityGroupIds:
      - Ref: VpcLinkSecurityGroup
      Tags:
        Fn::If:
        - ApplyTags
        - zerve:owned: 'true'
          zerve:environment:
            Ref: Env
        - Ref: AWS::NoValue
  VpcLinkSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Condition: CreateFargateApiDeploymentsInfra
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      GroupDescription: Security group for vpc link
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  PublicLBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      GroupDescription: Security group for public load balancer of a Zerve hosted
        app
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        IpProtocol: tcp
        FromPort: 80
        ToPort: 80
      - CidrIp: 0.0.0.0/0
        IpProtocol: tcp
        FromPort: 443
        ToPort: 443
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  EcsApiServiceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Condition: CreateFargateApiDeploymentsInfra
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      GroupDescription: Security group for ECS service of a Zerve API deployment
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      SecurityGroupIngress:
      - SourceSecurityGroupId:
          Ref: VpcLinkSecurityGroup
        IpProtocol: tcp
        FromPort: 0
        ToPort: 65535
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  EcsHostedAppSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      GroupDescription: Security group for ECS service of a Zerve hosted app
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      SecurityGroupIngress:
      - SourceSecurityGroupId:
          Ref: PublicLBSecurityGroup
        IpProtocol: tcp
        FromPort: 0
        ToPort: 65535
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  CanvasBlockSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      GroupDescription: Security group for blocks in a canvas
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  DeployCallbackSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for deploy callback lambda
      VpcId:
        Fn::If:
        - CreateVpc
        - Fn::GetAtt:
          - ZerveNetworking
          - Outputs.VPC
        - Ref: VpcId
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
  EcsCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: zerve-ecs-cluster
      Tags:
        Fn::If:
        - ApplyTags
        - - Key: zerve:owned
            Value: 'true'
          - Key: zerve:environment
            Value:
              Ref: Env
        - Ref: AWS::NoValue
