Find and Fix AWS Security Misconfigurations

Audit and harden an S3 bucket and IAM user against real-world misconfigurations.

Introduction

30 Second Summary

Every few months, another headline breaks about sensitive data leaking from a misconfigured cloud storage bucket. In most cases, the fix takes minutes. The hard part is knowing where to look.

In this project, you will simulate a real-world security audit by intentionally creating a vulnerable AWS environment, then systematically detecting and fixing each misconfiguration like a security engineer.

What You'll Build

You will harden an S3 bucket and IAM user against the most common AWS security misconfigurations, then set up logging to create a permanent audit trail.

By the end of this project, you'll have:

  • A hardened S3 bucket with Block Public Access enforced and the public bucket policy removed.
  • A scoped-down IAM policy following the principle of least privilege, restricting a user to a single bucket.
  • A logging bucket capturing server access logs as an audit trail for all requests to your bucket.
  • Secret Mission: Use CloudTrail Event History to forensically trace the exact API calls that created the vulnerability and create a trail for long-term monitoring.

Are there any prerequisites?

You need an AWS account with administrative access. Familiarity with navigating the AWS Console is helpful but not required.

Create a Vulnerable S3 Bucket

Security audits start by understanding how misconfigurations happen in the first place. In this step, you will intentionally create a vulnerable S3 bucket to simulate what security engineers commonly find in real AWS accounts.

You will disable the built-in public access protections, upload fake sensitive data, and apply a policy that makes everything readable by anyone on the internet. This is the exact misconfiguration pattern responsible for some of the largest cloud data breaches.

In this step, get ready to:
  • Create an S3 bucket with public access protections disabled.
  • Upload a fake credentials file to simulate sensitive data exposure.
  • Apply a public bucket policy that makes the bucket readable by anyone on the internet.
Create a new S3 bucket with public access disabled

Every S3 bucket comes with Block Public Access enabled by default. This safety layer overrides any policy that would make your bucket public. You are going to disable it to simulate a common misconfiguration where a developer turns off protections to "make things work" during development.

  • In the AWS Console, type S3 in the search bar at the top and select S3 from the results.
  • In the left navigation pane, select General purpose buckets.
  • Click Create bucket.
  • For Bucket name, enter a name like security-lab-yourname-2026 (replace yourname with your actual name to make it globally unique).
  • Scroll down to the Block Public Access settings for this bucket section.
  • Uncheck Block all public access. This disables all four Block Public Access settings.
  • A warning appears asking you to acknowledge that the bucket might become public. Check the acknowledgment box to confirm.
  • Leave all other settings at their defaults.
  • Click Create bucket at the bottom of the page.

Your new bucket appears in the S3 bucket list.

What is Block Public Access?

Block Public Access is a safety layer that overrides any policy or ACL that would make your bucket or objects public. There are four separate settings, and enabling "Block all public access" turns on all four at once.

By disabling it, you are removing that safety net entirely. This simulates the exact mistake that leads to public data exposures in real accounts.

Bucket creation failed?

S3 bucket names must be globally unique across all AWS accounts. If you see a "Bucket already exists" error, try a more specific name like security-lab-jsmith-may-2026.

Also ensure your bucket name uses only lowercase letters, numbers, and hyphens.

Help me troubleshoot my S3 bucket creation error.

Upload a fake credentials file

Now you will upload a file containing fake credentials. This represents the kind of sensitive data that should never be publicly accessible. In a real scenario, this could be API keys, database passwords, or internal configuration accidentally committed to a public bucket.

  • Open a text editor on your computer (Notepad on Windows, TextEdit on macOS, or any code editor).
  • Create a new file and paste the following content into it:
# FAKE CREDENTIALS - FOR SECURITY LAB ONLY
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
DB_PASSWORD=SuperSecretPassword123!
API_TOKEN=sk-fake-token-do-not-use-in-production

Why fake credentials?

The access key AKIAIOSFODNN7EXAMPLE is the placeholder key from AWS documentation. It cannot be used for real access. Using fake data lets you simulate the danger of a public bucket without any actual security risk.

  • Save the file as sensitive-credentials.txt on your Desktop.
  • Back in the S3 console, click on your bucket name to open it.
  • Click Upload.
  • Click Add files and select the sensitive-credentials.txt file from your Desktop.
  • Click Upload.

