<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aditi Dange</title>
    <description>The latest articles on DEV Community by Aditi Dange (@aditi_dange_20cc3d78635f7).</description>
    <link>https://dev.to/aditi_dange_20cc3d78635f7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4162781%2Fe12286f6-5206-4bb4-88b8-7d7796c962bb.png</url>
      <title>DEV Community: Aditi Dange</title>
      <link>https://dev.to/aditi_dange_20cc3d78635f7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aditi_dange_20cc3d78635f7"/>
    <language>en</language>
    <item>
      <title>Testing S3 Drop Zone Upload Limits: What Happens When You Pause a Request?</title>
      <dc:creator>Aditi Dange</dc:creator>
      <pubDate>Mon, 12 Oct 2026 03:59:12 +0000</pubDate>
      <link>https://dev.to/aditi_dange_20cc3d78635f7/testing-s3-drop-zone-upload-limits-what-happens-when-you-pause-a-request-mmo</link>
      <guid>https://dev.to/aditi_dange_20cc3d78635f7/testing-s3-drop-zone-upload-limits-what-happens-when-you-pause-a-request-mmo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft48yjt1dw4rqg5cjr474.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft48yjt1dw4rqg5cjr474.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;A paused upload request looks like a stopped upload channel. But does changing the request's state also invalidate the authorization already embedded in a saved page?&lt;/p&gt;

&lt;p&gt;I tested this with &lt;a href="https://buckets.serverlesscreed.com/" rel="noopener noreferrer"&gt;Buckets by Serverless Creed&lt;/a&gt;, comparing browser behavior with decoded POST conditions, controlled requests sent directly to S3, and independently verified objects. The results separated three boundaries: page validation, S3 authorization, and application request state.&lt;/p&gt;

&lt;h2&gt;
  
  
  The upload path and tested configuration
&lt;/h2&gt;

&lt;p&gt;Buckets generates an HTML recipient page containing signed POST fields. The browser submits a multipart request directly to S3, which evaluates the signature, policy conditions and applicable AWS permissions. A saved page carries issued authorization; uploading through it does not require the recipient to sign into AWS.&lt;/p&gt;

&lt;p&gt;The experiment used &lt;strong&gt;Buckets 2.7.54 on Windows&lt;/strong&gt;, a local HTML page, and a disposable private bucket in &lt;strong&gt;us-east-1&lt;/strong&gt; on October 11–12, 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Tested value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Request&lt;/td&gt;
&lt;td&gt;Vendor Upload Test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucket&lt;/td&gt;
&lt;td&gt;&lt;code&gt;buckets-intern-aditi-dropzone-20261011&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object prefix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;incoming/vendor/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-size display&lt;/td&gt;
&lt;td&gt;1 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-count limit&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allowed type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text/plain&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expiry selection&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bucket creation settings selected Block All Public Access and SSE-S3. Exact OS/browser versions and the signing credentials' lifetime were not recorded.&lt;/p&gt;

&lt;p&gt;For reproduction, use the &lt;a href="https://buckets.serverlesscreed.com/downloads" rel="noopener noreferrer"&gt;Buckets downloads page&lt;/a&gt;, an approved private sandbox, Python 3 and authorized AWS Console/CLI access. The sandbox budget alarm was confirmed before testing; direct POST replay was conducted under reported owner approval.&lt;/p&gt;

&lt;p&gt;CORS allowed &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;HEAD&lt;/code&gt;, with wildcard origins and headers. Successful browser uploads showed HTTP 200 preflight and HTTP 204 upload responses. &lt;strong&gt;CORS controls browser cross-origin access; it does not grant S3 write permission.&lt;/strong&gt; A non-browser replay client is not subject to browser CORS enforcement. &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/cors.html" rel="noopener noreferrer"&gt;AWS CORS documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Establishing a valid baseline
&lt;/h2&gt;

&lt;p&gt;Deterministic files made the size boundary reproducible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blog03-fixtures&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;valid.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Aditi upload fixture&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# 21 bytes
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;second.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Second file&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;               &lt;span class="c1"&gt;# 12 bytes
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrong.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;p&amp;gt;Harmless test&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# 20 bytes
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;too-large.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1_048_577&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;# one byte over 1 MiB
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page accepted &lt;code&gt;valid.txt&lt;/code&gt; with HTTP 204. AWS Console independently showed the 21-byte object at &lt;code&gt;incoming/vendor/abb7e962f9cc45c9-valid.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The generated token changed the final key, so verification used the actual stored key rather than assuming it matched the filename. Downloading the object and comparing SHA-256 with PowerShell's &lt;code&gt;Get-FileHash&lt;/code&gt; produced the same digest as the source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;860DB5A8887A82E09C1C812D0CBBAE23CADDD7D2A39575100A2998387647A758
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That established byte integrity as well as upload completion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29qahvoba2vty372rp1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F29qahvoba2vty372rp1b.png" alt="Recipient page showing valid.txt uploaded with 21 bytes beside Network responses of 204 and 200." width="799" height="374"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1. Valid 21-byte upload: HTTP 204 with a successful preflight response.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the browser rejected
&lt;/h2&gt;

&lt;p&gt;Selecting &lt;code&gt;wrong.html&lt;/code&gt; produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File type 'text/html' not allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cleared, recording Network panel captured no request. This was a page-side rejection, not an S3 policy response. The page already contained a successful upload, so this was not an isolated fresh-session MIME test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1h8km2lxaycq3k08xasw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1h8km2lxaycq3k08xasw.png" alt="wrong.html rejected as text/html beside an empty recording Network panel." width="799" height="383"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2. Browser rejection of text/html without a captured upload request.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The 1,048,577-byte fixture produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File exceeds 1 MB limit (1 MB)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both values were rounded to “1 MB,” obscuring a one-byte difference. The screenshot established the displayed rejection, but did not retain Network evidence for that attempt.&lt;/p&gt;

&lt;p&gt;A subsequent 21-byte &lt;code&gt;recovery.txt&lt;/code&gt; uploaded from the same page without a refresh. HTTP 204 and an independently listed S3 object confirmed recovery after rejected input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4goiiwd8ca0ygvz7bbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4goiiwd8ca0ygvz7bbr.png" alt="Oversized-file error retained while recovery.txt shows Uploaded and Network records HTTP 204." width="520" height="448"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 3. After rejecting the oversized file, the same page accepted a valid 21-byte retry without a refresh.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the signed policy actually constrained
&lt;/h2&gt;

