CloudFront: multi-destination access logging with Firehose HTTP endpoint - #121
Open
devin-ai-integration[bot] wants to merge 6 commits into
Open
CloudFront: multi-destination access logging with Firehose HTTP endpoint#121devin-ai-integration[bot] wants to merge 6 commits into
devin-ai-integration[bot] wants to merge 6 commits into
Conversation
Co-Authored-By: brandon <brandon@flightcontrol.dev>
Co-Authored-By: brandon <brandon@flightcontrol.dev>
Co-Authored-By: brandon <brandon@flightcontrol.dev>
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Ravion Module Publish PlanDry run only. No Ravion API mutations were made.
Diffsrvn-cloudfront 1.3.0 -> 2.0.0--- remote
+++ compiled
label: Access logging
type: section
- default: true
- description: Enable CloudFront access logging. Logs are delivered to CloudWatch Logs by default and can be viewed in Ravion.
+ description: Enable CloudFront access logging. Select one or more destinations below; CloudWatch Logs can be viewed in Ravion.
id: logging_enabled
label: CloudFront access logging
type: boolean
- - default: cloudwatch
- description: Where CloudFront delivers access logs.
- id: logging_destination
- label: Logging destination
+ - default:
+ - cloudwatch
+ description: Select one or more destinations for CloudFront access logs. CloudWatch Logs keeps the Ravion Logs panel available; Firehose sends JSON records to an HTTP endpoint; S3 uses legacy standard logging.
+ id: logging_destinations
+ label: Logging destinations
+ moved_from:
+ - logging_destination
+ required: true
show_when:
logging_enabled: true
- type: string
+ type: string_array
values:
- description: View access logs directly in Ravion. Ingestion costs more at very high traffic.
label: CloudWatch Logs
@@
- description: Deliver compressed log files to an automatically created S3 bucket. Cheapest for high traffic.
label: S3 bucket
value: s3
+ - description: Stream selected JSON access-log fields to an HTTP endpoint through Amazon Data Firehose.
+ label: Firehose
+ value: firehose
+ - description: HTTPS URL for the Firehose HTTP endpoint. Applies when Firehose is selected in Logging destinations.
+ id: logging_firehose_endpoint_url
+ label: Firehose endpoint URL
+ placeholder: https://example.com/firehose
+ type: string
+ - description: Optional display name for the Firehose HTTP endpoint. Applies when Firehose is selected in Logging destinations.
+ id: logging_firehose_endpoint_name
+ label: Firehose endpoint name
+ type: string
+ - description: Secrets Manager ARN containing the Firehose HTTP endpoint access key. Required when Firehose is selected unless an access key is supplied through Advanced Terraform variables.
+ id: logging_firehose_access_key_secret_arn
+ label: Firehose access-key secret
+ type: string
+ - description: Optional KMS key ARN used to encrypt the Firehose HTTP endpoint access-key secret. Applies when Firehose is selected and the secret uses a customer-managed KMS key.
+ id: logging_firehose_access_key_secret_kms_key_arn
+ label: Firehose access-key secret KMS key
+ type: string
- default: 90
description: Days to retain CloudFront access logs in CloudWatch Logs or the automatically created S3 logging bucket.
id: logging_bucket_retention_days
@@
The default configuration is safe for dynamic apps: responses are cached at the edge only when your app returns Cache-Control headers, and the full viewer request, including the Host header, cookies, and query strings, is forwarded to the origin. You get TLS termination close to users, HTTP/2 and HTTP/3, connection reuse to the origin, optional WAF, and per-path caching for static assets.
- Terraform source: [ravionhq/modules/cdn/cloudfront](https://github.com/ravionhq/modules/tree/rvn-cloudfront@1.3.0/cdn/cloudfront)
+ Terraform source: [ravionhq/modules/cdn/cloudfront](https://github.com/ravionhq/modules/tree/rvn-cloudfront@2.0.0/cdn/cloudfront)
## Use cases
@@
## Access logging
- CloudFront access logging is on by default, delivered to CloudWatch Logs and viewable in Ravion. Choose where logs are delivered:
+ CloudFront access logging is on by default. Select any combination of destinations:
| Destination | How it works |
| --- | --- |
| CloudWatch Logs (default) | CloudFront standard logging v2 delivers access logs to a module-managed CloudWatch Logs group, and the module UI shows them in the Logs panel. Log ingestion costs more than S3 at very high traffic. |
| S3 bucket | Legacy standard logging delivers compressed log files to an automatically created S3 bucket. Cheapest for high-traffic sites; not viewable in Ravion. |
+ | Firehose | CloudFront standard logging v2 delivers selected fields as JSON through an Amazon Data Firehose HTTP endpoint. Firehose keeps failed deliveries in a module-managed S3 backup bucket. |
- Logging retention days defaults to 90 and controls the CloudWatch log group retention or the S3 bucket lifecycle expiry, depending on the destination. CloudWatch retention must be one of the standard CloudWatch Logs retention values (1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, and larger).
+ Firehose requires an HTTPS endpoint URL and a Secrets Manager ARN containing the endpoint access key. On upgrade from a 1.x definition, confirm the Logging destinations selection; a prior S3-only configuration must be selected as S3 again. Logging retention days defaults to 90 and controls the CloudWatch log group and module-managed S3 bucket lifecycle expiry. CloudWatch retention must be one of the standard CloudWatch Logs retention values (1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, and larger).
## Configuration
@@
| Custom cache behaviors | No | [] | Path-based caching and routing before the default behavior |
| Price class | No | All edge locations | Edge location coverage |
| Additional metrics | No | false | Enables all 8 CloudFront additional metrics and their flat CloudWatch cost |
- | CloudFront access logging | No | true | Delivers logs to CloudWatch Logs or S3 |
- | Logging destination | No | CloudWatch Logs | Visible when logging is enabled; CloudWatch shows logs in Ravion |
+ | CloudFront access logging | No | true | Enables access logging |
+ | Logging destinations | No | CloudWatch Logs | Select any combination of CloudWatch Logs, S3, and Firehose |
+ | Firehose endpoint URL | When Firehose is selected | None | HTTPS URL receiving JSON access-log records |
+ | Firehose endpoint name | No | None | Optional Firehose HTTP endpoint display name |
+ | Firehose access-key secret | When Firehose is selected | None | Secrets Manager ARN containing the HTTP endpoint access key |
| Tags | No | Standard Ravion tags | Additional tags merged with Ravion ownership tags |
| Advanced Terraform variables | No | {} | Raw lower-level overrides for exceptional cases |
@@
base_path: cdn/cloudfront
branch: main
execution_environment_id: << module.input.execution_environment_id >>
- ref: rvn-cloudfront@1.3.0
+ ref: rvn-cloudfront@2.0.0
repo: https://github.com/ravionhq/modules
stack_id: <<stack.id>>
terraform_variables:
@@
geo_restriction_locations: << module.input.geo_restriction_locations >>
geo_restriction_type: << module.input.geo_restriction_type >>
http_version: << module.input.http_version >>
- logging_bucket_creation_enabled: << module.input.logging_enabled && module.input.logging_destination == "s3" >>
+ logging_bucket_creation_enabled: << module.input.logging_enabled && len(module.input.logging_destinations || []) > 0 && (module.input.logging_destinations[0] == "s3" || (len(module.input.logging_destinations || []) > 1 && module.input.logging_destinations[1] == "s3") || (len(module.input.logging_destinations || []) > 2 && module.input.logging_destinations[2] == "s3")) >>
logging_bucket_domain_name: null
logging_bucket_retention_days: << module.input.logging_bucket_retention_days >>
- logging_destination: << module.input.logging_destination >>
+ logging_destinations: << module.input.logging_destinations || [] >>
logging_enabled: << module.input.logging_enabled >>
+ logging_firehose_access_key_secret_arn: << module.input.logging_firehose_access_key_secret_arn || nil >>
+ logging_firehose_access_key_secret_kms_key_arn: << module.input.logging_firehose_access_key_secret_kms_key_arn || nil >>
+ logging_firehose_endpoint_name: << module.input.logging_firehose_endpoint_name || nil >>
+ logging_firehose_endpoint_url: << module.input.logging_firehose_endpoint_url || nil >>
logging_prefix: ""
name: << module.input.name >>
ordered_cache_behaviors: '<< module.input.cache_behaviors != nil ? map(module.input.cache_behaviors, {"path_pattern": #.path_pattern, "target_origin_id": #.target_origin_id, "viewer_protocol_policy": #.viewer_protocol_policy, "allowed_methods": (#.allowed_methods == "all" ? ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] : #.allowed_methods == "read_options" ? ["GET", "HEAD", "OPTIONS"] : ["GET", "HEAD"]), "cache_policy_id": #.cache_policy_id, "origin_request_policy_id": (#.origin_request_policy_id || nil), "trusted_key_groups": (#.signed_urls_enabled ? #.trusted_key_group_ids : [])}) : [] >>'
@@
>>
logs: |-
<<
- module.input.logging_enabled && module.input.logging_destination == "cloudwatch" ?
+ module.input.logging_enabled && len(module.input.logging_destinations || []) > 0 &&
+ (module.input.logging_destinations[0] == "cloudwatch" ||
+ (len(module.input.logging_destinations || []) > 1 && module.input.logging_destinations[1] == "cloudwatch") ||
+ (len(module.input.logging_destinations || []) > 2 && module.input.logging_destinations[2] == "cloudwatch")) ?
[{"id": "cloudfront_access_logs", "name": "CloudFront access logs", "source": {"type": "cloudwatch", "aws_account_id": module.input.aws_account_id, "region": "us-east-1", "log_group": stack.output.access_log_group_name}}] :
[]
>> |
Co-Authored-By: brandon <brandon@flightcontrol.dev>
Co-Authored-By: brandon <brandon@flightcontrol.dev>
Co-Authored-By: brandon <brandon@flightcontrol.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CloudFront access logging was single-choice (
logging_destination = cloudwatch | s3). It's now a set, and a third destination — Amazon Data Firehose to an HTTP endpoint — is added, so a distribution can keep the CloudWatch delivery that powers the Ravion Logs panel and stream logs to an external consumer at the same time. Driving use case: shipping ravion.com access logs to Lightsage agent analytics, which needs edge-level visibility (cache hits and the Mintlify docs origin never reach our ECS origin, so origin-side tracking can't see them).The Firehose path is standard logging v2, not
aws_cloudfront_realtime_log_config— it reuses the existing vended-log delivery chain incloudwatch_access_logs.tf, which means no CloudFront per-line charge and one shared delivery source per distribution:Destination resolution, with the old input kept as a fallback so existing callers are untouched:
Notes worth flagging:
logging_firehose_record_fieldsdefaults to the nine fields agent-analytics consumers ask for. Standard logging v2 uses the parenthesized spellingscs(User-Agent)/cs(Referer)(the hyphenatedcs-user-agentform is real-time-logs only).LogDeliveryEnabled = "true"tag required for it to be a vended-log destination.logging_firehose_access_key_secret_arn, consumed via Firehose'ssecrets_manager_configuration); asensitiveplaintext variable exists as a fallback but is deliberately not exposed in the module definition form.logging_destination(single select) is replaced bylogging_destinations(multi-select,moved_from: [logging_destination]).moved_fromonly exempts the immutable-input check permodule-schema.json— it does not promise value conversion — so the release notes and docs tell upgraders to confirm their selection, since an S3-only 1.x instance landing on the["cloudwatch"]default would lose S3 delivery.Follow-up (not in this PR): point
website-cdninravionhq/flightcontrol'sravion.yamlat the released version and provision the Lightsage key.Testing
tofu fmt -check -recursive,tofu init -backend=false,tofu validate,tofu test -filter=tests/basic.tftest.hcl(77 passed), definition validation,make readme, andtools/ravion-modulesunit tests (83 passed). New tests cover cloudwatch+firehose together, invalid destination values, firehose missing its endpoint URL, firehose missing an access key, empty destination set, and the legacylogging_destinationfallback.Link to Devin session: https://app.devin.ai/sessions/0fdbe26b973c4c8699234df3b2956bec
Requested by: @flybayer
Greptile Summary
The PR expands CloudFront logging from one selected destination to concurrent CloudWatch, S3, and Firehose delivery.
Confidence Score: 3/5
The PR should not merge until Firehose resource-name collisions and customer-managed KMS secret access are addressed.
Distinct valid module names can resolve to identical globally scoped backup-bucket and IAM-role names, and the generated Firehose role cannot retrieve endpoint credentials encrypted under a customer-managed KMS key.
Files Needing Attention: cdn/cloudfront/firehose_access_logs.tf
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR CF[CloudFront distribution] --> SRC[Standard logging v2 source] SRC --> CW[CloudWatch Logs destination] SRC --> FH[Firehose delivery stream] FH --> HTTP[HTTP endpoint] FH -->|FailedDataOnly| S3[S3 backup bucket] CF -->|Legacy logging| LS3[S3 logging destination]Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Document CloudFront logging upgrade sele..." | Re-trigger Greptile