- Home
- Traffic Generator
- Integrate
Integrate
Deployment Boundaries
Section titled “Deployment Boundaries”The repository supports two parallel deployments:
- Azure
terraform/: the existing public VM, SSH workflow, broad suite catalog, and Azure-shaped outputs remain supported. - AWS
terraform/aws/: a public-subnet EC2 worker for the canonicalcsd-violationsbrowser suite, with jumpbox-restricted SSH and Systems Manager recovery.
Each root owns independent state and resources. Never copy state, plans, variable files, output assumptions, or destroy commands between them.
AWS Client-Side Defense Integration
Section titled “AWS Client-Side Defense Integration”GitHub jumpbox -> restricted SSH /32 -> Elastic IP -> public AWS worker | +-> F5 XC HTTP LB -> AWS Juice Shop origin +-> SSM recovery and constrained runs +-> encrypted S3 evidence +-> encrypted CloudWatch logsThe AWS worker targets the exact authorized URL https://client-side-defense.f5-sales-demo.com. It runs headed Chrome under Xvfb without exposing Chrome DevTools. Terraform assigns an explicit Elastic IP while keeping associate_public_ip_address = false, and permits TCP/22 only from the revalidated operator_ssh_cidr. The private SSH key remains outside Terraform state.
After applying the independently reviewed AWS saved plan, use these exact non-sensitive Terraform outputs:
| Output | Integration use |
|---|---|
instance_id | Target for Systems Manager Run Command and status inspection |
public_ip | Explicit worker Elastic IP |
ssh_command | Ubuntu SSH command with the operator key-path hint |
ssm_document_name | Submit one of the 11 stable scenario names through Scenario |
evidence_bucket_name | Retrieve private screenshots, receipt.json, and SHA256SUMS |
runtime_log_group_name | Diagnose sanitized bootstrap and worker status |
public_subnet_id | Confirm the worker’s public-subnet placement |
worker_security_group_id | Confirm TCP/22 is restricted to the current jumpbox /32 |
target_url | Verify the exact authorized browser target |
source_commit | Verify immutable runtime provenance |
termination_protection_enabled | Confirm the destroy safeguard remains enabled |
Use only the AWS outputs from terraform/aws; do not substitute Azure state or output values.
CSD Observation Boundary
Section titled “CSD Observation Boundary”The browser receipt records immediate execution evidence: run, scenario, and step timestamps;
assertion checks; terminal network states; screenshot capture status, relative path, intended
object key, pending upload status, SHA-256, and masked-input count; CSD sensor and
__imp_apg__/api/dip request counts; and cleanup status. The worker creates SHA256SUMS before
upload. Upload success is represented by the Systems Manager command result, not by a rewritten
receipt field. A separate read-only F5 Distributed Cloud observation may correlate telemetry by
protected host and run window.
That correlation is not proof of causation. AWS datacenter reputation, browser automation signals, population thresholds, aggregation, and filtering can prevent or delay detection. Report only the observed status—OBSERVED, NOT_OBSERVED, PENDING, or ERROR—and never promise a detection, fixed delay, or risk classification.
Operator-side post-receipt correlation
Section titled “Operator-side post-receipt correlation”Perform correlation only after retrieving and validating the exact committed S3 prefix. The authoritative
upload-commit.json must exist at that prefix, name that exact prefix in its objectKey, record
status: committed, and contain SHA-256 digests that match the retrieved upload-manifest.json and
SHA256SUMS. Then validate SHA256SUMS, read receipt.json, and record runId, target.host,
startedAt, and completedAt. Build the host comparison allowlist only from that receipt: the protected
target.host and hosts in sanitized browser network outcomes that were actually observed. Use this exact
host allowlist only for detected_domains and scripts. The receipt stores no generated form-field
identifiers, so formFields is an optional aggregate observation for the receipt time window only. Do not
attribute its records to a generated field or infer a field name from a scenario name or synthetic value.
Retrieve one exact run/scenario prefix and fail closed before correlation:
set -euo pipefail
export AWS_PROFILE=280469140135_Usersexport AWS_REGION=us-east-1EVIDENCE_BUCKET='<terraform-output-evidence_bucket_name>'RUN_ID='<receipt-run-id>'SCENARIO='<allowlisted-scenario>'PREFIX="runs/${RUN_ID}/${SCENARIO}"WORK_DIR=$(mktemp -d)trap 'rm -rf "${WORK_DIR}"' EXIT
aws s3 cp "s3://${EVIDENCE_BUCKET}/${PREFIX}/upload-commit.json" "${WORK_DIR}/upload-commit.json"jq -e --arg object_key "${PREFIX}/upload-commit.json" \ '.status == "committed" and .objectKey == $object_key' \ "${WORK_DIR}/upload-commit.json" >/dev/null
aws s3 cp "s3://${EVIDENCE_BUCKET}/${PREFIX}/" "${WORK_DIR}/" --recursivejq -e --arg object_key "${PREFIX}/upload-commit.json" \ '.status == "committed" and .objectKey == $object_key' \ "${WORK_DIR}/upload-commit.json" >/dev/null
test "$(shasum -a 256 "${WORK_DIR}/upload-manifest.json" | awk '{print $1}')" = \ "$(jq -r '.uploadManifest.sha256' "${WORK_DIR}/upload-commit.json")"test "$(shasum -a 256 "${WORK_DIR}/SHA256SUMS" | awk '{print $1}')" = \ "$(jq -r '.checksumSet.sha256' "${WORK_DIR}/upload-commit.json")"( cd "${WORK_DIR}" shasum -a 256 -c SHA256SUMS)
START_TIME=$(jq -r '.startedAt | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601' "${WORK_DIR}/receipt.json")END_TIME=$(jq -r '.completedAt | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601' "${WORK_DIR}/receipt.json")test "${START_TIME}" -le "${END_TIME}"Run the following requests from an authenticated operator context with the supported xcsh_api tool. These blocks describe tool inputs; they are not shell commands. Replace the placeholders with the validated receipt values, epoch-second variables, and intended F5 Distributed Cloud namespace.
method: GETpath: /api/shape/csd/namespaces/{namespace}/detected_domainsparams: namespace: <namespace>method: POSTpath: /api/shape/csd/namespaces/{namespace}/scriptsparams: namespace: <namespace>payload: start_time: <START_TIME> end_time: <END_TIME>method: GETpath: /api/shape/csd/namespaces/{namespace}/formFieldsparams: namespace: <namespace> start_time: <START_TIME> end_time: <END_TIME>Response schemas can differ across these endpoints. Treat arrays nested beneath response objects as
candidate records. For detected_domains and scripts, count evidence only when a candidate’s
normalized host/domain exactly matches the receipt-derived host allowlist. For formFields, record
only the aggregate record count and endpoint classification for the receipt time window; never record
or claim a match to a specific generated field identifier. Preserve the raw operator response in the
separately controlled correlation record; do not copy it into or rewrite receipt.json.
Normalize one status for each endpoint:
| Status | Deterministic meaning |
|---|---|
OBSERVED | detected_domains or scripts succeeded and returned at least one exact receipt-derived host match; or formFields succeeded and returned a non-zero aggregate count for the receipt window. |
NOT_OBSERVED | detected_domains or scripts succeeded, no reviewed host matched, and the operator explicitly closed the observation review as final. This is absence in the queried response, not proof that detection cannot occur later. Do not use this status for formFields. |
PENDING | detected_domains or scripts succeeded with no host match while review remains open or processing is incomplete; or formFields succeeded with a zero aggregate count or incomplete processing. No fixed waiting period is implied. |
ERROR | The request failed, returned a non-success status, or could not be interpreted without guessing its schema. |
For a successful formFields response, classification is therefore only OBSERVED or PENDING; transport or uninterpretable-schema failures remain ERROR.
Record a separate correlation table; one row per endpoint and observation attempt:
| Run ID | Receipt window (UTC) | Endpoint | Reviewed comparison keys | Status | Observed result | Observation time (UTC) | Error/notes |
|---|---|---|---|---|---|---|---|
<runId> | <startedAt>–<completedAt> | detected_domains or scripts | Exact receipt-derived hosts | OBSERVED / NOT_OBSERVED / PENDING / ERROR | Returned non-secret host/domain identifiers only | Operator query time | Schema/transport detail without credentials |
<runId> | <startedAt>–<completedAt> | formFields | Aggregate receipt-window observation only | OBSERVED / PENDING / ERROR | Count and endpoint classification only | Operator query time | Schema/transport detail without credentials |
Complete the checklist deterministically:
- Retrieve
upload-commit.jsonfrom the exact run/scenario prefix and requirestatus: committedplus its exact expectedobjectKey. - Validate its
upload-manifest.jsonandSHA256SUMSdigests, then validate every object inSHA256SUMSand freeze the browser receipt as execution evidence. - Convert the receipt UTC timestamps to epoch seconds and extract the reviewed host allowlist from the receipt only.
- Submit all three operator-side requests with the exact namespace and epoch-second receipt window where specified.
- Compare exact normalized hosts for
detected_domainsandscripts; ignore all unrelated records. ForformFields, record only aggregate count and classification without field attribution. - Assign statuses using the deterministic endpoint-specific rules above and preserve errors rather than converting them to absence.
- Store the correlation table separately. Never change the browser scenario status, counts, receipt, or checksum set based on tenant telemetry.
Azure Integration
Section titled “Azure Integration”The Azure deployment continues to target an F5 Distributed Cloud HTTP load balancer through TARGET_FQDN; TARGET_ORIGIN_IP remains an optional direct-origin baseline.
Azure Traffic Generator -> F5 XC HTTP LB -> Azure Origin Server | | +-> SSH runner +-> WAF / Bot / API / CSD policiesThe origin server supplies the application paths used by the existing Azure suites, including Juice Shop, DVWA, VAmPI, crAPI, DVGA, Restaurant API, and the CSD demo. Configure the Azure runner in /opt/traffic-generator/config.env:
TARGET_FQDN=demo.example.comTARGET_ORIGIN_IP=20.10.5.100Run the existing Azure suites over SSH as documented in Runner. Direct-origin comparison is optional and valid only when the origin owner has authorized it. A script exit count is execution evidence, not proof that an attack succeeded or a security control detected it; verify application and F5 Distributed Cloud telemetry independently.
Deployment Order
Section titled “Deployment Order”- Deploy the chosen origin and verify application health.
- Configure the F5 Distributed Cloud origin pool and HTTP load balancer.
- Enable and verify the security capability required by the selected demo.
- Deploy one traffic-generator root—Azure or AWS—with its own state.
- Verify the runner access paths: source-restricted SSH and Systems Manager recovery for AWS, or SSH for Azure.
- Execute
csd-violationson AWS, or an applicable shell suite on Azure, and preserve its evidence outside Git. - Correlate platform telemetry only after browser or shell execution is proven.
The origin, F5 Distributed Cloud configuration, Azure traffic generator, and AWS traffic generator may have separate owners and state. Teardown one component only from its owning configuration; never use one state to delete another component’s resources.