diff --git a/.gitignore b/.gitignore
index dd3d655..521b971 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@ blog/static
test/
.DS_Store
+# terraform
+.terraform/
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 50e9341..ab8fe81 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,14 +1,17 @@
{
- "editor.defaultFormatter": "akmittal.hugofy",
- "editor.formatOnPaste": false,
- "[html]": {
- "editor.defaultFormatter": "HookyQR.beautify"
- },
- "[handlebars]": {
- },
- "beautify.config": {
- "indent_handlebars": false
- },
- "twig-language-2.endComma": "always",
+ "editor.formatOnPaste": false,
+ "[html]": {
+ "editor.defaultFormatter": "HookyQR.beautify"
+ },
+ "[handlebars]": {},
+ "beautify.config": {
+ "indent_handlebars": false
+ },
+ "twig-language-2.endComma": "always",
+ "[scss]": {
+ "editor.defaultFormatter": "HookyQR.beautify"
+ },
+ "[tfvars]": {
+ "editor.defaultFormatter": "hashicorp.terraform"
+ }
}
-
diff --git a/blog/config.toml b/blog/config.toml
index 32a4c67..382010d 100644
--- a/blog/config.toml
+++ b/blog/config.toml
@@ -2,13 +2,16 @@ baseURL = "http://127.0.0.1:6060"
title = "panaetius.io"
# theme = "panaetius-chunky-theme"
theme = ["hugo-notice-admonition", "panaetius-theme"]
-paginate = 2
+paginate = 3
+summaryLength = 2
languageCode = "en"
DefaultContentLanguage = "en"
enableInlineShortcodes = true
footnoteReturnLinkContents = "^"
description = "Tech blog showcasing Python, Machine-Learning, Vue, Homelab and other technologies to try at home."
+[permalinks]
+ post = "post/:year/:month/:slug/"
[languages]
@@ -33,17 +36,23 @@ url = "/about/"
weight = 2
[[menu.main]]
-identifier = "tags"
-name = "Tags"
-url = "/tags/"
+identifier = "series"
+name = "Series"
+url = "/series/"
weight = 3
[[menu.main]]
-identifier = "search"
-name = "Search"
-url = "/search/"
+identifier = "tags"
+name = "Tags"
+url = "/tags/"
weight = 4
+# [[menu.main]]
+# identifier = "search"
+# name = "Search"
+# url = "/search/"
+# weight = 4
+
[taxonomies]
category = "categories"
tag = "tags"
diff --git a/blog/content/post/first_post copy/images/banner.svg b/blog/content/post/first_post copy/images/banner.svg
new file mode 100644
index 0000000..47dc95f
--- /dev/null
+++ b/blog/content/post/first_post copy/images/banner.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blog/content/post/first_post copy/index.md b/blog/content/post/first_post copy/index.md
new file mode 100644
index 0000000..308c2dc
--- /dev/null
+++ b/blog/content/post/first_post copy/index.md
@@ -0,0 +1,49 @@
+---
+title: "First Post Copy"
+description: "The first post testing Hugo out for its markdown features and commento integration."
+date: "2020-05-04T02:14:50+01:00"
+images: ["images/banner.svg"]
+draft: true
+authors: ["Daniel Tomlinson"]
+tags: ["Introduction", "another"]
+---
+
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
+
+## Test code
+
+```python
+import flask
+
+def flask():
+ something = flask.something()
+ return something
+```
+
+## Instagram Simple Shortcode
+
+{{< instagram_simple BGvuInzyFAe hidecaption >}}
+
+
+
+---
+
+## YouTube Privacy Enhanced Shortcode
+
+{{< youtube ZJthWmvUzzc >}}
+
+
+
+---
+
+## Twitter Simple Shortcode
+
+{{< twitter_simple 1085870671291310081 >}}
+
+
+
+---
+
+## Vimeo Simple Shortcode
+
+{{< vimeo_simple 48912912 >}}
diff --git a/blog/content/post/first_post/index.md b/blog/content/post/first_post/index.md
index 8f68285..c0d8913 100644
--- a/blog/content/post/first_post/index.md
+++ b/blog/content/post/first_post/index.md
@@ -8,9 +8,10 @@ authors: ["Daniel Tomlinson"]
tags: ["Introduction", "another"]
---
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
-##
+
## Test code
diff --git a/blog/content/post/second_post copy 2/images/banner.svg b/blog/content/post/second_post copy 2/images/banner.svg
new file mode 100644
index 0000000..e1ada18
--- /dev/null
+++ b/blog/content/post/second_post copy 2/images/banner.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/blog/content/post/second_post copy 2/index.md b/blog/content/post/second_post copy 2/index.md
new file mode 100644
index 0000000..78a8bae
--- /dev/null
+++ b/blog/content/post/second_post copy 2/index.md
@@ -0,0 +1,91 @@
+---
+title: "Really long title Second Post Copy for layout scaling with flexbox using css 2."
+date: "2020-05-05T02:14:50+01:00"
+images: ["images/banner.svg"]
+draft: true
+authors:
+ - "Daniel Tomlinson"
+ - "New Authors"
+tags: ["Introduction", "test", "another", "tagging", "hugo", "newz"]
+---
+
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
+
+##
+
+## Test code
+
+```python
+import flask
+
+def flask():
+ something = flask.something()
+ return something
+```
+
+## Instagram Simple Shortcode
+
+{{< instagram_simple BGvuInzyFAe hidecaption >}}
+
+
+
+---
+
+## YouTube Privacy Enhanced Shortcode
+
+{{< youtube ZJthWmvUzzc >}}
+
+
+
+---
+
+## Twitter Simple Shortcode
+
+{{< twitter_simple 1085870671291310081 >}}
+
+
+
+---
+
+## Vimeo Simple Shortcode
+
+{{< vimeo_simple 48912912 >}}
+
+---
+
+## Test img shortcode
+
+{{< img "images/banner.svg*" >}}
+
+### Test indent
+
+something
+
+## Test table
+
+Does Hugo put the class of the table as `content table`? If so do we need to add the bootstrap `table` class?.
+
+Hugo adds no css to the table. In order to style it you should select the `
` element in the `.content` class, and add the `.table` class to it.
+
+| Name | Job |
+| ------ | -------- |
+| Daniel | Capacity |
+| Dale | Capacity |
+
+## Admonitions
+
+{{< notice note >}}
+Note Admonition
+{{< /notice >}}
+
+{{< notice tip >}}
+Tip Admonition
+{{< /notice >}}
+
+{{< notice info >}}
+Infomation Admonition
+{{< /notice >}}
+
+{{< notice warning >}}
+This is a warning notice. Be warned! `code`
+{{< /notice >}}
diff --git a/blog/content/post/second_post copy/images/banner.svg b/blog/content/post/second_post copy/images/banner.svg
new file mode 100644
index 0000000..267d8ce
--- /dev/null
+++ b/blog/content/post/second_post copy/images/banner.svg
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blog/content/post/second_post copy/index.md b/blog/content/post/second_post copy/index.md
new file mode 100644
index 0000000..846ff1c
--- /dev/null
+++ b/blog/content/post/second_post copy/index.md
@@ -0,0 +1,104 @@
+---
+title: "Really long title Second Post Copy for layout scaling with flexbox using css."
+date: "2020-05-06T02:14:51+01:00"
+images:
+ - "images/banner.svg"
+draft: true
+authors:
+ - "Daniel Tomlinson"
+ - "New Authors"
+tags:
+ - "Introduction"
+ - "test"
+ - "another"
+ - "tagging"
+ - "hugo"
+ - "newz"
+series:
+ - "Test series of articles"
+---
+
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds. and it goes on for more than one line.
+
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
+
+Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
+
+
+
+## Test code
+
+```python
+import flask
+
+def flask():
+ something = flask.something()
+ return something
+```
+
+## Instagram Simple Shortcode
+
+{{< instagram_simple BGvuInzyFAe hidecaption >}}
+
+
+
+---
+
+## YouTube Privacy Enhanced Shortcode
+
+{{< youtube ZJthWmvUzzc >}}
+
+
+
+---
+
+## Twitter Simple Shortcode
+
+{{< twitter_simple 1085870671291310081 >}}
+
+
+
+---
+
+## Vimeo Simple Shortcode
+
+{{< vimeo_simple 48912912 >}}
+
+---
+
+## Test img shortcode
+
+{{< img "images/banner.svg*" >}}
+
+### Test indent
+
+something
+
+## Test table
+
+Does Hugo put the class of the table as `content table`? If so do we need to add the bootstrap `table` class?.
+
+Hugo adds no css to the table. In order to style it you should select the `` element in the `.content` class, and add the `.table` class to it.
+
+| Name | Job |
+| ------ | -------- |
+| Daniel | Capacity |
+| Dale | Capacity |
+
+## Admonitions
+
+{{< notice note >}}
+Note Admonition
+{{< /notice >}}
+
+{{< notice tip >}}
+Tip Admonition
+{{< /notice >}}
+
+{{< notice info >}}
+Infomation Admonition
+{{< /notice >}}
+
+{{< notice warning >}}
+This is a warning notice. Be warned! `code`
+{{< /notice >}}
diff --git a/blog/content/post/second_post/images/banner.svg b/blog/content/post/second_post/images/banner.svg
index e1ada18..267d8ce 100644
--- a/blog/content/post/second_post/images/banner.svg
+++ b/blog/content/post/second_post/images/banner.svg
@@ -1 +1,341 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blog/content/post/second_post/index.md b/blog/content/post/second_post/index.md
index 45ba436..a8bd260 100644
--- a/blog/content/post/second_post/index.md
+++ b/blog/content/post/second_post/index.md
@@ -1,17 +1,30 @@
---
title: "Second Post"
-date: "2020-05-05T02:14:50+01:00"
-images: ["images/banner.svg"]
+date: "2020-05-06T02:14:49+01:00"
+images:
+ - "images/banner.svg"
draft: true
authors:
- "Daniel Tomlinson"
- "New Authors"
-tags: ["Introduction", "test", "another", "tagging", "hugo", "newz"]
+tags:
+ - "Introduction"
+ - "test"
+ - "another"
+ - "tagging"
+ - "hugo"
+ - "newz"
+series:
+ - "Test series of articles"
---
Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
-##
+{{< notice series >}}
+Part 1 of the [Test series of articles](/series/test-series-of-articles/) series
+{{< /notice >}}
+
+
## Test code
@@ -89,3 +102,4 @@ Infomation Admonition
{{< notice warning >}}
This is a warning notice. Be warned! `code`
{{< /notice >}}
+
diff --git a/blog/content/series/test-series-of-articles/_index.md b/blog/content/series/test-series-of-articles/_index.md
new file mode 100644
index 0000000..eaa45cd
--- /dev/null
+++ b/blog/content/series/test-series-of-articles/_index.md
@@ -0,0 +1,6 @@
+---
+Title: "Test series of articles"
+Description: "some test descriptions"
+---
+
+Some text heres.
diff --git a/blog/gulpfile.js/index.js b/blog/gulpfile.js/index.js
index 720d17d..44e43c4 100644
--- a/blog/gulpfile.js/index.js
+++ b/blog/gulpfile.js/index.js
@@ -34,12 +34,12 @@ async function buildHugo(cb) {
function minifyImages(cb) {
gulp
.src([
- `${currentDir}/content/**/*.png`,
- `${currentDir}/content/**/*.svg`,
- `${currentDir}/static/**/*.png`,
- `${currentDir}/static/**/*.svg`,
- `${themeDir}/static/**/*.png`,
- `${themeDir}/static/**/*.svg`,
+ // `${currentDir}/content/**/*.png`,
+ // `${currentDir}/content/**/*.svg`,
+ // `${currentDir}/static/**/*.png`,
+ // `${currentDir}/static/**/*.svg`,
+ // `${themeDir}/static/**/*.png`,
+ // `${themeDir}/static/**/*.svg`,
`${currentDir}/public/**/*.png`,
`${currentDir}/public/**/*.svg`,
])
diff --git a/blog/hugolayout.md b/blog/hugolayout.md
index 5485db6..fc48ced 100644
--- a/blog/hugolayout.md
+++ b/blog/hugolayout.md
@@ -899,3 +899,31 @@ Hugo ships with internal templates for common metadata for sites:
+
+If using bootstrap and you want to apply the class `active` to a navbar item when it has been selected, you should add the following to the navbar:
+
+```Hugo
+
+ {{- if .Site.Params.showLanguageSwitcher -}}
+ {{ partial "i18nlist.html" . }}
+ {{- end -}}
+ {{ with .Site.Menus.main }}
+ {{ range . }}
+
+ {{ end }}
+ {{ end }}
+```
+
+You should make sure in your `config.toml` that the navbar item url ends with a trailing `/`:
+
+```toml
+[[menu.main]]
+identifier = "series"
+name = "Series"
+url = "/series/"
+weight = 3
+```
diff --git a/blog/themes/hugo-notice-admonition b/blog/themes/hugo-notice-admonition
index 1b7157d..f08dd40 160000
--- a/blog/themes/hugo-notice-admonition
+++ b/blog/themes/hugo-notice-admonition
@@ -1 +1 @@
-Subproject commit 1b7157d341020302ea14cedfe0472bebfc9d9fb6
+Subproject commit f08dd406cc63f912032bdf914e893acc751324ed
diff --git a/blog/themes/panaetius-theme b/blog/themes/panaetius-theme
index 8fa7c40..412ab93 160000
--- a/blog/themes/panaetius-theme
+++ b/blog/themes/panaetius-theme
@@ -1 +1 @@
-Subproject commit 8fa7c40eca61df09e39765018878887fd65dfbe2
+Subproject commit 412ab931c34399a3902f3c3cb7861f31988db368
diff --git a/blog/todo-webpack.todo b/blog/todo-webpack.todo
index 7e0674c..f5e0b63 100644
--- a/blog/todo-webpack.todo
+++ b/blog/todo-webpack.todo
@@ -14,22 +14,25 @@ Tasks:
✔ Create a gulpfile to build the search index. @done (6/3/2020, 4:05:01 AM)
☐ Add matomo to project.
☐ Using archetypes.
- ☐ Theme similar to forestry.
+ ✔ Theme similar to forestry. @done (6/14/2020, 2:49:09 AM)
+ ☐ Document making bavbar active (goes in the header.html or navbar) make sure in config.toml the url ends in /.
Theme:
- ☐ Colour scheme (forestry)
- ☐ Choose a Colour
- ☐ Change link colour
- ☐ Change post info colour
- ☐ Info, warning admonitions (using colour scheme)
- ☐ Post layout
- ☐ TOC
+ ✔ Colour scheme (forestry) @done (6/9/2020, 12:24:25 PM)
+ ✔ Choose a Colour @done (6/9/2020, 12:24:26 PM)
+ ✔ Change link colour @done (6/9/2020, 12:24:25 PM)
+ ✔ Change post info colour @done (6/12/2020, 9:55:06 PM)
+ ✔ Info, warning admonitions (using colour scheme) @done (6/9/2020, 12:24:29 PM)
+ ✔ Post layout @done (6/12/2020, 9:55:05 PM)
+ ✔ TOC @done (6/9/2020, 12:24:31 PM)
+ ✔ Create a series admonition as a shortcode - use yellow. Include this in any series posts. @done (6/14/2020, 2:48:59 AM)
Search:
- ☐ Search bar like Font awesome
+ ✔ Search bar like Font awesome @done (6/9/2020, 12:24:33 PM)
✔ Have search auto run whenever a button is pressed @done (6/7/2020, 5:38:31 PM)
Gulp:
+ ☐ Change lunr insert - should insert the whole script html with a dummy tag that it can use to find.
✔ Using and to handle hashed images. @done (6/4/2020, 1:28:15 AM)
Notes:
✔ If you are not using Hugo, you could use the above to dynamically reference images in your html, and use gulp to replace them with the images bundled with webpack. Name the images the same as they're referenced, then replace any ` ` with the bundled image in the html. You can get the mapping from the output from webpack, using the unique image name as the key.. You can then use gulp to minimise or resize the images. @done (6/4/2020, 1:28:13 AM)
diff --git a/infrastructure/Makefile b/infrastructure/Makefile
new file mode 100644
index 0000000..129a367
--- /dev/null
+++ b/infrastructure/Makefile
@@ -0,0 +1,214 @@
+# Copyright 2016 Philip G. Porada
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.ONESHELL:
+.SHELL := /usr/bin/bash
+.PHONY: apply destroy-backend destroy destroy-target plan-destroy plan plan-target prep
+
+-include Makefile.env
+VARS="variables/$(ENV)-$(REGION).tfvars"
+CURRENT_FOLDER=$(shell basename "$$(pwd)")
+S3_BUCKET="$(ENV)-$(REGION)-$(PROJECT)-terraform"
+DYNAMODB_TABLE="$(ENV)-$(REGION)-$(PROJECT)-terraform"
+WORKSPACE="$(ENV)-$(REGION)"
+BOLD=$(shell tput bold)
+RED=$(shell tput setaf 1)
+GREEN=$(shell tput setaf 2)
+YELLOW=$(shell tput setaf 3)
+RESET=$(shell tput sgr0)
+
+help:
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+set-env:
+ @if [ -z $(ENV) ]; then \
+ echo "$(BOLD)$(RED)ENV was not set$(RESET)"; \
+ ERROR=1; \
+ fi
+ @if [ -z $(REGION) ]; then \
+ echo "$(BOLD)$(RED)REGION was not set$(RESET)"; \
+ ERROR=1; \
+ fi
+ @if [ -z $(AWS_PROFILE) ]; then \
+ echo "$(BOLD)$(RED)AWS_PROFILE was not set.$(RESET)"; \
+ ERROR=1; \
+ fi
+ @if [ ! -z $${ERROR} ] && [ $${ERROR} -eq 1 ]; then \
+ echo "$(BOLD)Example usage: \`AWS_PROFILE=whatever ENV=demo REGION=us-east-2 make plan\`$(RESET)"; \
+ exit 1; \
+ fi
+ @if [ ! -f "$(VARS)" ]; then \
+ echo "$(BOLD)$(RED)Could not find variables file: $(VARS)$(RESET)"; \
+ exit 1; \
+ fi
+
+prep: set-env ## Prepare a new workspace (environment) if needed, configure the tfstate backend, update any modules, and switch to the workspace
+ @echo "$(BOLD)Verifying that the S3 bucket $(S3_BUCKET) for remote state exists$(RESET)"
+ @if ! aws --profile $(AWS_PROFILE) s3api head-bucket --region $(REGION) --bucket $(S3_BUCKET) > /dev/null 2>&1 ; then \
+ echo "$(BOLD)S3 bucket $(S3_BUCKET) was not found, creating new bucket with versioning enabled to store tfstate$(RESET)"; \
+ aws --profile $(AWS_PROFILE) s3api create-bucket \
+ --bucket $(S3_BUCKET) \
+ --acl private \
+ --region $(REGION) \
+ --create-bucket-configuration LocationConstraint=$(REGION) > /dev/null 2>&1 ; \
+ aws --profile $(AWS_PROFILE) s3api put-bucket-versioning \
+ --bucket $(S3_BUCKET) \
+ --versioning-configuration Status=Enabled > /dev/null 2>&1 ; \
+ echo "$(BOLD)$(GREEN)S3 bucket $(S3_BUCKET) created$(RESET)"; \
+ else
+ echo "$(BOLD)$(GREEN)S3 bucket $(S3_BUCKET) exists$(RESET)"; \
+ fi
+ @echo "$(BOLD)Verifying that the DynamoDB table exists for remote state locking$(RESET)"
+ @if ! aws --profile $(AWS_PROFILE) --region $(REGION) dynamodb describe-table --table-name $(DYNAMODB_TABLE) > /dev/null 2>&1 ; then \
+ echo "$(BOLD)DynamoDB table $(DYNAMODB_TABLE) was not found, creating new DynamoDB table to maintain locks$(RESET)"; \
+ aws --profile $(AWS_PROFILE) dynamodb create-table \
+ --region $(REGION) \
+ --table-name $(DYNAMODB_TABLE) \
+ --attribute-definitions AttributeName=LockID,AttributeType=S \
+ --key-schema AttributeName=LockID,KeyType=HASH \
+ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 > /dev/null 2>&1 ; \
+ echo "$(BOLD)$(GREEN)DynamoDB table $(DYNAMODB_TABLE) created$(RESET)"; \
+ echo "Sleeping for 10 seconds to allow DynamoDB state to propagate through AWS"; \
+ sleep 10; \
+ else
+ echo "$(BOLD)$(GREEN)DynamoDB Table $(DYNAMODB_TABLE) exists$(RESET)"; \
+ fi
+ @aws ec2 --profile=$(AWS_PROFILE) describe-key-pairs | jq -r '.KeyPairs[].KeyName' | grep "$(ENV)_infra_key" > /dev/null 2>&1; \
+ if [ $$? -ne 0 ]; then \
+ echo "$(BOLD)$(RED)EC2 Key Pair $(INFRA_KEY)_infra_key was not found$(RESET)"; \
+ read -p '$(BOLD)Do you want to generate a new keypair? [y/Y]: $(RESET)' ANSWER && \
+ if [ "$${ANSWER}" == "y" ] || [ "$${ANSWER}" == "Y" ]; then \
+ mkdir -p ~/.ssh; \
+ ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/$(ENV)_infra_key; \
+ aws ec2 --profile=$(AWS_PROFILE) import-key-pair --key-name "$(ENV)_infra_key" --public-key-material "file://~/.ssh/$(ENV)_infra_key.pub"; \
+ fi; \
+ else \
+ echo "$(BOLD)$(GREEN)EC2 Key Pair $(ENV)_infra_key exists$(RESET)";\
+ fi
+ @echo "$(BOLD)Configuring the terraform backend$(RESET)"
+ @terraform init \
+ -input=false \
+ -force-copy \
+ -lock=true \
+ -upgrade \
+ -verify-plugins=true \
+ -backend=true \
+ -backend-config="profile=$(AWS_PROFILE)" \
+ -backend-config="region=$(REGION)" \
+ -backend-config="bucket=$(S3_BUCKET)" \
+ -backend-config="key=$(ENV)/$(CURRENT_FOLDER)/terraform.tfstate" \
+ -backend-config="dynamodb_table=$(DYNAMODB_TABLE)"\
+ -backend-config="acl=private"
+ @echo "$(BOLD)Switching to workspace $(WORKSPACE)$(RESET)"
+ @terraform workspace select $(WORKSPACE) || terraform workspace new $(WORKSPACE)
+
+plan: prep ## Show what terraform thinks it will do
+ @terraform plan \
+ -lock=true \
+ -input=false \
+ -refresh=true \
+ -var-file="$(VARS)"
+
+format: prep ## Rewrites all Terraform configuration files to a canonical format.
+ @terraform fmt \
+ -write=true \
+ -recursive
+
+# https://github.com/terraform-linters/tflint
+lint: prep ## Check for possible errors, best practices, etc in current directory!
+ @tflint
+
+# https://github.com/liamg/tfsec
+check-security: prep ## Static analysis of your terraform templates to spot potential security issues.
+ @tfsec .
+
+documentation: prep ## Generate README.md for a module
+ @terraform-docs \
+ markdown table \
+ --sort-by-required . > README.md
+
+plan-target: prep ## Shows what a plan looks like for applying a specific resource
+ @echo "$(YELLOW)$(BOLD)[INFO] $(RESET)"; echo "Example to type for the following question: module.rds.aws_route53_record.rds-master"
+ @read -p "PLAN target: " DATA && \
+ terraform plan \
+ -lock=true \
+ -input=true \
+ -refresh=true \
+ -var-file="$(VARS)" \
+ -target=$$DATA
+
+plan-destroy: prep ## Creates a destruction plan.
+ @terraform plan \
+ -input=false \
+ -refresh=true \
+ -destroy \
+ -var-file="$(VARS)"
+
+apply: prep ## Have terraform do the things. This will cost money.
+ @terraform apply \
+ -lock=true \
+ -input=false \
+ -refresh=true \
+ -var-file="$(VARS)"
+
+destroy: prep ## Destroy the things
+ @terraform destroy \
+ -lock=true \
+ -input=false \
+ -refresh=true \
+ -var-file="$(VARS)"
+
+destroy-target: prep ## Destroy a specific resource. Caution though, this destroys chained resources.
+ @echo "$(YELLOW)$(BOLD)[INFO] Specifically destroy a piece of Terraform data.$(RESET)"; echo "Example to type for the following question: module.rds.aws_route53_record.rds-master"
+ @read -p "Destroy target: " DATA && \
+ terraform destroy \
+ -lock=true \
+ -input=false \
+ -refresh=true \
+ -var-file=$(VARS) \
+ -target=$$DATA
+
+destroy-backend: ## Destroy S3 bucket and DynamoDB table
+ @if ! aws --profile $(AWS_PROFILE) dynamodb delete-table \
+ --region $(REGION) \
+ --table-name $(DYNAMODB_TABLE) > /dev/null 2>&1 ; then \
+ echo "$(BOLD)$(RED)Unable to delete DynamoDB table $(DYNAMODB_TABLE)$(RESET)"; \
+ else
+ echo "$(BOLD)$(RED)DynamoDB table $(DYNAMODB_TABLE) does not exist.$(RESET)"; \
+ fi
+ @if ! aws --profile $(AWS_PROFILE) s3api delete-objects \
+ --region $(REGION) \
+ --bucket $(S3_BUCKET) \
+ --delete "$$(aws --profile $(AWS_PROFILE) s3api list-object-versions \
+ --region $(REGION) \
+ --bucket $(S3_BUCKET) \
+ --output=json \
+ --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')" > /dev/null 2>&1 ; then \
+ echo "$(BOLD)$(RED)Unable to delete objects in S3 bucket $(S3_BUCKET)$(RESET)"; \
+ fi
+ @if ! aws --profile $(AWS_PROFILE) s3api delete-objects \
+ --region $(REGION) \
+ --bucket $(S3_BUCKET) \
+ --delete "$$(aws --profile $(AWS_PROFILE) s3api list-object-versions \
+ --region $(REGION) \
+ --bucket $(S3_BUCKET) \
+ --output=json \
+ --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')" > /dev/null 2>&1 ; then \
+ echo "$(BOLD)$(RED)Unable to delete markers in S3 bucket $(S3_BUCKET)$(RESET)"; \
+ fi
+ @if ! aws --profile $(AWS_PROFILE) s3api delete-bucket \
+ --region $(REGION) \
+ --bucket $(S3_BUCKET) > /dev/null 2>&1 ; then \
+ echo "$(BOLD)$(RED)Unable to delete S3 bucket $(S3_BUCKET) itself$(RESET)"; \
+ fi
diff --git a/infrastructure/Makefile.env b/infrastructure/Makefile.env
new file mode 100644
index 0000000..2b458fc
--- /dev/null
+++ b/infrastructure/Makefile.env
@@ -0,0 +1,4 @@
+ENV="prod"
+REGION="eu-west-1"
+PROJECT="panaetius-blog"
+AWS_PROFILE="admin"
diff --git a/infrastructure/main.tf b/infrastructure/main.tf
new file mode 100644
index 0000000..c22396d
--- /dev/null
+++ b/infrastructure/main.tf
@@ -0,0 +1,52 @@
+provider "aws" {
+ region = var.region
+ profile = var.profile
+ version = "~> 2.66"
+}
+
+locals {
+ tags = {
+ "Project" = "panaetius-blog"
+ "Description" = "terraform resources to host the blog"
+ }
+}
+
+module "cloudfront_s3_cdn" {
+ source = "git::https://github.com/cloudposse/terraform-aws-cloudfront-s3-cdn.git?ref=tags/0.23.1"
+ stage = var.stage
+ name = var.name
+ parent_zone_id = var.parent_zone_id
+ acm_certificate_arn = var.acm_certificate_arn
+ # log_expiration_days = var.log_expiration_days
+ # log_standard_transition_days = var.log_standard_transition_days
+ use_regional_s3_endpoint = true
+ origin_force_destroy = true
+ cors_allowed_headers = ["*"]
+ cors_allowed_methods = ["GET", "HEAD", "PUT", "POST"]
+ cors_allowed_origins = var.allowed_origins
+ tags = local.tags
+ aliases = var.aliases
+ additional_bucket_policy = <<-EOT
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid":"PublicRead",
+ "Effect":"Allow",
+ "Principal": "*",
+ "Action":["s3:GetObject"],
+ "Resource": "arn:aws:s3:::${var.bucket_name}/*"
+ }
+ ]
+ }
+ EOT
+}
+
+resource "aws_s3_bucket_object" "index" {
+ bucket = module.cloudfront_s3_cdn.s3_bucket
+ key = "index.html"
+ acl = "public-read"
+ source = "${path.module}/test/index.html"
+ content_type = "text/html"
+ etag = md5(file("${path.module}/test/index.html"))
+}
diff --git a/infrastructure/outputs.tf b/infrastructure/outputs.tf
new file mode 100644
index 0000000..eb09683
--- /dev/null
+++ b/infrastructure/outputs.tf
@@ -0,0 +1,39 @@
+output "cf_id" {
+ value = module.cloudfront_s3_cdn.cf_id
+ description = "ID of AWS CloudFront distribution"
+}
+
+output "cf_arn" {
+ value = module.cloudfront_s3_cdn.cf_arn
+ description = "ARN of AWS CloudFront distribution"
+}
+
+output "cf_status" {
+ value = module.cloudfront_s3_cdn.cf_status
+ description = "Current status of the distribution"
+}
+
+output "cf_domain_name" {
+ value = module.cloudfront_s3_cdn.cf_domain_name
+ description = "Domain name corresponding to the distribution"
+}
+
+output "cf_etag" {
+ value = module.cloudfront_s3_cdn.cf_etag
+ description = "Current version of the distribution's information"
+}
+
+output "cf_hosted_zone_id" {
+ value = module.cloudfront_s3_cdn.cf_hosted_zone_id
+ description = "CloudFront Route 53 zone ID"
+}
+
+output "s3_bucket" {
+ value = module.cloudfront_s3_cdn.s3_bucket
+ description = "Name of S3 bucket"
+}
+
+output "s3_bucket_domain_name" {
+ value = module.cloudfront_s3_cdn.s3_bucket_domain_name
+ description = "Domain of S3 bucket"
+}
diff --git a/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate b/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate
new file mode 100644
index 0000000..312ecd7
--- /dev/null
+++ b/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate
@@ -0,0 +1,742 @@
+{
+ "version": 4,
+ "terraform_version": "0.12.26",
+ "serial": 90,
+ "lineage": "cda52006-90fc-4aec-a630-42e69057b365",
+ "outputs": {
+ "cf_arn": {
+ "value": "arn:aws:cloudfront::745437999005:distribution/E2IHXIMPI3MZ2X",
+ "type": "string"
+ },
+ "cf_domain_name": {
+ "value": "d244ranky0ff54.cloudfront.net",
+ "type": "string"
+ },
+ "cf_etag": {
+ "value": "E2SEL7AYXF1CKS",
+ "type": "string"
+ },
+ "cf_hosted_zone_id": {
+ "value": "Z2FDTNDATAQYW2",
+ "type": "string"
+ },
+ "cf_id": {
+ "value": "E2IHXIMPI3MZ2X",
+ "type": "string"
+ },
+ "cf_status": {
+ "value": "Deployed",
+ "type": "string"
+ },
+ "s3_bucket": {
+ "value": "prod-panaetius-blog-origin",
+ "type": "string"
+ },
+ "s3_bucket_domain_name": {
+ "value": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "type": "string"
+ }
+ },
+ "resources": [
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_iam_policy_document",
+ "name": "origin",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "id": "3493490045",
+ "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"PublicRead\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\"\n ],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": \"*\"\n }\n ]\n}",
+ "override_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\":\"PublicRead\",\n \"Effect\":\"Allow\",\n \"Principal\": \"*\",\n \"Action\":[\"s3:GetObject\"],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\"\n }\n ]\n}\n",
+ "policy_id": null,
+ "source_json": null,
+ "statement": [
+ {
+ "actions": [
+ "s3:GetObject"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "${cloudfront_origin_access_identity_iam_arn}"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}${origin_path}*"
+ ],
+ "sid": "S3GetObjectForCloudFront"
+ },
+ {
+ "actions": [
+ "s3:ListBucket"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "${cloudfront_origin_access_identity_iam_arn}"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}"
+ ],
+ "sid": "S3ListBucketForCloudFront"
+ }
+ ],
+ "version": "2012-10-17"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_iam_policy_document",
+ "name": "origin_website",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "id": "736817168",
+ "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"*\"\n }\n },\n {\n \"Sid\": \"PublicRead\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\"\n ],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": \"*\"\n }\n ]\n}",
+ "override_json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\":\"PublicRead\",\n \"Effect\":\"Allow\",\n \"Principal\": \"*\",\n \"Action\":[\"s3:GetObject\"],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\"\n }\n ]\n}\n",
+ "policy_id": null,
+ "source_json": null,
+ "statement": [
+ {
+ "actions": [
+ "s3:GetObject"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "*"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}${origin_path}*"
+ ],
+ "sid": "S3GetObjectForCloudFront"
+ }
+ ],
+ "version": "2012-10-17"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_region",
+ "name": "current",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "current": null,
+ "description": "Europe (Ireland)",
+ "endpoint": "ec2.eu-west-1.amazonaws.com",
+ "id": "eu-west-1",
+ "name": "eu-west-1"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "data",
+ "type": "aws_route53_zone",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "caller_reference": "321439A9-2EB4-9C82-858E-22E353E3CC06",
+ "comment": "blog",
+ "id": "Z05316671VABVSMAAF1RC",
+ "linked_service_description": null,
+ "linked_service_principal": null,
+ "name": "panaetius.io.",
+ "name_servers": [
+ "ns-1774.awsdns-29.co.uk",
+ "ns-667.awsdns-19.net",
+ "ns-1261.awsdns-29.org",
+ "ns-401.awsdns-50.com"
+ ],
+ "private_zone": false,
+ "resource_record_set_count": 5,
+ "tags": {},
+ "vpc_id": null,
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_s3_bucket",
+ "name": "selected",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "arn": "arn:aws:s3:::prod-panaetius-blog-origin",
+ "bucket": "prod-panaetius-blog-origin",
+ "bucket_domain_name": "prod-panaetius-blog-origin.s3.amazonaws.com",
+ "bucket_regional_domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-origin",
+ "region": "eu-west-1",
+ "website_domain": null,
+ "website_endpoint": null
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "template_file",
+ "name": "default",
+ "provider": "provider.template",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "filename": null,
+ "id": "ef8d6cdd8c782d412e41e1e574ea39e8674f2d80726946a8f8dbe8ea50c1ac8b",
+ "rendered": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n },\n {\n \"Sid\": \"PublicRead\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\"\n ],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": \"*\"\n }\n ]\n}",
+ "template": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"PublicRead\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\"\n ],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": \"*\"\n }\n ]\n}",
+ "vars": {
+ "bucket_name": "prod-panaetius-blog-origin",
+ "cloudfront_origin_access_identity_iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5",
+ "origin_path": "/"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_cloudfront_distribution",
+ "name": "default",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 1,
+ "attributes": {
+ "active_trusted_signers": {
+ "enabled": "false",
+ "items.#": "0"
+ },
+ "aliases": [
+ "panaetius.io"
+ ],
+ "arn": "arn:aws:cloudfront::745437999005:distribution/E2IHXIMPI3MZ2X",
+ "cache_behavior": [],
+ "caller_reference": "terraform-20200713232651089800000002",
+ "comment": "Managed by Terraform",
+ "custom_error_response": [],
+ "default_cache_behavior": [
+ {
+ "allowed_methods": [
+ "DELETE",
+ "GET",
+ "HEAD",
+ "OPTIONS",
+ "PATCH",
+ "POST",
+ "PUT"
+ ],
+ "cached_methods": [
+ "GET",
+ "HEAD"
+ ],
+ "compress": false,
+ "default_ttl": 60,
+ "field_level_encryption_id": "",
+ "forwarded_values": [
+ {
+ "cookies": [
+ {
+ "forward": "none",
+ "whitelisted_names": []
+ }
+ ],
+ "headers": [
+ "Access-Control-Request-Headers",
+ "Access-Control-Request-Method",
+ "Origin"
+ ],
+ "query_string": false,
+ "query_string_cache_keys": []
+ }
+ ],
+ "lambda_function_association": [],
+ "max_ttl": 31536000,
+ "min_ttl": 0,
+ "smooth_streaming": false,
+ "target_origin_id": "prod-panaetius-blog",
+ "trusted_signers": [],
+ "viewer_protocol_policy": "redirect-to-https"
+ }
+ ],
+ "default_root_object": "index.html",
+ "domain_name": "d244ranky0ff54.cloudfront.net",
+ "enabled": true,
+ "etag": "E2SEL7AYXF1CKS",
+ "hosted_zone_id": "Z2FDTNDATAQYW2",
+ "http_version": "http2",
+ "id": "E2IHXIMPI3MZ2X",
+ "in_progress_validation_batches": 0,
+ "is_ipv6_enabled": true,
+ "last_modified_time": "2020-07-15 00:18:34.684 +0000 UTC",
+ "logging_config": [
+ {
+ "bucket": "prod-panaetius-blog-logs.s3.amazonaws.com",
+ "include_cookies": false,
+ "prefix": ""
+ }
+ ],
+ "ordered_cache_behavior": [],
+ "origin": [
+ {
+ "custom_header": [],
+ "custom_origin_config": [],
+ "domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "origin_id": "prod-panaetius-blog",
+ "origin_path": "",
+ "s3_origin_config": [
+ {
+ "origin_access_identity": "origin-access-identity/cloudfront/E21A7YWJ1RT3K5"
+ }
+ ]
+ }
+ ],
+ "origin_group": [],
+ "price_class": "PriceClass_100",
+ "restrictions": [
+ {
+ "geo_restriction": [
+ {
+ "locations": [],
+ "restriction_type": "none"
+ }
+ ]
+ }
+ ],
+ "retain_on_delete": false,
+ "status": "Deployed",
+ "tags": {
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "viewer_certificate": [
+ {
+ "acm_certificate_arn": "arn:aws:acm:us-east-1:745437999005:certificate/60af49f0-07bb-4680-8f5b-3c9a33f756e5",
+ "cloudfront_default_certificate": false,
+ "iam_certificate_id": "",
+ "minimum_protocol_version": "TLSv1",
+ "ssl_support_method": "sni-only"
+ }
+ ],
+ "wait_for_deployment": true,
+ "web_acl_id": ""
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_cloudfront_origin_access_identity",
+ "name": "default",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "caller_reference": "terraform-20200713232645930800000001",
+ "cloudfront_access_identity_path": "origin-access-identity/cloudfront/E21A7YWJ1RT3K5",
+ "comment": "prod-panaetius-blog",
+ "etag": "EESE0U5KF261",
+ "iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5",
+ "id": "E21A7YWJ1RT3K5",
+ "s3_canonical_user_id": "2d7779400635ec843efe9b677769fc4f82b0d384408cf22382bf3a90540502e09e75d1346e7105b4da159515b229f39b"
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "managed",
+ "type": "aws_route53_record",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 2,
+ "attributes": {
+ "alias": [
+ {
+ "evaluate_target_health": false,
+ "name": "d244ranky0ff54.cloudfront.net",
+ "zone_id": "Z2FDTNDATAQYW2"
+ }
+ ],
+ "allow_overwrite": null,
+ "failover_routing_policy": [],
+ "fqdn": "panaetius.io",
+ "geolocation_routing_policy": [],
+ "health_check_id": "",
+ "id": "Z05316671VABVSMAAF1RC_panaetius.io_A",
+ "latency_routing_policy": [],
+ "multivalue_answer_routing_policy": null,
+ "name": "panaetius.io",
+ "records": [],
+ "set_identifier": "",
+ "ttl": 0,
+ "type": "A",
+ "weighted_routing_policy": [],
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjIifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_distribution.default",
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "managed",
+ "type": "aws_route53_record",
+ "name": "ipv6",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 2,
+ "attributes": {
+ "alias": [
+ {
+ "evaluate_target_health": false,
+ "name": "d244ranky0ff54.cloudfront.net",
+ "zone_id": "Z2FDTNDATAQYW2"
+ }
+ ],
+ "allow_overwrite": null,
+ "failover_routing_policy": [],
+ "fqdn": "panaetius.io",
+ "geolocation_routing_policy": [],
+ "health_check_id": "",
+ "id": "Z05316671VABVSMAAF1RC_panaetius.io_AAAA",
+ "latency_routing_policy": [],
+ "multivalue_answer_routing_policy": null,
+ "name": "panaetius.io",
+ "records": [],
+ "set_identifier": "",
+ "ttl": 0,
+ "type": "AAAA",
+ "weighted_routing_policy": [],
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjIifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_distribution.default",
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.logs",
+ "mode": "managed",
+ "type": "aws_s3_bucket",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "acceleration_status": "",
+ "acl": "log-delivery-write",
+ "arn": "arn:aws:s3:::prod-panaetius-blog-logs",
+ "bucket": "prod-panaetius-blog-logs",
+ "bucket_domain_name": "prod-panaetius-blog-logs.s3.amazonaws.com",
+ "bucket_prefix": null,
+ "bucket_regional_domain_name": "prod-panaetius-blog-logs.s3.eu-west-1.amazonaws.com",
+ "cors_rule": [],
+ "force_destroy": true,
+ "grant": [],
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-logs",
+ "lifecycle_rule": [
+ {
+ "abort_incomplete_multipart_upload_days": 0,
+ "enabled": true,
+ "expiration": [
+ {
+ "date": "",
+ "days": 90,
+ "expired_object_delete_marker": false
+ }
+ ],
+ "id": "prod-panaetius-blog-logs",
+ "noncurrent_version_expiration": [
+ {
+ "days": 90
+ }
+ ],
+ "noncurrent_version_transition": [
+ {
+ "days": 30,
+ "storage_class": "GLACIER"
+ }
+ ],
+ "prefix": "",
+ "tags": {},
+ "transition": [
+ {
+ "date": "",
+ "days": 30,
+ "storage_class": "STANDARD_IA"
+ },
+ {
+ "date": "",
+ "days": 60,
+ "storage_class": "GLACIER"
+ }
+ ]
+ }
+ ],
+ "logging": [],
+ "object_lock_configuration": [],
+ "policy": "",
+ "region": "eu-west-1",
+ "replication_configuration": [],
+ "request_payer": "BucketOwner",
+ "server_side_encryption_configuration": [
+ {
+ "rule": [
+ {
+ "apply_server_side_encryption_by_default": [
+ {
+ "kms_master_key_id": "",
+ "sse_algorithm": "AES256"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "tags": {
+ "Attributes": "logs",
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog-logs",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "versioning": [
+ {
+ "enabled": false,
+ "mfa_delete": false
+ }
+ ],
+ "website": [],
+ "website_domain": null,
+ "website_endpoint": null
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_s3_bucket",
+ "name": "origin",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "acceleration_status": "",
+ "acl": "private",
+ "arn": "arn:aws:s3:::prod-panaetius-blog-origin",
+ "bucket": "prod-panaetius-blog-origin",
+ "bucket_domain_name": "prod-panaetius-blog-origin.s3.amazonaws.com",
+ "bucket_prefix": null,
+ "bucket_regional_domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "cors_rule": [
+ {
+ "allowed_headers": [
+ "*"
+ ],
+ "allowed_methods": [
+ "GET",
+ "HEAD",
+ "PUT",
+ "POST"
+ ],
+ "allowed_origins": [
+ "*.panaetius.io",
+ "panaetius.io"
+ ],
+ "expose_headers": [
+ "ETag"
+ ],
+ "max_age_seconds": 3600
+ }
+ ],
+ "force_destroy": true,
+ "grant": [],
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-origin",
+ "lifecycle_rule": [],
+ "logging": [],
+ "object_lock_configuration": [],
+ "policy": null,
+ "region": "eu-west-1",
+ "replication_configuration": [],
+ "request_payer": "BucketOwner",
+ "server_side_encryption_configuration": [],
+ "tags": {
+ "Attributes": "origin",
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog-origin",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "versioning": [
+ {
+ "enabled": false,
+ "mfa_delete": false
+ }
+ ],
+ "website": [],
+ "website_domain": null,
+ "website_endpoint": null
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "mode": "managed",
+ "type": "aws_s3_bucket_object",
+ "name": "index",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "acl": "public-read",
+ "bucket": "prod-panaetius-blog-origin",
+ "cache_control": "",
+ "content": null,
+ "content_base64": null,
+ "content_disposition": "",
+ "content_encoding": "",
+ "content_language": "",
+ "content_type": "text/html",
+ "etag": "83350948ee374f30e5513497c69c0fe5",
+ "force_destroy": false,
+ "id": "index.html",
+ "key": "index.html",
+ "kms_key_id": null,
+ "metadata": {},
+ "object_lock_legal_hold_status": "",
+ "object_lock_mode": "",
+ "object_lock_retain_until_date": "",
+ "server_side_encryption": "",
+ "source": "./test/index.html",
+ "storage_class": "STANDARD",
+ "tags": {},
+ "version_id": "",
+ "website_redirect": ""
+ },
+ "private": "bnVsbA==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_s3_bucket_policy",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "bucket": "prod-panaetius-blog-origin",
+ "id": "prod-panaetius-blog-origin",
+ "policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n },\n {\n \"Sid\": \"PublicRead\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:GetObject\"\n ],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": \"*\"\n }\n ]\n}"
+ },
+ "private": "bnVsbA==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate.backup b/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate.backup
new file mode 100644
index 0000000..f4171dd
--- /dev/null
+++ b/infrastructure/terraform.tfstate.d/prod-eu-west-1/terraform.tfstate.backup
@@ -0,0 +1,743 @@
+{
+ "version": 4,
+ "terraform_version": "0.12.26",
+ "serial": 88,
+ "lineage": "cda52006-90fc-4aec-a630-42e69057b365",
+ "outputs": {
+ "cf_arn": {
+ "value": "arn:aws:cloudfront::745437999005:distribution/E2IHXIMPI3MZ2X",
+ "type": "string"
+ },
+ "cf_domain_name": {
+ "value": "d244ranky0ff54.cloudfront.net",
+ "type": "string"
+ },
+ "cf_etag": {
+ "value": "E2SEL7AYXF1CKS",
+ "type": "string"
+ },
+ "cf_hosted_zone_id": {
+ "value": "Z2FDTNDATAQYW2",
+ "type": "string"
+ },
+ "cf_id": {
+ "value": "E2IHXIMPI3MZ2X",
+ "type": "string"
+ },
+ "cf_status": {
+ "value": "Deployed",
+ "type": "string"
+ },
+ "s3_bucket": {
+ "value": "prod-panaetius-blog-origin",
+ "type": "string"
+ },
+ "s3_bucket_domain_name": {
+ "value": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "type": "string"
+ }
+ },
+ "resources": [
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_iam_policy_document",
+ "name": "origin",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "id": "1149999058",
+ "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n }\n ]\n}",
+ "override_json": "{\n \"Sid\":\"PublicRead\",\n \"Effect\":\"Allow\",\n \"Principal\": \"*\",\n \"Action\":[\"s3:GetObject\"],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\"\n}\n",
+ "policy_id": null,
+ "source_json": null,
+ "statement": [
+ {
+ "actions": [
+ "s3:GetObject"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "${cloudfront_origin_access_identity_iam_arn}"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}${origin_path}*"
+ ],
+ "sid": "S3GetObjectForCloudFront"
+ },
+ {
+ "actions": [
+ "s3:ListBucket"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "${cloudfront_origin_access_identity_iam_arn}"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}"
+ ],
+ "sid": "S3ListBucketForCloudFront"
+ }
+ ],
+ "version": "2012-10-17"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_iam_policy_document",
+ "name": "origin_website",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "id": "239689126",
+ "json": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"*\"\n }\n }\n ]\n}",
+ "override_json": "{\n \"Sid\":\"PublicRead\",\n \"Effect\":\"Allow\",\n \"Principal\": \"*\",\n \"Action\":[\"s3:GetObject\"],\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\"\n}\n",
+ "policy_id": null,
+ "source_json": null,
+ "statement": [
+ {
+ "actions": [
+ "s3:GetObject"
+ ],
+ "condition": [],
+ "effect": "Allow",
+ "not_actions": [],
+ "not_principals": [],
+ "not_resources": [],
+ "principals": [
+ {
+ "identifiers": [
+ "*"
+ ],
+ "type": "AWS"
+ }
+ ],
+ "resources": [
+ "arn:aws:s3:::${bucket_name}${origin_path}*"
+ ],
+ "sid": "S3GetObjectForCloudFront"
+ }
+ ],
+ "version": "2012-10-17"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_region",
+ "name": "current",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "current": null,
+ "description": "Europe (Ireland)",
+ "endpoint": "ec2.eu-west-1.amazonaws.com",
+ "id": "eu-west-1",
+ "name": "eu-west-1"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "data",
+ "type": "aws_route53_zone",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "caller_reference": "321439A9-2EB4-9C82-858E-22E353E3CC06",
+ "comment": "blog",
+ "id": "Z05316671VABVSMAAF1RC",
+ "linked_service_description": null,
+ "linked_service_principal": null,
+ "name": "panaetius.io.",
+ "name_servers": [
+ "ns-1774.awsdns-29.co.uk",
+ "ns-667.awsdns-19.net",
+ "ns-1261.awsdns-29.org",
+ "ns-401.awsdns-50.com"
+ ],
+ "private_zone": false,
+ "resource_record_set_count": 5,
+ "tags": {},
+ "vpc_id": null,
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "aws_s3_bucket",
+ "name": "selected",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "arn": "arn:aws:s3:::prod-panaetius-blog-origin",
+ "bucket": "prod-panaetius-blog-origin",
+ "bucket_domain_name": "prod-panaetius-blog-origin.s3.amazonaws.com",
+ "bucket_regional_domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-origin",
+ "region": "eu-west-1",
+ "website_domain": null,
+ "website_endpoint": null
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "data",
+ "type": "template_file",
+ "name": "default",
+ "provider": "provider.template",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "filename": null,
+ "id": "bf2245baaea68e5cc89448356e64936cbd79d0706457d884cdd7badc903719e8",
+ "rendered": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin/*\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::prod-panaetius-blog-origin\",\n \"Principal\": {\n \"AWS\": \"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"\n }\n }\n ]\n}",
+ "template": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"S3GetObjectForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}${origin_path}*\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n },\n {\n \"Sid\": \"S3ListBucketForCloudFront\",\n \"Effect\": \"Allow\",\n \"Action\": \"s3:ListBucket\",\n \"Resource\": \"arn:aws:s3:::${bucket_name}\",\n \"Principal\": {\n \"AWS\": \"${cloudfront_origin_access_identity_iam_arn}\"\n }\n }\n ]\n}",
+ "vars": {
+ "bucket_name": "prod-panaetius-blog-origin",
+ "cloudfront_origin_access_identity_iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5",
+ "origin_path": "/"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_cloudfront_distribution",
+ "name": "default",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 1,
+ "attributes": {
+ "active_trusted_signers": {
+ "enabled": "false",
+ "items.#": "0"
+ },
+ "aliases": [
+ "panaetius.io"
+ ],
+ "arn": "arn:aws:cloudfront::745437999005:distribution/E2IHXIMPI3MZ2X",
+ "cache_behavior": [],
+ "caller_reference": "terraform-20200713232651089800000002",
+ "comment": "Managed by Terraform",
+ "custom_error_response": [],
+ "default_cache_behavior": [
+ {
+ "allowed_methods": [
+ "DELETE",
+ "GET",
+ "HEAD",
+ "OPTIONS",
+ "PATCH",
+ "POST",
+ "PUT"
+ ],
+ "cached_methods": [
+ "GET",
+ "HEAD"
+ ],
+ "compress": false,
+ "default_ttl": 60,
+ "field_level_encryption_id": "",
+ "forwarded_values": [
+ {
+ "cookies": [
+ {
+ "forward": "none",
+ "whitelisted_names": []
+ }
+ ],
+ "headers": [
+ "Access-Control-Request-Headers",
+ "Access-Control-Request-Method",
+ "Origin"
+ ],
+ "query_string": false,
+ "query_string_cache_keys": []
+ }
+ ],
+ "lambda_function_association": [],
+ "max_ttl": 31536000,
+ "min_ttl": 0,
+ "smooth_streaming": false,
+ "target_origin_id": "prod-panaetius-blog",
+ "trusted_signers": [],
+ "viewer_protocol_policy": "redirect-to-https"
+ }
+ ],
+ "default_root_object": "index.html",
+ "domain_name": "d244ranky0ff54.cloudfront.net",
+ "enabled": true,
+ "etag": "E2SEL7AYXF1CKS",
+ "hosted_zone_id": "Z2FDTNDATAQYW2",
+ "http_version": "http2",
+ "id": "E2IHXIMPI3MZ2X",
+ "in_progress_validation_batches": 0,
+ "is_ipv6_enabled": true,
+ "last_modified_time": "2020-07-15 00:18:34.684 +0000 UTC",
+ "logging_config": [
+ {
+ "bucket": "prod-panaetius-blog-logs.s3.amazonaws.com",
+ "include_cookies": false,
+ "prefix": ""
+ }
+ ],
+ "ordered_cache_behavior": [],
+ "origin": [
+ {
+ "custom_header": [],
+ "custom_origin_config": [],
+ "domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "origin_id": "prod-panaetius-blog",
+ "origin_path": "",
+ "s3_origin_config": [
+ {
+ "origin_access_identity": "origin-access-identity/cloudfront/E21A7YWJ1RT3K5"
+ }
+ ]
+ }
+ ],
+ "origin_group": [],
+ "price_class": "PriceClass_100",
+ "restrictions": [
+ {
+ "geo_restriction": [
+ {
+ "locations": [],
+ "restriction_type": "none"
+ }
+ ]
+ }
+ ],
+ "retain_on_delete": false,
+ "status": "Deployed",
+ "tags": {
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "viewer_certificate": [
+ {
+ "acm_certificate_arn": "arn:aws:acm:us-east-1:745437999005:certificate/60af49f0-07bb-4680-8f5b-3c9a33f756e5",
+ "cloudfront_default_certificate": false,
+ "iam_certificate_id": "",
+ "minimum_protocol_version": "TLSv1",
+ "ssl_support_method": "sni-only"
+ }
+ ],
+ "wait_for_deployment": true,
+ "web_acl_id": ""
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_cloudfront_origin_access_identity",
+ "name": "default",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "caller_reference": "terraform-20200713232645930800000001",
+ "cloudfront_access_identity_path": "origin-access-identity/cloudfront/E21A7YWJ1RT3K5",
+ "comment": "prod-panaetius-blog",
+ "etag": "EESE0U5KF261",
+ "iam_arn": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5",
+ "id": "E21A7YWJ1RT3K5",
+ "s3_canonical_user_id": "2d7779400635ec843efe9b677769fc4f82b0d384408cf22382bf3a90540502e09e75d1346e7105b4da159515b229f39b"
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "managed",
+ "type": "aws_route53_record",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 2,
+ "attributes": {
+ "alias": [
+ {
+ "evaluate_target_health": false,
+ "name": "d244ranky0ff54.cloudfront.net",
+ "zone_id": "Z2FDTNDATAQYW2"
+ }
+ ],
+ "allow_overwrite": null,
+ "failover_routing_policy": [],
+ "fqdn": "panaetius.io",
+ "geolocation_routing_policy": [],
+ "health_check_id": "",
+ "id": "Z05316671VABVSMAAF1RC_panaetius.io_A",
+ "latency_routing_policy": [],
+ "multivalue_answer_routing_policy": null,
+ "name": "panaetius.io",
+ "records": [],
+ "set_identifier": "",
+ "ttl": 0,
+ "type": "A",
+ "weighted_routing_policy": [],
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjIifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_distribution.default",
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.dns",
+ "mode": "managed",
+ "type": "aws_route53_record",
+ "name": "ipv6",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 2,
+ "attributes": {
+ "alias": [
+ {
+ "evaluate_target_health": false,
+ "name": "d244ranky0ff54.cloudfront.net",
+ "zone_id": "Z2FDTNDATAQYW2"
+ }
+ ],
+ "allow_overwrite": null,
+ "failover_routing_policy": [],
+ "fqdn": "panaetius.io",
+ "geolocation_routing_policy": [],
+ "health_check_id": "",
+ "id": "Z05316671VABVSMAAF1RC_panaetius.io_AAAA",
+ "latency_routing_policy": [],
+ "multivalue_answer_routing_policy": null,
+ "name": "panaetius.io",
+ "records": [],
+ "set_identifier": "",
+ "ttl": 0,
+ "type": "AAAA",
+ "weighted_routing_policy": [],
+ "zone_id": "Z05316671VABVSMAAF1RC"
+ },
+ "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjIifQ==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_distribution.default",
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin",
+ "module.cloudfront_s3_cdn.module.logs.aws_s3_bucket.default"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn.module.logs",
+ "mode": "managed",
+ "type": "aws_s3_bucket",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "acceleration_status": "",
+ "acl": "log-delivery-write",
+ "arn": "arn:aws:s3:::prod-panaetius-blog-logs",
+ "bucket": "prod-panaetius-blog-logs",
+ "bucket_domain_name": "prod-panaetius-blog-logs.s3.amazonaws.com",
+ "bucket_prefix": null,
+ "bucket_regional_domain_name": "prod-panaetius-blog-logs.s3.eu-west-1.amazonaws.com",
+ "cors_rule": [],
+ "force_destroy": true,
+ "grant": [],
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-logs",
+ "lifecycle_rule": [
+ {
+ "abort_incomplete_multipart_upload_days": 0,
+ "enabled": true,
+ "expiration": [
+ {
+ "date": "",
+ "days": 90,
+ "expired_object_delete_marker": false
+ }
+ ],
+ "id": "prod-panaetius-blog-logs",
+ "noncurrent_version_expiration": [
+ {
+ "days": 90
+ }
+ ],
+ "noncurrent_version_transition": [
+ {
+ "days": 30,
+ "storage_class": "GLACIER"
+ }
+ ],
+ "prefix": "",
+ "tags": {},
+ "transition": [
+ {
+ "date": "",
+ "days": 30,
+ "storage_class": "STANDARD_IA"
+ },
+ {
+ "date": "",
+ "days": 60,
+ "storage_class": "GLACIER"
+ }
+ ]
+ }
+ ],
+ "logging": [],
+ "object_lock_configuration": [],
+ "policy": "",
+ "region": "eu-west-1",
+ "replication_configuration": [],
+ "request_payer": "BucketOwner",
+ "server_side_encryption_configuration": [
+ {
+ "rule": [
+ {
+ "apply_server_side_encryption_by_default": [
+ {
+ "kms_master_key_id": "",
+ "sse_algorithm": "AES256"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "tags": {
+ "Attributes": "logs",
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog-logs",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "versioning": [
+ {
+ "enabled": false,
+ "mfa_delete": false
+ }
+ ],
+ "website": [],
+ "website_domain": null,
+ "website_endpoint": null
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_s3_bucket",
+ "name": "origin",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "acceleration_status": "",
+ "acl": "private",
+ "arn": "arn:aws:s3:::prod-panaetius-blog-origin",
+ "bucket": "prod-panaetius-blog-origin",
+ "bucket_domain_name": "prod-panaetius-blog-origin.s3.amazonaws.com",
+ "bucket_prefix": null,
+ "bucket_regional_domain_name": "prod-panaetius-blog-origin.s3.eu-west-1.amazonaws.com",
+ "cors_rule": [
+ {
+ "allowed_headers": [
+ "*"
+ ],
+ "allowed_methods": [
+ "GET",
+ "HEAD",
+ "PUT",
+ "POST"
+ ],
+ "allowed_origins": [
+ "*.panaetius.io",
+ "panaetius.io"
+ ],
+ "expose_headers": [
+ "ETag"
+ ],
+ "max_age_seconds": 3600
+ }
+ ],
+ "force_destroy": true,
+ "grant": [],
+ "hosted_zone_id": "Z1BKCTXD74EZPE",
+ "id": "prod-panaetius-blog-origin",
+ "lifecycle_rule": [],
+ "logging": [],
+ "object_lock_configuration": [],
+ "policy": null,
+ "region": "eu-west-1",
+ "replication_configuration": [],
+ "request_payer": "BucketOwner",
+ "server_side_encryption_configuration": [],
+ "tags": {
+ "Attributes": "origin",
+ "Description": "terraform resources to host the blog",
+ "Name": "prod-panaetius-blog-origin",
+ "Project": "panaetius-blog",
+ "Stage": "prod"
+ },
+ "versioning": [
+ {
+ "enabled": false,
+ "mfa_delete": false
+ }
+ ],
+ "website": [],
+ "website_domain": null,
+ "website_endpoint": null
+ },
+ "private": "bnVsbA=="
+ }
+ ]
+ },
+ {
+ "mode": "managed",
+ "type": "aws_s3_bucket_object",
+ "name": "index",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "schema_version": 0,
+ "attributes": {
+ "acl": "public-read",
+ "bucket": "prod-panaetius-blog-origin",
+ "cache_control": "",
+ "content": null,
+ "content_base64": null,
+ "content_disposition": "",
+ "content_encoding": "",
+ "content_language": "",
+ "content_type": "text/html",
+ "etag": "83350948ee374f30e5513497c69c0fe5",
+ "force_destroy": false,
+ "id": "index.html",
+ "key": "index.html",
+ "kms_key_id": null,
+ "metadata": {},
+ "object_lock_legal_hold_status": "",
+ "object_lock_mode": "",
+ "object_lock_retain_until_date": "",
+ "server_side_encryption": "",
+ "source": "./test/index.html",
+ "storage_class": "STANDARD",
+ "tags": {},
+ "version_id": "",
+ "website_redirect": ""
+ },
+ "private": "bnVsbA==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin"
+ ]
+ }
+ ]
+ },
+ {
+ "module": "module.cloudfront_s3_cdn",
+ "mode": "managed",
+ "type": "aws_s3_bucket_policy",
+ "name": "default",
+ "each": "list",
+ "provider": "provider.aws",
+ "instances": [
+ {
+ "index_key": 0,
+ "schema_version": 0,
+ "attributes": {
+ "bucket": "prod-panaetius-blog-origin",
+ "id": "prod-panaetius-blog-origin",
+ "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"S3GetObjectForCloudFront\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::prod-panaetius-blog-origin/*\"},{\"Sid\":\"S3ListBucketForCloudFront\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E21A7YWJ1RT3K5\"},\"Action\":\"s3:ListBucket\",\"Resource\":\"arn:aws:s3:::prod-panaetius-blog-origin\"}]}"
+ },
+ "private": "bnVsbA==",
+ "dependencies": [
+ "module.cloudfront_s3_cdn.aws_cloudfront_origin_access_identity.default",
+ "module.cloudfront_s3_cdn.aws_s3_bucket.origin"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/infrastructure/variables.tf b/infrastructure/variables.tf
new file mode 100644
index 0000000..837bbd3
--- /dev/null
+++ b/infrastructure/variables.tf
@@ -0,0 +1,44 @@
+variable "name" {
+
+}
+
+variable "region" {
+
+}
+
+variable "stage" {
+
+}
+
+variable "profile" {
+
+}
+
+variable "bucket_name" {
+
+}
+
+variable "acm_certificate_arn" {
+
+}
+
+variable "parent_zone_id" {
+
+}
+
+variable "aliases" {
+
+}
+
+variable "allowed_origins" {
+
+}
+
+
+# variable "log_expiration_days" {
+
+# }
+
+# variable "log_standard_transition_days" {
+
+# }
diff --git a/infrastructure/variables/prod-eu-west-1.tfvars b/infrastructure/variables/prod-eu-west-1.tfvars
new file mode 100644
index 0000000..f74486a
--- /dev/null
+++ b/infrastructure/variables/prod-eu-west-1.tfvars
@@ -0,0 +1,11 @@
+name = "panaetius-blog"
+region = "eu-west-1"
+stage = "prod"
+profile = "admin"
+bucket_name = "prod-panaetius-blog-origin"
+acm_certificate_arn = "arn:aws:acm:us-east-1:745437999005:certificate/60af49f0-07bb-4680-8f5b-3c9a33f756e5"
+parent_zone_id = "Z05316671VABVSMAAF1RC"
+aliases = ["panaetius.io"]
+allowed_origins = ["*.panaetius.io"]
+# log_expiration_days = 60
+# log_standard_transition_days = 60
diff --git a/tasks.todo b/tasks.todo
index 115554a..de475f6 100644
--- a/tasks.todo
+++ b/tasks.todo
@@ -1,26 +1,36 @@
Projects:
+ ✔ Fix the navbar on mobile. @done (6/11/2020, 11:18:31 PM)
+ ✔ Change text on homepage on mobile. @done (6/11/2020, 11:18:32 PM)
- ☐ Fix the navbar on mobile.
- ☐ Change text on homepage on mobile.
+ CSS:
+ ☐ Document using transition.
+
+ Hugo:
+ ☐ Document pagination
+ Notes:
+ ☐ Link and .
+ ☐ Link to git
Images:
- ☐ Add random animal image to corner of card.
+ ✔ Add random animal image to corner of card. @done (6/9/2020, 1:18:32 PM)
Note:
How to edit the homepage, how to edit taxonomy content (the _index.html) file and what this means.
- ☐ Refactor front page like (https://www.educative.io/edpresso)
- ☐ Another layout for cards (https://codewithhugo.com)
+ ✔ Refactor front page like (https://www.educative.io/edpresso) @done (6/11/2020, 11:18:37 PM)
+ ✔ Another layout for cards (https://codewithhugo.com) @done (6/11/2020, 11:18:38 PM)
Misc:
- ☐ Add social metadata
- ☐ Create own admonitions with shortcode with custom animal themeing.
+ ☐ Create archetypes for posts.
+ ✔ Configure pagination for homepage. @done (6/11/2020, 11:18:48 PM)
+ ✔ Add social metadata @done (6/9/2020, 1:27:26 PM)
+ ✔ Create own admonitions with shortcode with custom animal themeing. @done (6/9/2020, 1:27:24 PM)
Custom layout:
- ☐ Use the envanto website layouts (whole static themes) to find suitable wallpaper for a post page.
- ☐ Add tags to front page cards
- ☐ Using date in the slug, customising the slugs further?
- ☐ Find a font from envanto and customise the vars in bootstrap (https://getbootstrap.com/docs/4.0/content/reboot/#native-font-stack)
+ ✔ Use the envanto website layouts (whole static themes) to find suitable wallpaper for a post page. @done (6/9/2020, 1:27:29 PM)
+ ✔ Add tags to front page cards @done (6/11/2020, 11:18:52 PM)
+ ✔ Using date in the slug, customising the slugs further? @done (6/11/2020, 11:18:54 PM)
+ ✔ Find a font from envanto and customise the vars in bootstrap (https://getbootstrap.com/docs/4.0/content/reboot/#native-font-stack) @done (6/9/2020, 1:27:33 PM)
Content:
@@ -30,7 +40,7 @@ Projects:
Each series needs its own page with image and intro + TOC (https://simpleisbetterthancomplex.com/series/beginners-guide/1.11/)
Could have a banner or side content saying this is part N in a series?
Use this shortcode on pages in a series: - showing what part of N it is and of what series. Should dynamically show depending on whether it is a series or not.
- ☐ Have a categories taxonomy (https://www.integralist.co.uk/posts/static-search-with-lunr/ at the bottom)
+ ✔ Have a categories taxonomy (https://www.integralist.co.uk/posts/static-search-with-lunr/ at the bottom) @done (6/11/2020, 11:20:04 PM)
Notes:
Categories are high level: code, guides/tutorials, deployment etc
Tags will be specifics: python, aws etc
diff --git a/terraform.md b/terraform.md
new file mode 100644
index 0000000..cd462ff
--- /dev/null
+++ b/terraform.md
@@ -0,0 +1,60 @@
+# Terraform
+
+## Structure
+
+The following should go in the root of your project - this is for the LS VSCode which needs the terraform in the root of the project.
+
+Place the `Makefile` in the root of this folder.
+
+Create a `Makefile.env` file
+
+Create a `./variables` folder and create `.tfvars` files in here with the naming convention `stage-environment.tfvars` e.g `prod-us-east-2.tfvars`.
+
+You can then create a `main.tf`, `outputs.tf` and `variables.tf` file in the root of your folder.
+
+## Makefile
+
+Using the makefile from .
+
+`wget https://raw.githubusercontent.com/pgporada/terraform-makefile/master/Makefile`.
+
+Current version has a pull request pending that fixes a dynamo db issue:
+
+`wget https://raw.githubusercontent.com/geftactics/terraform-makefile/geftactics-dynamodb-check/Makefile`.
+
+- Add `-include Makefile.env` after the `.PHONY` entry to the `Makefile`.
+- Change the `S3_BUCKET` and `DYNAMODB_TABLE` to:
+
+```env
+S3_BUCKET="$(ENV)-$(REGION)-$(PROJECT)-terraform"
+DYNAMODB_TABLE="$(ENV)-$(REGION)-$(PROJECT)-terraform"
+```
+
+In the `Makefile.env` add the environment variables needed for the `Makfile`:
+
+```env
+ENV="prod"
+REGION="eu-west-1"
+PROJECT="panaetius-blog"
+AWS_PROFILE="admin"
+```
+
+### Options
+
+```text
+$ make
+apply Have terraform do the things. This will cost money.
+destroy-backend Destroy S3 bucket and DynamoDB table
+destroy Destroy the things
+destroy-target Destroy a specific resource. Caution though, this destroys chained resources.
+plan-destroy Creates a destruction plan.
+plan Show what terraform thinks it will do
+plan-target Shows what a plan looks like for applying a specific resource
+prep Prepare a new workspace (environment) if needed, configure the tfstate backend, update any modules, and switch to the workspace
+```
+
+## Commands
+
+### New project
+
+`gmake prep` - this will create an S3 bucket for tfstate and a DynamoDB table for the lock state.