You should see a green "Upload succeeded" banner. The file now appears in your bucket's Objects list.

Never upload real credentials to S3

This exercise uses fake example keys only. Never upload real API keys, passwords, or secrets to S3, even in a private bucket. Use AWS Secrets Manager or Parameter Store for real credentials.

Upload not working?

Make sure you clicked into your bucket first (you should see the Objects tab). If you are still on the bucket list page, click your bucket name to open it before uploading.

Help me upload a file to my S3 bucket.

Add a public bucket policy

Disabling Block Public Access removed the safety net, but the bucket is not actually public yet. You now need to add a bucket policy that explicitly grants read access to anyone on the internet.

  • Click on the Permissions tab in your bucket.
  • Scroll down to the Bucket policy section and click Edit.
  • Paste the following policy into the editor, replacing your-bucket-name with your actual bucket name:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::[[BUCKET_NAME=\"security-lab-yourname-2026\"]]/*"
        }
    ]
}

What does this policy do?

This policy has two critical elements that make it dangerous:

  • "Principal": "*" means anyone, including people without an AWS account.
  • "Action": "s3:GetObject" allows downloading any object in the bucket.

Together, these make every file in your bucket downloadable by anyone on the internet. This is the exact policy pattern behind most public S3 data breaches.

  • Click Save changes.

Back on the Permissions tab, you should now see a red "Publicly accessible" warning badge next to your bucket. This confirms the misconfiguration is live.

Policy won't save?

The most common cause is a mismatch between your actual bucket name and the name in the policy's Resource field. Double-check that the ARN in the policy matches your bucket name exactly, including the /* at the end.

If you see an error about Block Public Access, go back to the Block Public Access settings section above and confirm all four checkboxes are unchecked.

Help me fix my S3 bucket policy error.

Your vulnerable bucket is live. Anyone with the URL can now download your fake credentials file. In the next step, you will create an overprivileged IAM user that has far more S3 access than any analyst should need.

Create an Overprivileged IAM User

Your S3 bucket is now publicly exposed. The second most common misconfiguration in AWS accounts is overprivileged IAM users.

In this step, you will create an IAM user with far more access than it needs. This simulates the real-world pattern where developers grant blanket permissions to "get things working" and never scope them down.

In this step, get ready to:
  • Create an IAM user with console access.
  • Attach a policy that grants full S3 access to every bucket in your account.
  • Note the console sign-in URL for IAM users.
Create the junior-analyst IAM user

The principle of least privilege says that every identity should only have the minimum permissions it needs to do its job. You are about to deliberately violate this principle so you can detect and fix the problem later.

  • Open the AWS Console and search for IAM in the top search bar.
  • Click on the IAM service result to open the IAM Console.
  • In the left navigation pane, click Users.
  • Click Create user.

You are now on the Specify user details page.

  • In the User name field, enter junior-analyst.
  • Check the box next to Provide user access to the AWS Management Console.
  • Select I want to create an IAM user.
  • Under Console password, select Custom password and enter a password you will remember.
  • Uncheck User must create a new password at next sign-in.
  • Click Next.

You are now on the Set permissions page.

  • Under Permissions options, select Attach policies directly.
  • Skip selecting any policy for now. You will attach a policy in the next substep.
  • Click Next.
  • On the Review and create page, click Create user.

What is an IAM user?

An IAM user is a permanent identity inside your AWS account. Each user has its own credentials (username and password or access keys) and its own set of permissions.

In a real company, junior-analyst might represent a new team member who only needs to read data from one specific bucket.

You should see a success banner confirming your user was created.

Don't see the Create user button?

Make sure you are signed in with an account that has administrative access. Standard IAM users without iam:CreateUser permission cannot create new users.

help me troubleshoot why I can't create an IAM user in the AWS Console

Attach the AmazonS3FullAccess policy

Now you will give this user far too much power. The AmazonS3FullAccess managed policy grants s3:* on all resources (*). That means this single user can read, write, and delete objects in every S3 bucket in your account.

  • In the IAM Console, click Users in the left navigation pane.
  • Click the junior-analyst user name link.
  • Select the Permissions tab.
  • Click Add permissions, then click Add permissions again from the dropdown.
  • Select Attach policies directly.
  • In the search box, type AmazonS3FullAccess.
  • Check the box next to AmazonS3FullAccess.
  • Click Next, then click Add permissions.

