Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuring the bucket as a website #21

Closed
simonw opened this issue Nov 8, 2021 · 9 comments
Closed

Support configuring the bucket as a website #21

simonw opened this issue Nov 8, 2021 · 9 comments
Labels
enhancement New feature or request
Milestone

Comments

@simonw
Copy link
Owner

simonw commented Nov 8, 2021

It would be useful to have an opt-in option for saying "this bucket should be configured as a website" - because setting that up without a tool is quite fiddly.

https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteAccessPermissionsReqd.html has the details:

When you configure a bucket as a static website, if you want your website to be public, you can grant public read access. To make your bucket publicly readable, you must disable block public access settings for the bucket and write a bucket policy that grants public read access.

See #20 for "block public access" setting, and #19 for bucket policies.

@simonw simonw added the enhancement New feature or request label Nov 8, 2021
@simonw
Copy link
Owner Author

simonw commented Nov 8, 2021

Relevant boto3 documentation: https://boto3.amazonaws.com/v1/documentation/api/1.9.42/guide/s3-example-static-web-host.html

import boto3

# Create an S3 client
s3 = boto3.client("s3")

# Create the configuration for the website
website_configuration = {
    "ErrorDocument": {"Key": "error.html"},
    "IndexDocument": {"Suffix": "index.html"},
}

# Set the new policy on the selected bucket
s3.put_bucket_website(Bucket="my-bucket", WebsiteConfiguration=website_configuration)

@simonw
Copy link
Owner Author

simonw commented Nov 8, 2021

I think the --website option can default to error.html and index.html in the above, maybe providing separate --website-error= and --website-index= options for people who want to customize those.

@simonw
Copy link
Owner Author

simonw commented Nov 8, 2021

I manually confirmed that turning off the "block public access" stuff and configuring the website settings still isn't enough to expose files uploaded to the bucket - you also need to add the following bucket policy (see #19):

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"PublicRead",
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject","s3:GetObjectVersion"],
      "Resource":["arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"]
    }
  ]
}

@simonw simonw added this to the 1.0 milestone Nov 11, 2021
simonw added a commit that referenced this issue Dec 7, 2021
Will help with buckets as websites in #21

Includes integration test cowerage for put-object content-type in #43
@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

I'm going to always set them to index.html and error.html - I think those are perfectly sensible defaults. If someone really wants something else they can figure out how to do that outside of using this tool.

So I'll have a --website flag which implies --public and configures those.

@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

Prototype:

diff --git a/s3_credentials/cli.py b/s3_credentials/cli.py
index 110c153..a9b1f84 100644
--- a/s3_credentials/cli.py
+++ b/s3_credentials/cli.py
@@ -252,6 +252,11 @@ def policy(buckets, read_only, write_only, prefix, extra_statements, public_buck
     help="Make the created bucket public: anyone will be able to download files if they know their name",
     is_flag=True,
 )
+@click.option(
+    "--website",
+    help="Configure bucket to act as a website, using index.html and error.html",
+    is_flag=True,
+)
 @click.option("--read-only", help="Only allow reading from the bucket", is_flag=True)
 @click.option("--write-only", help="Only allow writing to the bucket", is_flag=True)
 @click.option(
@@ -286,6 +291,7 @@ def create(
     create_bucket,
     prefix,
     public,
+    website,
     read_only,
     write_only,
     policy,
@@ -331,6 +337,9 @@ def create(
     if not user_permissions_boundary and (policy or extra_statements):
         user_permissions_boundary = "none"
 
+    if website:
+        public = True
+
     s3 = None
     iam = None
     sts = None
@@ -376,6 +385,10 @@ def create(
                     if bucket_policy:
                         click.echo("... then attach the following bucket policy to it:")
                         click.echo(json.dumps(bucket_policy, indent=4))
+                    if website:
+                        click.echo(
+                            "... then configure index.html and error.html website settings"
+                        )
                 else:
                     s3.create_bucket(Bucket=bucket, **kwargs)
                     info = "Created bucket: {}".format(bucket)
@@ -388,6 +401,18 @@ def create(
                             Bucket=bucket, Policy=json.dumps(bucket_policy)
                         )
                         log("Attached bucket policy allowing public access")
+                    if website:
+                        s3.put_bucket_website(
+                            Bucket=bucket,
+                            WebsiteConfiguration={
+                                "ErrorDocument": {"Key": "error.html"},
+                                "IndexDocument": {"Suffix": "index.html"},
+                            },
+                        )
+                        log(
+                            "Configured website: IndexDocument=index.html, ErrorDocument=error.html"
+                        )
+
     # At this point the buckets definitely exist - create the inline policy for assume_role()
     assume_role_policy = {}
     if policy:

@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

Point of confusion: if you do this, you still need to change the overall URL you are using to access the bucket in order to get website behaviour: https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html

http://bucket-name.s3-website.Region.amazonaws.com/

@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

I used my prototype to create this: http://sfms-slides.s3-website.us-east-1.amazonaws.com/

Weirdly https://sfms-slides.s3-website.us-east-1.amazonaws.com/ (using https not http) doesn't seem to work for me.

@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

https://docs.aws.amazon.com/AmazonS3/latest/userguide/website-hosting-custom-domain-walkthrough.html says:

Amazon S3 website endpoints do not support HTTPS or access points. If you want to use HTTPS, you can use Amazon CloudFront to serve a static website hosted on Amazon S3.

For more information, see How do I use CloudFront to serve a static website hosted on Amazon S3?

and Requiring HTTPS for communication between viewers and CloudFront.

@simonw
Copy link
Owner Author

simonw commented Aug 12, 2022

Would be useful if this could output that URL as part of running the command, since figuring out the URL is tricky.

Could also return that URL from the s3-credentials list-buckets --details command - which would then also need to be able to figure out what region the bucket is in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant