Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- name: Wait for wrangler dev to be ready
run: |
for i in $(seq 1 30); do
if curl -sf http://localhost:8787/logs/dev2026h1a/ct/v1/get-roots > /dev/null 2>&1; then
if curl -sf http://localhost:8787/logs/dev2026h2a/ct/v1/get-roots > /dev/null 2>&1; then
echo "wrangler dev is ready"
exit 0
fi
Expand All @@ -61,7 +61,7 @@ jobs:
run: cargo test -p integration_tests --test static_ct_api --verbose
env:
BASE_URL: http://localhost:8787
LOG_NAME: dev2026h1a
LOG_NAME: dev2026h2a

integration-tlog-mirror:
name: TLog Mirror Integration Tests
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ npx wrangler -e=dev dev &
# From workspace root:
cargo test -p integration_tests --test static_ct_api
# Override defaults:
BASE_URL=http://localhost:8787 LOG_NAME=dev2026h1a cargo test -p integration_tests --test static_ct_api
BASE_URL=http://localhost:8787 LOG_NAME=dev2026h2a cargo test -p integration_tests --test static_ct_api

# Worker deploy
npx wrangler -e=${ENV} deploy
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions crates/ct_worker/.dev.vars
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
SIGNING_KEY_dev2025h1a="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguu9K86g+++gKa7ag\ntkPw5E3xPhTeSkj69l0VL06EeQGhRANCAAQLOWnBI0PojH8rWoAoitlJ+Ip6iQl4\nWycheJdCWsXF2NzbOLM5aFMGpz3Bwm5egkGCzrLbhGW7z9p3FAI0N08o\n-----END PRIVATE KEY-----\n"
WITNESS_KEY_dev2025h1a="-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIHwiErJNKCNGZL+Osj+O8MqSMiwPP4kdcC4iTpojV9Od\n-----END PRIVATE KEY-----\n"
SIGNING_KEY_dev2025h2a="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgR2CdNf+JR6afd0gb\n+lMSINqCqiLDb7L88lo1qhxBynOhRANCAARLjKsvuNqvDER1Jasmnfm55/vz1Rgu\nZr8XTHtt8GlbYpac3nK4MTleB44Ap5YzdGnJwJkXbFEYCnaIcUJrg+2o\n-----END PRIVATE KEY-----\n"
WITNESS_KEY_dev2025h2a="-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEINKYH1WadDgPJEXYzLx0OWzNoi4hRcpUnYpoWrTc7BDO\n-----END PRIVATE KEY-----\n"
SIGNING_KEY_dev2026h1a="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgMcpVNLWTILGapBcQ\n0e59OCX+MC3ik6S/o3EzrBvISi2hRANCAATuqQUZCcCoG0yQWPiXy11zQwhUCNjw\nQb7fWqyzNGBZSgeDeUXB1+F1J3x6Nv9wb+PWj91XRYKN5zMpBwoZXrfz\n-----END PRIVATE KEY-----\n"
WITNESS_KEY_dev2026h1a="-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIGttRSMUB4BfaxIWodXTMiGqLnBMaNAmOdms0gVelXvn\n-----END PRIVATE KEY-----\n"
SIGNING_KEY_dev2026h2a="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgt14ClEtNlyhyy8IQ\njYA1gV0KH35xcHbaJ5g5tU7TbGqhRANCAAR1lWiAPxLrYQ5OjAWIwaYRDckh2+GD\nS2pyO25lj/lWJg94IY2MY/CaRbrIuWGUWjBRJczMjDBkajeaFC//dpG9\n-----END PRIVATE KEY-----\n"
WITNESS_KEY_dev2026h2a="-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIFBSB+nqtrOlOg5f3GiVYlt9Q1ni9s+ooqPBDyciEQzw\n-----END PRIVATE KEY-----\n"
SIGNING_KEY_dev2027h1a="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggM2mn5ZSIIMwO7XG\nn2t6qcJWBUCx2rO2F6nAdY6OdIahRANCAARQiB2uy0Xl37DU8SROPUaQugrkqwRI\nw3JFQfZql6u7y++P68b5mad7vQShq5Js0kZ0YPV6rRlVJ5elhe2NQ5Dp\n-----END PRIVATE KEY-----\n"
Expand Down
62 changes: 15 additions & 47 deletions crates/ct_worker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,6 @@ The Batcher receives requests (keeping them open) and groups the entries into ba