You should see AmazonS3FullAccess listed under the user's permissions policies.

Why is this dangerous?

This policy grants s3:* on * (all resources). The user can access, modify, or delete objects in any bucket in your account. If the user's credentials were compromised, an attacker could exfiltrate or destroy data across your entire S3 environment.

In a later step, you will replace this with a scoped policy that only grants access to one specific bucket.

Can't find AmazonS3FullAccess?

Make sure you selected Attach policies directly as the permissions option. Also confirm you are typing the exact policy name AmazonS3FullAccess in the filter box. AWS managed policies appear with an AWS icon next to them.

help me find and attach the AmazonS3FullAccess policy to my IAM user

Note the IAM console sign-in URL

IAM users sign in through a different URL than the root account. You need this URL to test access as junior-analyst later.

  • In the left navigation pane of the IAM Console, click Dashboard.
  • Look for the AWS Account section on the right side of the page.
  • Find the Sign-in URL for IAM users in this account link.
  • Copy this URL and save it somewhere you can find it later (a text file or sticky note).

What does this URL look like?

The sign-in URL follows the format https://YOUR-ACCOUNT-ID.signin.aws.amazon.com/console/. Your 12-digit AWS account ID or account alias appears at the start.

This URL is the entry point for any IAM user in your account to sign in to the AWS Management Console.

Your vulnerable environment is almost complete. You now have a publicly exposed S3 bucket and an overprivileged IAM user. Next up, you will verify just how exposed these resources are by accessing your sensitive data from outside your account.

Verify the Exposure

You have created both misconfigurations. Now you need to prove they are actually exploitable.

In a real security audit, you would never assume a misconfiguration is dangerous just because it looks wrong in the console. You verify the exposure by testing it the way an attacker would. In this step, you will confirm the public bucket is leaking data and review just how much power the overprivileged IAM user has.

In this step, get ready to:
  • Confirm the S3 bucket is publicly readable by accessing a file from your browser.
  • Review the IAM policy JSON to see exactly what the overprivileged user can do.
  • Document the two security findings that need remediation.
Access your file via the public URL

Every object in a public S3 bucket has a predictable URL. Anyone on the internet can construct this URL and access the file directly.

  • Open a new browser tab (or an incognito/private window for a cleaner test).
  • Type the following URL into the address bar, replacing the bucket name with your actual bucket name:
https://[[BUCKET_NAME="security-lab-yourname-2026"]].s3.amazonaws.com/sensitive-credentials.txt
  • Press Enter to navigate to the URL.

You should see the fake credentials displayed directly in your browser. This is the exact text you uploaded in Step 1, now readable by anyone with the URL.

Why is this dangerous?

Automated scanners crawl predictable S3 URL patterns looking for exposed files. If this were a real credentials file, an attacker could find it within hours and use those keys to compromise your entire AWS account.

Seeing an Access Denied error?

Double check that your bucket name in the URL matches the exact name you used when creating the bucket. Bucket names are case-sensitive.

Make sure you unchecked all four Block Public Access options in Step 1. Go to your bucket's Permissions tab and confirm Block Public Access is off.

help me troubleshoot why my S3 bucket is not publicly accessible even though I disabled Block Public Access and added a public bucket policy

Review what AmazonS3FullAccess actually grants

The name "AmazonS3FullAccess" already hints at the problem. Now you will look at the actual policy JSON to see the scope of access your junior-analyst user has.

  • Navigate to the IAM console by searching for IAM in the AWS search bar.
  • Click Users in the left sidebar.
  • Click on junior-analyst to open the user details.
  • Click on the Permissions tab.
  • Click the + icon next to AmazonS3FullAccess to expand the policy and view the JSON.

You should see policy JSON that looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*",
                "s3-object-lambda:*"
            ],
            "Resource": "*"
        }
    ]
}

What does this policy mean?

The s3:* action means every possible S3 operation: read, write, delete, change permissions, and more. The Resource: "*" means these actions apply to every bucket in your entire AWS account.

This junior-analyst user can access, modify, or delete objects in any bucket. That violates the principle of least privilege, which says a user should only have permissions for what they actually need to do.

Document your findings

In a real security audit, you would create formal findings at this point. Each finding documents what is wrong, what risk it creates, and what needs to happen to fix it.

