AWSTemplateFormatVersion: '2010-09-09'
Description: Glean Cloud Formation template
Parameters:
  # Required
  ContactEmail:
    Type: String
    Description: Contact email to notify when your Glean workspace is ready to be configured
    AllowedPattern: ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$
    ConstraintDescription: Must be a valid email address
  SkipGleanImageVerification:
    Type: String
    Description: If true, allows running deploy images that have not been signed by Glean's central build orchestrator. Useful for sandbox/test accounts, or in situations where the image signer can't be used due to an SCP. Do not change this value unless explicitly instructed by Glean.
    AllowedValues:
      - "true"
      - "false"
    Default: "false"
  LatestAmiId:
    Description: SSM parameter path for desired AMI to use for the ECR image pre-processing instance
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64'
  SkipImagePreprocessing:
    Type: String
    Description: If true, skips running the image preprocessing instance and instead uses the regional central aws_deploy_build ECR repository. Please only use this if instructed by Glean.
    AllowedValues:
      - "true"
      - "false"
    Default: "false"
Conditions:
  RunImagePreprocessing: !Equals
    - !Ref SkipImagePreprocessing
    - "false"
  SkipImagePreprocessing: !Equals
    - !Ref SkipImagePreprocessing
    - "true"
Resources:
  # First, we define a set of resources dedicated to pulling a Glean-hosted ECR image to operate the deployment lambda
  # function. We should be able to deploy this lambda in any region, but Glean only builds its images in us-east-1, so
  # we first need to pull the desired image from Glean's central repo and re-upload to the regional, account-specific
  # ECR repository in the customer's account
  ### BEGIN DEPLOY_BUILD IMAGE PULL RESOURCES ###
  # First, define the role used to run the instance that will pre-process the image
  GleanDeployFunctionImagePullInstanceIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: GleanDeployFunctionImagePull
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: GleanDeployBuildImagePull
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:BatchGetImage
                  - ecr:DescribeImages
                  - ecr:GetDownloadUrlForLayer
                  - ecr:ListImages
                Resource: "arn:aws:ecr:us-east-1:518642952506:repository/aws_deploy_build"
              - Effect: Allow
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:BatchGetImage
                  - ecr:DescribeImages
                  - ecr:GetDownloadUrlForLayer
                  - ecr:ListImages
                  - ecr:CompleteLayerUpload
                  - ecr:UploadLayerPart
                  - ecr:InitiateLayerUpload
                  - ecr:PutImage
                Resource:
                  Fn::Sub: "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/aws_deploy_build"
              - Effect: Allow
                Action:
                  - cloudformation:SignalResource
                  - ecr:GetAuthorizationToken
                Resource: "*"
  # Also define the IAM instance profile so it can be attached to the EC2 instance
  GleanDeployFunctionImagePullInstanceIAMProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: GleanDeployFunctionImagePull
      Roles:
        - !Ref GleanDeployFunctionImagePullInstanceIAMRole
  # Then, define an ECR repository where the new regional, account-specific image will live. The deploy_build lambda
  # function should be able to pull from it.
  GleanDeployFunctionECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: aws_deploy_build
      EmptyOnDelete: true
      RepositoryPolicyText: !Sub |
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "AllowInternalLambdas",
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              },
              "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ecr:GetDownloadUrlForLayer",
                "ecr:ListImages"
              ],
              "Condition": {
                "StringLike": {
                  "aws:sourceArn": "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:*"
                }
              }
            }
          ]
        }
  # Now, create a VPC in which the instance can run
  BootstrapVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.2.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: glean-bootstrap-vpc
  # Create a subnet in that vpc
  BootstrapPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref BootstrapVpc
      CidrBlock: 10.2.128.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone:
        Fn::Select:
          - 1
          - Fn::GetAZs:
              Ref: "AWS::Region"
      Tags:
        - Key: Name
          Value: "bootstrap-public-subnet"
  # Create an IGW and associate with the bootstrap vpc
  BootstrapIgw:
    Type: AWS::EC2::InternetGateway
    Properties: { }
  BootstrapVpcGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref BootstrapVpc
      InternetGatewayId: !Ref BootstrapIgw
  # Create a route table for the subnet
  BootstrapRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref BootstrapVpc
  # Add a route to the table sending 0.0.0.0/0 to the IGW
  BootstrapInternetRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref BootstrapIgw
      RouteTableId: !Ref BootstrapRouteTable
  # Associate the route table with the subnet
  BootstrapPublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref BootstrapRouteTable
      SubnetId: !Ref BootstrapPublicSubnet
  # Create a security group for the instance that allows outbound access to pull in the image and download requirements
  BootstrapSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Glean bootstrap EC2 instance
      VpcId: !Ref BootstrapVpc
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          FromPort: 0
          ToPort: 0
          IpProtocol: "-1"
  # Create a launch template for the instance so we can set all the appropriate fields (the AWS::EC2::Instance spec
  # doesn't allow for some things like metadata options etc.)
  GleanDeployFunctionImagePullInstanceLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        EbsOptimized: true
        IamInstanceProfile:
          Arn:
            Fn::GetAtt: [ GleanDeployFunctionImagePullInstanceIAMProfile, Arn ]
        ImageId: !Ref LatestAmiId
        InstanceInitiatedShutdownBehavior: terminate
        InstanceType: t3.medium
        BlockDeviceMappings:
          - DeviceName: /dev/sda1
            Ebs:
              VolumeSize: 50
              DeleteOnTermination: "true"
        MetadataOptions:
          HttpTokens: "required"
          HttpEndpoint: "enabled"
          HttpPutResponseHopLimit: 2
        NetworkInterfaces:
          # TODO: remove the public ip and add a NAT here instead
          - AssociatePublicIpAddress: true
            DeviceIndex: "0"
            DeleteOnTermination: true
            SubnetId: !Ref BootstrapPublicSubnet
            Groups:
              - !Ref BootstrapSecurityGroup
  # Create the instance - it'll run the user data code below on startup, then immediately shut itself down and
  # terminate, since it won't be needed again. Once the instance has pre-processed the image successfully, it will
  # send a notification to this CFT stack that it's effective creation is complete (see the `CreationPolicy` field
  # below).
  GleanDeployFunctionImagePullInstance:
    Type: AWS::EC2::Instance
    DependsOn:
      - GleanDeployFunctionECRRepository
    CreationPolicy: # <--- creation policy with timeout of 5 minutes - waits for the instance to signal that the image pull is successful
      ResourceSignal:
        Timeout: PT5M
    Condition: RunImagePreprocessing
    Properties:
      Tags:
        - Key: Name
          Value: GleanDeployFunctionImagePull
      LaunchTemplate:
        LaunchTemplateId: !Ref GleanDeployFunctionImagePullInstanceLaunchTemplate
        Version: !GetAtt GleanDeployFunctionImagePullInstanceLaunchTemplate.DefaultVersionNumber
      # The following script downloads the PROD image for Glean's deploy_build lambda function and then re-uploads it to
      # the regional, account-specific ECR repository in this account. We have to do this since lambda functions require
      # that source images are pulled from the same region, and Glean only builds images in us-east-1 repositories
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          set -ex
          sudo yum update -y
          sudo yum install -y docker
          sudo service docker start
          sudo usermod -a -G docker ec2-user
          sudo chmod 666 /var/run/docker.sock
          aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 518642952506.dkr.ecr.us-east-1.amazonaws.com
          docker pull 518642952506.dkr.ecr.us-east-1.amazonaws.com/aws_deploy_build:PROD
          docker tag 518642952506.dkr.ecr.us-east-1.amazonaws.com/aws_deploy_build:PROD ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/aws_deploy_build:PROD
          aws ecr get-login-password --region ${AWS::Region} | docker login --username AWS --password-stdin ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com
          docker push ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/aws_deploy_build:PROD
          aws cloudformation --region ${AWS::Region} signal-resource --stack-name ${AWS::StackName} --logical-resource-id 'GleanDeployFunctionImagePullInstance' --unique-id 'glean-deploy-build-image-download' --status SUCCESS
          sudo shutdown
  ### END DEPLOY BUILD IMAGE PULL RESOURCES ###
  # Now, define all the standard Glean bootstrapping resources (deploy-build lambda function and IAM roles/policies)
  # This wait condition hack is taken from https://garbe.io/blog/2017/07/17/cloudformation-hacks/ - CFT's don't support
  # conditional DependsOn blocks directly, so this is the workaround:
  RunImagePreprocessWaitHandle:
    Condition: RunImagePreprocessing
    DependsOn: GleanDeployFunctionImagePullInstance
    Type: "AWS::CloudFormation::WaitConditionHandle"
  SkipImagePreprocessWaitHandle:
    Type: "AWS::CloudFormation::WaitConditionHandle"
  ImagePreprocessWaitCondition:
    Type: "AWS::CloudFormation::WaitCondition"
    Properties:
      Handle:
        Fn::If:
          - RunImagePreprocessing
          - !Ref RunImagePreprocessWaitHandle
          - !Ref SkipImagePreprocessWaitHandle
      Timeout: "10"
      Count: 0
  GleanDeployFunction:
    Type: AWS::Lambda::Function
    # Ensure we only deploy the lambda after preprocessing the image
    DependsOn: ImagePreprocessWaitCondition
    Properties:
      Architectures:
        - x86_64
      Code:
        ImageUri:
          'Fn::If':
            - RunImagePreprocessing
            - Fn::Sub: "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/aws_deploy_build:PROD"
            - Fn::Sub: "518642952506.dkr.ecr.${AWS::Region}.amazonaws.com/aws_deploy_build:PROD"
      Description: Lambda used to run deployment operations for Glean installation
      FunctionName: deploy_build
      MemorySize: 512
      PackageType: Image
      Role:
        Fn::GetAtt: [ DeployBuildFunctionRole, Arn ]
      Timeout: 900
      Environment:
        Variables:
          allow_untrusted:
            Ref: SkipGleanImageVerification
  # Role to execute the deploy_build lambda function
  # https://docs.google.com/document/d/16V_BHAKTNJV1IMeXzeO5gxMajLIKWNwbweZfHcrNGgU/edit#bookmark=kix.18veayq6sbdq
  DeployBuildFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      Policies:
        - PolicyName: DeployBuildConfigReadPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - s3:Get*
                  - s3:ListBucket*
                Resource:
                  - Fn::Sub: "arn:aws:s3:::config-${AWS::AccountId}"
                  - Fn::Sub: "arn:aws:s3:::config-${AWS::AccountId}/*"
        - PolicyName: DeployBuildCodeBuildPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - ecr:GetAuthorizationToken
                  - signer:Describe*
                  - signer:Get*
                  - signer:List*
                Resource: "*"
              - Effect: Allow
                Action:
                  - ec2:DescribeVpcs
                  - ec2:DescribeSubnets
                  - ec2:DescribeSecurityGroups
                Resource: "*"
              - Effect: Allow
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:BatchGetImage
                  - ecr:DescribeImages
                  - ecr:GetDownloadUrlForLayer
                  - ecr:ListImages
                Resource: "arn:aws:ecr:us-east-1:518642952506:repository/*"
              - Effect: Allow
                Action:
                  - codebuild:BatchGetBuilds
                  - codebuild:BatchGetProjects
                  - codebuild:CreateProject
                  - codebuild:StartBuild
                Resource: "*"
              - Effect: Allow
                Action:
                  - iam:PassRole
                Resource:
                  Fn::GetAtt: [ CodebuildRole, Arn ]
      RoleName: deploy-build
  # Role for Glean to invoke the deploy_build lambda function:
  # https://docs.google.com/document/d/16V_BHAKTNJV1IMeXzeO5gxMajLIKWNwbweZfHcrNGgU/edit#bookmark=id.fczxyy4sk6st
  GleanDeployerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Federated: accounts.google.com
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                # GCP Service Account ID for Glean-owned deployer service account
                accounts.google.com:aud: "102499298255048943192"
      Policies:
        - PolicyName: GleanDeployBuildInvoker
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - lambda:InvokeFunction
                Resource:
                  Fn::GetAtt: [ GleanDeployFunction, Arn ]
        # Additional policies added to assist in setting up central infrastructure - will be removed after setup is complete
        - PolicyName: GleanInitialSetup
          PolicyDocument:
            Statement:
              - Sid: ElasticLoadBalancingView
                Effect: Allow
                Action:
                  - elasticloadbalancing:DescribeLoadBalancers
                  - elasticloadbalancing:DescribeListeners
                  - elasticloadbalancing:DescribeListenerCertificates
                Resource: "*"
              - Sid: CertificateManagerView
                Effect: Allow
                Action:
                  - acm:DescribeCertificate
                  - acm:ListCertificates
                Resource: "*"
              - Sid: IPJCSecretWrite
                Effect: Allow
                Action:
                  - secretsmanager:PutSecretValue
                Resource:
                  - Fn::GetAtt: [ GleanIPJCSecret, Id ]
              - Sid: ContactEmailSecretRead
                Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource:
                  - Fn::GetAtt: [ GleanContactEmailSecret, Id ]
      RoleName: glean-deployer
  # Role to run Glean deployment code in codebuild builds
  # https://docs.google.com/document/d/16V_BHAKTNJV1IMeXzeO5gxMajLIKWNwbweZfHcrNGgU/edit#bookmark=id.ffl7ykp9qjc
  CodebuildRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action: sts:AssumeRole
      RoleName: codebuild
  # Role for Glean engineers to view resources within the account for debugging purposes
  # https://docs.google.com/document/d/16V_BHAKTNJV1IMeXzeO5gxMajLIKWNwbweZfHcrNGgU/edit#bookmark=id.gf53wz7q6vp4
  GleanViewerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2008-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: arn:aws:iam::518642952506:root
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
        - arn:aws:iam::aws:policy/AmazonVPCReadOnlyAccess
        - arn:aws:iam::aws:policy/ElasticLoadBalancingReadOnly
        - arn:aws:iam::aws:policy/AmazonBedrockReadOnly
        - arn:aws:iam::aws:policy/AWSBillingReadOnlyAccess
      Policies:
        - PolicyName: GleanCodeBuildViewer
          PolicyDocument:
            Statement:
              - Sid: ViewCodeBuildProjectsAndBuilds
                Effect: Allow
                Action:
                  - codebuild:BatchGet*
                  - codebuild:List*
                Resource: "*"
        - PolicyName: GleanSagemakerViewer
          PolicyDocument:
            Statement:
              - Sid: ReadSagemakerTrainingJobs
                Effect: Allow
                Action:
                  - sagemaker:ListTags
                  - sagemaker:ListTrainingJobs
                  - sagemaker:DescribeTrainingJob
                Resource: "*"
        - PolicyName: GleanLambdaViewer
          PolicyDocument:
            Statement:
              - Sid: ReadLambdaResources
                Effect: Allow
                Action:
                  - lambda:Get*
                  - lambda:List*
                Resource:
                  - Fn::Sub: "arn:aws:lambda:*:${AWS::AccountId}:function:*"
                  - Fn::Sub: "arn:aws:lambda:*:${AWS::AccountId}:code-signing-config:*"
                  - Fn::Sub: "arn:aws:lambda:*:${AWS::AccountId}:event-source-mapping:*"
                  - Fn::Sub: "arn:aws:lambda:*:${AWS::AccountId}:layer:*"
              - Sid: ReadGeneralLambdaInfo
                Effect: Allow
                Action:
                  - lambda:ListFunctions
                  - lambda:ListEventSourceMappings
                  - lambda:ListLayerVersions
                  - lambda:ListLayers
                  - lambda:GetAccountSettings
                  - lambda:ListCodeSigningConfigs
                Resource: "*"
        - PolicyName: GleanEKSViewer
          PolicyDocument:
            Statement:
              - Sid: ViewGlobalEKSInfo
                Effect: Allow
                Action:
                  - eks:DescribeAddonConfiguration
                  - eks:ListClusters
                  - eks:DescribeAddonVersions
                Resource: "*"
              - Sid: ViewGleanClusterAndKubeResources
                Effect: Allow
                Action:
                  - eks:AccessKubernetesApi
                  - eks:Describe*
                  - eks:List*
                Resource:
                  - Fn::Sub: "arn:aws:eks:*:${AWS::AccountId}:cluster/glean-cluster*"
                  - Fn::Sub: "arn:aws:eks:*:${AWS::AccountId}:addon/glean-cluster*"
                  - Fn::Sub: "arn:aws:eks:*:${AWS::AccountId}:identityproviderconfig/glean-cluster*"
                  - Fn::Sub: "arn:aws:eks:*:${AWS::AccountId}:nodegroup/glean-cluster*"
                  - Fn::Sub: "arn:aws:eks:*:${AWS::AccountId}:fargateprofile/glean-cluster*"
        - PolicyName: GleanCloudWatchViewer
          PolicyDocument:
            Statement:
              - Sid: LogInfoViewer
                Effect: Allow
                Action:
                  - logs:Describe*
                  - logs:GetLogDelivery
                  - logs:StartLiveTail
                  - logs:StopLiveTail
                  - logs:StopQuery
                  - logs:TestMetricFilter
                Resource: "*"
              - Sid: GetScrubbedLogs
                Effect: Allow
                Action:
                  - logs:FilterLogEvents
                  - logs:GetLogEvents
                  - logs:GetLogGroupFields
                  - logs:GetLogRecord
                  - logs:GetQueryResults
                  - logs:ListTagsLogGroup
                  - logs:StartQuery
                Resource:
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/codebuild/*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/lambda/*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/containerinsights/*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/eks/*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/sagemaker/*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:glean_application_logs:*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:extra-logs:*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:operation-log:*"
                  - Fn::Sub: "arn:aws:logs:*:${AWS::AccountId}:log-group:rltp-adjustment-log:*"
              - Sid: GetCWInfo
                Effect: Allow
                Action:
                  - cloudwatch:GetDashboard
                  - cloudwatch:GetMetricData
                  - cloudwatch:GetMetricStatistics
                  - cloudwatch:GetMetricStream
                  - cloudwatch:ListDashboards
                  - cloudwatch:ListMetrics
                  - cloudwatch:ListMetricStreams
                Resource: "*"
              - Sid: RdsView
                Effect: Allow
                Action:
                  - rds:Describe*
                  - rds:List*
                Resource: "*"
              - Sid: ViewCodeGuruProfiles
                Effect: Allow
                Action:
                  - codeguru-profiler:Get*
                  - codeguru-profiler:BatchGet*
                  - codeguru-profiler:Describe*
                  - codeguru-profiler:List*
                Resource: "*"
        - PolicyName: DescribeBuckets
          PolicyDocument:
            Statement:
              - Sid: BucketInfo
                Effect: Allow
                Action:
                  - s3:GetBucket*
                  - s3:GetEncryptionConfiguration
                  - s3:GetIntelligentTieringConfiguration
                  - s3:GetInventoryConfiguration
                  - s3:GetLifecycleConfiguration
                  - s3:GetMetricsConfiguration
                  - s3:ListAllMyBuckets
                Resource: "*"
        - PolicyName: DecodeAuthErrors
          PolicyDocument:
            Statement:
              - Sid: STS
                Effect: Allow
                Action:
                  - sts:DecodeAuthorizationMessage
                Resource: "*"
        - PolicyName: GleanBillingViewer
          PolicyDocument:
            Statement:
              - Sid: ViewCostExplorer
                Effect: Allow
                Action:
                  - ce:DescribeReport
                Resource: "*"
        - PolicyName: GleanCloudFormationViewer
          PolicyDocument:
            Statement:
              - Sid: CloudFormation
                Effect: Allow
                Action:
                  - cloudformation:ListStacks
                  - cloudformation:DescribeStacks
                  - cloudformation:DescribeStackEvents
                  - cloudformation:DescribeStackResource
                  - cloudformation:DescribeStackResources
                Resource: "*"
        - PolicyName: GleanWafViewer
          PolicyDocument:
            Statement:
              - Sid: WafV2
                Effect: Allow
                Action:
                  - wafv2:CheckCapacity
                  - wafv2:Describe*
                  - wafv2:Get*
                  - wafv2:List*
                Resource: "*"
        - PolicyName: GleanECRViewer
          PolicyDocument:
            Statement:
              - Sid: ECRView
                Effect: Allow
                Action:
                  - ecr:GetAccountSetting
                  - ecr:GetRepositoryPolicy
                  - ecr:GetRegistryPolicy
                  - ecr:Describe*
                  - ecr:List*
                Resource: "*"
        - PolicyName: GleanRDSViewer
          PolicyDocument:
            Statement:
              - Sid: RDSView
                Effect: Allow
                Action:
                  - rds:Describe*
                  - rds:List*
                  - pi:Get*
                  - pi:Describe*
                  - pi:List*
                Resource: "*"
        - PolicyName: GleanIAMViewer
          PolicyDocument:
            Statement:
              - Sid: IAMView
                Effect: Allow
                Action:
                  - iam:ListRoles
                  - iam:ListRolePolicies
                  - iam:ListRoleTags
                  - iam:GetRole
                  - iam:GetRolePolicy
                  - iam:GetPolicy
                  - iam:GetPolicyVersion
                  - iam:ListPolicies
                  - iam:ListAttachedRolePolicies
                  - iam:ListEntitiesForPolicy
                Resource: "*"
        - PolicyName: GleanFirehoseViewer
          PolicyDocument:
            Statement:
              - Sid: FirehoseView
                Effect: Allow
                Action:
                  - firehose:ListDeliveryStreams
                  - firehose:DescribeDeliveryStream
                  - firehose:ListTagsForDeliveryStream
                Resource: "*"
        - PolicyName: GleanSupportCasesViewer
          PolicyDocument:
            Statement:
              - Sid: SupportCasesView
                Effect: Allow
                Action:
                  - support:DescribeCases
                  - support:DescribeCommunications
                  - support:DescribeIssues
                  - support:DescribeIssueTypes
                  - support:DescribeServices
                  - support:DescribeSeverityLevels
                  - support:DescribeTrustedAdvisorCheckRefreshStatuses
                  - support:DescribeTrustedAdvisorCheckResult
                  - support:DescribeTrustedAdvisorCheckSummaries
                Resource: "*"
        - PolicyName: GleanServiceQuotaViewer
          PolicyDocument:
            Statement:
              - Sid: ServiceQuotas
                Effect: Allow
                Action:
                  - servicequotas:Get*
                  - servicequotas:List*
                Resource: "*"
      RoleName: glean-viewer
  # Secret used temporarily for secure communication with Glean
  GleanIPJCSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: ipjc_auth_token
  GleanContactEmailSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: glean_contact_email
      SecretString:
        Ref: ContactEmail
  # IAM Managed Policy allowing roles to pull from Glean's central ECR repositories
  GleanEngineeringECRPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Resource:
              - arn:aws:iam::518642952506:role/CentralStorageSourcesReader
      PolicyName: AssumeCentralStorageSourcesReader
      Roles:
        - Ref: CodebuildRole
  # IAM Managed Policy allowing the codebuild role to set up all necessary infrastructure within the account
  GleanCodeBuildDeployPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: GleanCodeBuildDeploy
      Roles:
        - Ref: CodebuildRole
      PolicyDocument:
        Version: '2012-10-17'
        # NOTE: this policy was partially generated using the IAM Analyzer feature
        Statement:
          - Sid: ServiceQuotas
            Effect: Allow
            Action:
              - servicequotas:Get*
              - servicequotas:List*
              - servicequotas:RequestServiceQuotaIncrease
            Resource: "*"
          - Sid: BastionSSMAccess
            Effect: Allow
            Action:
              - ssm:Get*
              - ssm:List*
              - ssm:StartSession
              - ssm:TerminateSession
              - ssm:Describe*
            Resource: "*"
          - Sid: ACM
            Effect: Allow
            Action:
              - acm:AddTagsToCertificate
              - acm:DeleteCertificate
              - acm:DescribeCertificate
              - acm:GetCertificate
              - acm:ListCertificates
              - acm:ListTagsForCertificate
              - acm:RemoveTagsFromCertificate
              - acm:RenewCertificate
              - acm:RequestCertificate
              - acm:UpdateCertificateOptions
            Resource: "*"
          - Sid: InternalRepositoryPermissions
            Effect: Allow
            Action:
              - ecr:BatchCheckLayerAvailability
              - ecr:BatchGetImage
              - ecr:DescribeImages
              - ecr:DescribeRepositories
              - ecr:GetDownloadUrlForLayer
              - ecr:ListImages
              - ecr:CompleteLayerUpload
              - ecr:UploadLayerPart
              - ecr:InitiateLayerUpload
              - ecr:PutImage
              - ecr:TagResource
              - ecr:UntagResource
              - ecr:ListTagsForResource
              - ecr:DeleteRepository
              - ecr:DeleteRepositoryPolicy
              - ecr:GetRepositoryPolicy
              - ecr:SetRepositoryPolicy
            Resource:
              Fn::Sub: "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/*"
          - Sid: InternalEcrPermissions
            Effect: Allow
            Action:
              - ecr:GetAuthorizationToken
              - ecr:CreateRepository
            Resource: "*"
          - Sid: ComputePrimitives
            Effect: Allow
            Action:
              - autoscaling:CreateOrUpdateTags
              - autoscaling:Describe*
              - autoscaling:DeleteTags
              - ec2:AllocateAddress
              - ec2:AssociateRouteTable
              - ec2:AttachInternetGateway
              - ec2:AttachVolume
              - ec2:AuthorizeSecurityGroup*
              - ec2:CreateInternetGateway
              - ec2:CreateLaunchTemplate*
              - ec2:CreateNatGateway
              - ec2:CreateNetworkInterface*
              - ec2:CreateRoute
              - ec2:CreateRouteTable
              - ec2:CreateSecurityGroup
              - ec2:RevokeSecurityGroupEgress
              - ec2:RevokeSecurityGroupIngress
              - ec2:CreateSubnet
              - ec2:CreateTags
              - ec2:CreateVolume
              - ec2:CreateVpc*
              - ec2:DeleteLaunchTemplate*
              - ec2:DeleteNatGateway
              - ec2:DeleteNetworkInterface
              - ec2:DeleteSecurityGroup
              - ec2:DeleteTags
              - ec2:DeleteVpcEndpoint
              - ec2:Describe*
              - ec2:DetachVolume
              - ec2:DisableEbsEncryptionByDefault
              - ec2:EnableEbsEncryptionByDefault
              - ec2:GetEbsEncryptionByDefault
              - ec2:GetSecurityGroupsForVpc
              - ec2:ModifyLaunchTemplate
              - ec2:ModifySubnetAttribute
              - ec2:ModifyNetworkInterfaceAttribute
              - ec2:ModifyVpcAttribute
              - ec2:ReleaseAddress
              - ec2:RevokeSecurityGroup*
              - ec2:RunInstances
              - ec2:TerminateInstances
              - ec2:Delete*
              - ec2:Disassociate*
              - ec2:Detach*
              - ec2:StopInstances
              - elasticloadbalancing:CreateListener
              - elasticloadbalancing:CreateLoadBalancer
              - elasticloadbalancing:CreateTargetGroup
              - elasticloadbalancing:Delete*
              - elasticloadbalancing:DeregisterTargets
              - elasticloadbalancing:Describe*
              - elasticloadbalancing:ModifyLoadBalancerAttributes
              - elasticloadbalancing:ModifyTargetGroupAttributes
              - elasticloadbalancing:RegisterTargets
              - elasticloadbalancing:SetWebACL
              - lambda:*
              - route53:AssociateVPCWithHostedZone
              - codebuild:BatchGetProjects
            Resource: "*"

          - Sid: ElastiCache
            Effect: Allow
            Action:
              - elasticache:AddTagsToResource
              - elasticache:BatchApplyUpdateAction
              - elasticache:CreateCacheCluster
              - elasticache:CreateCacheSecurityGroup
              - elasticache:CreateCacheSubnetGroup
              - elasticache:DeleteCacheCluster
              - elasticache:DeleteCacheParameterGroup
              - elasticache:DeleteCacheSecurityGroup
              - elasticache:DeleteCacheSubnetGroup
              - elasticache:Describe*
              - elasticache:List*
              - elasticache:ModifyCacheCluster
              - elasticache:ModifyCacheSubnetGroup
              - elasticache:RemoveTagsFromResource
            Resource: "*"

          - Sid: IAM
            Effect: Allow
            Action:
              - iam:AddRoleToInstanceProfile
              - iam:AttachRolePolicy
              - iam:CreateInstanceProfile
              - iam:CreateOpenIDConnectProvider
              - iam:CreatePolicy*
              - iam:CreateRole
              - iam:CreateServiceLinkedRole
              - iam:DeleteInstanceProfile
              - iam:DeletePolicy*
              - iam:DeleteRole
              - iam:DeleteRolePolicy
              - iam:DetachRolePolicy
              - iam:Get*
              - iam:List*
              - iam:PutRolePolicy
              - iam:PutRolePermissionsBoundary
              - iam:PassRole
              - iam:RemoveRoleFromInstanceProfile
              - iam:Tag*
              - iam:Untag*
              - iam:DeleteOpenIDConnectProvider
              - iam:UpdateOpenIDConnectProviderThumbprint
              - iam:UpdateAssumeRolePolicy
              - iam:UpdateRoleDescription
            Resource: "*"

          - Sid: K8s
            Effect: Allow
            Action:
              - ecr:BatchGetImage
              - ecr:DescribeImages
              - ecr:GetAuthorizationToken
              - ecr:GetDownloadUrlForLayer
              - eks:Create*
              - eks:Delete*
              - eks:Describe*
              - eks:List*
              - eks:Update*
              - eks:TagResource
              - eks:UntagResource
              - eks:AssociateEncryptionConfig
            Resource: "*"

          - Sid: KMSandSecrets
            Effect: Allow
            Action:
              - kms:CreateAlias
              - kms:CreateGrant
              - kms:CreateKey
              - kms:Decrypt
              - kms:DescribeKey
              - kms:EnableKeyRotation
              - kms:DeleteAlias
              - kms:ScheduleKeyDeletion
              - kms:Encrypt
              - kms:GenerateDataKey
              - kms:GetKeyPolicy
              - kms:GetKeyRotationStatus
              - kms:ListAliases
              - kms:ListResourceTags
              - kms:PutKeyPolicy
              - kms:Sign
              - kms:TagResource
              - secretsmanager:CreateSecret
              - secretsmanager:GetSecretValue
              - secretsmanager:TagResource
              - secretsmanager:DescribeSecret
              - secretsmanager:GetResourcePolicy
              - dynamodb:ListTables
            Resource: "*"
          - Sid: DynamoDbForTerraform
            Effect: Allow
            Action:
              - dynamodb:DescribeTable
              - dynamodb:GetItem
              - dynamodb:PutItem
              - dynamodb:DeleteItem
              - dynamodb:CreateTable
            Resource:
              Fn::Sub: "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/glean-terraform-state"
          - Sid: RAM
            Effect: Allow
            Action:
              - ram:Get*
              - ram:List*
              - ram:AcceptResourceShareInvitation
              - ram:DissociateResourceShare
            Resource: "*"
          - Sid: RDS
            Effect: Allow
            Action:
              - rds:AddTagsToResource
              - rds:CreateDBInstance
              - rds:CreateDBParameterGroup
              - rds:CreateDBSubnetGroup
              - rds:Describe*
              - rds:ListTagsForResource
              - rds:ModifyDBParameterGroup
              - rds:RebootDBInstance
              - rds:RestoreDBInstanceFromDBSnapshot
              - rds:StartDBInstance
              - rds:StopDBInstance
              - rds:DeleteDBInstance
              - rds:DeleteDBParameterGroup
              - rds:DeleteDBSubnetGroup
              - rds:ModifyDBInstance
              - rds:ResetDBParameterGroup
              - rds:CreateDBSnapshot
              - rds:RemoveTagsFromResource
            Resource: "*"

          - Sid: SNSandSQS
            Effect: Allow
            Action:
              - sns:AddPermission
              - sns:CheckIfPhoneNumberIsOptedOut
              - sns:ConfirmSubscription
              - sns:CreateTopic
              - sns:DeleteEndpoint
              - sns:DeleteTopic
              - sns:Get*
              - sns:List*
              - sns:Publish
              - sns:RemovePermission
              - sns:SetSubscriptionAttributes
              - sns:SetTopicAttributes
              - sns:Subscribe
              - sns:TagResource
              - sns:UntagResource
              - sns:Unsubscribe
              - sqs:Get*
              - sqs:List*
              - sqs:CreateQueue
              - sqs:DeleteQueue
              - sqs:SetQueueAttributes
              - sqs:TagQueue
              - sqs:UntagQueue
            Resource: "*"

          - Sid: S3
            Effect: Allow
            Action:
              - s3:CreateBucket
              - s3:DeleteBucket
              - s3:DeleteBucketPolicy
              - s3:DeleteObject*
              - s3:GetAccelerateConfiguration
              - s3:Get*
              - s3:GetEncryptionConfiguration
              - s3:GetLifecycleConfiguration
              - s3:GetReplicationConfiguration
              - s3:List*
              - s3:Put*
              - s3:TagResource
              - s3:UntagResource
            Resource: "*"

          - Sid: Util
            Effect: Allow
            Action:
              - logs:*
              - sts:GetCallerIdentity
              - tag:GetResources
              - tag:TagResources
              - tag:UntagResources
            Resource: "*"

          - Sid: WAF
            Effect: Allow
            Action:
              - wafv2:AssociateWebACL
              - wafv2:CreateIPSet
              - wafv2:CreateRegexPatternSet
              - wafv2:CreateWebACL
              - wafv2:DeleteIPSet
              - wafv2:DeleteWebACL
              - wafv2:DisassociateWebACL
              - wafv2:Get*
              - wafv2:List*
              - wafv2:TagResource
              - wafv2:UntagResource
              - wafv2:UpdateIPSet
              - wafv2:UpdateWebACL
              - wafv2:PutLoggingConfiguration
              - wafv2:DeleteLoggingConfiguration
              - wafv2:DeleteRegexPatternSet
            Resource: "*"
          - Sid: GlueAthena
            Effect: Allow
            Action:
              - athena:Get*
              - athena:List*
              - athena:CreateDataCatalog
              - athena:CreateWorkGroup
              - athena:DeleteWorkGroup
              - athena:TagResource
              - athena:UntagResource
              - glue:Get*
              - glue:List*
              - glue:CreateDatabase
              - glue:CreateTable
              - glue:DeleteDatabase
              - glue:DeleteTable
              - glue:TagResource
              - glue:UntagResource
              - glue:UpdateTable
            Resource: "*"
          - Sid: Firehose
            Effect: Allow
            Action:
              - firehose:CreateDeliveryStream
              - firehose:DeleteDeliveryStream
              - firehose:DescribeDeliveryStream
              - firehose:ListDeliveryStreams
              - firehose:PutRecord
              - firehose:PutRecordBatch
              - firehose:TagDeliveryStream
              - firehose:UntagDeliveryStream
              - firehose:UpdateDestination
              - firehose:ListTagsForDeliveryStream
            Resource: "*"
          - Sid: Support
            Effect: Allow
            Action:
              - support:AddCommunicationToCase
              - support:CreateCase
              - support:DescribeCases
              - support:DescribeCommunications
              - support:DescribeIssues
              - support:DescribeIssueTypes
              - support:DescribeServices
              - support:DescribeSeverityLevels
              - support:DescribeTrustedAdvisorCheckRefreshStatuses
              - support:DescribeTrustedAdvisorCheckResult
              - support:DescribeTrustedAdvisorCheckSummaries
              - support:ResolveCase
            Resource: "*"
