Create a MicroSite on AWS S3

How to setup a micro-site on AWS S3 with custom DNS.

Create the needed S3 Buckets

This is going to create www., logs. and apex domain S3 buckets.

Do I have to have the www.? Yes.

SITE=edthe.dev
ansible-playbook -e "s3bucket=$SITE" s3site_1_create_buckets.yml
# 
---
- name: Set up static site buckets on AWS as static s3 bucket
  hosts: localhost
  connection: local
  gather_facts: no

  tasks:
  - name: Create S3 bucket
    amazon.aws.s3_bucket:
      name: 'www.{{s3bucket}}'
      state: present
      versioning: yes
  - name: Setup S3 Bucket as website
    community.aws.s3_website:
      name: 'www.{{s3bucket}}'
      state: present
      suffix: index.html
      error_key: 404.html
  - name: Add pages
    community.aws.s3_sync:
      bucket: 'www.{{s3bucket}}'
      file_root: 'files/www'
    tags:
      - debug
  - name: Create empty apex redirect bucket
    amazon.aws.s3_bucket:
      name: '{{s3bucket}}'
      state: present
      versioning: no
  - name: Setup redirect from apex to www.
    community.aws.s3_website:
      name: '{{s3bucket}}'
      redirect_all_requests: 'www.{{s3bucket}}'
      state: present
  - name: Create logs bucket
    amazon.aws.s3_bucket:
      name: 'logs.{{s3bucket}}'
      state: present
      versioning: no
  # 

Manual Step: Go 'allow public access'

Now go do a manual change, because security teams say we cannot have nice things.

In the new www. bucket, and the apex domain bucket, find and uncheck 'Block all public access'.

Once that is done, this command (which will otherwise fail in the next playbook) should succeed.

aws s3api put-bucket-policy --bucket "www.$SITE" --policy "file:///tmp/www.$SITE.acl.json"

Enable public access

This command will enable public access to the www. and apex S3 buckets.

ansible-playbook -e "s3bucket=$SITE" s3site_2_allow_public_access.yml
# 
---
- name: Set up static site buckets on AWS as static s3 bucket
  hosts: localhost
  connection: local
  gather_facts: no

  tasks:
  - name: create www. ACL file
    template:
      dest: /tmp/www.{{s3bucket}}.acl.json
      src: files/www.public_s3.j2
  - name: Clear www. access controls
    shell:
      aws s3api put-bucket-policy --bucket 'www.{{s3bucket}}' --policy 'file:///tmp/www.{{s3bucket}}.acl.json'
  - name: create apex ACL file
    template:
      dest: /tmp/{{s3bucket}}.acl.json
      src: files/public_s3.j2
  - name: Clear apex access controls
    shell:
      aws s3api put-bucket-policy --bucket '{{s3bucket}}' --policy 'file:///tmp/{{s3bucket}}.acl.json'
  # 

Verify public access

You can verify this worked by visiting the URL you under Bucket website hosting in the www. bucket.Find in under Properties -> Static website hosting.

If you get a 404 Not Found, double check that you provided an index.html file, and a errors/404.html file.

Logging

Now we use the AWS console again to enable controlling the logs bucket with Ansible.

In logs. find Edit Object Ownership and set it to ACLs Enabled. This is probably some kind of legacy thing, but this whole process is already a pain, and we are not building an enterprise here.

Now run the next playbook:

ansible-playbook -e "s3bucket=$SITE" s3site_3_add_logging.yml
# 
---
- name: Set up static site buckets on AWS as static s3 bucket
  hosts: localhost
  connection: local
  gather_facts: no

  tasks:
  - name: setup logging from www. to logs.
    community.aws.s3_logging:
      name: 'www.{{s3bucket}}'
      state: present
      target_bucket: 'logs.{{s3bucket}}'
      target_prefix: 'logs/'
  - name: log cleanup 
    community.aws.s3_lifecycle:
      name: 'logs.{{s3bucket}}'
      transition_days: 7
      expiration_days: 90
      prefix: logs/
      status: enabled
      state: present
# 

Allow your IAM users to update the S3 bucket

This step will create an IAM group that grants access to modify the contents of your new shiny www. S3 bucket.

It will also grant members of the IAM group the ability to generate their own access keys, which they need if they are going to use a program like VSCode to maintain the files in the S3 bucket.

You will add your existing IAM user to this group manually as a final step.

ansible-playbook -e "s3bucket=$SITE" s3site_4_create_iam_group.yml
# 
---
- name: Set up IAM user groups
  hosts: localhost
  connection: local
  gather_facts: no

  tasks:
  - name: create IAM policy file
    template:
      dest: '/tmp/iam_edit_s3_{{ s3bucket }}.json'
      src: files/iam_edit_s3.j2
  - name: create IAM group
    community.aws.iam_group:
      name: 'edit_{{ s3bucket }}'
      state: present
      purge_policies: yes # We are about to add the only desired policy
  - name: apply policy
    community.aws.iam_policy:
      iam_name: 'edit_{{ s3bucket }}'
      iam_type: group
      policy_name: 'policy-edit-{{ s3bucket }}'
      state: present
      policy_document: '/tmp/iam_edit_s3_{{ s3bucket }}.json'
  - name: allow this group to manage own access keys
    community.aws.iam_group:
      name: 'self_manage_acces_keys'
      state: present
      purge_policies: yes # We are about to add the only desired policy
  - name: apply policy
    community.aws.iam_policy:
      iam_name: 'self_manage_acces_keys'
      iam_type: group
      policy_name: 'policy-manage-access-keys'
      state: present
      policy_document: 'files/iam.allow.accesskeys.json'
# 

Setup DNS

Next up, setup DNS for a static website on S3.