Description: Create IAM roles for tidbcloud o11y
Parameters:
  O11yGlobalRoleArns:
    Type: CommaDelimitedList
    Default: "arn:aws:iam::557537366020:role/globalserver-role-780c8f0,arn:aws:iam::380838443567:role/tidbcloud-global-apigw"
    Description: "The ARNs of the O11Y global IAM roles that can assume the API Gateway role (comma-separated list)"
  RequiredManagedByTagValue:
    Type: String
    Default: "PingCAP"
    Description: "Required value for the ManagedBy tag on O11Y resources"
Resources:
  # TiDBCloud O11y Control Plane Role
  #
  # Note:
  # During new region provisioning, only the trust relationship of this role
  # (tidbcloud-o11y-control-plane-role) will be dynamically updated to authorize
  # the EKS OIDC provider.
  #
  # No new IAM permission actions or resource scopes will be introduced.
  # After provisioning is completed, this IAM role will not be modified further.
  TiDBCloudO11yControlPlaneRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: tidbcloud-o11y-control-plane-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              # placeholder, will be replaced after eks creation
              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
            Action: sts:AssumeRole
      Policies:
        # Ownership contract for mutable resources:
        # - creation requires aws:RequestTag/ManagedBy
        # - later writes require aws:ResourceTag/ManagedBy
        # Service-specific exceptions remain in their owning policy.
        - PolicyName: O11yControlPlanePolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              # EC2 resources used by O11Y control-plane provisioning.
              - Effect: Allow
                Action:
                  - ec2:DescribeRouteTables
                  - ec2:DescribeSubnets
                  - ec2:DescribeVpcEndpointServiceConfigurations
                  - ec2:DescribeVpcEndpointServicePermissions
                  - ec2:DescribeVpcEndpointServices
                Resource: "*"
              - Effect: Allow
                Action:
                  - ec2:CreateVpcEndpointServiceConfiguration
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - ec2:CreateRoute
                  - ec2:DeleteRoute
                  - ec2:DeleteVpcEndpointServiceConfigurations
                  - ec2:ModifyVpcEndpointServiceConfiguration
                  - ec2:ModifyVpcEndpointServicePermissions
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Sid: EC2CreateTagsOnCreateWithRequiredTag
                Effect: Allow
                Action:
                  - ec2:CreateTags
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
                    "ec2:CreateAction":
                      - CreateVpcEndpointServiceConfiguration
              - Sid: EC2CreateTagsOnTaggedResources
                Effect: Allow
                Action:
                  - ec2:CreateTags
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
                  StringEqualsIfExists:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - ec2:DeleteTags
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
                  ForAllValues:StringNotEquals:
                    "aws:TagKeys": ManagedBy

              # EKS: read, create, mutate, and tag lifecycle.
              - Effect: Allow
                Action:
                  - eks:DescribeCluster
                  - eks:DescribeAddon
                  - eks:DescribeNodegroup
                  - eks:ListAddons
                  - eks:ListClusters
                  - eks:ListNodegroups
                Resource: "*"
              - Effect: Allow
                Action:
                  - eks:CreateCluster
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue

              # Child creation is authorized against the existing parent cluster.
              # Require ownership of both the parent and the new child resource.
              - Effect: Allow
                Action:
                  - eks:CreateAddon
                  - eks:CreateNodegroup
                Resource: !Sub arn:aws:eks:*:${AWS::AccountId}:cluster/*
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue

              # Existing-resource writes use the ownership tag as their boundary.
              - Effect: Allow
                Action:
                  - eks:DeleteAddon
                  - eks:DeleteCluster
                  - eks:DeleteNodeGroup
                  - eks:UpdateAddon
                  - eks:UpdateClusterConfig
                  - eks:UpdateClusterVersion
                  - eks:UpdateNodegroupConfig
                  - eks:UpdateNodegroupVersion
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue

              # RequestTag constrains the tags being written; the ARN prefix
              # constrains which existing component resources can be claimed.
              - Effect: Allow
                Action:
                  - eks:TagResource
                Resource:
                  - !Sub arn:aws:eks:*:${AWS::AccountId}:addon/o11y-*/*
                  - !Sub arn:aws:eks:*:${AWS::AccountId}:cluster/o11y-*
                  - !Sub arn:aws:eks:*:${AWS::AccountId}:nodegroup/o11y-*/*
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - eks:UntagResource
                Resource: "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
                  ForAllValues:StringNotEquals:
                    "aws:TagKeys":
                      - ManagedBy

              # S3: bucket and object lifecycle.
              - Effect: Allow
                Action:
                  - s3:CreateBucket
                Resource:
                  - arn:aws:s3:::*o11y*
              - Effect: Allow
                Action:
                  - s3:GetLifecycleConfiguration
                  - s3:ListBucket
                  - s3:PutLifecycleConfiguration
                Resource:
                  - arn:aws:s3:::*o11y*
                Condition:
                  StringEquals:
                    s3:ResourceAccount: !Ref AWS::AccountId
              - Effect: Allow
                Action:
                  - s3:AbortMultipartUpload
                  - s3:DeleteObject
                  - s3:GetObject
                  - s3:ListMultipartUploadParts
                  - s3:PutObject
                Resource:
                  - arn:aws:s3:::*o11y*/*
                Condition:
                  StringEquals:
                    s3:ResourceAccount: !Ref AWS::AccountId

              # Supporting STS, ECR, and IAM permissions used by provisioning.
              - Effect: Allow
                Action:
                  - ecr:GetAuthorizationToken
                  - sts:GetCallerIdentity
                Resource: "*"
              - Effect: Allow
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:BatchGetImage
                  - ecr:DescribeImages
                  - ecr:GetDownloadUrlForLayer
                  - ecr:ListImages
                Resource:
                  - "*"
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - iam:GetRole
                  - iam:ListAttachedRolePolicies
                Resource:
                  - !Sub arn:aws:iam::${AWS::AccountId}:role/tidbcloud-o11y-eks-cluster-role
                  - !Sub arn:aws:iam::${AWS::AccountId}:role/tidbcloud-o11y-eks-node-role
              - Effect: Allow
                Action:
                  - iam:PassRole
                Resource:
                  - !Sub arn:aws:iam::${AWS::AccountId}:role/tidbcloud-o11y-eks-node-role
                Condition:
                  StringEquals:
                    iam:PassedToService: eks.amazonaws.com

        - PolicyName: AWSLoadBalancerPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Action:
                  - cognito-idp:DescribeUserPoolClient
                  - acm:ListCertificates
                  - acm:DescribeCertificate
                  - shield:GetSubscriptionState
                  - shield:DescribeProtection
                  - shield:CreateProtection
                  - shield:DeleteProtection
                Effect: Allow
                Resource: "*"
              - Action:
                  - iam:CreateServiceLinkedRole
                Condition:
                  StringEquals:
                    iam:AWSServiceName: elasticloadbalancing.amazonaws.com
                Effect: Allow
                Resource: "*"
              - Action:
                  - ec2:DescribeAccountAttributes
                  - ec2:DescribeAddresses
                  - ec2:DescribeAvailabilityZones
                  - ec2:DescribeInternetGateways
                  - ec2:DescribeVpcs
                  - ec2:DescribeVpcPeeringConnections
                  - ec2:DescribeSubnets
                  - ec2:DescribeSecurityGroups
                  - ec2:DescribeInstances
                  - ec2:DescribeNetworkInterfaces
                  - ec2:DescribeTags
                  - ec2:GetCoipPoolUsage
                  - ec2:DescribeCoipPools
                  - elasticloadbalancing:DescribeLoadBalancers
                  - elasticloadbalancing:DescribeLoadBalancerAttributes
                  - elasticloadbalancing:DescribeListeners
                  - elasticloadbalancing:DescribeListenerAttributes
                  - elasticloadbalancing:DescribeListenerCertificates
                  - elasticloadbalancing:DescribeSSLPolicies
                  - elasticloadbalancing:DescribeRules
                  - elasticloadbalancing:DescribeTargetGroups
                  - elasticloadbalancing:DescribeTargetGroupAttributes
                  - elasticloadbalancing:DescribeTargetHealth
                  - elasticloadbalancing:DescribeTags
                Effect: Allow
                Resource: "*"
              - Action:
                  - ec2:AuthorizeSecurityGroupIngress
                  - ec2:RevokeSecurityGroupIngress
                Effect: Allow
                Resource: "*"
              - Action:
                  - ec2:CreateSecurityGroup
                Effect: Allow
                Resource: "*"
              - Action:
                  - ec2:CreateTags
                Condition:
                  "Null":
                    aws:RequestTag/elbv2.k8s.aws/cluster: "false"
                  StringEquals:
                    ec2:CreateAction: CreateSecurityGroup
                Effect: Allow
                Resource: arn:aws:ec2:*:*:security-group/*
              - Action:
                  - ec2:CreateTags
                  - ec2:DeleteTags
                Condition:
                  "Null":
                    aws:RequestTag/elbv2.k8s.aws/cluster: "true"
                    aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
                Effect: Allow
                Resource: arn:aws:ec2:*:*:security-group/*
              - Action:
                  - ec2:AuthorizeSecurityGroupIngress
                  - ec2:RevokeSecurityGroupIngress
                  - ec2:DeleteSecurityGroup
                Condition:
                  "Null":
                    aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
                Effect: Allow
                Resource: "*"
              - Action:
                  - elasticloadbalancing:CreateLoadBalancer
                  - elasticloadbalancing:CreateTargetGroup
                Condition:
                  "Null":
                    aws:RequestTag/elbv2.k8s.aws/cluster: "false"
                Effect: Allow
                Resource: "*"
              - Action:
                  - elasticloadbalancing:CreateListener
                  - elasticloadbalancing:DeleteListener
                  - elasticloadbalancing:CreateRule
                  - elasticloadbalancing:DeleteRule
                Effect: Allow
                Resource: "*"
              - Action:
                  - elasticloadbalancing:AddTags
                  - elasticloadbalancing:RemoveTags
                Effect: Allow
                Resource:
                  - arn:aws:elasticloadbalancing:*:*:targetgroup/*/*
                  - arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*
                  - arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*
              - Action:
                  - elasticloadbalancing:AddTags
                  - elasticloadbalancing:RemoveTags
                Effect: Allow
                Resource:
                  - arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*
                  - arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*
                  - arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*
                  - arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*
              - Action:
                  - elasticloadbalancing:ModifyLoadBalancerAttributes
                  - elasticloadbalancing:SetIpAddressType
                  - elasticloadbalancing:SetSecurityGroups
                  - elasticloadbalancing:SetSubnets
                  - elasticloadbalancing:DeleteLoadBalancer
                  - elasticloadbalancing:ModifyTargetGroup
                  - elasticloadbalancing:ModifyTargetGroupAttributes
                  - elasticloadbalancing:DeleteTargetGroup
                Condition:
                  "Null":
                    aws:ResourceTag/elbv2.k8s.aws/cluster: "false"
                Effect: Allow
                Resource: "*"
              - Action:
                  - elasticloadbalancing:RegisterTargets
                  - elasticloadbalancing:DeregisterTargets
                Effect: Allow
                Resource: arn:aws:elasticloadbalancing:*:*:targetgroup/*/*
              - Action:
                  - elasticloadbalancing:SetWebAcl
                  - elasticloadbalancing:ModifyListener
                  - elasticloadbalancing:AddListenerCertificates
                  - elasticloadbalancing:RemoveListenerCertificates
                  - elasticloadbalancing:ModifyRule
                  - elasticloadbalancing:SetRulePriorities
                Effect: Allow
                Resource: "*"
        - PolicyName: ClusterAutoscalerPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - autoscaling:DescribeAutoScalingGroups
                  - autoscaling:DescribeAutoScalingInstances
                  - autoscaling:DescribeLaunchConfigurations
                  - autoscaling:DescribeTags
                  - ec2:DescribeLaunchTemplateVersions
                Resource: "*"
              - Effect: Allow
                Action:
                  - autoscaling:SetDesiredCapacity
                  - autoscaling:TerminateInstanceInAutoScalingGroup
                Resource: !Sub arn:aws:autoscaling:*:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/*
                Condition:
                  StringEquals:
                    aws:ResourceTag/k8s.io/cluster-autoscaler/enabled: "true"
                    aws:ResourceTag/ManagedBy: !Ref RequiredManagedByTagValue

        - PolicyName: EKSClusterBackupPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeSnapshots
                  - ec2:DescribeVolumes
                Resource: "*"

              # Backup and restore can only read from managed source resources.
              - Effect: Allow
                Action:
                  - ec2:CreateSnapshot
                Resource: !Sub arn:aws:ec2:*:${AWS::AccountId}:volume/*
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - ec2:CreateVolume
                Resource: arn:aws:ec2:*:*:snapshot/*
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue

              # New backup resources must carry the ownership tag.
              - Effect: Allow
                Action:
                  - ec2:CreateSnapshot
                Resource: arn:aws:ec2:*:*:snapshot/*
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - ec2:CreateVolume
                Resource: !Sub arn:aws:ec2:*:${AWS::AccountId}:volume/*
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
              - Effect: Allow
                Action:
                  - ec2:CreateTags
                Resource:
                  - arn:aws:ec2:*:*:snapshot/*
                  - !Sub arn:aws:ec2:*:${AWS::AccountId}:volume/*
                Condition:
                  StringEquals:
                    "aws:RequestTag/ManagedBy": !Ref RequiredManagedByTagValue
                    "ec2:CreateAction":
                      - CreateSnapshot
                      - CreateVolume
              - Effect: Allow
                Action:
                  - ec2:DeleteSnapshot
                Resource: arn:aws:ec2:*:*:snapshot/*
                Condition:
                  StringEquals:
                    "aws:ResourceTag/ManagedBy": !Ref RequiredManagedByTagValue

        - PolicyName: DeadmanswitchPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - cloudwatch:PutMetricData
                Resource:
                  - "*"
  TiDBCloudO11yDataPlaneAgentRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: "tidbcloud-o11y-agent-role"
      # inline policies for access s3 by o11y agent
      Policies:
        - PolicyName: AllowS3Access
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:ListBucket
                Resource: "arn:aws:s3:::o11y*"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/tidbcloud-eks-node-role
  TiDBCloudO11yEKSClusterRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: tidbcloud-o11y-eks-cluster-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: eks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
  TiDBCloudO11yEKSNodeRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: tidbcloud-o11y-eks-node-role
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly
  TiDBCloudO11yAPIGWRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: tidbcloud-o11y-apigw-role
      Policies:
        - PolicyName: APIGatewayInvokePolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - execute-api:Invoke
                Resource: !Sub arn:aws:execute-api:*:${AWS::AccountId}:*/tidbcloud/*
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Ref O11yGlobalRoleArns
            Action: sts:AssumeRole
