diff --git a/.gitignore b/.gitignore
index fa2fc8c..d998f85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ infra/terraform.tfstate*
infra/terraform.tfvars
infra/backend.tf
infra/templates/email-invite.html
+infra/*.pem
diff --git a/README.md b/README.md
index 7786a70..f0cfa56 100644
--- a/README.md
+++ b/README.md
@@ -66,48 +66,27 @@ cd lambda
./build.sh
```
-### 4. Setup your CloudFront private key
+### 4. Create a CloudFront key pair
Authentication relies on cookies signed with a key pair.
-This is a sensitive value, so the stack expects it to be stored encrypted in
-[SSM Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html).
-
-First, generate a new key pair locally:
+You must generate a new one locally:
``` bash
+cd infra
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
```
-Then store the public key on CloudFront:
-
-1. Open the CloudFront UI
-2. Navigate to "Key management", then "Public keys"
-3. Upload the public key, and take note of the Key ID you receive
-4. Navigate to the "Key group" section just underneath
-5. Create a new key group which includes the public key above
-
-Then store the values in Parameter Store:
-
-1. Open the Parameter Store UI
-2. Create the 2 following entries:
+These keys will be deployed as part of the infrastructure. AWS recommends rotating them every 3 months.
-| Name | Type | KMS Key ID | Value | Example |
-|------|------|------------|-------|---------|
-| `cloudfront_keypair_id` | `String` | - | Public ID of the key pair | `ABC123456789` |
-| `cloudfront_private_key` | `Secure String` | `alias/aws/ssm` | Contents of the private key | `-----BEGIN RSA PRIVATE KEY-----`
`...`
`-----END RSA PRIVATE KEY-----` |
-
-You should then delete the private key you have downloaded.
-AWS recommends rotating this key pair every 3 months.
-
-*Note:* the Parameter Store values are cached in the Lambda function to speed up invocation.
+Note: the values are cached by the Lambda function (in memory) to speed up invocation.
When you rotate the key pair, the old value will still be used until the next **Lambda cold start**.
You can re-deploy the Lambda function to force a cold-start.
-### 4. Deploy infrastructure
+### 5. Deploy infrastructure
The whole infrastructure is written as [Terraform](https://www.terraform.io/) templates.
-First, authenticate against AWS with the [AWS CLI](https://aws.amazon.com/cli):
+First, authenticate against AWS with the [AWS CLI](https://aws.amazon.com/cli):
- run `aws configure` and enter the access key and secret key
- if you saved your credentials as a non-default profile, run `export AWS_PROFILE=profile_name`
@@ -121,13 +100,7 @@ terraform apply
```
If you make any subsequent changes, simply re-run `terraform apply` to apply the update.
-
-!!NOTE!! The code has not yet been updated to take advantage of CloudFront Keypairs.
-Once deployed, you must:
-
-- go into the CloudFront distribution
-- edit the "behaviours" section for **HTML** and **Default**
-- update `Trusted authorization type` from `Self` to the keygroup you created above
+The Terraform code relies on `public_key.pem` and `private_key.pem` existing in the `infra` folder.
### 6. Create users
diff --git a/infra/cloudfront.tf b/infra/cloudfront.tf
index 0bacf57..6d27e53 100644
--- a/infra/cloudfront.tf
+++ b/infra/cloudfront.tf
@@ -5,6 +5,18 @@ data "aws_acm_certificate" "domain" {
most_recent = true
}
+resource "aws_cloudfront_public_key" "cookie_signer" {
+ comment = "Cookie signer public key"
+ encoded_key = file("public_key.pem")
+ name = "cookie-signer"
+}
+
+resource "aws_cloudfront_key_group" "cookie_signer" {
+ comment = "example key group"
+ items = [aws_cloudfront_public_key.cookie_signer.id]
+ name = "cookie-signer"
+}
+
resource "aws_cloudfront_distribution" "distribution" {
aliases = ["${var.website_domain}"]
price_class = "PriceClass_100"
@@ -87,7 +99,7 @@ resource "aws_cloudfront_distribution" "distribution" {
path_pattern = "/api/*"
smooth_streaming = false
target_origin_id = "Login API gateway"
- trusted_signers = []
+ trusted_key_groups = [aws_cloudfront_key_group.cookie_signer.name]
viewer_protocol_policy = "https-only"
forwarded_values {
@@ -142,7 +154,7 @@ resource "aws_cloudfront_distribution" "distribution" {
min_ttl = 15552000
smooth_streaming = false
target_origin_id = "S3-${var.s3_bucket_name}"
- trusted_signers = ["self"]
+ trusted_key_groups = [aws_cloudfront_key_group.cookie_signer.name]
lambda_function_association = []
viewer_protocol_policy = "redirect-to-https"
diff --git a/infra/parameterstore.tf b/infra/parameterstore.tf
new file mode 100644
index 0000000..0eef78b
--- /dev/null
+++ b/infra/parameterstore.tf
@@ -0,0 +1,13 @@
+resource "aws_ssm_parameter" "keypair_id" {
+ name = "cloudfront_keypair_id"
+ description = "ID of the public key in CloudFront"
+ type = "String"
+ value. = aws_cloudfront_public_key.cookie_signer.id
+}
+
+resource "aws_ssm_parameter" "private_key" {
+ name = "cloudfront_private_key"
+ description = "Private key for signing CloudFront cookies"
+ type = "SecureString"
+ value = file("private_key.pem")
+}