&lt;p&gt;Decoding the saved policy exposed these conditions. This is a sanitized excerpt, not the complete signed policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expiration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-12T17:32:08.054Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"starts-with"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"incoming/vendor/"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"content-length-range"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1048576&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"starts-with"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text/plain"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The displayed “1 MB” corresponded to &lt;strong&gt;1 MiB: 1,048,576 bytes&lt;/strong&gt;. The key condition restricted the submitted object key to &lt;code&gt;incoming/vendor/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The MIME condition was a &lt;strong&gt;prefix comparison on the submitted &lt;code&gt;Content-Type&lt;/code&gt; field&lt;/strong&gt;, not strict equality or file-content inspection. Rejecting &lt;code&gt;text/html&lt;/code&gt; does not prove that S3 recognizes the bytes as plain text. &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/developerguide/sigv4-HTTPPOSTConstructPolicy.html" rel="noopener noreferrer"&gt;AWS POST policy documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test S3 independently of the page, a local Python client submitted the saved signed fields as multipart POST requests. A valid baseline succeeded first; each negative then changed one tested boundary while retaining the policy and signature.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Direct POST test&lt;/th&gt;
&lt;th&gt;Changed input&lt;/th&gt;
&lt;th&gt;HTTP&lt;/th&gt;
&lt;th&gt;S3 result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;Valid prefix, 21 bytes, &lt;code&gt;text/plain&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;204&lt;/td&gt;
&lt;td&gt;Object created&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prefix&lt;/td&gt;
&lt;td&gt;Key under &lt;code&gt;outside-vendor/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AccessDenied&lt;/code&gt;; failed key-prefix condition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;1,048,577-byte file&lt;/td&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EntityTooLarge&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Submitted MIME&lt;/td&gt;
&lt;td&gt;Form field &lt;code&gt;Content-Type=text/html&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AccessDenied&lt;/code&gt;; failed MIME-prefix condition&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The size response stated: “Your proposed upload exceeds the maximum allowed size.” The MIME replay preserved the plain-text bytes and file part's &lt;code&gt;text/plain&lt;/code&gt; header, isolating the changed form field.&lt;/p&gt;

&lt;p&gt;Correct multipart construction matters: preserve signed fields, avoid duplicate &lt;code&gt;key&lt;/code&gt; or &lt;code&gt;Content-Type&lt;/code&gt; fields, generate a matching boundary header, and place the file part last. &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/developerguide/RESTObjectPOST.html" rel="noopener noreferrer"&gt;AWS POST Object documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A whole-bucket AWS CLI listing showed five successful objects: four browser uploads and the replay baseline. None of the failed replay keys appeared. Checking only the allowed prefix would have missed an incorrectly accepted outside-prefix object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w6ygybvufyg0em02u96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w6ygybvufyg0em02u96.png" alt="AWS CLI output showing prefix and MIME rejection with 403 AccessDenied, size rejection with 400 EntityTooLarge, and five accepted objects." width="798" height="180"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 4. S3 rejected prefix, size and submitted MIME violations; independent listing showed only the five successful uploads.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one file was not a global quota
&lt;/h2&gt;

&lt;p&gt;After the first upload, selecting &lt;code&gt;second.txt&lt;/code&gt; in the same page returned “File limit reached,” with no captured Network request.&lt;/p&gt;

&lt;p&gt;Reopening the saved HTML in a new tab allowed that same file to upload with HTTP 204. AWS showed both objects, although the page still displayed a one-file limit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjmppm9u4tkvh64yqzha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjmppm9u4tkvh64yqzha.png" alt="Same page showing valid.txt uploaded and second.txt rejected with File limit reached." width="800" height="351"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 5. The existing page rejected a second valid file.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F391wyv5wec0s0roo2e40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F391wyv5wec0s0roo2e40.png" alt="Reopened page showing second.txt uploaded while still displaying the one-file limit." width="800" height="370"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 6. Reopening the saved HTML reset the page counter and allowed the second file.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For this saved-page flow, the counter operated within the page instance. It did not enforce a shared quota across uses of the issued authorization. A global limit requires an authoritative shared admission mechanism; a browser counter alone cannot provide it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Pause stopped—and what remained usable
&lt;/h2&gt;

&lt;p&gt;Pausing the request changed its card to “Paused” and disabled the save and host controls. That established the UI behavior; no backend refusal response was captured from those disabled controls.&lt;/p&gt;

&lt;p&gt;The previously saved HTML still uploaded &lt;code&gt;after-pause.txt&lt;/code&gt; successfully. HTTP 204 and the independently verified 23-byte object &lt;code&gt;incoming/vendor/63ce607d042713f2-after-pause.txt&lt;/code&gt; established that issued authorization remained usable during pause.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwjuphggoy3p4n62foe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwjuphggoy3p4n62foe4.png" alt="Buckets request marked Paused with save and host controls disabled." width="800" height="301"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 7. Pausing disabled the request’s save and host controls.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fi440xm3d4o2m8mwqfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fi440xm3d4o2m8mwqfy.png" alt="Previously saved page showing after-pause.txt uploaded with 23 bytes and HTTP 204 while the request was paused." width="800" height="372"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 8. Previously saved HTML successfully uploaded a file while the request was paused.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After the Drop Zone record was deleted, the controlled POST baseline also succeeded with the saved fields. In this run, &lt;strong&gt;pausing or deleting the application record did not invalidate the already-issued S3 authorization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This distinction matters operationally: stopping new page generation and revoking existing upload authority are separate controls. Hosted-page removal was not tested, so these results apply to saved HTML and direct replay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expiry, verification and cleanup
&lt;/h2&gt;

&lt;p&gt;The policy expiration was &lt;strong&gt;October 12, 2026, 23:02:08.054 IST&lt;/strong&gt;. It was inspected, not tested with a fresh POST after that time. Credential validity and AWS permissions can end signed access earlier; the policy timestamp alone does not guarantee a full day of usability. &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html" rel="noopener noreferrer"&gt;AWS credential-expiration guidance&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Boundary&lt;/th&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;th&gt;Supported conclusion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prefix&lt;/td&gt;
&lt;td&gt;Direct 403; failed key absent&lt;/td&gt;
&lt;td&gt;S3 enforced the signed prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;Page error; direct 400&lt;/td&gt;
&lt;td&gt;One byte above the bound rejected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MIME&lt;/td&gt;
&lt;td&gt;Page rejection; direct 403&lt;/td&gt;
&lt;td&gt;Submitted MIME prefix enforced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File count&lt;/td&gt;
&lt;td&gt;Same-page rejection; reopened-page success&lt;/td&gt;
&lt;td&gt;Page-instance scope observed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pause&lt;/td&gt;
&lt;td&gt;Disabled controls; saved-page upload succeeded&lt;/td&gt;
&lt;td&gt;Existing authorization remained usable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expiry&lt;/td&gt;
&lt;td&gt;Decoded timestamp only&lt;/td&gt;
&lt;td&gt;Elapsed expiry untested&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Exact-bound acceptance and file-content validation were not tested.&lt;/p&gt;

