AWSTemplateFormatVersion: '2010-09-09'
Description: 'Transilience Managed Compliance - SecurityAudit Read-Only Onboarding'

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Transilience Configuration"
        Parameters:
          - CustomerEmail
          - CustomerName
    ParameterLabels:
      CustomerEmail:
        default: "Your Email Address"
      CustomerName:
        default: "Your Company Name"

Parameters:
  CustomerEmail:
    Type: String
    Description: Email address for notifications and account identification
    AllowedPattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
    ConstraintDescription: Must be a valid email address
  
  CustomerName:
    Type: String
    Description: Your company or organization name
    MinLength: 2
    MaxLength: 100

  TransilienceBackendUrl:
    Type: String
    Default: "https://transilience-mcs-dev--api-server-api-server.modal.run/create"
    Description: Transilience backend API endpoint (do not modify)

Resources:
  #============================================================================
  # OIDC Identity Provider for Modal.com
  #============================================================================
  ModalOIDCProvider:
    Type: AWS::IAM::OIDCProvider
    Properties:
      Url: https://oidc.modal.com
      ClientIdList:
        - oidc.modal.com
      ThumbprintList:
        - "9e99a48a9960b14926bb7f3b02e22da2b0ab7280"
      Tags:
        - Key: Purpose
          Value: Transilience-Managed-Compliance
        - Key: CreatedBy
          Value: Transilience-CloudFormation

  #============================================================================
  # IAM Role for Transilience Access
  #============================================================================
  TransilienceComplianceRole:
    Type: AWS::IAM::Role
    DependsOn: ModalOIDCProvider
    Properties:
      RoleName: TransilienceComplianceRole
      Description: Role for Transilience Managed Compliance service to access AWS resources
      MaxSessionDuration: 3600
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: AllowModalOIDCAssumeRole
            Effect: Allow
            Principal:
              Federated: !Sub "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.modal.com"
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                "oidc.modal.com:aud": "oidc.modal.com"
              StringLike:
                "oidc.modal.com:sub":
                  - "modal:workspace_id:ac-v1CZ9TWcqA7282i3kcFYa9:*"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/SecurityAudit
      Tags:
        - Key: Purpose
          Value: Transilience-Managed-Compliance
        - Key: CreatedBy
          Value: Transilience-CloudFormation
        - Key: CustomerEmail
          Value: !Ref CustomerEmail
  #============================================================================
  # Lambda Execution Role for the Registration Function
  #============================================================================
  RegistrationLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: TransilienceRegistrationLambdaRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Tags:
        - Key: Purpose
          Value: Transilience-Registration

  #============================================================================
  # Lambda Function to Register with Transilience Backend
  #============================================================================
  RegistrationFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: TransilienceRegistration
      Description: Registers AWS account with Transilience backend on stack creation
      Runtime: python3.12
      Handler: index.handler
      Role: !GetAtt RegistrationLambdaRole.Arn
      Timeout: 30
      MemorySize: 128
      Environment:
        Variables:
          BACKEND_URL: !Ref TransilienceBackendUrl
      Code:
        ZipFile: |
          import json
          import urllib.request
          import urllib.error
          import os
          import cfnresponse

          def handler(event, context):
              """
              CloudFormation Custom Resource handler.
              Sends account registration data to Transilience backend.
              """
              print(f"Received event: {json.dumps(event)}")
              
              request_type = event.get('RequestType', '')
              
              if request_type == 'Delete':
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {
                      'Message': 'Delete acknowledged - no action taken'
                  })
                  return
              
              try:
                  properties = event.get('ResourceProperties', {})
                  account_id = properties.get('AccountId')
                  role_arn = properties.get('RoleArn')
                  role_name = properties.get('RoleName')
                  customer_email = properties.get('CustomerEmail')
                  customer_name = properties.get('CustomerName')
                  stack_id = event.get('StackId', '')
                  region = properties.get('Region')
                  
                  payload = {
                      'account_id': account_id,
                      'role_arn': role_arn,
                      'role_name': role_name,
                      'customer_email': customer_email,
                      'customer_name': customer_name,
                      'stack_id': stack_id,
                      'region': region,
                      'request_type': request_type,
                      'source': 'cloudformation-onboarding'
                  }
                  
                  print(f"Sending payload to backend: {json.dumps(payload)}")
                  
                  backend_url = os.environ.get('BACKEND_URL')
                  
                  req = urllib.request.Request(
                      backend_url,
                      data=json.dumps(payload).encode('utf-8'),
                      headers={
                          'Content-Type': 'application/json',
                          'User-Agent': 'Transilience-CloudFormation-Onboarding/1.0'
                      },
                      method='POST'
                  )
                  
                  with urllib.request.urlopen(req, timeout=25) as response:
                      response_body = response.read().decode('utf-8')
                      print(f"Backend response: {response_body}")
                      
                      cfnresponse.send(event, context, cfnresponse.SUCCESS, {
                          'Message': 'Successfully registered with Transilience',
                          'AccountId': account_id,
                          'RoleArn': role_arn
                      })
                      
              except urllib.error.HTTPError as e:
                  error_body = e.read().decode('utf-8') if e.fp else str(e)
                  print(f"HTTP Error: {e.code} - {error_body}")
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {
                      'Message': f'Role created but registration failed: {error_body}',
                      'Warning': 'Please contact support@transilience.ai'
                  })
                  
              except Exception as e:
                  print(f"Error: {str(e)}")
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {
                      'Message': f'Role created but registration encountered an error: {str(e)}',
                      'Warning': 'Please contact support@transilience.ai'
                  })
      Tags:
        - Key: Purpose
          Value: Transilience-Registration

  #============================================================================
  # Custom Resource to Trigger Registration
  #============================================================================
  AccountRegistration:
    Type: Custom::TransilienceRegistration
    DependsOn:
      - TransilienceComplianceRole
      - ModalOIDCProvider
    Properties:
      ServiceToken: !GetAtt RegistrationFunction.Arn
      AccountId: !Ref AWS::AccountId
      RoleArn: !GetAtt TransilienceComplianceRole.Arn
      RoleName: !Ref TransilienceComplianceRole
      CustomerEmail: !Ref CustomerEmail
      CustomerName: !Ref CustomerName
      Region: !Ref AWS::Region
      Timestamp: !Sub "${AWS::StackName}-${AWS::Region}"

#============================================================================
# Outputs
#============================================================================
Outputs:
  AccountId:
    Description: AWS Account ID that was onboarded
    Value: !Ref AWS::AccountId
    Export:
      Name: !Sub "${AWS::StackName}-AccountId"

  RoleArn:
    Description: ARN of the Transilience Compliance Role
    Value: !GetAtt TransilienceComplianceRole.Arn
    Export:
      Name: !Sub "${AWS::StackName}-RoleArn"

  RoleName:
    Description: Name of the Transilience Compliance Role
    Value: !Ref TransilienceComplianceRole
    Export:
      Name: !Sub "${AWS::StackName}-RoleName"

  OIDCProviderArn:
    Description: ARN of the Modal OIDC Provider
    Value: !GetAtt ModalOIDCProvider.Arn
    Export:
      Name: !Sub "${AWS::StackName}-OIDCProviderArn"



  OnboardingStatus:
    Description: Status of the onboarding registration
    Value: !GetAtt AccountRegistration.Message

  PermissionsSummary:
    Description: Summary of permissions granted
    Value: "SecurityAudit"
