Skip to content

Commit

Permalink
Add UI bucket and CDN
Browse files Browse the repository at this point in the history
  • Loading branch information
jarrod-lowe committed Aug 18, 2024
1 parent 28c2628 commit 0ab7aa3
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 25 deletions.
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ dev: $(GRAPHQL_DEV) terraform-format terraform/environment/aws-dev/.apply terraf
@true

terraform/environment/aws-dev/.apply: terraform/environment/aws-dev/*.tf terraform/module/iac-roles/*.tf
./terraform/environment/aws-dev/deploy.sh $(ACCOUNT_ID) dev
AUTO_APPROVE=yes ./terraform/environment/aws-dev/deploy.sh $(ACCOUNT_ID) dev
touch $@

terraform/environment/wildsea-dev/plan.tfplan: terraform/environment/wildsea-dev/*.tf terraform/module/wildsea/*.tf terraform/environment/wildsea-dev/.terraform $(GRAPHQL_JS)
cd terraform/environment/wildsea-dev ; ../../../scripts/run-as.sh $(RO_ROLE) \
terraform plan -out=./plan.tfplan

terraform/environment/wildsea-dev/.apply: terraform/environment/wildsea-dev/plan.tfplan $(GRAPHQL_JS)
cd terraform/environment/wildsea-dev ; ../../../scripts/run-as.sh $(RW_ROLE) \
terraform apply ./plan.tfplan ; \
status=$$? ; \
rm -f $< ; \
[ "$$status" -eq 0 ]
cd terraform/environment/wildsea-dev ; \
../../../scripts/run-as.sh $(RW_ROLE) \
terraform apply ./plan.tfplan || status=$$? ; \
rm -v ./plan.tfplan ; \
[ -z "$$status" ] || exit $$status
touch $@

terraform/environment/wildsea-dev/.terraform: terraform/environment/wildsea-dev/*.tf terraform/module/wildsea/*.tf
Expand Down
9 changes: 4 additions & 5 deletions graphql/graphql.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@ graphql: $(GRAPHQL_JS) graphql-test
.PHONY: graphql-test
graphql-test: graphql/node_modules
if [ -z "$(IN_PIPELINE)" ] ; then \
docker run --rm -it --user $$(id -u):$$(id -g) -v $(PWD)/graphql:/app -w /app --entrypoint ./node_modules/jest/bin/jest.js node:20 \
docker run --rm -it --user $$(id -u):$$(id -g) -v $(PWD)/graphql:/app -w /app --entrypoint ./node_modules/jest/bin/jest.js node:20 ; \
else \
cd graphql && jest ; \
cd graphql && ./node_modules/jest/bin/jest.js ; \
fi

# Won't auto-fix in pipeline
.PHONY: graphql-eslint
graphql-eslint: $(GRAPHQL_TS)
if [ -z "$(IN_PIPELINE)" ] ; then \
docker run --rm -it --user $$(id -u):$$(id -g) -v $(PWD)/graphql:/code pipelinecomponents/eslint eslint --fix
docker run --rm -it --user $$(id -u):$$(id -g) -v $(PWD)/graphql:/code pipelinecomponents/eslint eslint --fix ; \
else \
cd graphql && eslint ;:w
\
cd graphql && eslint ; \
fi
2 changes: 1 addition & 1 deletion terraform/environment/aws/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ terraform init \
-backend-config="key=${ENVIRONMENT}/aws.tfstate" \
-backend-config="region=${AWS_REGION}"

terraform apply \
terraform apply ${AUTO_APPROVE:+-auto-approve} \
-var environment="${ENVIRONMENT}" \
-var state_bucket="${STATE_BUCKET}"
64 changes: 51 additions & 13 deletions terraform/module/iac-roles/policy.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ data "aws_iam_policy_document" "ro" {
"s3:GetObject"
]
resources = [
"${var.state_bucket_arn}/${var.environment}/terraform.tfstate"
"${var.state_bucket_arn}/${var.environment}/terraform.tfstate",
]
}

statement {
sid = "ListState"
actions = [
"s3:ListBucket"
"s3:ListBucket",
"s3:GetBucket*",
"s3:Get*Configuration",
]
resources = [
var.state_bucket_arn
var.state_bucket_arn,
"arn:${data.aws_partition.current.id}:s3:::${lower(var.app_name)}-${var.environment}-ui",
]
}

Expand Down Expand Up @@ -43,12 +46,17 @@ data "aws_iam_policy_document" "ro" {
}

statement {
sid = "CognitoIdpGlobal"
sid = "Global"
actions = [
"cognito-idp:DescribeUserPoolDomain",
"wafv2:GetWebACLForResource",
"wafv2:GetWebAcl",
"appsync:GetResolver",
"cloudfront:List*",
"cloudfront:Get*Policy",
"cloudfront:GetDistribution",
"cloudfront:GetOriginAccessControl",
"iam:SimulatePrincipalPolicy",
]
resources = [
"*"
Expand Down Expand Up @@ -157,9 +165,11 @@ data "aws_iam_policy_document" "rw" {
"dynamodb:TagResource",
"dynamodb:UntagResource",
"dynamodb:Update*",
"s3:Put*Configuration",
]
resources = [
"arn:${data.aws_partition.current.id}:dynamodb:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:table/${var.app_name}-${var.environment}"
"arn:${data.aws_partition.current.id}:dynamodb:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:table/${var.app_name}-${var.environment}",
"arn:${data.aws_partition.current.id}:s3:::${lower(local.prefix)}-*",
]
}

Expand Down Expand Up @@ -188,7 +198,7 @@ data "aws_iam_policy_document" "rw" {
}

statement {
sid = "CognitoIdentityGlobal"
sid = "Global"
actions = [
"cognito-identity:CreateIdentityPool",
"cognito-identity:SetIdentityPoolRoles",
Expand All @@ -198,6 +208,13 @@ data "aws_iam_policy_document" "rw" {
"appsync:DeleteResolver",
"appsync:UpdateResolver",
"appsync:SetWebACL",
"s3:CreateBucket",
"cloudfront:CreateOriginAccessControl",
"cloudfront:DeleteOriginAccessControl",
"cloudfront:CreateDistribution*",
"cloudfront:UpdateDistribution",
"cloudfront:DeleteDistribution",
"cloudfront:TagResource",
]
resources = [
"*"
Expand Down Expand Up @@ -254,7 +271,7 @@ data "aws_iam_policy_document" "rw" {
"appsync:UntagResource",
]
resources = [
"arn:${data.aws_partition.current.id}:appsync:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:*"
"arn:${data.aws_partition.current.id}:appsync:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:*",
]
condition {
test = "StringEquals"
Expand All @@ -270,9 +287,12 @@ data "aws_iam_policy_document" "rw" {
"logs:TagResource",
"logs:UntagResource",
"logs:PutRetentionPolicy",
"s3:DeleteBucket",
"s3:PutBucket*",
]
resources = [
"arn:${data.aws_partition.current.id}:logs:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:log-group:*"
"arn:${data.aws_partition.current.id}:logs:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:log-group:*",
"arn:${data.aws_partition.current.id}:s3:::${lower(local.prefix)}-*",
]
}

Expand Down Expand Up @@ -335,18 +355,21 @@ data "aws_iam_policy_document" "rw_boundary" {
]
resources = [
"${var.state_bucket_arn}/${var.environment}/terraform.tfstate",
"arn:${data.aws_partition.current.id}:s3:::${lower(var.app_name)}-${var.environment}-*/*"
"arn:${data.aws_partition.current.id}:s3:::${lower(var.app_name)}-${var.environment}-*/*",
]
}