After persisting log state, the Sequencer returns sequenced entry metadata (7) to the Batcher, which in turn sends entry metadata to waiting Frontend requests and writes batch metadata to the deduplication cache in Workers KV. When the Frontend receives the response, it returns a Signed Certificate Timestamp (SCT) to the client (8).

## Test logs

Two prototype logs are available for testing, with configuration in `wrangler.jsonc` and `config.cftest.json` and roots from `roots.default.pem`.

curl -s https://static-ct.cloudflareresearch.com/logs/cftest2025h1a/metadata | jq
{
"description": "Cloudflare Research 'cftest2025h1a' log",
"log_type": "test",
"log_id": "7DSwkhPo35hYEZa4DVlPq6Pm/bG4aOw/kqhHvYd6z/k=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8LxK0sAKYODiZe9gDeak7agggQ0wvBOeEMSi7cLlFzcTlm1AexxsC04r/4rBIhf8liQqyRTrL3u1jpz6NJ4tLg==",
"witness_key": "MCowBQYDK2VwAyEAWTVSsOnsIYq+LZ6CUxgI8ONvJvE+YSF27N9BXZ02EP8=",
"mmd": 86400,
"submission_url": "https://static-ct.cloudflareresearch.com/logs/cftest2025h1a/",
"monitoring_url": "https://static-ct-public-cftest2025h1a.cloudflareresearch.com/",
"temporal_interval": {
"start_inclusive": "2025-01-01T00:00:00Z",
"end_exclusive": "2025-07-01T00:00:00Z"
}
}

curl -s https://static-ct.cloudflareresearch.com/logs/cftest2025h2a/metadata | jq
{
"description": "Cloudflare Research 'cftest2025h2a' log",
"log_type": "test",
"log_id": "2KJiliJSBM2181NJWC5O1mWiRRsPJ6i2iWE2s7n8Bwg=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYipauBOPEktPb0JVpkRQq6wtRDRIj8GmKYvzM0Lpw1oSh9Uis9khpPCH6xyrDstk019AHuCq19KT5f+/MkY/yA==",
"witness_key": "MCowBQYDK2VwAyEA8jhNnqw2LXtyjb0Os+R3eiKfxnsP8tnke5iZZ16nBbU=",
"mmd": 86400,
"submission_url": "https://static-ct.cloudflareresearch.com/logs/cftest2025h2a/",
"monitoring_url": "https://static-ct-public-cftest2025h2a.cloudflareresearch.com/",
"temporal_interval": {
"start_inclusive": "2025-07-01T00:00:00Z",
"end_exclusive": "2026-01-01T00:00:00Z"
}
}

## Deployment

### Local deployment
Expand All @@ -81,33 +45,37 @@ Follow these instructions to spin up a CT log on your local machine using the `d
prefix=$(head -n1 $file | grep -o "pre-")
cat $file | while (set -o pipefail; openssl x509 -outform DER 2>/dev/null | base64); do :; done |\
sed '/^$/d' | sed 's/.*/"&"/' | jq -sc '{"chain":.}' |\
curl -s "http://localhost:8787/logs/dev2025h1a/ct/v1/add-${prefix}chain" -d@- &
curl -s "http://localhost:8787/logs/dev2026h2a/ct/v1/add-${prefix}chain" -d@- &
done
rm -r $tmpdir
```

Checkpoints and other static data can also be retrieved through the worker (or directly from the R2 bucket):

curl -s "http://localhost:8787/logs/dev2025h1a/checkpoint"
curl -s "http://localhost:8787/logs/dev2026h2a/checkpoint"

Metadata necessary for writing to or consuming from logs is available at /metadata.json.

curl -s "http://localhost:8787/logs/dev2026h2a/metadata.json"

Metadata necessary for writing to or consuming from logs is available at /metadata.
The operator list is available at /operator-list.json.

curl -s "http://localhost:8787/logs/dev2025h1a/metadata"
curl -s "http://localhost:8787/operator-list.json"

Prometheus metrics are exposed _publicly_ at /metrics.

