Skip to content
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The [`master`](https://github.com/codequest-eu/terraform-single-page-app/tree/ma

| Name | Description | Type | Default | Required |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | :----: | :----------------: | :------: |
| basic\_auth\_credentials | Basic auth credentials in user:pass format | string | n/a | yes |
| bucket | Kebab-cased bucket name override | string | `""` | no |
| certificate\_arn | ACM certificate ARN to use instead of the default cloudfront certificate | string | `""` | no |
| cloudfront\_price\_class | CloudFront price class, which specifies where the distribution should be replicated, one of: PriceClass_100, PriceClass_200, PriceClass_All | string | `"PriceClass_100"` | no |
Expand Down
5 changes: 3 additions & 2 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ module "basic" {
}

# only project name and environment are required
project = "terraform-spa"
environment = "example"
project = "terraform-spa-auth"
environment = "example"
basic_auth_credentials = "example:app"
}

resource "aws_s3_bucket_object" "basic_index" {
Expand Down
41 changes: 41 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
provider "aws" {
alias = "middleware"
}

resource "aws_s3_bucket" "assets" {
bucket = "${var.bucket != "" ? var.bucket : "${local.name_prefix}-assets"}"
acl = "private"
Expand Down Expand Up @@ -94,6 +98,12 @@ resource "aws_cloudfront_distribution" "assets" {
forward = "none"
}
}

lambda_function_association {
event_type = "viewer-request"
lambda_arn = "${module.basic_auth.arn}"
include_body = false
}
}

custom_error_response {
Expand All @@ -118,3 +128,34 @@ resource "aws_cloudfront_distribution" "assets" {

tags = "${local.tags}"
}

module "middleware_common" {
source = "./middleware_common"

name_prefix = "${local.name_prefix}"

providers = {
aws = "aws.middleware"
}
}

data "template_file" "basic_auth" {
template = "${file("${path.module}/templates/basic-auth.js")}"

vars {
credentials = "${base64encode("${var.basic_auth_credentials}")}"
}
}

module "basic_auth" {
source = "./middleware"

name = "${local.name_prefix}-basic-auth"
code = "${data.template_file.basic_auth.rendered}"
role_arn = "${module.middleware_common.role_arn}"
tags = "${local.tags}"

providers = {
aws = "aws.middleware"
}
}
26 changes: 26 additions & 0 deletions templates/basic-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Expected Authorization header value
const authorization = "Basic ${credentials}"

exports.handler = (event, context, callback) => {
// Get request and request headers
const request = event.Records[0].cf.request
const headers = request.headers

// Require Basic authentication
if (
!headers.authorization ||
headers.authorization[0].value !== authorization
) {
return callback(null, {
status: "401",
statusDescription: "Unauthorized",
body: "Unauthorized",
headers: {
"www-authenticate": [{ key: "WWW-Authenticate", value: "Basic" }],
},
})
}

// Continue request processing if authentication passed
callback(null, request)
}
4 changes: 4 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ variable "bucket" {
description = "Kebab-cased bucket name override"
default = ""
}

variable "basic_auth_credentials" {
description = "Basic auth credentials in user:pass format"
}