&lt;p&gt;Cleanup removed the request and all five uploaded objects, then deleted the disposable bucket. An independent AWS CLI bucket-list query filtered for its exact name returned &lt;code&gt;[]&lt;/code&gt;, corroborating deletion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjrf4vws2rlyqe15rd1tc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjrf4vws2rlyqe15rd1tc.png" alt="AWS CLI bucket-list query filtered for the deleted test bucket returning an empty JSON array." width="800" height="186"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 9. Independent AWS verification returned an empty list for the deleted test bucket.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Saved HTML and extracted signed fields are authorization material. Keep them private and remove local signed copies after evidence collection; publish only sanitized conditions and responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The useful question is not whether an upload page displays a limit, but where that limit is enforced.&lt;/p&gt;

&lt;p&gt;In this run, S3 enforced the signed key prefix, file-size range and submitted MIME prefix. The page's file counter reset on reopening. Pausing disabled new generation controls, yet previously saved authorization still worked.&lt;/p&gt;

&lt;p&gt;For engineers, the practical lesson is to verify each boundary at its own layer: inspect exact policy conditions, observe browser requests, test approved direct submissions and check actual S3 state. Treat request management, issued authorization and object cleanup as separate operations.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>security</category>
      <category>testing</category>
    </item>
    <item>
      <title>Deploy a Private-Origin Site with Buckets and Verify an Incremental Update</title>
      <dc:creator>Aditi Dange</dc:creator>
      <pubDate>Thu, 08 Oct 2026 16:23:25 +0000</pubDate>
      <link>https://dev.to/aditi_dange_20cc3d78635f7/deploy-a-private-origin-site-with-buckets-and-verify-an-incremental-update-41b2</link>
      <guid>https://dev.to/aditi_dange_20cc3d78635f7/deploy-a-private-origin-site-with-buckets-and-verify-an-incremental-update-41b2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqb5ly452nbx9ppnu95fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqb5ly452nbx9ppnu95fw.png" alt="Cover Image" width="800" height="450"&gt;&lt;/a&gt;A static site can be publicly available through CloudFront while its S3 origin remains private. This gives visitors an HTTPS endpoint without making the underlying S3 objects anonymously readable.&lt;/p&gt;

&lt;p&gt;In this tutorial, I use &lt;a href="https://buckets.serverlesscreed.com/" rel="noopener noreferrer"&gt;Buckets by Serverless Creed&lt;/a&gt; to review and deploy a small static site, verify its access boundary in AWS, and inspect an incremental update. The update changes one file, adds another and leaves two files unchanged.&lt;/p&gt;

&lt;p&gt;The walkthrough draws on my Windows deployment tests and a supplementary run on 8 October 2026. Historical examples are labelled with their original application versions and fixtures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the delivery setup
&lt;/h2&gt;

&lt;p&gt;Visitors access the site through CloudFront over HTTPS. CloudFront requests the files from an S3 REST origin using an Origin Access Control (OAC). The bucket policy grants object-read access to the intended CloudFront distribution.&lt;/p&gt;

&lt;p&gt;This setup makes the site available through CloudFront while restricting anonymous access to the underlying S3 objects.&lt;/p&gt;

&lt;p&gt;An S3 REST origin differs from an S3 static website endpoint. This walkthrough uses the REST origin because OAC does not apply to S3 website endpoints. See &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html" rel="noopener noreferrer"&gt;AWS’s guidance on restricting access to an S3 origin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare the environment and test files
&lt;/h2&gt;

&lt;p&gt;Install Buckets from the &lt;a href="https://buckets.serverlesscreed.com/downloads" rel="noopener noreferrer"&gt;official download page&lt;/a&gt;. Before deploying, confirm your approval for the AWS resources, public site delivery and associated costs. Check the active AWS account, profile, budget alerts and cleanup plan.&lt;/p&gt;

&lt;p&gt;My supplementary run on &lt;strong&gt;8 October 2026&lt;/strong&gt; used &lt;strong&gt;Buckets by Serverless Creed v2.7.49 on Windows&lt;/strong&gt;, with the &lt;code&gt;aws-admin&lt;/code&gt; profile in the &lt;code&gt;us-east-1&lt;/code&gt; AWS region.&lt;/p&gt;

&lt;p&gt;Earlier supporting tests used v2.7.17 for the initial deployment (TC-SITE-001) and v2.7.20 for incremental deployment (TC-SITE-002), using the &lt;code&gt;default&lt;/code&gt; AWS profile.&lt;/p&gt;

