Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a CloudFront keypair instead of root keys #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ infra/terraform.tfstate*
infra/terraform.tfvars
infra/backend.tf
infra/templates/email-invite.html
infra/*.pem
43 changes: 8 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-----`<br />`...`<br/>`-----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`
Expand All @@ -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

Expand Down
16 changes: 14 additions & 2 deletions infra/cloudfront.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"

Expand Down
13 changes: 13 additions & 0 deletions infra/parameterstore.tf
Original file line number Diff line number Diff line change
@@ -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")
}