AWSTemplateFormatVersion: 2010-09-09
Description: Deploys the Observer component as part of the AWS Backup Lens Solution For AWS Backup  
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: AWS Backup Lens Solution For AWSBackup - Observer Configuration
        Parameters: 
            - ReporterRegion
            - ReporterAccountID
      - Label:
          default: AWS Backup Lens Solution For AWSBackup - Binary Location
        Parameters: 
            - StackBinaryURL 
    ParameterLabels:
      ReporterRegion:
        default: Region where the Reporter stack was setup
      ReporterAccountID:
        default: AWS AccountId where the Reporter stack was setup        
      StackBinaryURL:
        default: The URL for the StackBinary Zip File 
Parameters:
  StackBinaryURL:
    Description: The URL for the StackBinary Zip File [DO NOT CHANGE]
    Type: String    
    Default: 'https://awsstorageblogresources.s3.us-west-2.amazonaws.com/backupobserverblog/bos-for-aws-backup.zip'
  CIRefreshSchedule:
    Description: The Default Refresh Schedule for AWS Backup CIs [DO NOT CHANGE]
    Type: String    
    Default: 'cron(0 1 * * ? *)'
  ReporterRegion:
    Description: The region for reporting infrastructure
    Type: String  
  ReporterAccountID:
    Description: The account id for reporting infrastructure
    Type: String