You have confirmed two security misconfigurations that need remediation:

  • Finding 1: S3 bucket is publicly readable. Anyone on the internet can access objects in the bucket using the public URL.
  • Finding 2: IAM user has excessive permissions. The junior-analyst user can perform any S3 action on any bucket in the account, far beyond what a junior analyst role needs.

Why document findings before fixing them?

Documenting first creates a clear audit trail. It forces you to understand the exact risk before you act, and gives you evidence to compare against after remediation. In professional environments, these findings feed into compliance reports and risk dashboards.

You have confirmed both vulnerabilities are live and exploitable. Next up, you will lock down the S3 bucket so that public URL stops working entirely.

Lock Down the S3 Bucket

You have confirmed the vulnerability is real. Your fake credentials file is readable by anyone on the internet, and the junior-analyst user can access every bucket in your account.

Now it is time to fix the first finding: the publicly accessible S3 bucket. You will enable Block Public Access, remove the dangerous bucket policy, and verify that the exposure is closed.

In this step, get ready to:
  • Enable all four Block Public Access settings on your bucket.
  • Delete the public bucket policy that grants anonymous read access.
  • Verify that the public URL now returns Access Denied.
Enable Block Public Access

S3 Block Public Access is a set of four independent settings that override any policy or ACL granting public access. Enabling all four guarantees that nothing can make the bucket publicly accessible, even if a future policy mistake is made.

  • Open the S3 console and click on your security-lab-yourname-2026 bucket.
  • Click the Permissions tab.
  • Scroll down to the Block public access (bucket settings) section.
  • Click Edit.
  • Check the Block all public access checkbox. This enables all four settings at once.
  • Click Save changes.
  • A confirmation dialog appears. Type confirm in the text field and click Confirm.

The page refreshes. You should see all four settings now show as On under Block public access.

What are the four Block Public Access settings?

Each setting protects against a different way public access can be granted:

  • BlockPublicAcls prevents new public ACLs from being applied to the bucket or its objects.
  • IgnorePublicAcls tells S3 to ignore any existing public ACLs already on the bucket.
  • BlockPublicPolicy rejects any bucket policy that would grant public access.
  • RestrictPublicBuckets limits access to only authorized users and AWS service principals, even if a public policy exists.

Together, these four settings create a safety net that catches every common way a bucket can be accidentally exposed.

Don't see the Edit button?

Make sure you are on the Permissions tab of the bucket itself, not the account-level S3 settings. The Block public access section sits below the Bucket policy section on this tab.

help me find the Block Public Access settings for my S3 bucket

Delete the public bucket policy

Block Public Access prevents new public policies from being applied, but the existing public policy is still attached to your bucket. Removing it ensures the bucket is fully private with no lingering permissions.

  • Still on the Permissions tab, scroll up to the Bucket policy section.
  • Click Edit.
  • Select all the policy JSON in the editor and delete it so the field is completely empty.
  • Click Save changes.

After saving, the Bucket policy section should show an empty state with no policy attached. Navigate back to your bucket list in S3. The Publicly accessible warning that previously appeared next to your bucket should now be gone.

Why delete the policy instead of just relying on Block Public Access?

Block Public Access overrides the policy at the access layer, but the policy JSON still exists. If someone later disables Block Public Access (accidentally or intentionally), the bucket would become public again instantly. Deleting the policy removes that risk entirely.

Still seeing the Publicly accessible warning?

The S3 console can take a moment to update the bucket status. Refresh the page. If the warning persists, double check that all four Block Public Access options show as On and that the bucket policy is completely empty.

help me remove the public access warning from my S3 bucket

Verify the bucket is no longer publicly accessible

The true test is whether the outside world can still reach your file. You will use the same public URL from Step 3 to confirm the exposure is closed.

  • Open a new browser tab (or an incognito window).
  • Paste the public URL for your file. It follows this format:
https://[[BUCKET_NAME="your-bucket-name"]].s3.amazonaws.com/sensitive-credentials.txt
  • Press Enter to load the URL.

You should now see an Access Denied XML response instead of your fake credentials. This confirms the bucket is no longer publicly accessible.

What does Access Denied mean here?

The Access Denied response means S3 received the request but refused to serve the object because the requester has no permission. Before your fix, the bucket policy granted permission to everyone ("Principal": "*"). Now that the policy is gone and Block Public Access is enabled, anonymous requests are rejected.

