Files
qbit-cdn/docs/cloudfront-expected-config.md
james.maesandClaude Opus 5.5 ae2a9237d4 feat(cloudfront): CloudFront adapter (invalidations, test connection, edge stats, drift)
- CloudFrontCdnProvider: PATHS/ALL batches -> CreateInvalidation with the
  batch caller reference as CallerReference (idempotent), IN_PROGRESS with
  the invalidation id; checkPurge -> GetInvalidation. TAG/HOST batches are
  refused. Throttling, TooManyInvalidationsInProgress, 429/5xx and network
  failures are retryable; AccessDenied, InvalidArgument, NoSuchDistribution
  and other 4xx are permanent. No SDK-level retries.
- testConnection: GetDistributionConfig + ListInvalidations(MaxItems=1) to
  prove IAM scope, optional GetDistribution for domain/status, reports
  whether X-Origin-Verify is configured without reading out its value.
- importStats: CloudWatch GetMetricData (AWS/CloudFront, DistributionId +
  Region=Global, daily) into the new spi CdnEdgeStat.
- readConfig + CloudFrontDriftCheck.compare against the tofu
  expected_config output (docs/cloudfront-expected-config.md).
- Credentials: env vars <secretRef>_ACCESS_KEY_ID / _SECRET_ACCESS_KEY.
- Tests use a JDK HttpServer stub (WireMock cannot start: the QQQ BOM pins
  Jetty 12) with hand-built fixtures; CloudWatch (RPC v2 CBOR) is mocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:22:00 -05:00

73 lines
3.8 KiB
Markdown

# CloudFront `expected_config` (drift check input)
The OpenTofu root `terraform/cdn-cloudfront/` exports an output named
`expected_config`: a JSON object describing what the distribution should look
like. The qbit's "Check config drift" action reads the live distribution with
`GetDistributionConfig` (`CloudFrontCdnProvider.readConfig`) and compares it
with this JSON (`CloudFrontDriftCheck.compare`). Each difference becomes a
`CloudFrontDriftFinding(area, expected, actual)`.
**Every key is optional. A key that is absent is not checked.** Unknown keys
are ignored, so tofu can add informational fields such as `distribution_id`.
## Schema
| Key | Type | Compared with | Finding `area` |
|---|---|---|---|
| `enabled` | boolean | `DistributionConfig.Enabled` | `enabled` |
| `aliases` | string[] | alternate domain names, compared as a sorted set | `aliases` |
| `origin_domain` | string | domain name of the default behavior's origin | `origin.domain` |
| `origin_port` | number | that origin's HTTPS port (HTTP port when `http-only`) | `origin.port` |
| `origin_protocol_policy` | string | `https-only`, `http-only` or `match-viewer` | `origin.protocol` |
| `origin_header_names` | string[] | each name must be an origin custom header (case-insensitive). **Names only: header values are secrets and are never read or exported.** | `origin.header:<name>` |
| `behavior_paths` | string[] | ordered path patterns of the non-default cache behaviors. Missing, unexpected and reordered behaviors are all findings, because CloudFront matches behaviors in order. | `behavior:<path>`, `behavior_order` |
| `never_cache_paths` | string[] | each path must be a behavior whose cache policy is `caching_disabled_policy_id` | `never_cache:<path>` |
| `caching_disabled_policy_id` | string | the policy id required by `never_cache_paths`. Default: the AWS managed `CachingDisabled` policy, `4135ea2d-6df8-44a3-9df3-4b5a84be39ad`. | (none) |
| `price_class` | string | `PriceClass` | `price_class` |
| `http_version` | string | `HttpVersion` (`http2`, `http2and3`, ...) | `http_version` |
| `distribution_id` | string | not compared (informational) | (none) |
In findings, `actual` is `(missing)` when the live config has no such value.
For `origin.header:*` and `behavior:*` findings, `expected`/`actual` are
`present` / `absent` / `(missing)`.
## Example (kof22)
```json
{
"distribution_id": "E2EXAMPLE123",
"enabled": true,
"aliases": ["kof22.com", "www.kof22.com", "api.kof22.com", "s3.kof22.com"],
"origin_domain": "origin.kof22.com",
"origin_port": 8443,
"origin_protocol_policy": "https-only",
"origin_header_names": ["X-Origin-Verify"],
"behavior_paths": ["/_next/static/*", "/_next/image*", "/kof22-website-files/*", "/api/*", "/preview*", "/v1/me*", "/v1/contact*", "/oauth/*"],
"never_cache_paths": ["/api/*", "/preview*", "/v1/me*", "/v1/contact*", "/oauth/*"],
"price_class": "PriceClass_All",
"http_version": "http2and3"
}
```
A sketch of the tofu output:
```hcl
output "expected_config" {
value = jsonencode({
distribution_id = aws_cloudfront_distribution.kof22.id
enabled = aws_cloudfront_distribution.kof22.enabled
aliases = sort(tolist(aws_cloudfront_distribution.kof22.aliases))
origin_domain = "origin.kof22.com"
origin_port = 8443
origin_protocol_policy = "https-only"
origin_header_names = ["X-Origin-Verify"]
behavior_paths = [for b in aws_cloudfront_distribution.kof22.ordered_cache_behavior : b.path_pattern]
never_cache_paths = local.never_cache_paths
price_class = aws_cloudfront_distribution.kof22.price_class
http_version = aws_cloudfront_distribution.kof22.http_version
})
}
```
The output must never include the origin header **value**.