PCG logo
Article

Avoiding Double Costs: EFS Automatic Backups and AWS Backup Plans

In this blog post, I will discuss Amazon Elastic File System (EFS) in conjunction with AWS Backup. It's quite possible that when using both EFS and AWS Backup, you may inadvertently create duplicate backups, leading to double AWS Backup costs. In this article, I will explain why this happens and suggest a solution to monitor this using an AWS Config Custom Rule.

What Are EFS and AWS Backup?

Amazon Elastic File System (EFS) is a managed file system service that provides scalable, elastic storage for use with AWS services and on-premises resources. It allows multiple instances to access data concurrently, making it ideal for use cases like big data and analytics, media processing workflows, and content management.

AWS Backup is a fully managed service that centralizes and automates data protection across AWS services. It simplifies the process of backing up and restoring data, ensuring business continuity and compliance with regulatory requirements.

The "Trap" of Double Backup Costs

When a new Amazon Elastic File System (EFS) is created, the "Automatic backups" feature of EFS is enabled by default. This results in the creation of an AWS Backup Plan named "aws/efs/automatic-backup-plan" and a Backup Vault named "aws/efs/automatic-backup-vault", where the backups are automatically stored with a total retention period of 5 weeks.

image-1d350d07d4e2

Creation wizard for creating an EFS file system

image-063a7ed9701e

Automatic Backups are enabled by default

However, if AWS Backup Plans are also rolled out across all accounts in the AWS Organization, or if the account user sets up additional AWS Backup Plans that include the EFS either by resource type or via tags, then the EFS file system gets backed up into different Backup Vaults. This redundancy results in double AWS Backup costs.

image-c76afbdda883

Creating an AWS Backup Plan

In this example, I created two EFS file systems: one with "Automatic Backups" enabled and one without. Additionally, all EFS file systems are backed up using a custom AWS Backup Plan. As a result, overnight, two backups were stored in the backup vault "test-vault-efs" and one in the "Automatic Backup" vault "aws/efs/automatic-backup-vault".

image-b80a271d8a1b

AWS Backup Vault view

How Can We Monitor for Duplicate Backups for EFS File Systems?

To monitor whether duplicate backups are being created for EFS file systems, I have created an AWS Config Custom Rule. This rule checks every 12 hours to see if any EFS file systems have recovery points in more than one backup vault. If so, the EFS is marked as noncompliant.

Here’s an example with my two test EFS file systems, where one is compliant and the other is noncompliant.

image-bc02404696e2

AWS Config Custom Rule

If EFS file systems with duplicate backups are found (i.e., labeled as noncompliant), you can simply disable the EFS automatic backup for these systems.

Additionally, the associated AWS Lambda function generates a log that shows exactly which EFS file systems have backups in which backup vaults.

image-0340fcdc19d9

Lambda Log Groups

Below is the CloudFormation template that creates the Lambda function for the check, the corresponding IAM role, as well as the AWS Config Rule that runs every 12 hours.

This stack can either be deployed directly in your AWS account, or across the entire AWS Organization via CloudFormation StackSet or solutions like CfCTExternal Link or LZAExternal Link. If the AWS Config Aggregator is set up in your environment, you also have the ability to check for duplicate backups of EFS file systems across the entire AWS Organization.

Code Copied!copy-button
AWSTemplateFormatVersion: '2010-09-09'
Description: >
  CloudFormation Template to create a Lambda function, IAM role, and AWS Config Rule to check if duplicate EFS backups exist.