curl -s "http://localhost:8787/logs/dev2025h1a/metrics"
curl -s "http://localhost:8787/logs/dev2026h2a/metrics"

### Deployment to a workers.dev subdomain

Follow these instructions to deploy a CT log with the `dev` configuration to Cloudflare's network.

Run the following for each of the `dev2025h1a` and `dev2025h2a` log shards to configure resources (or use `scripts/create-log.sh`):
Run the following for each configured log shard to configure resources (or use `scripts/create-log.sh`):

1. Set log shard name and deployment environment. The [location hint][location-hint] is optional.

```bash
export LOG_NAME=dev2025h1a
export LOG_NAME=dev2026h2a
export CLOUDFLARE_ACCOUNT_ID=some-account-id-here
export ENV=dev
export LOCATION=wnam # optional
Expand Down Expand Up @@ -149,18 +117,18 @@ npx wrangler -e=${ENV} tail

### Deployment to a custom domain

Follow these instructions to deploy to a custom domain, suitable for running a public CT log. We'll use the `cftest` environment as an example, which was used to deploy the [test logs][#test-logs].
Follow these instructions to deploy to a custom domain, suitable for running a public CT log.

1. Create a new [deployment environment](https://developers.cloudflare.com/workers/wrangler/environments/) in `wrangler.jsonc` by copying or editing the existing `cftest` environment.
1. Create a new [deployment environment](https://developers.cloudflare.com/workers/wrangler/environments/) in `wrangler.jsonc`.

1. Create a file `config.${ENV}.json` with the configuration for the log shards.

1. (Optional) Create a file `roots.${ENV}.pem` with any custom accepted roots for the log shards, in PEM format. If `enable_ccadb_roots` is set to true, these roots are used in addition to roots auto-pulled from the CCADB list. If `enable_ccadb_roots` is set to false for any logs in the deployment, `roots.${ENV}.pem` is required to exist and contain at least one certificate. All logs shards deployed within the same Worker script use the same set of additional roots. Roots can be updated later, but roots should generally not be removed once added.

1. First set environment variables to specify the log shard name and deployment environment as below and then follow the [instructions above](#deployment-to-a-workersdev-subdomain) to create resources for each log shard.

export LOG_NAME=cftest2025h1a
export ENV=cftest
export LOG_NAME=example2027h1
export ENV=example

1. Configure R2 buckets via Cloudflare dashboard. The monitoring APIs are served directly from the bucket, so configure for public access with caching and compression.

Expand Down
14 changes: 6 additions & 8 deletions crates/ct_worker/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use chrono::Months;
use config::AppConfig;
use config::LogType;
use config::IntendedUse;
use std::env;
use std::fs;
use url::Url;
Expand All @@ -23,11 +23,11 @@ fn main() {
&& (3..R2_BUCKET_PREFIX_LEN).contains(&name.len()),
"invalid shard name '{name}'. Shard names only contain lowercase letters, numbers, and be between 3 and {R2_BUCKET_PREFIX_LEN} characters long."
);
if params.log_type != Some(LogType::Test) {
if params.intended_use == IntendedUse::Production {
// Chrome's CT policy (https://googlechrome.github.io/CertificateTransparency/log_policy.html) states:
// "The certificate expiry ranges for CT Logs must be no longer than one calendar year and should be no shorter than six months."
// "each log's expiry range should be between 3 and 12 months."
assert!(
(params.temporal_interval.start_inclusive + Months::new(6)
(params.temporal_interval.start_inclusive + Months::new(3)
..=params.temporal_interval.start_inclusive + Months::new(12))
.contains(&params.temporal_interval.end_exclusive),
"{name} invalid temporal interval: [{}, {})",
Expand All @@ -46,10 +46,8 @@ fn main() {
);
}

check_url(&params.submission_url);
if !params.monitoring_url.is_empty() {
check_url(&params.monitoring_url);
}
check_url(&params.submission_endpoint.url);
check_url(&params.monitoring_endpoint.url);
}

// Get and validate roots from an embedded roots file, which must exist if
Expand Down
33 changes: 0 additions & 33 deletions crates/ct_worker/config.cftest.json

This file was deleted.

77 changes: 36 additions & 41 deletions crates/ct_worker/config.dev.json
Original file line number Diff line number Diff line change
@@ -1,54 +1,41 @@
{
"logging_level": "info",
"operator_name": "Cloudflare",
"logs": {
"e2etestshard": {
"description": "e2e test shard",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/e2etestshard/",
"friendly_name": "e2e test shard",
"intended_use": "test",
"status": "active",
"status_timestamp": "2026-09-23T00:00:00Z",
"submission_endpoint": { "url": "http://localhost:8787/logs/e2etestshard/" },
"monitoring_endpoint": { "url": "http://localhost:8787/logs/e2etestshard/" },
"temporal_interval": {
"start_inclusive": "2026-01-01T00:00:00Z",
"end_exclusive": "2076-01-01T00:00:00Z"
},
"location_hint": "enam"
},
"dev2025h1a": {
"description": "Dev 2025h1a",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/dev2025h1a/",
"temporal_interval": {
"start_inclusive": "2025-01-01T00:00:00Z",
"end_exclusive": "2025-07-01T00:00:00Z"
},
"location_hint": "enam"
},
"dev2025h2a": {
"description": "Dev 2025h2a",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/dev2025h2a/",
"temporal_interval": {
"start_inclusive": "2025-07-01T00:00:00Z",
"end_exclusive": "2026-01-01T00:00:00Z"
},
"max_sequence_skips": 1,
"sequence_interval_millis": 750,
"sequence_skip_threshold_millis": 250,
"location_hint": "enam"
},
"dev2026h1a": {
"description": "Dev 2026h1a",
"log_type": "test",
"reject_expired": false,
"submission_url": "http://localhost:8787/logs/dev2026h1a/",
"readonlytest": {
"friendly_name": "read-only test shard",
"intended_use": "test",
"status": "readonly",
"status_timestamp": "2026-09-23T00:00:00Z",
"submission_endpoint": { "url": "http://localhost:8787/logs/readonlytest/" },
"monitoring_endpoint": { "url": "http://localhost:8787/logs/readonlytest/" },
"temporal_interval": {
"start_inclusive": "2026-01-01T00:00:00Z",
"end_exclusive": "2026-07-01T00:00:00Z"
"end_exclusive": "2076-01-01T00:00:00Z"
},
"location_hint": "enam"
},
"dev2026h2a": {
"description": "Dev 2026h2a",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/dev2026h2a/",
"friendly_name": "Dev 2026h2a",
"intended_use": "test",
"status": "active",
"status_timestamp": "2026-07-01T00:00:00Z",
"reject_expired": false,
"submission_endpoint": { "url": "http://localhost:8787/logs/dev2026h2a/" },
"monitoring_endpoint": { "url": "http://localhost:8787/logs/dev2026h2a/" },
"temporal_interval": {
"start_inclusive": "2026-07-01T00:00:00Z",
"end_exclusive": "2027-01-01T00:00:00Z"
Expand All @@ -59,19 +46,27 @@
"location_hint": "enam"
},
"dev2027h1a": {
"description": "Dev 2027h1a",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/dev2027h1a/",
"friendly_name": "Dev 2027h1a",
"intended_use": "test",
"status": "active",
"status_timestamp": "2026-09-23T00:00:00Z",
"submission_endpoint": { "url": "http://localhost:8787/logs/dev2027h1a/" },
"monitoring_endpoint": { "url": "http://localhost:8787/logs/dev2027h1a/" },
"include_in_operator_list": true,
"temporal_interval": {
"start_inclusive": "2027-01-01T00:00:00Z",
"end_exclusive": "2027-07-01T00:00:00Z"
},
"location_hint": "enam"
},
"dev2027h2a": {
"description": "Dev 2027h2a",
"log_type": "test",
"submission_url": "http://localhost:8787/logs/dev2027h2a/",
"friendly_name": "Dev 2027h2a",
"intended_use": "test",
"status": "active",
"status_timestamp": "2026-09-23T00:00:00Z",
"submission_endpoint": { "url": "http://localhost:8787/logs/dev2027h2a/" },
"monitoring_endpoint": { "url": "http://localhost:8787/logs/dev2027h2a/" },
"include_in_operator_list": true,
"temporal_interval": {
"start_inclusive": "2027-07-01T00:00:00Z",
"end_exclusive": "2028-01-01T00:00:00Z"
Expand Down
Loading
Loading