&lt;p&gt;Create a local folder named &lt;code&gt;site&lt;/code&gt; containing these three files:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The page we will modify during the update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;style.css&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A stylesheet we will leave unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;large-test.bin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A binary file we will also leave unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Save &lt;code&gt;index.html&lt;/code&gt; as UTF-8:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;`html
&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Aditi sandbox site&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Deployment revision 1&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save &lt;code&gt;style.css&lt;/code&gt; as UTF-8:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a 1 MiB binary test file by running this Python code from inside the &lt;code&gt;site&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;large-test.bin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1048576&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The binary file provides an unchanged object to track during the incremental update.&lt;/p&gt;

&lt;p&gt;Before editing any files, record their names, sizes and SHA-256 hashes. Open PowerShell inside the &lt;code&gt;site&lt;/code&gt; folder and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'SHA256'&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;Expression&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-FileHash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LiteralPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Algorithm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Export&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;..\&lt;/span&gt;&lt;span class="nx"&gt;manifest&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;NoTypeInformation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This saves &lt;code&gt;manifest-before.csv&lt;/code&gt; in the parent directory. Keep manifests and screenshots outside the &lt;code&gt;site&lt;/code&gt; folder so they are not uploaded as website content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review and Deploy the Site
&lt;/h2&gt;

&lt;p&gt;In Buckets, open &lt;strong&gt;Build → Publish → Folder → Live Site&lt;/strong&gt;&lt;br&gt;
and select the local site folder.&lt;br&gt;
Choose the disposable destination bucket and verify the AWS profile and region. For the initial deployment, use a new CloudFront distribution. Leave Delete remote-only objects unchecked.&lt;br&gt;
Select Preview diff. My initial preview showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 uploads: index.html, style.css and large-test.bin&lt;/li&gt;
&lt;li&gt;0 unchanged files&lt;/li&gt;
&lt;li&gt;0 remote-only files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fursticeg95j4a42bu19l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fursticeg95j4a42bu19l.png" alt="Buckets initial deployment preview showing three uploads with remote-object deletion unchecked." width="478" height="526"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Initial deployment preview: three uploads, no unchanged files and no remote-only objects.&lt;/em&gt;&lt;br&gt;
Select Confirm deploy, then review the affected resources, required permissions and estimated costs in the Cost &amp;amp; permission review before submitting.&lt;br&gt;
The deployment connects the S3 bucket to an OAC-backed CloudFront distribution. Buckets reported Deployment submitted and three paths invalidated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2jvibgknbuz677p0s1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2jvibgknbuz677p0s1h.png" alt="Buckets deployment result showing Deployment submitted and three paths invalidated." width="488" height="529"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Buckets reported deployment submission and three invalidated paths.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify delivery and the private S3 origin
&lt;/h2&gt;

&lt;p&gt;Open the CloudFront HTTPS URL in an Incognito or signed-out browser. In my supplementary run, the page displayed Deployment revision 1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fri6xo692fmefcbircg3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fri6xo692fmefcbircg3v.png" alt="Site displaying Deployment revision 1 through its CloudFront HTTPS URL in Incognito." width="800" height="219"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;CloudFront served Deployment revision 1 in Incognito.&lt;/em&gt;&lt;br&gt;
Next, copy the S3 Object URL for index.html from AWS Console and open it in Incognito. Use the plain object URL, without presigned credentials. My direct S3 request returned AccessDenied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs7bx3faaoqgxlnui9jdo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs7bx3faaoqgxlnui9jdo.png" alt="S3 REST object URL for index.html returning AccessDenied in Incognito." width="800" height="217"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An unsigned request for the S3 index object returned AccessDenied.&lt;/em&gt;&lt;br&gt;
Verify the configuration independently in AWS Console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under CloudFront → Distribution → Origins, confirm that the S3 origin has the intended OAC attached.&lt;/li&gt;
&lt;li&gt;Under S3 → Bucket → Permissions → Bucket policy, inspect the CloudFront access permission.
In my test, the bucket policy allowed s3:GetObject to the cloudfront.amazonaws.com service principal, with an AWS:SourceArn condition matching the intended distribution.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frlww3291gxk8rpnd1h8u.png" alt="CloudFront origin settings showing the attached Origin Access Control." width="800" height="383"&gt;
&lt;em&gt;The CloudFront S3 origin had an OAC attached.&lt;/em&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwa4cjb6x61qcslwq2fla.JPG" alt="S3 bucket policy showing the CloudFront service principal, GetObject permission and distribution SourceArn condition." width="619" height="381"&gt;
&lt;em&gt;The bucket policy scoped CloudFront object-read access to the intended distribution.&lt;/em&gt;
These results demonstrate the intended access boundary: the page was available through CloudFront, while the unsigned direct S3 request was denied. Check the stylesheet separately through the CloudFront URL at /style.css.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6x7jp4m49vvwbxixxagn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6x7jp4m49vvwbxixxagn.png" alt="Buckets incremental deployment preview showing two uploads, two unchanged files and zero remote-only files" width="490" height="542"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The incremental preview identified two uploads and two unchanged files.&lt;/em&gt;&lt;br&gt;
Review the changes and submit the deployment. In AWS Console, open the distribution’s Invalidations tab. My completed invalidation contained exactly these paths:&lt;br&gt;
/index.html&lt;br&gt;
/notes.txt&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frlmmszrl7r7vew0k1xqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frlmmszrl7r7vew0k1xqo.png" alt="CloudFront invalidation details showing Completed status and the paths /index.html and /notes.txt." width="800" height="194"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The completed invalidation targeted only /index.html and /notes.txt.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify the Updated Site and Deployment Scope
&lt;/h3&gt;

&lt;p&gt;After the incremental deployment, I verified that the CloudFront invalidation reached &lt;strong&gt;Completed&lt;/strong&gt; status and included exactly two paths: &lt;code&gt;/index.html&lt;/code&gt; and &lt;code&gt;/notes.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Buckets preview identified &lt;strong&gt;2 uploads and 2 unchanged files&lt;/strong&gt;, matching the intended changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modified:&lt;/strong&gt; &lt;code&gt;index.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Newly added:&lt;/strong&gt; &lt;code&gt;notes.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unchanged:&lt;/strong&gt; &lt;code&gt;style.css&lt;/code&gt; and &lt;code&gt;large-test.bin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This confirmed that Buckets correctly identified the files requiring an update while recognizing the unchanged files.&lt;/p&gt;

&lt;p&gt;As a final verification step, the updated &lt;code&gt;index.html&lt;/code&gt; and newly added &lt;code&gt;notes.txt&lt;/code&gt; can be accessed through the CloudFront HTTPS endpoint. For deeper verification, S3 object metadata such as &lt;strong&gt;Last modified&lt;/strong&gt; timestamps or version IDs can also be compared before and after deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify OAC list, create and delete operations
&lt;/h2&gt;

&lt;p&gt;Alongside the site deployment, I tested OAC management using a separate, disposable OAC that was not attached to a distribution.&lt;br&gt;
In Buckets, open the Origin Access Control list under the authorized AWS profile. Record the existing entries so they can be preserved.&lt;br&gt;
Create a test OAC with these settings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;buckets-intern-aditi-oac-20261007&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Origin type&lt;/td&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing behavior&lt;/td&gt;
&lt;td&gt;Always&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing protocol&lt;/td&gt;
&lt;td&gt;SigV4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After creation, I verified that the new OAC appeared in both Buckets and AWS Console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F72ejgyegruczxag5c2av.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F72ejgyegruczxag5c2av.png" alt="Buckets showing the newly created disposable Origin Access Control." width="800" height="568"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Buckets created the disposable OAC using S3, Always signing and SigV4.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqqj5zk8gxhcoy7g2o2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqqj5zk8gxhcoy7g2o2c.png" alt="AWS CloudFront Origin Access Control list containing the disposable test OAC." width="800" height="284"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The new OAC also appeared in AWS Console.&lt;/em&gt;&lt;br&gt;
I then deleted only the disposable, unattached OAC. Buckets displayed a successful deletion result, and an independent AWS Console check confirmed that the entry was absent. The pre-existing OAC remained in the list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7psfuvzr6cuu3kln7l09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7psfuvzr6cuu3kln7l09.png" alt="Buckets showing the deletion result for the disposable Origin Access Control." width="799" height="568"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Buckets reported successful deletion of the unattached test OAC.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feeanufxtuissbd86xb2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feeanufxtuissbd86xb2p.png" alt="AWS Origin Access Control list after deletion, showing only the preserved existing entry." width="800" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The refreshed AWS list no longer contained the test OAC; the existing entry remained.&lt;/em&gt;&lt;br&gt;
The deletion dialog also explained that AWS blocks deletion while an OAC is in use. This test demonstrated deletion of an unattached OAC; the OAC serving the deployed site was retained.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting: OAC Creation Error
&lt;/h3&gt;

&lt;p&gt;During one deployment attempt, the site files uploaded, but OAC creation returned “The parameter Name is too big.” I checked AWS to identify the resources already created before retrying with a shorter disposable bucket name. The retry successfully created the delivery stack. The exact generated-name cause was not confirmed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhczrgz2602ovawqi1a9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhczrgz2602ovawqi1a9m.png" alt="Buckets deployment result showing the OAC creation error: The parameter Name is too big." width="511" height="509"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;OAC creation failed with a name-length error after the site files uploaded&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleanup and Resource Teardown
&lt;/h2&gt;

&lt;p&gt;After completing the initial deployment, private-origin verification, and incremental update tests, I removed the disposable AWS resources created for this walkthrough.&lt;/p&gt;

&lt;p&gt;I followed the dependency-aware cleanup order to avoid deleting resources that were still in use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Remove the CloudFront distribution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I disabled and deleted the test CloudFront distribution. After deletion, the AWS CloudFront console displayed &lt;strong&gt;Distributions (0)&lt;/strong&gt;, confirming that no distributions remained in the selected account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjozw6tg7zdwm9zyusolu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjozw6tg7zdwm9zyusolu.png" alt="AWS CloudFront Distributions page displaying “Distributions (0)” and “No distributions,” confirming the distribution list is empty." width="799" height="248"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS CloudFront console showing zero distributions after deleting the test distribution.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Delete the Origin Access Control (OAC)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using the Origin Access Controls interface in Buckets, I deleted the OAC associated with the test deployment.&lt;/p&gt;

&lt;p&gt;Buckets displayed a successful deletion message. I independently checked the AWS CloudFront console, which showed &lt;strong&gt;Origin access controls (0)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jiaj9hpolqqlt3m90mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jiaj9hpolqqlt3m90mm.png" alt="Buckets Origin Access Controls interface displaying a green success message confirming deletion of the selected S3 Origin Access Control." width="800" height="402"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Buckets confirming successful deletion of the test Origin Access Control.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Empty the S3 bucket&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before deleting the bucket, I used Buckets to remove the four test objects. The application confirmed that the bucket was emptied and the bucket list was synchronized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Delete the S3 bucket&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, I deleted the disposable S3 bucket using Buckets. The application displayed a successful deletion notification and synchronized the bucket list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foag01wr4kkq15tr2o0db.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foag01wr4kkq15tr2o0db.png" alt="Buckets notifications displaying “Bucket Deleted” and “Bucket List Synchronized” after removal of the test S3 bucket." width="381" height="289"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Buckets confirming deletion of the disposable S3 bucket and synchronization of the bucket list.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleanup Result
&lt;/h3&gt;

&lt;p&gt;The CloudFront distribution and OAC were confirmed absent in AWS, while Buckets confirmed the deletion of the four S3 objects and the test bucket.&lt;/p&gt;

&lt;p&gt;This completed the application-side cleanup of the disposable resources used for the tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this walkthrough, we deployed a static website using &lt;strong&gt;Buckets by Serverless Creed&lt;/strong&gt;, with Amazon S3 as a private origin and Amazon CloudFront providing HTTPS delivery.&lt;/p&gt;

&lt;p&gt;We verified that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The website was accessible through its CloudFront HTTPS URL while direct, unauthenticated S3 access was denied.&lt;/li&gt;
&lt;li&gt;CloudFront Origin Access Control (OAC) was configured to support access to the private S3 origin.&lt;/li&gt;
&lt;li&gt;The incremental deployment preview identified the changed and newly added files for upload while marking unchanged files separately.&lt;/li&gt;
&lt;li&gt;CloudFront invalidation targeted the updated paths, allowing the latest website content to be served.&lt;/li&gt;
&lt;li&gt;The disposable CloudFront distribution, OAC, and S3 resources were removed after testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key takeaway is that &lt;strong&gt;deploying a website is only part of the process&lt;/strong&gt;. Verifying origin access, reviewing incremental changes, checking cache invalidation, and cleaning up test resources are equally important.&lt;/p&gt;

&lt;p&gt;By combining the Buckets deployment workflow with independent AWS Console checks, we can better understand what the application performs and what AWS actually enforces.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Create a Private S3 Bucket with Buckets and Verify Its Settings in AWS</title>
      <dc:creator>Aditi Dange</dc:creator>
      <pubDate>Tue, 06 Oct 2026 12:36:08 +0000</pubDate>
      <link>https://dev.to/aditi_dange_20cc3d78635f7/create-a-private-s3-bucket-with-buckets-and-verify-its-settings-in-aws-29pi</link>
      <guid>https://dev.to/aditi_dange_20cc3d78635f7/create-a-private-s3-bucket-with-buckets-and-verify-its-settings-in-aws-29pi</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creating an S3 bucket is only part of the setup. You also need to verify that its configuration matches the settings you selected.&lt;/p&gt;

&lt;p&gt;In this tutorial, I use &lt;a href="https://buckets.serverlesscreed.com/" rel="noopener noreferrer"&gt;Buckets by Serverless Creed&lt;/a&gt; to create a disposable private S3 bucket with versioning, Amazon S3-managed encryption (SSE-S3), and Block Public Access enabled. I then compare the selected settings with the configuration in AWS.&lt;/p&gt;

&lt;p&gt;The walkthrough also explains bucket-list refresh, the empty-bucket view, and recovery from denied access-control requests. A supplementary run verifies Object Ownership and records both bucket-level and account-level Block Public Access settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and tested environment
&lt;/h2&gt;

&lt;p&gt;Before following the walkthrough, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buckets installed on your computer. The installer is available from the &lt;a href="https://buckets.serverlesscreed.com/downloads" rel="noopener noreferrer"&gt;official download page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An approved AWS sandbox and an authorized profile for bucket creation, configuration checks, and cleanup.&lt;/li&gt;
&lt;li&gt;AWS Console access to independently verify the bucket settings.&lt;/li&gt;
&lt;li&gt;A separate approved restricted profile for the permission-denied example.&lt;/li&gt;
&lt;li&gt;A unique disposable bucket name and an approved AWS Region.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use your assigned sandbox permissions rather than granting yourself general administrator access.&lt;/p&gt;

&lt;p&gt;The evidence comes from separate documented tests on Windows in &lt;code&gt;us-east-1&lt;/code&gt;, followed by a supplementary run using Buckets 2.7.47:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part of the walkthrough&lt;/th&gt;
&lt;th&gt;Recorded application version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Private bucket creation&lt;/td&gt;
&lt;td&gt;2.7.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucket-list refresh and empty-state checks&lt;/td&gt;
&lt;td&gt;2.7.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Historical denied CORS write&lt;/td&gt;
&lt;td&gt;2.7.17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supplementary creation, verification, empty view and denied reads&lt;/td&gt;
&lt;td&gt;2.7.47&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The historical tests used different disposable buckets. The supplementary run used one fresh bucket for the creation, empty view, AWS configuration checks and restricted-profile checks. Historical screenshots are labelled separately; they do not represent one continuous execution on a single build. Interface labels may differ between versions.&lt;br&gt;
The supplementary work was performed on 6–7 October 2026 (India Standard Time). Its authorized profile was named &lt;code&gt;aws-admin&lt;/code&gt;; older records use the profile name &lt;code&gt;default&lt;/code&gt;. A profile name identifies a local configuration, so verify the account and identity rather than relying on the name alone. Private approval and account details belong in the supporting evidence record.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Choose the bucket settings
&lt;/h2&gt;

&lt;p&gt;Before creating the bucket, decide which settings you intend to apply. For this test, I used the following configuration:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Selected value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS Region&lt;/td&gt;
&lt;td&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object Versioning&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default encryption&lt;/td&gt;
&lt;td&gt;Amazon S3-managed encryption (SSE-S3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block All Public Access&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object Lock&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static Website Hosting&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Versioning retains multiple versions of objects. SSE-S3 provides encryption at rest, while Block Public Access restricts public access through policies and ACLs. These controls serve different purposes: encryption does not grant access, and versioning does not prevent every form of deletion.&lt;/p&gt;

&lt;p&gt;Object Ownership is checked separately in AWS. Only describe it as an application selection if that control is actually available in the tested form.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Create the bucket in Buckets
&lt;/h2&gt;

&lt;p&gt;Open the bucket-creation form in Buckets and select the authorized AWS profile. Enter a unique bucket name, choose the approved Region, and select the configuration listed above.&lt;/p&gt;

&lt;p&gt;For my recorded creation test, I used the default profile and a disposable bucket in us-east-1. I enabled Object Versioning, SSE-S3 encryption, and Block All Public Access, while leaving Object Lock and Static Website Hosting disabled.&lt;/p&gt;

&lt;p&gt;Review the name, Region, and selected options before confirming creation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fir55tw8yoqlc9ip7rrqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fir55tw8yoqlc9ip7rrqp.png" alt="Buckets creation form with versioning, SSE-S3 encryption and Block All Public Access selected" width="665" height="722"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1. Bucket-creation form showing the disposable bucket name, Region and selected options before confirmation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After confirming, follow the operation through its creation stages. A bucket appearing in the list does not, by itself, prove that every selected setting was applied.&lt;/p&gt;

&lt;p&gt;In my recorded test, creation completed without an observed error or partial-failure message. I reopened the bucket’s properties in Buckets, where Versioning appeared as &lt;strong&gt;Enabled&lt;/strong&gt; and Public access appeared as &lt;strong&gt;Fully blocked&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These application values were an initial check. I then verified the configuration independently in AWS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F176hdhr3kp63724kqxk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F176hdhr3kp63724kqxk6.png" alt="Bucket properties panel showing enabled versioning and fully blocked public access" width="799" height="426"&gt;&lt;/a&gt;&lt;br&gt;
After creation, Buckets displayed Versioning as Enabled and Public access as Fully blocked.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Verify the bucket settings in AWS
&lt;/h2&gt;

&lt;p&gt;After checking the bucket’s properties in Buckets, open the same bucket in AWS Console. Confirm its name and Region before inspecting the configuration.&lt;/p&gt;

&lt;p&gt;Check &lt;strong&gt;Bucket Versioning&lt;/strong&gt; and &lt;strong&gt;Default encryption&lt;/strong&gt; under &lt;strong&gt;Properties&lt;/strong&gt;, then check &lt;strong&gt;Block Public Access&lt;/strong&gt; and &lt;strong&gt;Object Ownership&lt;/strong&gt; under &lt;strong&gt;Permissions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My recorded creation test documented the following AWS results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Selected in Buckets&lt;/th&gt;
&lt;th&gt;Recorded AWS result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucket Versioning&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default encryption&lt;/td&gt;
&lt;td&gt;SSE-S3&lt;/td&gt;
&lt;td&gt;Server-side encryption with Amazon S3 managed keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block All Public Access&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;On; all four individual flags enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fadniq1tmqdw19sn2wjim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fadniq1tmqdw19sn2wjim.png" alt="S3 Default encryption section showing Amazon S3 managed keys" width="800" height="227"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Console verification of SSE-S3 default encryption.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobtpt8lpewj7vuvk7sla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobtpt8lpewj7vuvk7sla.png" alt="S3 Bucket Versioning section showing Enabled" width="800" height="263"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Console verification of enabled bucket versioning.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq8dlndeome98bbh0r6ml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq8dlndeome98bbh0r6ml.png" alt="S3 Block Public Access settings showing all four flags enabled." width="800" height="321"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Console verification of all four bucket-level public-access blocks&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These checks confirm the recorded configuration, rather than providing an absolute security guarantee. Versioning, encryption and access controls serve different purposes, and the bucket’s access also depends on applicable policies and account-level restrictions.&lt;/p&gt;

&lt;p&gt;The documented AWS values matched the selected configuration. If a value differs, record the mismatch rather than treating the operation as fully successful.&lt;/p&gt;
&lt;h2&gt;
  
  
  Object Ownership and account-level checks in the supplementary run
&lt;/h2&gt;

&lt;p&gt;In the supplementary 2.7.47 run, AWS Console showed versioning &lt;strong&gt;Enabled&lt;/strong&gt;, default encryption &lt;strong&gt;SSE-S3&lt;/strong&gt;, and all four bucket-level Block Public Access flags &lt;strong&gt;On&lt;/strong&gt;. AWS also showed &lt;strong&gt;Bucket owner enforced&lt;/strong&gt; Object Ownership, with ACLs disabled. Ownership was independently verified in AWS; I do not describe it as an option selected in Buckets.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting or check&lt;/th&gt;
&lt;th&gt;Intended value / source&lt;/th&gt;
&lt;th&gt;Observed result in the supplementary run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;us-east-1&lt;/code&gt; shown in Buckets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Versioning&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;td&gt;Enabled in AWS Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default encryption&lt;/td&gt;
&lt;td&gt;SSE-S3&lt;/td&gt;
&lt;td&gt;Amazon S3 managed keys in AWS Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucket-level Block Public Access&lt;/td&gt;
&lt;td&gt;All four flags enabled&lt;/td&gt;
&lt;td&gt;All four flags On in AWS Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object Ownership&lt;/td&gt;
&lt;td&gt;Independently inspect AWS state&lt;/td&gt;
&lt;td&gt;Bucket owner enforced; ACLs disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Account-level Block Public Access&lt;/td&gt;
&lt;td&gt;Inspect existing settings without changing them&lt;/td&gt;
&lt;td&gt;All four settings Off&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ylrwzuiofmxt5ovugm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ylrwzuiofmxt5ovugm5.png" alt="Supplementary run: AWS Console shows Bucket owner enforced ownership and disabled ACLs." width="800" height="174"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Supplementary run: AWS Console shows Bucket owner enforced ownership and disabled ACLs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxzwrc2xcbqunvgvnp91h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxzwrc2xcbqunvgvnp91h.png" alt="AWS S3 account-level Block Public Access settings showing all four options Off." width="799" height="334"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All four account-level Block Public Access settings were Off at the time of inspection; no account settings were changed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Account-level settings being Off does not automatically grant public access. S3 applies the most restrictive combination of applicable bucket, account and organization settings. In this fixture, the bucket-level flags remained On. See AWS documentation on &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html" rel="noopener noreferrer"&gt;Block Public Access&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html" rel="noopener noreferrer"&gt;Bucket owner enforced&lt;/a&gt;, ACLs are disabled. The Access Control ACL tab displayed that ownership state. This is different from an IAM permission-denied response; I did not enable ACLs for the test.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Refresh the bucket list
&lt;/h2&gt;

&lt;p&gt;Refresh the bucket list under the same authorized AWS profile, then locate and open your bucket.&lt;/p&gt;

&lt;p&gt;In a separate supporting Buckets version 2.7.12 on Windows, I created a disposable bucket directly in AWS Console. It did not initially appear in Buckets. Selecting &lt;strong&gt;Refresh Bucket List&lt;/strong&gt; made it visible.&lt;/p&gt;

&lt;p&gt;After deleting that test bucket through AWS Console, its entry remained visible in Buckets until I refreshed again. Refreshing removed the stale entry. This demonstrates why the displayed list should be refreshed after changes made outside the application.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffqymask7kqwvxxsxj8mz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffqymask7kqwvxxsxj8mz.png" alt="After creation and refresh: the new bucket appears in Buckets" width="685" height="311"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The bucket created in AWS Console appeared in Buckets after refreshing the list&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvv1prm3u0wxmg74754t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvv1prm3u0wxmg74754t.png" alt="After deletion and refresh: the test bucket is absent." width="750" height="279"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Refreshing after AWS-side deletion removed the test bucket from the list&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Inspect the empty-bucket view
&lt;/h2&gt;

&lt;p&gt;Open the bucket under the authorized AWS profile and inspect its object list.&lt;/p&gt;

&lt;p&gt;In a separate supporting test on Windows version 2.7.12 and  supplementary run using Buckets 2.7.47 on Windows, I opened an empty disposable bucket. Buckets displayed &lt;strong&gt;Create Folder&lt;/strong&gt; and &lt;strong&gt;Upload Files&lt;/strong&gt; actions, providing clear next steps for adding content.&lt;/p&gt;

&lt;p&gt;Keep the bucket empty while capturing this part of the walkthrough. A failed or access-denied request does not prove that a bucket is empty; confirm that the object-list request completed successfully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F65mu72jig1e5mijhojxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F65mu72jig1e5mijhojxq.png" alt="Empty bucket view in Buckets with Create Folder and Upload Files buttons" width="800" height="361"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Separate empty-state test: an empty bucket displays Create Folder and Upload Files actions.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Handle denied access-control requests
&lt;/h2&gt;

&lt;p&gt;A restricted AWS profile may be prevented from reading security settings, changing them, or both. The following tests demonstrate these differences.&lt;/p&gt;
&lt;h3&gt;
  
  
  Restricted-profile checks in Buckets 2.7.47
&lt;/h3&gt;

&lt;p&gt;In the supplementary test using Buckets 2.7.47 on Windows, I used a separate temporary profile named &lt;code&gt;tcacl006-restricted&lt;/code&gt;. It allowed bucket listing and basic reads of the disposable test bucket, while explicitly denying access to its security configuration.&lt;/p&gt;

&lt;p&gt;Under this profile, I opened &lt;strong&gt;Access Control&lt;/strong&gt; and checked the available tabs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tab&lt;/th&gt;
&lt;th&gt;Observed result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bucket Policy&lt;/td&gt;
&lt;td&gt;Loading failed with an explicit deny for &lt;code&gt;s3:GetBucketPolicy&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public Access&lt;/td&gt;
&lt;td&gt;Loading failed with an explicit deny for &lt;code&gt;s3:GetBucketPublicAccessBlock&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS&lt;/td&gt;
&lt;td&gt;Loading failed with an explicit deny for &lt;code&gt;s3:GetBucketCORS&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3iecyq3q0ptxo8af76sd.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3iecyq3q0ptxo8af76sd.JPG" alt="Restricted-profile Public Access denial." width="800" height="306"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The restricted profile could not load Public Access settings because its identity policy explicitly denied &lt;code&gt;s3:GetBucketPublicAccessBlock&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Access Control dialog remained usable: I could switch tabs and close it after the errors.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;ACL&lt;/strong&gt; tab displayed &lt;strong&gt;“ACLs disabled — Bucket owner enforced.”&lt;/strong&gt; This was an ownership-related restriction, rather than a displayed IAM authorization error. I did not enable ACLs or change Object Ownership.&lt;/p&gt;

&lt;p&gt;Because the Public Access settings failed to load, the tab did not display editable flags or a Save control. Resubmitting the existing Public Access Block values was therefore unavailable in this UI state. This test demonstrates denied configuration reads, rather than a denied PAB save.&lt;/p&gt;
&lt;h3&gt;
  
  
  Recover using the authorized profile
&lt;/h3&gt;

&lt;p&gt;I closed the dialog, switched to the authorized &lt;code&gt;aws-admin&lt;/code&gt; profile, and reopened Access Control for the same bucket.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Public Access&lt;/strong&gt; tab loaded successfully with all four blocking flags checked. The &lt;strong&gt;CORS&lt;/strong&gt; tab displayed an empty configuration, &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzyuhyw6dyx02t9n8yaqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzyuhyw6dyx02t9n8yaqa.png" alt="Authorized-profile Public Access recovery" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After switching to the authorized profile, the same bucket’s Public Access settings loaded with all four blocking flags checked.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I then completed an independent AWS Console check before cleanup to confirm that the intended configuration remained unchanged.&lt;/p&gt;

&lt;p&gt;Recovery used the existing authorized profile. It did not require broadening the restricted profile’s permissions or weakening public-access controls.&lt;/p&gt;
&lt;h3&gt;
  
  
  Historical example: a denied CORS write in Buckets 2.7.17
&lt;/h3&gt;

&lt;p&gt;An earlier, separate supporting test used Buckets 2.7.17 on Windows and a different disposable bucket. In that test, the restricted profile could read configuration, while security-configuration writes were restricted. The authorized profile was named &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Under the restricted profile, I opened &lt;strong&gt;Access Control → CORS&lt;/strong&gt;. The application initially displayed an empty configuration, &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I attempted to save this test configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AllowedOrigins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://example.invalid"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AllowedMethods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS rejected the save. Buckets displayed an authorization error identifying &lt;code&gt;s3:PutBucketCORS&lt;/code&gt; and an explicit deny in the restricted identity’s policy. The Access Control dialog remained usable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftc3j1733byfy4fowuo84.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftc3j1733byfy4fowuo84.JPG" alt="Buckets CORS editor displaying an authorization error for s3:PutBucketCORS." width="799" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Historical test on Buckets 2.7.17: AWS rejected the restricted profile’s CORS write with an explicit deny for &lt;code&gt;s3:PutBucketCORS&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify that the denied CORS change was not applied
&lt;/h3&gt;

&lt;p&gt;After the failed save, I closed and reopened the CORS section. It again displayed &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I independently checked the bucket using the authorized &lt;code&gt;default&lt;/code&gt; profile. The following command illustrates that verification; replace the example bucket and profile names with your approved test values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s3api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;get-bucket-cors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EXAMPLE_BUCKET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AUTHORIZED_PROFILE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS returned &lt;code&gt;NoSuchCORSConfiguration&lt;/code&gt;, confirming that no CORS configuration existed after the denied save. Together with the initial empty configuration, this supported the conclusion that the attempted change was not applied.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffx6zllszq4hsxlb7syx9.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffx6zllszq4hsxlb7syx9.JPG" alt="AWS CLI get-bucket-cors response showing NoSuchCORSConfiguration." width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Historical test: an independent check using the authorized &lt;code&gt;default&lt;/code&gt; profile returned &lt;code&gt;NoSuchCORSConfiguration&lt;/code&gt; after the denied save.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The historical test demonstrates a denied write. The supplementary 2.7.47 test demonstrates denied reads and successful configuration loading after returning to the authorized profile. They are separate tests with different permission settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Clean up the disposable resources
&lt;/h2&gt;

&lt;p&gt;After retaining the evidence, remove only the disposable resources created for the walkthrough.&lt;/p&gt;

&lt;p&gt;For the historical creation test, my cleanup record states that the bucket was empty and was deleted after evidence collection. For the separate empty-state test, I removed the uploaded test object and folder before deleting its bucket.&lt;/p&gt;

&lt;p&gt;The historical permissions-test cleanup removed the temporary restricted IAM identity, access key, profile and associated test policy. The authorized &lt;code&gt;default&lt;/code&gt; profile remained unchanged.&lt;/p&gt;

&lt;p&gt;For the supplementary test using Buckets 2.7.47, I completed the final AWS configuration check and deleted the disposable bucket and temporary restricted IAM user after collecting evidence.&lt;/p&gt;

&lt;p&gt;For your own cleanup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm that the bucket is the disposable resource you are authorized to remove.&lt;/li&gt;
&lt;li&gt;Remove any test objects. If versioning is enabled and objects were uploaded, remove all created versions and delete markers as authorized.&lt;/li&gt;
&lt;li&gt;Delete the disposable bucket.&lt;/li&gt;
&lt;li&gt;Refresh the lists in AWS Console and Buckets to verify that the bucket is absent, rather than merely empty.&lt;/li&gt;
&lt;li&gt;Remove the temporary restricted identity, its access keys and test policy. Remove any remaining local or application profile entries and temporary credential files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Preserve shared resources and retain the final configuration checks and cleanup evidence with the test record.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Tested scope and limitations
&lt;/h2&gt;

&lt;p&gt;This article combines historical Windows tests using Buckets versions 2.7.9, 2.7.12 and 2.7.17 with a supplementary test using version 2.7.47.&lt;/p&gt;

&lt;p&gt;The historical tests used different disposable buckets. The supplementary test used one fresh bucket for creation, the empty-bucket view, AWS configuration verification and restricted-profile checks. The labelled screenshots should therefore be read in their respective test contexts.&lt;/p&gt;

&lt;p&gt;The supplementary AWS verification showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bucket Versioning enabled.&lt;/li&gt;
&lt;li&gt;SSE-S3 default encryption.&lt;/li&gt;
&lt;li&gt;All four bucket-level Block Public Access flags enabled.&lt;/li&gt;
&lt;li&gt;Bucket owner enforced Object Ownership, with ACLs disabled.&lt;/li&gt;
&lt;li&gt;All four account-level Block Public Access settings disabled at the time of inspection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Object Ownership was independently verified in AWS; it is not presented as an option selected in the Buckets creation form. Account-level settings were inspected without modification. Their disabled state does not automatically grant public access: S3 applies the most restrictive combination of applicable public-access blocking settings.&lt;/p&gt;

&lt;p&gt;The historical permissions example demonstrates a denied CORS write and subsequent verification that the change was not applied. The supplementary example demonstrates denied bucket-policy, Public Access Block and CORS reads, followed by successful loading through the authorized profile.&lt;/p&gt;

&lt;p&gt;The ACL tab displayed ownership-related restrictions rather than an ACL permission-denied error. A PAB save attempt was unavailable because the restricted profile could not load the settings and the tab did not expose a Save control.&lt;/p&gt;

&lt;p&gt;These observations describe the tested configurations and operations. They do not provide an absolute security guarantee or establish every possible access path or behaviour in other application versions.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>infrastructure</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
