AWSTemplateFormatVersion: '2010-09-09'
Description: >
  Sentasity Access Roles — Organization Deployment.
  Creates IAM roles granting Sentasity read access in this management account
  and deploys the same roles to all member accounts via a SERVICE_MANAGED StackSet.

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Organization Configuration"
        Parameters:
          - OrganizationRootId
    ParameterLabels:
      OrganizationRootId:
        default: "Organization Root ID"

Parameters:
  OrganizationRootId:
    Type: String
    AllowedPattern: "^r-[a-z0-9]+$"
    ConstraintDescription: "Must be a Root ID starting with r- (e.g., r-xxxx)"
    Description: >
      The AWS Organizations Root ID to deploy roles to all member accounts.
      Find this in the AWS Organizations console (e.g., r-xxxx).

Rules:
  ValidateOrgRootId:
    Assertions:
      - Assert: !Not [!Equals [!Ref OrganizationRootId, ""]]
        AssertDescription: "OrganizationRootId must not be empty"

Resources:

  # =========================================================
  # MANAGEMENT ACCOUNT ROLES
  # =========================================================

  SentasityViewOnlySecurityRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: SentasityViewOnlySecurityRole
      Description: "Sentasity ViewOnly access for cost optimization and security scanning"
      MaxSessionDuration: 43200
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: "arn:aws:iam::886557787053:root"
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
        - "arn:aws:iam::aws:policy/SecurityAudit"
      Policies:
        - PolicyName: SecurityScanReadOnly
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: AllowAdditionalSecurityReads
                Effect: Allow
                Action:
                  - "account:Get*"
                  - "appstream:Describe*"
                  - "appstream:List*"
                  - "backup:List*"
                  - "bedrock:List*"
                  - "bedrock:Get*"
                  - "cloudtrail:GetInsightSelectors"
                  - "codeartifact:List*"
                  - "codebuild:BatchGet*"
                  - "codebuild:ListReportGroups"
                  - "cognito-idp:GetUserPoolMfaConfig"
                  - "dlm:Get*"
                  - "drs:Describe*"
                  - "ds:Get*"
                  - "ds:Describe*"
                  - "ds:List*"
                  - "dynamodb:GetResourcePolicy"
                  - "ec2:GetEbsEncryptionByDefault"
                  - "ec2:GetSnapshotBlockPublicAccessState"
                  - "ec2:GetInstanceMetadataDefaults"
                  - "ecr:Describe*"
                  - "ecr:GetRegistryScanningConfiguration"
                  - "elasticfilesystem:DescribeBackupPolicy"
                  - "glue:GetConnections"
                  - "glue:GetSecurityConfiguration*"
                  - "glue:SearchTables"
                  - "lambda:GetFunction*"
                  - "logs:FilterLogEvents"
                  - "lightsail:GetRelationalDatabases"
                  - "macie2:GetMacieSession"
                  - "macie2:GetAutomatedDiscoveryConfiguration"
                  - "s3:GetAccountPublicAccessBlock"
                  - "shield:DescribeProtection"
                  - "shield:GetSubscriptionState"
                  - "securityhub:BatchImportFindings"
                  - "securityhub:GetFindings"
                  - "servicecatalog:Describe*"
                  - "servicecatalog:List*"
                  - "ssm:GetDocument"
                  - "ssm-incidents:List*"
                  - "states:ListTagsForResource"
                  - "support:Describe*"
                  - "tag:GetTagKeys"
                  - "wellarchitected:List*"
                Resource: "*"
              - Sid: AllowAPIGatewayReadOnly
                Effect: Allow
                Action:
                  - "apigateway:GET"
                Resource:
                  - "arn:*:apigateway:*::/restapis/*"
                  - "arn:*:apigateway:*::/apis/*"
      Tags:
        - Key: "ManagedBy"
          Value: "Sentasity-CloudFormation"
        - Key: "Purpose"
          Value: "Cost optimization and security scanning"

  SentasityReadOnlyRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: SentasityReadOnlyRole
      Description: "Sentasity ReadOnly role for cost data and CUR access"
      MaxSessionDuration: 43200
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: "arn:aws:iam::886557787053:root"
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/ReadOnlyAccess"
      Policies:
        - PolicyName: SentasityCURDiscovery
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: CURDiscovery
                Effect: Allow
                Action:
                  - cur:DescribeReportDefinitions
                  - bcm-data-exports:ListExports
                  - bcm-data-exports:GetExport
                Resource: "*"
      Tags:
        - Key: "ManagedBy"
          Value: "Sentasity-CloudFormation"
        - Key: "Purpose"
          Value: "Cost and usage data access"

  # =========================================================
  # STACKSET: Deploys roles to member accounts (Org mode)
  # =========================================================
  SentasityAccessStackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: "Sentasity-Access-Roles"
      Description: "Deploys Sentasity access roles to all member accounts in the organization"
      PermissionModel: SERVICE_MANAGED
      AutoDeployment:
        Enabled: true
        RetainStacksOnAccountRemoval: false
      CallAs: SELF
      Capabilities:
        - CAPABILITY_NAMED_IAM
      OperationPreferences:
        MaxConcurrentPercentage: 10
        FailureTolerancePercentage: 5
        RegionConcurrencyType: PARALLEL
      Parameters:
        - ParameterKey: TrustedAccountId
          ParameterValue: "886557787053"
      StackInstancesGroup:
        - DeploymentTargets:
            OrganizationalUnitIds:
              - !Ref OrganizationRootId
          Regions:
            - "us-east-1"
      TemplateBody: |
        AWSTemplateFormatVersion: '2010-09-09'
        Description: "Sentasity Access Roles (Member Account)"
        Parameters:
          TrustedAccountId:
            Type: String
        Resources:
          SentasityViewOnlySecurityRole:
            Type: AWS::IAM::Role
            Properties:
              RoleName: SentasityViewOnlySecurityRole
              Description: "Sentasity ViewOnly access for cost optimization and security scanning"
              MaxSessionDuration: 43200
              AssumeRolePolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: Allow
                    Principal:
                      AWS: !Sub "arn:aws:iam::${TrustedAccountId}:root"
                    Action: sts:AssumeRole
              ManagedPolicyArns:
                - "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
                - "arn:aws:iam::aws:policy/SecurityAudit"
              Policies:
                - PolicyName: SecurityScanReadOnly
                  PolicyDocument:
                    Version: '2012-10-17'
                    Statement:
                      - Sid: AllowAdditionalSecurityReads
                        Effect: Allow
                        Action:
                          - "account:Get*"
                          - "appstream:Describe*"
                          - "appstream:List*"
                          - "backup:List*"
                          - "bedrock:List*"
                          - "bedrock:Get*"
                          - "cloudtrail:GetInsightSelectors"
                          - "codeartifact:List*"
                          - "codebuild:BatchGet*"
                          - "codebuild:ListReportGroups"
                          - "cognito-idp:GetUserPoolMfaConfig"
                          - "dlm:Get*"
                          - "drs:Describe*"
                          - "ds:Get*"
                          - "ds:Describe*"
                          - "ds:List*"
                          - "dynamodb:GetResourcePolicy"
                          - "ec2:GetEbsEncryptionByDefault"
                          - "ec2:GetSnapshotBlockPublicAccessState"
                          - "ec2:GetInstanceMetadataDefaults"
                          - "ecr:Describe*"
                          - "ecr:GetRegistryScanningConfiguration"
                          - "elasticfilesystem:DescribeBackupPolicy"
                          - "glue:GetConnections"
                          - "glue:GetSecurityConfiguration*"
                          - "glue:SearchTables"
                          - "lambda:GetFunction*"
                          - "logs:FilterLogEvents"
                          - "lightsail:GetRelationalDatabases"
                          - "macie2:GetMacieSession"
                          - "macie2:GetAutomatedDiscoveryConfiguration"
                          - "s3:GetAccountPublicAccessBlock"
                          - "shield:DescribeProtection"
                          - "shield:GetSubscriptionState"
                          - "securityhub:BatchImportFindings"
                          - "securityhub:GetFindings"
                          - "servicecatalog:Describe*"
                          - "servicecatalog:List*"
                          - "ssm:GetDocument"
                          - "ssm-incidents:List*"
                          - "states:ListTagsForResource"
                          - "support:Describe*"
                          - "tag:GetTagKeys"
                          - "wellarchitected:List*"
                        Resource: "*"
                      - Sid: AllowAPIGatewayReadOnly
                        Effect: Allow
                        Action:
                          - "apigateway:GET"
                        Resource:
                          - "arn:*:apigateway:*::/restapis/*"
                          - "arn:*:apigateway:*::/apis/*"
              Tags:
                - Key: "ManagedBy"
                  Value: "Sentasity-CloudFormation"
                - Key: "Purpose"
                  Value: "Cost optimization and security scanning"
          SentasityReadOnlyRole:
            Type: AWS::IAM::Role
            Properties:
              RoleName: SentasityReadOnlyRole
              Description: "Sentasity ReadOnly role for cost data and CUR access"
              MaxSessionDuration: 43200
              AssumeRolePolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: Allow
                    Principal:
                      AWS: !Sub "arn:aws:iam::${TrustedAccountId}:root"
                    Action: sts:AssumeRole
              ManagedPolicyArns:
                - "arn:aws:iam::aws:policy/ReadOnlyAccess"
              Policies:
                - PolicyName: SentasityCURDiscovery
                  PolicyDocument:
                    Version: '2012-10-17'
                    Statement:
                      - Sid: CURDiscovery
                        Effect: Allow
                        Action:
                          - cur:DescribeReportDefinitions
                          - bcm-data-exports:ListExports
                          - bcm-data-exports:GetExport
                        Resource: "*"
              Tags:
                - Key: "ManagedBy"
                  Value: "Sentasity-CloudFormation"
                - Key: "Purpose"
                  Value: "Cost and usage data access"
        Outputs:
          ViewOnlyRoleArn:
            Description: "ARN of the Sentasity ViewOnly security scanning role"
            Value: !GetAtt SentasityViewOnlySecurityRole.Arn
          ReadOnlyRoleArn:
            Description: "ARN of the Sentasity ReadOnly cost data role"
            Value: !GetAtt SentasityReadOnlyRole.Arn

Outputs:
  ViewOnlyRoleArn:
    Description: "ARN of the Sentasity ViewOnly security scanning role (management account)"
    Value: !GetAtt SentasityViewOnlySecurityRole.Arn

  ReadOnlyRoleArn:
    Description: "ARN of the Sentasity ReadOnly cost data role (management account)"
    Value: !GetAtt SentasityReadOnlyRole.Arn

  StackSetId:
    Description: "ID of the StackSet deploying roles to member accounts"
    Value: !Ref SentasityAccessStackSet
