Viewing 9 replies - 1 through 9 (of 9 total)
  • Plugin Author Yani

    (@yaniiliev)

    Ben, I have not seen this request before. I imagine it will be useful to others in the future. If you find a solution, please share it here.

    Thread Starter Ben

    (@cyberliciousben)

    Hi Yani and team,

    Quick update on verifying whether AIOWPM deletes older backups from S3 when using the S3 extension.

    What we found:

    • Initially, CloudTrail showed only management events (GetBucketLocationListBuckets) for our AIOWPM IAM user. No object-level events were visible.
    • We realized our Control Tower baseline trail does not log S3 data events by default, so PutObject/DeleteObject(s) wouldn’t appear.

    What we did to troubleshoot:

    • Created a temporary, account-only CloudTrail trail that logs S3 data events (write-only) for our backups bucket.
    • Configured Custom FieldSelectors (new CloudTrail UI) to capture only:
      • eventCategory = Data
      • resources.type = AWS::S3::Object
      • resources.ARN startsWith arn:aws:s3:::<our-bucket>/
      • readOnly = false (write-only)
    • We’re letting this run for ~24 hours (or hourly backups) to capture PutObject and any DeleteObject(s) if they occur.

    Interim workaround:

    • Implemented an S3 lifecycle rule to automatically delete backups older than 30 days, and abort incomplete multipart uploads after 1 day.
    • This keeps storage usage under control while we confirm the plugin’s delete behavior.

    What’s next:

    • After the trail collects data, we’ll look specifically for DeleteObject/DeleteObjects.
    • If there are no delete attempts, we’ll assume retention is not handled by the plugin and keep the lifecycle rule in place.

    If you have documentation on expected delete/retention behavior for the S3 extension, or recommended settings, that would be super helpful. We’ll report back with what we see in CloudTrail once the capture window completes.

    Ben

    Thread Starter Ben

    (@cyberliciousben)

    We goofed! Forgot to add a wildcard (*): resources.ARN startsWith arn:aws:s3:::<our-bucket>/<our-subdirectory>/*. CloudTrail was only capturing the bucket not the subdirectory in the bucket. Based on our backup schedule and retention settings, here’s when we should expect to see data events in CloudTrail:

    Expected Data Events Timeline:

    1. Next Upload Event:
      • When: September 5, 2025 at 7:20 AM (about 3 hours from now)
      • Event TypePutObject
      • Visible in CloudTrail: By 7:35 AM (15 minutes after backup)
    2. First Deletion Events:
      • When: After the 7:20 AM backup completes
      • Why: We currently have 22 objects, but retention is set to keep only 7 most recent
      • Expected: We should see DeleteObject or DeleteObjects events removing ~15-16 old backups
      • Visible in CloudTrail: By 7:35-7:40 AM
    3. Age-Based Deletions:
      • When: Your oldest backup is from August 31 (5 days old)
      • 14-day rule: Won’t trigger deletions until backups are 14+ days old
      • First age-based deletion: Around September 14, 2025 (when August 31 backups turn 14 days old)

    Immediate (next few hours):

    • PutObject event around 7:20 AM
    • Multiple DeleteObject/DeleteObjects events shortly after (removing excess backups beyond the 7 most recent)

    Your retention policy should delete ~15 backups because:

    • Current: 22 objects
    • After new backup: 23 objects
    • Keep most recent 7: Delete 16 objects
    • Final count: 7 objects

    We’ll run our CloudTrail query around 8:00 AM to see both the upload and the expected cleanup deletions. If we don’t see deletion events by then, our retention policy isn’t working correctly.

    The “keep 7 most recent” rule should trigger immediately after the next backup, so we should see significant deletion activity very soon, correct?

    P.S. Don’t you just love AI/ML? I’m like 100 employees now. Yay! lol

    Thread Starter Ben

    (@cyberliciousben)

    Well, that was fun! The CloudTrail Trail is not quite what we wanted, but gave some hints. We upgraded to a CloudTrail Lake instead. The log files from the trail at least pointed us to the API calls. The Event data store ID was created and we can now query it…once the syntax is right…use your Event data store ID for your FROM <Event data store ID> statement. Example:

    SELECT eventName,
    count(*) as event_count
    FROM <Event data store ID>
    WHERE userIdentity.userName = <IAM user>
    AND eventtime >= timestamp '2025-09-01 00:00:00'
    GROUP BY eventName
    ORDER BY event_count DESC;

    Result:

    UploadPart 1183
    CreateMultipartUpload 12
    CompleteMultipartUpload 12

    With DeleteObject or DeleteObjects missing, it would seem retention is not working. There’s 24 objects when we should have “the most recent 7 backups.”

    Are you able to recreate this issue on your end or is this isolated to us? I would have taken this privately, but there’s not a dang thing publicly about this config nor how to troubleshoot it. I’m even having to correct AI/ML. lol

    Thread Starter Ben

    (@cyberliciousben)

    Hi Yani and Team,
    It ran all weekend and we now have 76 total objects in S3. To recap, our retention settings are:

    Keep the most recent 7 backups. Default: 0 unlimited
    Limit the total size of backups to 0 MB Default: 0 unlimited
    Remove backups older than 14 days. Default: 0 off

    Our <iam_user> permissions are:

    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "s3:PutObject",
    "s3:GetObject",
    "s3:DeleteObject",
    "s3:DeleteObjectVersion",
    "s3:ListBucket",
    "s3:GetBucketLocation",
    "s3:DeleteBucket"
    ],
    "Resource": [
    "arn:aws:s3:::<bucket_name>",
    "arn:aws:s3:::<bucket_name>/" ] }, { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": ""
    }
    ]
    }

    Our CloudTrail Event data store event selectors are:

    eventSource equals s3.amazon.com
    resource.ARN starts with arn:aws:s3:::<bucket_name>/<object_name>/*
    readOnly equals false
    eventType equals AwsApiCall

    Our basic CloudTrail query is:

    SELECT eventName,
    count(*) as event_count
    FROM <event_data_store_ID>
    WHERE userIdentity.userName = '<iam_user>'
    AND eventtime >= timestamp '2025-09-05 00:00:00'
    GROUP BY eventName
    ORDER BY event_count DESC;

    Result:

    eventName		event_count
    UploadPart 794
    CompleteMultipartUpload 8
    CreateMultipartUpload 8

    Our deep dive CloudTrail query-picky query:

    SELECT eventTime,
    eventName,
    JSON_EXTRACT_SCALAR(CAST(requestParameters AS JSON), '$.bucketName') AS bucketName,
    JSON_EXTRACT_SCALAR(CAST(requestParameters AS JSON), '$.key') AS objectKey,
    JSON_EXTRACT(CAST(requestParameters AS JSON), '$.delete.objects') AS deletedObjects,
    userIdentity.arn AS callerArn,
    r.ARN AS resourceArn
    FROM <event_data_store_ID>
    CROSS JOIN UNNEST(resources) AS r (ARN, accountId, type, name)
    WHERE eventSource = 's3.amazonaws.com'
    AND eventTime >= TIMESTAMP '2025-09-05 00:00:00'
    AND JSON_EXTRACT_SCALAR(CAST(requestParameters AS JSON), '$.bucketName') = '<bucket_name>'
    AND eventName IN ('PutObject','UploadPart','CompleteMultipartUpload','DeleteObject','DeleteObjects')
    AND r.ARN LIKE 'arn:aws:s3:::<bucket_name>/<object_name>/%'
    ORDER BY eventTime DESC;

    Result:

    0 records matched | 810 records (335.8 kB) scanned in 1.2s @ 651.1 records/s (269.9 kB/s)

    Shall we debug WordPress?

    I cannot find anything on our end that would prevent object deletions. Our service control policy (SCP) where MFA is required to delete objects in S3 is for a completely different Organizational Unit (OU) than the WordPress websites. We’re unable to find anything else in AWS that would be restricting it, and the plugin is not even attempting the DeleteObject API call it seems.

    Plugin Author Yani

    (@yaniiliev)

    Hi Ben,

    You might be able to find out the issue easier if you use aws cli locally, on your computer with the same access and secret keys that you are using in the plugin.
    The issue is something to do with permissions – IAM, Policy conflicts, MFA, etc..
    So try to delete a file using aws cli and the same keys then debug from there.

    After each backup completes, the plugin:
    1. Delete backups older than X days (your setting: 14 days)
    2. Delete backups when total size exceeds limit (your setting: 0 = unlimited)
    3. Delete oldest backups beyond count limit (your setting: 7 backups)

    Given that you have no data in CloudTrail, it implies that there are permission issues preventing the deletion of the files.

    Thread Starter Ben

    (@cyberliciousben)

    Side Note: Using a terminal inside VSCode (Virtual Studio Code) for CLI.

    We rotated keys, meaning I tossed this guy’s secret key on creation, created a profile using the new key, and it worked:

    aws configure set aws_access_key_id <new_access_key> --profile wp-migration-test
    aws configure set aws_secret_access_key <new_secret_key> --profile wp-migration-test
    aws configure set region us-east-1 --profile wp-migration-test

    Ensure I was connected to the correct AWS account:

    aws sts get-caller-identity --profile wp-migration-test

    {
    "UserId": "<user_id>",
    "Account": "<account_id>",
    "Arn": "arn:aws:iam::<account_id>:user/<iam_user_name>"
    }
    aws s3 rm s3://<bucket_name>/<object_name>/<oldest_filename> --profile wp-migration-test
    delete: s3://<bucket_name>/<object_name>/<oldest_filename>

    The plugin now has the new key, and the next backup date: September 8, 2025 10:20 am. Stay tuned…

    Thread Starter Ben

    (@cyberliciousben)

    It ran, and there are now 77 objects when it should have 7: Keep the most recent 7 backups. It runs again at 11:20 am so the new keys are working and I can delete via CLI as shown above.

    Thread Starter Ben

    (@cyberliciousben)

    How thoroughly have you guys tested this? Just because you can AWS CLI delete with access keys does not mean the plugin works:

    // The order is very important - we delete files by date, by size, and finally by total count
    $this->delete_backups_older_than();
    $this->delete_backups_when_total_size_over();
    $this->delete_backups_when_total_count_over();

    The get_limit() method in the cleanup code returns 0 instead of 7, causing the entire deletion process to be skipped. The database is correct: ai1wmve_schedule_events contains: “retention”;a:4:{s:7:”backups”;i:7;…}

    Tag, you’re it…

Viewing 9 replies - 1 through 9 (of 9 total)

The topic ‘Amazon S3 Retention Settings Not Removing Backups’ is closed to new replies.