statement {
sid = "ListState"
actions = [
"s3:ListBucket"
"s3:ListBucket",
"s3:GetBucket*",
"s3:Get*Configuration",
"s3:Put*Configuration",
]
resources = [
"${var.state_bucket_arn}/${var.environment}/terraform.tfstate",
"arn:${data.aws_partition.current.id}:s3:::${lower(var.app_name)}-${var.environment}-*/*"
"arn:${data.aws_partition.current.id}:s3:::${lower(var.app_name)}-${var.environment}-*",
]
}

Expand Down Expand Up @@ -397,6 +420,18 @@ data "aws_iam_policy_document" "rw_boundary" {
"appsync:DeleteResolver",
"appsync:UpdateResolver",
"appsync:GetResolver",
"s3:CreateBucket",
"cloudfront:List*",
"cloudfront:Get*Policy",
"cloudfront:CreateOriginAccessControl",
"cloudfront:GetOriginAccessControl",
"cloudfront:DeleteOriginAccessControl",
"cloudfront:CreateDistribution*",
"cloudfront:UpdateDistribution",
"cloudfront:DeleteDistribution",
"cloudfront:TagResource",
"cloudfront:GetDistribution",
"iam:SimulatePrincipalPolicy",
]
resources = [
"*"
Expand Down Expand Up @@ -487,7 +522,7 @@ data "aws_iam_policy_document" "rw_boundary" {
"appsync:GetGraphqlApi",
]
resources = [
"arn:${data.aws_partition.current.id}:appsync:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:*"
"arn:${data.aws_partition.current.id}:appsync:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:*",
]
condition {
test = "StringEquals"
Expand All @@ -505,9 +540,12 @@ data "aws_iam_policy_document" "rw_boundary" {
"logs:PutRetentionPolicy",
"logs:DescribeLogGroups",
"logs:ListTagsForResource",
"s3:DeleteBucket",
"s3:PutBucket*",
]
resources = [
"arn:${data.aws_partition.current.id}:logs:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:log-group:*"
"arn:${data.aws_partition.current.id}:logs:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:log-group:*",
"arn:${data.aws_partition.current.id}:s3:::${lower(local.prefix)}-*",
]
}

Expand Down
20 changes: 20 additions & 0 deletions terraform/module/iac-roles/sim.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Doesn't work yet - TODO
# data "aws_iam_principal_policy_simulation" "state_read" {
# action_names = [
# "s3:GetObject"
# ]
# policy_source_arn = aws_iam_role.ro.arn
# resource_arns = [
# "${var.state_bucket_arn}/${var.environment}/terraform.tfstate",
# ]
# #resource_policy_json = data.aws_iam_policy_document.ro.json
#
# depends_on = [aws_iam_policy.ro]
#
# lifecycle {
# postcondition {
# condition = self.all_allowed
# error_message = "state_read check failed: ${jsonencode(self.results)}"
# }
# }
# }
148 changes: 148 additions & 0 deletions terraform/module/wildsea/ui-bucket.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
locals {
ui = "${var.prefix}-ui"
}

resource "aws_s3_bucket" "ui" {
# checkov:skip=CKV_AWS_18:Chosen not to enable access logging yet
# checkov:skip=CKV2_AWS_62:No need for S3 events
# checkov:skip=CKV_AWS_144:No need for cross-region replication
# checkov:skip=CKV_AWS_145:AWS ley is sufficient
bucket = lower(local.ui)

tags = {
Name = local.ui
}
}

resource "aws_s3_bucket_policy" "ui" {
bucket = aws_s3_bucket.ui.id
policy = data.aws_iam_policy_document.ui.json
}

data "aws_iam_policy_document" "ui" {
statement {
sid = "CDNRead"
effect = "Allow"
actions = ["s3:GetObject"]
resources = ["${aws_s3_bucket.ui.arn}/*"]
principals {
type = "Service"
identifiers = ["cloudfront.${data.aws_partition.current.dns_suffix}"]
}
condition {
test = "StringEquals"
variable = "aws:SourceArn"
values = [aws_cloudfront_distribution.cdn.arn]
}
}

statement {
sid = "CDNList"
effect = "Allow"
actions = ["s3:ListBucket"]
resources = [aws_s3_bucket.ui.arn]
principals {
type = "Service"
identifiers = ["cloudfront.${data.aws_partition.current.dns_suffix}"]
}
condition {
test = "StringEquals"
variable = "aws:SourceArn"
values = [aws_cloudfront_distribution.cdn.arn]
}
}

# Block all HTTP Access
statement {
sid = "BlockHTTP"
effect = "Deny"
actions = ["s3:*"]
resources = [
aws_s3_bucket.ui.arn,
"${aws_s3_bucket.ui.arn}/*",
]
principals {
type = "AWS"
identifiers = ["*"]
}
condition {
test = "Bool"
variable = "aws:SecureTransport"
values = ["false"]
}
}
}

resource "aws_s3_bucket_public_access_block" "ui" {
bucket = aws_s3_bucket.ui.id

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

resource "aws_s3_bucket_ownership_controls" "ui" {
bucket = aws_s3_bucket.ui.id

rule {
object_ownership = "BucketOwnerEnforced"
}
}

resource "aws_s3_bucket_versioning" "ui" {
bucket = aws_s3_bucket.ui.id

versioning_configuration {
status = "Enabled"
}
}

resource "aws_s3_bucket_server_side_encryption_configuration" "ui" {
bucket = aws_s3_bucket.ui.id

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}

# Use recommended CORS rules for bucket behind cloudfront
resource "aws_s3_bucket_cors_configuration" "ui" {
bucket = aws_s3_bucket.ui.id

cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET", "HEAD"]
allowed_origins = ["https://${aws_cloudfront_distribution.cdn.domain_name}"]
expose_headers = ["ETag"]
max_age_seconds = 3000
}
}

# Lifecycle to:
# * Delete incomplete multipart uploads after 3 days
# * Limit old versions to maximum of 5 or and age of 30 days
# * Keep the current version forever
resource "aws_s3_bucket_lifecycle_configuration" "ui" {
bucket = aws_s3_bucket.ui.id

rule {
id = "expire-versions"
status = "Enabled"

abort_incomplete_multipart_upload {
days_after_initiation = 3
}

noncurrent_version_expiration {
newer_noncurrent_versions = 5
noncurrent_days = 30
}

expiration {
expired_object_delete_marker = true
}
}
}
Loading

0 comments on commit 0ab7aa3

Please sign in to comment.