Resources: 
  ObserverInitializationHandler:
    Type: Custom::ObserverInitializationHandler
    Properties:
      ServiceToken: !GetAtt ObserverForAWSBackupLambda.Arn
      ProcessDelay: 300
      RefreshBackupAuditManagerReports: true 
      BackupManagerArn: !GetAtt ObserverForAWSBackupLambda.Arn
                        
  ObserverForAWSBackupLambdaS3EventPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt ObserverForAWSBackupLambda.Arn
      Action: lambda:InvokeFunction
      Principal: s3.amazonaws.com
      SourceAccount: !Ref 'AWS::AccountId'
      SourceArn: !Sub arn:${AWS::Partition}:s3:::${SolutionLocalCacheBucket}
      
  ManageNotificationsForBackupAuditManagerReports:
    Type: Custom::managenotifications
    Properties:
      ServiceToken: !GetAtt ObserverForAWSBackupLambda.Arn  
      S3Bucket: !Ref SolutionLocalCacheBucket
      S3PrefixList: 'AWSBackupAuditManagerReports'
      S3EventHandlerLambdaArn: !GetAtt ObserverForAWSBackupLambda.Arn
              
  SolutionLocalCacheBucket:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Delete
    UpdateReplacePolicy: Retain
    Properties:
      LifecycleConfiguration:
              Rules:
                - Id: DeleteOldObjects
                  Status: Enabled
                  ExpirationInDays: 14
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true  

  CleanupSolutionLocalCacheBucketOnDelete:
    Type: Custom::CleanupBucket
    Properties:
      ServiceToken: !GetAtt GlobalCfnCodeReplicatorLambda.Arn
      S3BucketToCleanup: !Ref SolutionLocalCacheBucket  

  CopySolutionToLocalCacheBucket:
    Type: Custom::ReplicateSolutionBinaries
    Properties:
      ServiceToken: !GetAtt GlobalCfnCodeReplicatorLambda.Arn
      SolutionDestinationBucket: !Ref SolutionLocalCacheBucket
      SolutionURL: !Ref StackBinaryURL
  
  GlobalCfnCodeReplicatorLambda:
    Type: AWS::Lambda::Function
    Metadata:
        cfn_nag:
          rules_to_suppress:
            - id: W89
              reason: "Custom resource deployed in default VPC"
            - id: W92
              reason: "ReservedConcurrentExecutions not needed since this function runs once when CloudFormation deploys"    
    Properties:
      Code:
        ZipFile: |-
          #!/usr/bin/env python
          # -*- coding: utf-8 -*-
          import json
          import boto3
          import urllib3
          import os
          import shutil
          from urllib.parse import urlparse
          physical_resource_id = 'GlobalCfnCodeReplicator'  
          def process_bucket_cleanup_request(bucket_name):
              print(f"process_bucket_cleanup_request starting for bucket_name : {bucket_name}")
              s3 = boto3.resource('s3')
              bucket_to_delete = s3.Bucket(bucket_name)
              response = bucket_to_delete.objects.all().delete()
              print(f"process_bucket_cleanup_request all object delete done. Response : {response}")
        
          def download_url(url, save_path):
            c = urllib3.PoolManager()
            with c.request('GET',url, preload_content=False) as resp, open(save_path, 'wb') as out_file:
                shutil.copyfileobj(resp, out_file)
            resp.release_conn()
            
          def lambda_handler(event, context):
            try:
                print(f'Handling event : {event}')
                request_type = event.get('RequestType')              
                solution_url = event['ResourceProperties'].get('SolutionURL')
                lambda_layer_url = event['ResourceProperties'].get('LambdaLayerURL')
                solution_bucket = event['ResourceProperties'].get('SolutionDestinationBucket')
                response_data = {
                    'RequestType': request_type,
                    'SolutionURL' : solution_url,
                    'LambdaLayerURL' : lambda_layer_url,
                    'SolutionDestinationBucket' : solution_bucket
                }
                if request_type == 'Create' or request_type == 'Update':
                    if solution_url:
                        download_file_from_url(solution_bucket,solution_url)
                    if lambda_layer_url:
                        download_file_from_url(solution_bucket,lambda_layer_url)                        
                elif request_type == 'Delete':
                    solution_bucket = event['ResourceProperties'].get('S3BucketToCleanup')
                    if solution_bucket:
                        process_bucket_cleanup_request(solution_bucket)
                    
                send(event, context, 'SUCCESS', response_data, physical_resource_id)
            except Exception as e:
                print(f'{e}')
                send(event, context, 'FAILED', response_data, physical_resource_id)
                                        
          
          def download_file_from_url(solution_bucket,file_url):
              print(f'downloading file from : {file_url}')
              a = urlparse(file_url)
              original_file_name = os.path.basename(a.path)
              temp_file_name = '/tmp/'+original_file_name
              download_url(file_url,temp_file_name)
              file_size = (os.stat(temp_file_name).st_size / 1024)
              print(f'Downloaded File : {temp_file_name} , Size : {file_size}')
              #Upload this to the Bucket
              s3_client = boto3.client('s3')
              print(f"uploading payload to : {solution_bucket} at {original_file_name}")
              extraArgsForUpload = {'ACL':'bucket-owner-full-control', 'Tagging':'Source=ElastioRTIntegration'}
              s3_client.upload_file(Filename=temp_file_name, Bucket=solution_bucket, Key=original_file_name,ExtraArgs=extraArgsForUpload)
                        
          def send(event, context, response_status, response_data, physical_resource_id, no_echo=False):
            http = urllib3.PoolManager()
            response_url = event['ResponseURL']
            json_response_body = json.dumps({
                'Status': response_status,
                'Reason': f'See the details in CloudWatch Log Stream: {context.log_stream_name}',
                'PhysicalResourceId': physical_resource_id,
                'StackId': event['StackId'],
                'RequestId': event['RequestId'],
                'LogicalResourceId': event['LogicalResourceId'],
                'NoEcho': no_echo,
                'Data': response_data
            }).encode('utf-8')
            headers = {
                'content-type': '',
                'content-length': str(len(json_response_body))
            }
            try:
                http.request('PUT', response_url,
                             body=json_response_body, headers=headers)
            except Exception as e:  # pylint: disable = W0703
                print(e)
      Description: Copy Solutions Binary to Local Cache Bucket
      Handler: index.lambda_handler
      Role : !GetAtt ObserverForAWSBackupRole.Arn
      Runtime: python3.12
      Architectures: 
            - arm64
      Timeout: 300

  ProcessAWSBackupVaultStatusEventRule: 
    Type: AWS::Events::Rule
    Properties: 
      Name: ProcessAWSBackupVaultStatusEventRule
      Description: "Rule to direct AWS Backup Events to Observer Lambda"
      State: "ENABLED"
      EventPattern: 
        source:
          - 'aws.backup'
        detail-type:
          - 'Backup Job State Change'
          - 'Restore Job State Change'
          - 'Copy Job State Change'
          - 'Recovery Point State Change'
          - 'Backup Vault State Change'
          - 'Backup Plan State Change'
          - 'Restore Testing Plan State Change'                                         
      Targets: 
        - Arn: !GetAtt ObserverForAWSBackupLambda.Arn
          Id: "ProcessAWSBackupEventsUsingLambda" 
          
  ProcessAWSBackupVaultStatusEventRuleInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref ObserverForAWSBackupLambda
      Principal: events.amazonaws.com
      SourceArn: !Sub ${ProcessAWSBackupVaultStatusEventRule.Arn}

  ProcessAWSBackupVaultStatusEventRuleLegacy: 
    Type: AWS::Events::Rule
    Properties: 
      Name: ProcessAWSBackupVaultStatusEventRuleLegacy
      Description: "Legacy rule for AWS Backup Events with 'status' field"
      State: "ENABLED"
      EventPattern: 
        source:
          - 'aws.backup'
        detail-type:
          - 'Backup Job State Change'
          - 'Restore Job State Change'
          - 'Copy Job State Change'
          - 'Recovery Point State Change'
          - 'Backup Vault State Change'
          - 'Backup Plan State Change'
          - 'Restore Testing Plan State Change'  
        detail:
          status:
            - ABORTED
            - FAILED
            - EXPIRED
            - PENDING            
            - MODIFIED                        
            - DELETED                        
            - COMPLETED                                          
      Targets: 
        - Arn: !GetAtt ObserverForAWSBackupLambda.Arn
          Id: "ProcessAWSBackupEventsUsingLambdaLegacy"
          
  ProcessAWSBackupVaultStatusEventRuleLegacyInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref ObserverForAWSBackupLambda
      Principal: events.amazonaws.com
      SourceArn: !Sub ${ProcessAWSBackupVaultStatusEventRuleLegacy.Arn} 
          
  ForwardObserverToReporterEventRule: 
    Type: AWS::Events::Rule
    Properties: 
      Name: ForwardObserverToReporterEventRule
      EventBusName: !Sub "arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default"
      Description: "Rule to forward processed Events to Global EB"
      State: "ENABLED"
      RoleArn: !GetAtt ObserverForAWSBackupRole.Arn
      EventPattern: 
        source:
          - 'observer.events'
          - 'backupauditmanager.events'
      Targets: 
        - Arn: !Sub "arn:${AWS::Partition}:events:${ReporterRegion}:${ReporterAccountID}:event-bus/GlobalBackupJobStatusEventBus-${ReporterAccountID}"   
          Id: "ForwardProcessedEventsToGlobalEB"
          RoleArn: !GetAtt ObserverForAWSBackupRole.Arn

  ObserverForAWSBackupLambda:
    Type: 'AWS::Lambda::Function'
    Metadata:
        cfn_nag:
          rules_to_suppress:
            - id: W89
              reason: "Custom resource deployed in default VPC"
            - id: W92
              reason: "ReservedConcurrentExecutions not needed since this function runs stateless"    
    DependsOn: CopySolutionToLocalCacheBucket
    Properties:
      Description: Function to manage AWS Backup events.
      FunctionName: ObserverForAWSBackupLambda
      Handler: lambda_handler.handler
      Role: !GetAtt ObserverForAWSBackupRole.Arn
      Runtime: python3.12
      Architectures: 
            - arm64
      MemorySize: 1024
      Timeout: 900
      Code:
        S3Bucket: !Ref SolutionLocalCacheBucket
        S3Key: 'bos-for-aws-backup.zip'
      Environment:
        Variables:
          S3BackupManagerLogBucket: !Ref SolutionLocalCacheBucket
          S3BackupManagerLogKey: 'aws-backup-logs'
          BackupManagerStackId: !Ref AWS::StackId
          AWSBackupEventsBusArn: !Sub "arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default"
          BackupAuditManagerReportItemsKey: 'reportItems'
          BackupAuditManagerReportBucket: !Ref SolutionLocalCacheBucket
          BackupAuditManagerReportFolder: 'AWSBackupAuditManagerReports'
          SupportedCompositeTypes: 'EC2'
          CopyDestinationTag: 'CopyDestination'


  SendRefreshNotificationForAWSBackupJobs:
    Type: Custom::managenotifications
    Properties:
      ServiceToken: !GetAtt ObserverForAWSBackupLambda.Arn
      ProcessDelay: 300
      RefreshConfigItems: true
      RefreshJobLogs: true 
      OverwriteJobLogs: true 
      BackupManagerArn: !GetAtt ObserverForAWSBackupLambda.Arn

  AWSBackupServiceRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "backup.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSBackupServiceRolePolicyForBackup'
        - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSBackupServiceRolePolicyForRestores'
        - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/AWSBackupOperatorAccess'   
        
  ObserverForAWSBackupRole:
    Type: 'AWS::IAM::Role'
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W11
            reason: "* resource needed for AuditManager S3 Events and ListTags in this policy"    
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSBackupServiceRolePolicyForBackup'
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSBackupServiceRolePolicyForRestores'
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/AWSBackupServiceRolePolicyForS3Backup'
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/AWSBackupServiceRolePolicyForS3Restore'
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSLambdaBasicExecutionRole'
          - !Sub 'arn:${AWS::Partition}:iam::${AWS::Partition}:policy/AWSBackupOperatorAccess'
      Policies:
          - PolicyName: PutEventsBus
            PolicyDocument:
              Version: 2012-10-17
              Statement:
              - Effect: Allow
                Action:
                - events:PutEvents
                Resource: 
                    - !Sub "arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default"
                    - !Sub "arn:${AWS::Partition}:events:${ReporterRegion}:${ReporterAccountID}:event-bus/GlobalBackupJobStatusEventBus-${ReporterAccountID}"   
                    - !Sub "arn:${AWS::Partition}:events:*:*:event-bus/BoS-ObserverInwardJobEventBus-*"   
          - PolicyName: invokeLambda
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
              - Effect: Allow
                Action:
                - lambda:InvokeFunction
                Resource: '*'           
          - PolicyName: AllowUserToPassAWSBackupServiceRole
            PolicyDocument:
              Version: 2012-10-17
              Statement:
                - Sid: AllowUserToPassAWSBackupServiceRole
                  Effect: Allow
                  Action: 'iam:PassRole'
                  Resource: !GetAtt AWSBackupServiceRole.Arn   
          - PolicyName: resourceTaggingRole
            PolicyDocument:
              Version: 2012-10-17
              Statement:
                - Effect: Allow
                  Action:
                    - 'backup:ListTags'
                    - 'ec2:DescribeTags'
                    - 'ec2:CreateTags'
                    - 'rds:ListTagsForResource'
                    - 'rds:AddTagsToResource'
                    - 'dynamodb:ListTagsOfResource'
                    - 'dynamodb:TagResource'
                    - 'elasticfilesystem:ListTagsForResource'
                    - 'elasticfilesystem:CreateTags'
                    - 'fsx:ListTagsForResource'
                    - 'fsx:TagResource'                    
                    - 'storagegateway:ListTagsForResource'
                    - 'storagegateway:AddTagsToResource'
                    - 's3:GetBucketTagging'
                    - 's3:PutBucketTagging'
                    - 'neptune:ListTagsForResource'    
                    - 'neptune:AddTagsToResource'
                    - 'redshift:DescribeTags'
                  Resource: '*'
          - PolicyName: s3LogBucketPermissions
            PolicyDocument:
              Statement:
              - Effect: Allow
                Action:
                  - kms:GenerateDataKey
                  - kms:Decrypt
                  - kms:Encrypt                  
                  - s3:PutObject*
                  - s3:GetObject*
                  - s3:DeleteObject
                  - s3:GetBucketNotification*
                  - s3:PutBucketNotification*
                  - s3:GetBucketLocation
                  - s3:ListBucket
                  - s3:DeleteBucket
                  - s3:ListBucketMultipartUploads
                  - s3:ListMultipartUploadParts
                  - s3:AbortMultipartUpload                  
                Resource: 
                  - !Sub 'arn:${AWS::Partition}:s3:::${SolutionLocalCacheBucket}/*'
                  - !Sub 'arn:${AWS::Partition}:s3:::${SolutionLocalCacheBucket}'  
          - PolicyName: logStreamPermissions
            PolicyDocument:
              Statement:                       
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: !Sub 'arn:${AWS::Partition}:logs:*:*:*'   

                
  BackupJobReportPlan:
    Type: "AWS::Backup::ReportPlan"
    Properties:
      ReportPlanDescription: 'Backup Job Report Created by BoS'
      ReportPlanName: !Join
                    - "_"
                    - - "BoS_BackupJobReport"
                      - !Select
                        - 0
                        - !Split
                          - "-"
                          - !Select
                            - 2
                            - !Split
                              - "/"
                              - !Ref "AWS::StackId"        
      ReportDeliveryChannel:
        Formats:
          - "CSV"
          - "JSON"
        S3BucketName: !Ref SolutionLocalCacheBucket
        S3KeyPrefix: 'AWSBackupAuditManagerReports'
      ReportSetting:
        ReportTemplate: 'BACKUP_JOB_REPORT'
      ReportPlanTags:
        - Key: "CreatedBy"
          Value: "BoS"
        - Key: "Account"
          Value: !Ref 'AWS::AccountId'
        - Key: "Region"
          Value: !Ref 'AWS::Region'   

  RestoreJobReportPlan:
    Type: "AWS::Backup::ReportPlan"
    Properties:
      ReportPlanDescription: 'Restore Job Report Created by BoS'
      ReportPlanName: !Join
                    - "_"
                    - - "BoS_RestoreJobReport"
                      - !Select
                        - 0
                        - !Split
                          - "-"
                          - !Select
                            - 2
                            - !Split
                              - "/"
                              - !Ref "AWS::StackId"        
      ReportDeliveryChannel:
        Formats:
          - "CSV"
          - "JSON"
        S3BucketName: !Ref SolutionLocalCacheBucket
        S3KeyPrefix: 'AWSBackupAuditManagerReports'
      ReportSetting:
        ReportTemplate: 'RESTORE_JOB_REPORT'
      ReportPlanTags:
        - Key: "CreatedBy"
          Value: "BoS"
        - Key: "Account"
          Value: !Ref 'AWS::AccountId'
        - Key: "Region"
          Value: !Ref 'AWS::Region' 

  CopyJobReportPlan:
    Type: "AWS::Backup::ReportPlan"
    Properties:
      ReportPlanDescription: 'Copy Job Report Created by BoS'
      ReportPlanName: !Join
                    - "_"
                    - - "BoS_CopyJobReport"
                      - !Select
                        - 0
                        - !Split
                          - "-"
                          - !Select
                            - 2
                            - !Split
                              - "/"
                              - !Ref "AWS::StackId"      
      ReportDeliveryChannel:
        Formats:
          - "CSV"
          - "JSON"
        S3BucketName: !Ref SolutionLocalCacheBucket
        S3KeyPrefix: 'AWSBackupAuditManagerReports'
      ReportSetting:
        ReportTemplate: 'COPY_JOB_REPORT'
      ReportPlanTags:
        - Key: "CreatedBy"
          Value: "BoS"
        - Key: "Account"
          Value: !Ref 'AWS::AccountId'
        - Key: "Region"
          Value: !Ref 'AWS::Region' 


  AWSBackupAuditManagerBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref SolutionLocalCacheBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 's3:PutObject'
            Effect: Allow
            Resource: !Join
              - ''
              - - !Sub 'arn:${AWS::Partition}:s3:::'
                - !Ref SolutionLocalCacheBucket
                - '/AWSBackupAuditManagerReports/*' 
            Principal: 
                'AWS' : !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/reports.backup.amazonaws.com/AWSServiceRoleForBackupReports'
            Condition:
              StringEquals:
                's3:x-amz-acl': 'bucket-owner-full-control'   
                
  ObserverInwardJobEventBus:
    Type: AWS::Events::EventBus
    Properties:
      Name: !Join [ '', ['BoS-ObserverInwardJobEventBus-', !Ref 'AWS::AccountId'] ]
      
  ObserverInwardJobEventBusPolicy:
    Type: AWS::Events::EventBusPolicy
    Properties: 
        EventBusName: !Ref ObserverInwardJobEventBus
        StatementId: "ObserverInwardJobEBP-AllowEventsFrmOthrRgnsAndAccnts"
        Statement: 
            Effect: "Allow"
            Principal: "*"
            Action: "events:PutEvents"
            Resource: !GetAtt "ObserverInwardJobEventBus.Arn"
            Condition:
                StringLike:
                    "aws:PrincipalArn" : "arn:*:*::*:*role*/*-ObserverForAWSBackupRole-*"         
      
  ObserverDailyRefreshEBEventRule: 
    Type: AWS::Events::Rule
    Properties: 
      Description: "Daily Refresh Schedule for AWS Backup CIs"
      State: "ENABLED"
      ScheduleExpression: !Ref CIRefreshSchedule
      Targets: 
        - Arn: !GetAtt ObserverForAWSBackupLambda.Arn
          Id: "BoSDailyCIRefreshSchedule"  

  ObserverDailyRefreshEBEventRuleInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref ObserverForAWSBackupLambda
      Principal: events.amazonaws.com
      SourceArn: !GetAtt ObserverDailyRefreshEBEventRule.Arn          

  ObserverInwardJobEventBusEventRule: 
    Type: AWS::Events::Rule
    Properties: 
      Description: "Incoming Command Events for Observer"
      EventBusName: !Ref ObserverInwardJobEventBus
      State: "ENABLED"
      EventPattern: 
        source:
          - 'observer.command'
      Targets: 
        - Arn: !GetAtt ObserverForAWSBackupLambda.Arn
          Id: "GlobalEventBridgeEvent"      
      
  ObserverInwardJobEventBusERInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref ObserverForAWSBackupLambda
      Principal: events.amazonaws.com
      SourceArn: !Sub ${ObserverInwardJobEventBusEventRule.Arn}     
      
Outputs:
  StackName:
    Value: !Ref AWS::StackName
    
  SolutionLocalCacheBucket:
    Value: !Ref SolutionLocalCacheBucket      