Skip to main content

Infrastructure targets

This page explains what an Infrastructure Target is in Proofarc, how it differs from the older Environment Target concept, and how the platform uses each.

If you've been running security scans (nmap, nuclei, trivy, ZAP) and want to understand the model behind the target you pick at scan time, this is the page for you.

The short version

Three things you need to know:

  1. An Infrastructure Target is a host, network, cluster, or registry — a real-world asset you scan. Top-level. Independent of any Project or Environment.
  2. An Environment Target is the way that asset is used inside an environment. Same host in dev/staging/prod = three environment targets, but they can all point at one Infrastructure Target.
  3. Findings are deduplicated at the Infrastructure level. When you scan a host across multiple environments, you don't end up with three disconnected sets of findings — they roll up to the canonical asset.

The model

┌──────────────────────────────────────────────────────────────┐
│ InfrastructureTarget (top-level, canonical) │
│ name "auth-host-prod" │
│ kind vm_host │
│ metadata {"ip":"10.0.1.5","hostname":"auth", │
│ "port":443} │
│ is_active true │
└──────────────────────────────────────────────────────────────┘

│ infrastructure_target_id (FK, nullable)

┌───────────────┴────────────────┐
│ EnvironmentTarget │
│ name "auth dev" │
│ target_type HOSTNAME │
│ host / ip auth.dev │
│ environment_id 1 (dev) │
└────────────────────────────────┘

One Infrastructure Target, N Environment Targets referencing it. The Environment Target can also stand alone (when it's a REST_SERVICE, WEB_APP, MOBILE_APP, or DATABASE — those aren't infra).

The four kinds

KindWhat it representsRequired metadataUsed by
vm_hostA single server, VM, or any host you can ssh / scan / curlip and/or hostname, optional portnmap, nikto, nuclei, ZAP
ip_rangeA subnet — 192.168.1.0/24 — for nmap-style sweepscidrnmap discovery, network mappers
k8s_clusterA Kubernetes API endpointapi_url, optional credential_tagtrivy-k8s, kube-bench
container_registryA Docker Hub / ECR / GCR / Harbor instanceregistry_url, optional credential_tag, optional registry_typetrivy image scans

The kind controls which metadata fields are required at save time and which scanners can target this row.

What you see in the UI

The Infrastructure Target registry. Each row is one canonical asset, showing kind, status, and a count of Environment Targets that link to it. The New Target button opens the wizard.

Environment Target detail (/environments/{id}/targets/{tid})

If the Environment Target points at infrastructure (target_type IP_ADDRESS, HOSTNAME, IP_RANGE, or NETWORK), there's a Linked Infrastructure Target chip linking back to its canonical row.

Scan templates that need infra

Scan templates with target_kind set (nmap, trivy-k8s, etc.) only accept Infrastructure Targets of matching kinds. You'll see a filtered dropdown when you set the target at scan time.

How existing data got here

When the Infrastructure Target registry shipped, the platform walked every existing Environment Target of type IP_ADDRESS, HOSTNAME, IP_RANGE, or NETWORK and either:

  1. Created a new Infrastructure Target with the same name, populating kind and metadata from the Environment Target's columns, or
  2. Reused an existing one with the same name (idempotent — re-running doesn't create duplicates).

Then set environment_targets.infrastructure_target_id to point at it. The original Environment Target row stays untouched; both rows coexist.

Application-shaped Environment Targets (REST_SERVICE, WEB_APP, MOBILE_APP) and DATABASE rows were not migrated — they aren't infrastructure, they're applications and data services.

Working with the API

List infrastructure targets

curl -s -H "Authorization: Bearer $TOKEN" \
"$URL/api/infrastructure/targets" | jq

Get the schema for each kind

curl -s -H "Authorization: Bearer $TOKEN" \
"$URL/api/infrastructure/kinds" | jq
{
"vm_host": {
"code": "vm_host",
"description": "Single server / VM",
"requiredFields": ["ip"],
"optionalFields": ["hostname", "port"]
},
"ip_range": {
"code": "ip_range",
"description": "CIDR range for network sweeps",
"requiredFields": ["cidr"],
"optionalFields": []
},
"k8s_cluster": {
"code": "k8s_cluster",
"description": "Kubernetes API endpoint",
"requiredFields": ["api_url"],
"optionalFields": ["credential_tag"]
},
"container_registry": {
"code": "container_registry",
"description": "Docker registry endpoint",
"requiredFields": ["registry_url"],
"optionalFields": ["credential_tag", "registry_type"]
}
}

Create a host

curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "auth-host-prod",
"kind": "vm_host",
"metadata": {"ip":"10.0.1.5","hostname":"auth","port":443}
}' "$URL/api/infrastructure/targets"

Create a subnet

curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "dmz-subnet",
"kind": "ip_range",
"metadata": {"cidr": "10.0.0.0/24"}
}' "$URL/api/infrastructure/targets"

Validation

The platform enforces the per-kind metadata schema. Trying to create an ip_range without cidr, or a vm_host with neither ip nor hostname, returns 400 with an inline error.

Why this matters for scanners

Today scanners reference Environment Targets. Once Phase E lands, they will follow the FK and dispatch against Infrastructure Targets instead. The user-visible effect:

  • One canonical set of findings per asset, instead of one per environment.
  • A K8s cluster scanned with trivy-k8s is named by its cluster row, not by which environment happened to be selected.
  • Container image scans target a Container Registry row directly.

Existing scans continue to work unchanged in the meantime — the Environment Target → Infrastructure Target link is purely additive.

Common questions

Q: Can the same Infrastructure Target be linked from multiple Environment Targets? Yes. That's the point. One auth-host-prod row, with dev/staging/prod Environment Targets all pointing at it.

Q: What if I rename a host? Rename the Infrastructure Target. Every Environment Target that links to it keeps working, because they reference it by FK id, not by name.

Q: Can I delete an Infrastructure Target? Yes, soft-delete (sets is_active = false). Environment Targets that reference it stay alive — their FK becomes a soft reference. To clean up properly, unlink the Environment Targets first or reassign them.

Q: What kind do I pick for a load balancer? vm_host — a load balancer IP plus port is just a host from the scanner's perspective. If you want to scan all backends behind the LB, that's an ip_range (CIDR) or multiple vm_host rows.