Resources:
  # IAM Role for Lambda
  DuplicateEFSBackupCheckRole:
    Type: 'AWS::IAM::Role'
    Properties: 
      AssumeRolePolicyDocument: 
        Version: '2012-10-17'
        Statement: 
          - Effect: "Allow"
            Principal: 
              Service: 
                - 'lambda.amazonaws.com'
            Action: 
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: 'DuplicateEFSBackupCheckPolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'elasticfilesystem:DescribeFileSystems'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'backup:ListBackupVaults'
                  - 'backup:ListRecoveryPointsByBackupVault'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'config:PutEvaluations'
                Resource: '*'

  # Lambda Function
  DuplicateEFSBackupCheckLambda:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: 'index.lambda_handler'
      Role: !GetAtt 'DuplicateEFSBackupCheckRole.Arn'
      Code:
        ZipFile: |
          import boto3
          from botocore.exceptions import ClientError
          import json

          def lambda_handler(event, context):
              message = json.loads(event['invokingEvent'])
              
              if message['messageType'] == 'ScheduledNotification':
                  handle_scheduled_config(event, message, context)
              else:
                  print(f'Unexpected event {event}.')

          def handle_scheduled_config(event, message, context):
              efs_client = boto3.client('efs')
              backup_client = boto3.client('backup')
              
              # Get List of all EFS File Systems
              file_systems = efs_client.describe_file_systems()
              
              # Iterate over the EFS File Systems
              for fs in file_systems['FileSystems']:
                  compliance_status = 'COMPLIANT'
                  file_system_id = fs['FileSystemId']
                  region = boto3.session.Session().region_name
                  account_id = context.invoked_function_arn.split(":")[4]
                  
                  # Construct the File System ARN
                  file_system_arn = f'arn:aws:elasticfilesystem:{region}:{account_id}:file-system/{file_system_id}'
                  
                  # Get list of all backup vaults
                  backup_vaults = backup_client.list_backup_vaults()
                  
                  recovery_point_count = 0
                  vaults_with_recovery_points = []
                  
                  # Iterate over each backup vault
                  for vault in backup_vaults['BackupVaultList']:
                      vault_name = vault['BackupVaultName']
                      
                      # List recovery points for the file system in each vault
                      try:
                          recovery_points = backup_client.list_recovery_points_by_backup_vault(
                              BackupVaultName=vault_name,
                              ByResourceArn=file_system_arn
                          )
                          if 'RecoveryPoints' in recovery_points and recovery_points['RecoveryPoints']:
                              recovery_point_count += 1
                              vaults_with_recovery_points.append(vault_name)
                      except ClientError as e:
                          print(f"Error describing recovery points for vault {vault_name} and file system {file_system_id}: {e}")
                          continue
                  
                  # Print the vaults with recovery points for the current file system
                  if vaults_with_recovery_points:
                      print(f"File System {file_system_id} has recovery points in the following vaults: {', '.join(vaults_with_recovery_points)}")
                  
                  # If the file system has recovery points in more than one backup vault, mark as NON_COMPLIANT
                  if recovery_point_count > 1:
                      print(f"File System {file_system_id} is NON_COMPLIANT")
                      compliance_status = 'NON_COMPLIANT'
                  else:
                      print(f"File System {file_system_id} is COMPLIANT")
                  
                  # Send evaluation result to AWS Config
                  send_evaluation_result(file_system_id, compliance_status, message['notificationCreationTime'], event['resultToken'])

          def send_evaluation_result(resource_id, compliance_status, timestamp, result_token):
              # Prepare evaluation result
              evaluation_result = {
                  'ComplianceResourceType': 'AWS::EFS::FileSystem',
                  'ComplianceResourceId': resource_id,
                  'ComplianceType': compliance_status,
                  'OrderingTimestamp': timestamp
              }
              
              # Create AWS Config client
              config_client = boto3.client('config')
              
              try:
                  # Put the evaluation result to AWS Config
                  config_client.put_evaluations(
                      Evaluations=[evaluation_result],
                      ResultToken=result_token
                  )
              except ClientError as e:
                  print(f"Error sending evaluation result to AWS Config: {e}")
      Runtime: 'python3.12'
      Timeout: 300

  # Lambda Permission
  DuplicateEFSBackupCheckLambdaPermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      FunctionName: !GetAtt 'DuplicateEFSBackupCheckLambda.Arn'
      Action: 'lambda:InvokeFunction'
      Principal: 'config.amazonaws.com'
      SourceAccount: !Sub ${AWS::AccountId}

  # AWS Config Rule
  DuplicateEFSBackupCheckConfigRule:
    Type: 'AWS::Config::ConfigRule'
    Properties: 
      ConfigRuleName: 'duplicate-efs-backup-check'
      Description: 'Checks if an EFS file system has backups in more than one backup vault.'
      Scope: 
        ComplianceResourceTypes: 
          - 'AWS::EFS::FileSystem'
      Source: 
        Owner: 'CUSTOM_LAMBDA'
        SourceIdentifier: !GetAtt 'DuplicateEFSBackupCheckLambda.Arn'
        SourceDetails: 
          - EventSource: 'aws.config'
            MessageType: 'ScheduledNotification'
            MaximumExecutionFrequency: 'Twelve_Hours'

Why Not Use an SCP?

A question might arise: If AWS Backup Plans are being automated across the AWS Organization to backup all EFS file systems, why not simply use an SCP (Service Control Policy) to disable EFS automatic backups? As of now (August 2024), it is unfortunately not possible to create an SCP that prevents EFS automatic backups from being enabled.

If your AWS Organization uses centrally managed AWS Backup Plans to backup all EFS file systems, you can utilize my AWS Config Custom Rule in conjunction with an AWS Config Remediation action to disable EFS automatic backups.


Final Words

I hope you enjoyed my article and find my AWS Config Custom Rule useful for monitoring duplicate EFS backups in your environment. The potential cost savings can be significant, I was able to save a client as much as $12,000 per month using this approach! Should you need further assistance with AWS cost optimization, our team at PCG is always ready to help.

Check out our AWS Cost Management and Optimisation!

Feel free to share your feedback and thoughts on the topic!


Services Used

Continue Reading

Article
Cost Management
Cost Optimisation Strategies for the Cloud

A comprehensive guide to implementing effective cost optimization strategies for the cloud: Explore practical insights to maximize efficiency, minimize spending, and enhance overall performance.

Learn more
Article
3 Reasons Why the Public Cloud Reduces Energy Costs

Switching IT infrastructure to the Public Cloud can save up to 80% energy, according to 451 Research study.

Learn more
Case Study
Software
Managed Services
PCG Managed Services with a focus on enablement and modernisation

Thanks to PCG's Managed Services, MBIC was able to keep the focus on the migration and enable the operations team together during operation, while still ensuring that the business runs smoothly.

Learn more
Article
Cloud Security
Managed Services
Building Resilient Cloud Architectures with AWS

A comprehensive guide to building resilient cloud architectures with AWS, covering EC2, S3, RDS, advanced features, designing for failure, Chaos Engineering, multi-region deployments, hybrid setups, and automation.

Learn more
See all

Let's work together

United Kingdom
Arrow Down