This module allows for Fleet software installers to be served via AWS Cloudfront instead of directly from Fleet.
This should improve the performance of software installer delivery. For general information about Fleet and Cloudfront see the following:
https://fleetdm.com/guides/cdn-signed-urls https://victoronsoftware.com/posts/cloudfront-signed-urls/
The second link includes a script that can be used to test and see if signed URLs are working outside of Fleet for troubleshooting purposes.
This addon is intentionally out of scope for AWS GovCloud compatibility. CloudFront is not available inside the AWS GovCloud (US) partition, so using it with GovCloud-hosted resources is a cross-partition architecture that should be designed and reviewed separately.
These are the minimum versions of modules required if used:
- tf-mod-root-v1.13.0
- tf-mod-byo-vpc-v1.14.0
- tf-mod-byo-db-v1.10.0
- tf-mod-byo-ecs-v1.9.0
- tf-mod-addon-logging-alb-v1.3.0
Previous versions do not allow for proper interaction with both the software installers and logging s3 buckets.
For any of these modules, software installers requires a customer-managed KMS key whenever KMS encryption is used at all. CloudFront access requires a key policy statement on that key, and the AWS-managed default key cannot be modified to accept that policy.
Breaking change: this addon no longer manages the software installers KMS key policy. That policy now lives in tf-mod-byo-ecs, which means CloudFront access to the CMK must be configured there by setting software_installers.cloudfront_distribution_arn to the static distribution ARN.
This is the relevant configuration starting at the software installers configuration block:
software_installers = {
bucket_prefix = "fleet-software-installers-"
create_kms_key = true
kms_alias = "fleet-software-installers"
cloudfront_distribution_arn = "arn:aws:cloudfront::<account-id>:distribution/<distribution-id>"
}
The required configuration items here are create_kms_key, kms_alias, and cloudfront_distribution_arn when CloudFront must read from an SSE-KMS bucket.
No changes required if using at least version tf-mod-addon-logging-alb-v1.3.0. Bucket ACLs are changed to allow for the alb logging bucket to accept Cloudfront logs via ACLs.
This example assumes that you used the following commands to create your public and private key for consumption by the module:
openssl genrsa -out cloudfront.key 2048
openssl rsa -pubout -in cloudfront.key -out cloudfront.pem
To be able to store these in source control in a sane manner, the objects will be KMS encrypted for storage at rest. This can happen by having a KMS key as follows:
resource "aws_kms_key" "customer_data_key" {
description = "key used to encrypt sensitive data stored in terraform"
}
resource "aws_kms_alias" "alias" {
name = "alias/fleet-terraform-encrypted"
target_key_id = aws_kms_key.customer_data_key.id
}
output "kms_key_id" {
value = aws_kms_key.customer_data_key.id
}
Then with the key, the following encrypt.sh script encrypt the objects:
#!/bin/bash
set -e
function usage() {
cat <<-EOUSAGE
Usage: $(basename ${0}) <KMS_KEY_ID> <SOURCE> <DESTINATION> [AWS_PROFILE]
This script encrypts an plaintext file from SOURCE into an
AWS KMS encrypted DESTINATION file. Optionally you
may provide the AWS_PROFILE you wish to use to run the aws kms
commands.
EOUSAGE
exit 1
}
[ $# -lt 3 ] && usage
if [ -n "${4}" ]; then
export AWS_PROFILE=${4}
fi
aws kms encrypt --key-id "${1:?}" --plaintext fileb://<(cat "${2:?}") --output text --query CiphertextBlob > "${3:?}"
We can do the following with that script to encrypt the objects:
./encrypt.sh <KMS_KEY_ID> cloudfront.key cloudfront.key.encrypted
./encrypt.sh <KMS_KEY_ID> cloudfront.pem cloudfront.pem.encrypted
Now with those encrypted we could setup the module with something like the following to populate the module (assuming we add the files to a /resources folder):
module "cloudfront-software-installers" {
source = "github.com/fleetdm/fleet-terraform/addons/cloudfront-software-installers?ref=tf-mod-addon-cloudfront-software-installers-v1.2.0"
customer = "fleet"
s3_bucket = module.main.byo-vpc.byo-db.byo-ecs.fleet_s3_software_installers_config.bucket_name
# OPTIONAL
# If you'd like to use an existing key_group_id for your new Cloudfront distribution, uncomment key_group_id and supply the value for the key_group_id
# If you're using an existing key_group_id, public_key_id is required. The public_key_id is the value of a public_key that is also part of the key group that you define.
# key_group_id = ""
# public_key_id = ""
public_key = data.aws_kms_secrets.cloudfront.plaintext["public_key"]
private_key = data.aws_kms_secrets.cloudfront.plaintext["private_key"]
enable_logging = true
logging_s3_bucket = module.logging_alb.log_s3_bucket_id
}
data "aws_kms_secrets" "cloudfront" {
secret {
name = "public_key"
key_id = aws_kms_key.customer_data_key.id
payload = file("${path.module}/resources/cloudfront.pem.encrypted")
}
secret {
name = "private_key"
key_id = aws_kms_key.customer_data_key.id
payload = file("${path.module}/resources/cloudfront.key.encrypted")
}
}
Then we need to include outputs from this module once applied back into the main fleet-config under the extra_secrets and extra_execution_roles:
This addon also outputs cloudfront_distribution_arn. Do not feed that output back into tf-mod-byo-ecs, because that creates a Terraform cycle. Instead, set the same static ARN directly in software_installers.cloudfront_distribution_arn.
Under the fleet_config section. If not using the mdm module, that could be omitted but was included to show how to include multiple extra items:
fleet_config = {
...
extra_execution_iam_policies = concat(
module.mdm.extra_execution_iam_policies,
module.cloudfront-software-installers.extra_execution_iam_policies,
)
extra_secrets = merge(
module.mdm.extra_secrets,
module.cloudfront-software-installers.extra_secrets
)
}
No requirements.
| Name | Version |
|---|---|
| aws | 6.36.0 |
| Name | Source | Version |
|---|---|---|
| cloudfront_software_installers | terraform-aws-modules/cloudfront/aws | 5.2.0 |
| Name | Type |
|---|---|
| aws_cloudfront_key_group.software_installers | resource |
| aws_cloudfront_public_key.software_installers | resource |
| aws_iam_policy.software_installers_secret | resource |
| aws_s3_bucket_policy.software_installers | resource |
| aws_secretsmanager_secret.software_installers | resource |
| aws_secretsmanager_secret_version.software_installers | resource |
| aws_iam_policy_document.software_installers_bucket | data source |
| aws_iam_policy_document.software_installers_secret | data source |
| aws_s3_bucket.logging | data source |
| aws_s3_bucket.software_installers | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| customer | Customer name for the cloudfront instance | string |
"fleet" |
no |
| enable_logging | Enable optional logging to s3 | bool |
false |
no |
| key_group_id | Cloudfront key group id | string |
null |
no |
| logging_s3_bucket | s3 bucket to log to | string |
null |
no |
| logging_s3_prefix | logging s3 bucket prefix | string |
"cloudfront" |
no |
| private_key | Private key used for signed URLs | string |
n/a | yes |
| public_key | Public key used for signed URLs | string |
n/a | yes |
| public_key_id | Cloudfront public key id. Required when passing in a key_group_id | string |
null |
no |
| s3_bucket | Name of the S3 bucket that Cloudfront will point to | string |
n/a | yes |
| Name | Description |
|---|---|
| cloudfront_arn | n/a |
| cloudfront_distribution_arn | n/a |
| extra_execution_iam_policies | n/a |
| extra_secrets | n/a |