Still seeing the file contents?

Your browser may have cached the previous response. Try opening the URL in a private/incognito window, or clear your browser cache and reload. If the file still displays, go back to the bucket's Permissions tab and confirm the bucket policy is empty and all four Block Public Access settings show as On.

why can I still see my S3 file at the public URL after enabling Block Public Access?

Your S3 bucket is now locked down. The first audit finding is resolved. Next up, you will fix the second finding by replacing the overprivileged AmazonS3FullAccess policy with a custom least-privilege policy scoped to this single bucket.

Apply Least-Privilege IAM Permissions

Your S3 bucket is locked down, but the junior-analyst user still has full access to every S3 bucket in your account.

In this step, you will replace the overly broad AmazonS3FullAccess managed policy with a custom policy that follows the principle of least privilege. This means granting only the specific permissions needed for the specific resource.

In this step, get ready to:
  • Create a custom IAM policy scoped to your single bucket.
  • Swap the overprivileged policy for the least-privilege one.
  • Verify the restriction using the IAM Policy Simulator.
Create a custom least-privilege policy

Instead of giving junior-analyst blanket access to all S3 resources, you will write a policy that only allows listing, reading, and writing objects in your specific bucket.

  • In the IAM console, choose Policies in the left navigation pane.
  • Click Create policy.
  • In the Policy editor section, choose the JSON option.
  • Delete any existing content in the editor, then paste the following policy JSON:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListBucket",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::[[BUCKET_NAME="your-bucket-name"]]"
        },
        {
            "Sid": "AllowObjectOperations",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::[[BUCKET_NAME="your-bucket-name"]]/*"
        }
    ]
}

What does this policy do?

This policy has two statements, each granting the minimum access needed:

  • AllowListBucket lets the user list the contents of your specific bucket. The resource is the bucket ARN without a trailing /* because ListBucket operates at the bucket level.
  • AllowObjectOperations lets the user read and upload objects inside the bucket. The resource includes /* because GetObject and PutObject operate on individual objects.

Compare this to AmazonS3FullAccess which grants s3:* on * (every action on every bucket). Your custom policy is far more restrictive.

  • Click Next.
  • On the Review and create page, enter SecurityLab-ScopedS3Access as the policy name.
  • Click Create policy.

You should see a success banner confirming the policy was created.

Seeing a validation error?

  • Make sure you replaced your-bucket-name with your actual bucket name (e.g. security-lab-yourname-2026) in both Resource fields.
  • Check that the JSON has matching curly braces and square brackets. A missing comma or bracket is the most common syntax error.
  • Confirm the bucket ARN format starts with arn:aws:s3::: (three colons before the bucket name).

Having trouble? Help me fix a policy validation error when creating my custom IAM policy.

Replace the overprivileged policy on junior-analyst

Now you will remove the blanket AmazonS3FullAccess policy and attach your new scoped policy to the junior-analyst user.

  • In the IAM console, choose Users in the left navigation pane.
  • Click the junior-analyst user.
  • Select the Permissions tab.
  • Find AmazonS3FullAccess in the permissions list. Click the Remove button next to it, then confirm removal.
  • Click Add permissions, then choose Attach policies directly.
  • Search for SecurityLab-ScopedS3Access in the search box.
  • Check the box next to your policy, then click Next.
  • Click Add permissions.

The Permissions tab should now show only SecurityLab-ScopedS3Access attached to the user.

Still seeing AmazonS3FullAccess?

  • Make sure you clicked Remove and then confirmed the removal in the dialog that appeared.
  • Refresh the page and check the Permissions tab again.

Need more help? Help me remove an AWS managed policy from an IAM user.

Verify the restriction with the IAM Policy Simulator

The IAM Policy Simulator lets you test whether a user's policies allow or deny specific actions without actually signing in as that user.

  • In the IAM console left navigation pane, choose Users.
  • Click junior-analyst.
  • Select the Permissions tab, expand SecurityLab-ScopedS3Access, and click Simulate policy on the far right.
  • The IAM Policy Simulator opens in a new window.
  • Under Policy Simulator, click Select service and choose S3.
  • Click Select actions and choose GetObject.
  • In the Resource field for GetObject, enter the ARN of your bucket with an object path, e.g. arn:aws:s3:::security-lab-yourname-2026/sensitive-credentials.txt.
  • Click Run Simulation. You should see allowed in the Permission column.
  • Now change the Resource ARN to a different bucket, e.g. arn:aws:s3:::some-other-bucket/*.
  • Click Run Simulation again. This time you should see denied.

Why does this prove least privilege?

The simulator confirmed that junior-analyst can only access objects in your specific bucket. Any attempt to reach a different bucket is denied.

This is exactly what least privilege looks like in practice. The user has just enough access to do their job and nothing more.

Seeing denied on your own bucket?

  • Double-check that the ARN you entered in the simulator matches the bucket name in your policy exactly (including capitalization).
  • Verify that you attached SecurityLab-ScopedS3Access to junior-analyst (not a different user).
  • Make sure the AmazonS3FullAccess policy was fully removed. If both policies are attached, the simulation still shows allowed, but you need to verify only the scoped policy remains.

Still stuck? Help me troubleshoot why IAM Policy Simulator is denying access to my S3 bucket.

Your IAM user is now locked down to a single bucket. Next up, you will enable server access logging to create an audit trail that records every request made to your bucket.

Enable Server Access Logging

Your S3 bucket is locked down and your IAM user follows least-privilege. You have fixed the two biggest misconfigurations in your environment.

Fixing problems is only half of a security audit. The other half is proving you can detect future problems. In this step, you will enable server access logging to create an audit trail that records every request made to your bucket.

In this step, get ready to:
  • Create a dedicated logging bucket to store access logs.
  • Enable server access logging on your original bucket.
  • Verify that log files appear after generating activity.
Create a logging destination bucket

S3 server access logs need a separate bucket to land in. You cannot write logs to the same bucket you are monitoring.

  • In the S3 console, click Create bucket.
  • Enter a bucket name like security-lab-yourname-logs-2026 (replace yourname with the same name you used earlier).
  • Leave all default settings, including Block all public access checked.
  • Click Create bucket.

Why a separate bucket for logs?

The destination bucket must be in the same AWS Region and account as the source bucket. It must not have Object Lock default retention or Requester Pays enabled.

Keeping logs separate prevents a situation where deleting the monitored bucket also destroys your audit evidence.

You should see your new logging bucket in the S3 bucket list alongside your original bucket.

Bucket name already taken?

S3 bucket names are globally unique across all AWS accounts. If your name is taken, add a random number to the end (e.g. security-lab-yourname-logs-2026-42).

help me pick a unique S3 bucket name for my logging bucket

Enable server access logging on your original bucket

Now you will point your original bucket's logging configuration at the new logging bucket. The S3 console handles the permission grant automatically.

  • Click on your original bucket (security-lab-yourname-2026) to open it.
  • Click the Properties tab.
  • Scroll down to the Server access logging section and click Edit.
  • Select Enable.
  • Under Target bucket, choose your logging bucket (security-lab-yourname-logs-2026).
  • In the Target prefix field, enter access-logs/.
  • Click Save changes.

What happens behind the scenes?

The S3 console automatically updates your logging bucket's policy to grant the logging.s3.amazonaws.com service principal s3:PutObject access. You do not need to configure this permission yourself.

There is no extra charge for enabling server access logging. You only pay standard S3 storage charges for the log files themselves, which are negligible for this lab.

After saving, the Server access logging section should now show Enabled with your logging bucket and prefix displayed.

Logging not showing as enabled?

Make sure you clicked Save changes after selecting Enable. If you navigated away before saving, the change was not applied.

Also confirm that your logging bucket is in the same AWS Region as your original bucket. The destination must be in the same Region and account.

help me troubleshoot why S3 server access logging is not showing as enabled

Generate log activity and verify logs appear

Enabling logging does not produce any logs on its own. You need to make requests to your bucket so the logging system has something to record.

  • Go to the Objects tab of your original bucket.
  • Click Upload and upload any small file from your computer (a text file or image works fine).
  • Click Upload to confirm.
  • After the upload completes, click on the file you just uploaded.
  • Click Download to generate a GET request that the logging system will capture.

How long do logs take to appear?

S3 server access logs are delivered periodically. They typically appear within a few minutes, but can take up to a few hours. If you do not see logs immediately, wait 5-10 minutes and check again.

  • Navigate back to the S3 bucket list.
  • Click on your logging bucket (security-lab-yourname-logs-2026).
  • Click on the access-logs/ prefix (folder) to open it.
  • You should see one or more log files listed. Each file name contains a timestamp and a unique identifier.

No log files yet?

Log delivery is not instant. Wait 5-10 minutes after your upload and download, then refresh the page. If the access-logs/ prefix does not exist yet, the first log batch has not been delivered.

Make sure you set the prefix to access-logs/ (with the trailing slash). If you used a different prefix, look for that folder name instead.

help me figure out why my S3 server access logs are not appearing

Your bucket now has a complete audit trail. Every request made to it is recorded in your logging bucket, giving you visibility into who accessed what and when. Next up, you will take this further by investigating your own actions with CloudTrail in the Secret Mission.

Secret mission

Investigate with CloudTrail

You fixed the misconfigurations. But who created them, and when? In this secret mission, you will use CloudTrail Event History to forensically trace the exact API calls that introduced each vulnerability. Then you will create a trail for permanent audit storage.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses IAM (always free), S3 (negligible storage for a few small files), and optionally a CloudTrail trail (first copy of management events to S3 is free).

Resources you used:

  • S3 bucket (your original security lab bucket).
  • S3 bucket (your logging destination bucket).
  • IAM user junior-analyst with console access.
  • IAM policy SecurityLab-ScopedS3Access (customer managed).
  • CloudTrail trail security-audit-trail and its S3 bucket (Secret Mission only).

Keep everything running

No action needed. Choose this if you want to continue experimenting with IAM policies or S3 security configurations.

Ongoing cost is negligible. IAM is always free, and the few small files in your S3 buckets cost fractions of a cent per month.

Pause - I'll come back to this later

Keep the CloudTrail trail running for ongoing security monitoring of your account. Delete the lab buckets and IAM user since they served their purpose in the exercise.

  • Follow the S3 bucket deletion steps in the Delete tab for your original bucket and logging bucket.
  • Follow the IAM user and policy deletion steps in the Delete tab for junior-analyst and SecurityLab-ScopedS3Access.
  • Keep the CloudTrail trail. A single management-event trail is free and provides ongoing security monitoring for your account.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps in order.

Delete your S3 buckets

You must empty each bucket before you can delete it.

  • Open the S3 console at https://console.aws.amazon.com/s3/.
  • In the left navigation pane, choose General purpose buckets.
  • Select the option next to your original security lab bucket and choose Empty.
  • Confirm by entering the bucket name, then choose Empty.
  • Return to the bucket list, select the same bucket, and choose Delete.
  • Confirm by entering the bucket name, then choose Delete bucket.
  • Repeat the empty and delete steps for your logging destination bucket.
  • If you completed the Secret Mission, repeat for the CloudTrail trail S3 bucket as well.
Delete the IAM policy and user
  • Open the IAM console at https://console.aws.amazon.com/iam/.
  • In the navigation pane, choose Users.
  • Select the checkbox next to junior-analyst and choose Delete at the top of the page.
  • Enter the username in the confirmation dialog and choose Delete. The console automatically removes the user's attached managed policies, inline policies, and group memberships.
  • In the navigation pane, choose Policies.
  • Select the radio button next to SecurityLab-ScopedS3Access.
  • Choose Actions, then Delete. Confirm the deletion.
Delete the CloudTrail trail (Secret Mission only)
  • Open the CloudTrail console at https://console.aws.amazon.com/cloudtrail/.
  • Open the Trails page.
  • Choose security-audit-trail.
  • At the top of the trail details page, choose Delete and confirm.
  • The trail is removed from the list. Log files already delivered to the trail's S3 bucket are not deleted automatically. Return to the S3 console and empty then delete that bucket using the same steps above.

Nice Work!

Nice Work!

You just completed a real-world security audit workflow on AWS. You went from a deliberately vulnerable environment to a fully hardened S3 setup with proper IAM controls and logging.

Here's what you learned:

  • Remediated a publicly exposed S3 bucket by enabling Block Public Access and removing a dangerous bucket policy.
  • Applied the principle of least privilege by replacing blanket AmazonS3FullAccess with a scoped IAM policy that restricts a user to a single bucket.
  • Enabled server access logging to create a permanent audit trail for all requests to your bucket.
  • Secret Mission: Used CloudTrail Event History to forensically trace security-relevant API calls and created a trail for long-term monitoring.

Ready to quiz yourself?