‹ NativeCAD for defense

GovCloud reference deployment

NativeCAD in your own AWS GovCloud (US) account, inside a VPC that has no route to the internet. This guide is for the admin who stands it up. It builds on the air-gap deployment guide: the kernel and the MCP server are pure JavaScript with no native dependencies, and nothing in them phones home. This page adds one container image, one CloudFormation stack, and the steps that connect the two.

What you get:

The no-egress contract

node deploy/govcloud/validate.js checks each of these properties by name. It needs no AWS account and no network, and CI runs it on every push:

propertyhow the stack enforces it
no route out of the VPCno internet gateway, NAT gateway, egress-only IGW, Elastic IP, VPN/Transit Gateway attachment or peering. The route table has no routes beyond the implicit local route and the S3 gateway endpoint's prefix-list route.
AWS APIs over private endpoints onlyVPC endpoints are exactly bedrock-runtime-fips, ecr.api, ecr.dkr, logs (interface, private DNS) and s3 (gateway). The S3 endpoint policy allows only GetObject on the regional ECR layer bucket.
nothing publicsubnets never assign public IPs, tasks run with AssignPublicIp: DISABLED, and the load balancer scheme is internal
encrypted at restone customer-managed KMS key with rotation on. It encrypts EFS /workspace, both log groups and the trail bucket (SSE-KMS). EFS also enforces TLS in transit.
least privilegethe root filesystem is read-only, the user is non-root, all Linux capabilities are dropped, and ECS Exec is off. The task role can only mount its own EFS access point, because the application makes no AWS API calls.
auditedCloudTrail is on, multi-region, with log-file validation and KMS encryption. VPC flow logs capture ALL traffic, which gives your assessor direct evidence that nothing leaves.

The image adds its own guarantees on top. Telemetry is off, set explicitly by DO_NOT_TRACK=1 and CADSOLVER_TELEMETRY=off. CADSOLVER_MCP_SHARE_OFFLINE=1 makes a confirmed share write its bundle locally instead of opening a socket. The modeler is served with a Content-Security-Policy of connect-src 'self', so the page in the user's browser cannot call out either.

Sandbox mode

The image sets NATIVECAD_SANDBOX=1, so the MCP server starts in sandbox mode. The VPC above stops traffic at the network. Sandbox mode stops it in the process, and records what the agent did. It is built for ITAR and CUI data, and it does three things.

1. The workspace jail. Every file path a tool is given is checked before the tool runs. That covers cad_import, cad_save, cad_export_body, drawing, print and slice outputs, FEA case directories, cad_configure's outputDirectory, and paths nested inside cad_batch. The path is resolved first: relative paths against the output directory and the working directory, ~ against home, and every symlink on the way, dangling ones included. A path that lands outside NATIVECAD_WORKSPACE (/workspace here) is refused with reason code SANDBOX_PATH, and the file is never opened. The audit directory itself is also off limits to tools.

2. No egress, from inside the process. The server replaces Node's network entry points before any module loads: http, https, net, tls, dgram, dns, fetch and WebSocket. Spawning a network tool (curl, wget, ssh, git, npm and the like) is refused too. Any attempt throws with reason code SANDBOX_EGRESS. Worker threads and child Node processes inherit the same guard. Sandbox mode also forces these switches, whatever the environment says:

switchforced towhat it stops
NATIVECAD_AUTO_UPDATEoffupdate checks and revocation-list downloads
CADSOLVER_TELEMETRY, DO_NOT_TRACKoff, 1usage telemetry and corpus capture
CADSOLVER_MCP_SHARE_OFFLINE1eval sharing (a local bundle only)
CADSOLVER_REVOKED_FILENATIVECAD_REVOCATION_FILE, else /workspace/revoked.jsonlicence revocation is read from a file you place, never fetched

cad_configure cannot switch telemetry, capture or auto-update back on. Tools that only make sense with a network or an outside toolchain are refused with SANDBOX_UNAVAILABLE: cad_report_bug, cad_quote_submit, cad_eval_share, cad_contest, cad_print, cad_print_status, cad_picogk, cad_rtl and cad_synth. cad_server_info lists each one with its reason under sandbox.unavailable. It also counts refused egress attempts and names the audit file.

3. The audit log. Every tool call, refusals included, is appended to /workspace/audit/audit-<UTC time>-<pid>-<id>.jsonl. Each server process gets its own file, so two tasks sharing the EFS volume never interleave. One line holds:

Each line carries the hash of the line before it. Verify a log with:

node tools/audit_verify.js /workspace/audit                 # exit 0 = every chain intact
node tools/audit_verify.js /workspace/audit --require-sealed # also fail an unsealed file

If a line is edited, inserted, removed or moved, verification fails and names the first broken line. A cleanly stopped server seals its file with a session-end line. A hash chain cannot prove that a whole file was not deleted, so ship /workspace/audit/ to WORM storage (CloudWatch Logs, or S3 with Object Lock) on a schedule. If the server cannot write an audit line, it refuses every later call with SANDBOX_AUDIT rather than run unaudited. The mcp-mode health probe writes to /workspace/audit/healthcheck/, so probes do not bury session logs. NATIVECAD_AUDIT_DIR moves the log, but only within the workspace.

To turn sandbox mode off for a non-CUI deployment, use -e NATIVECAD_SANDBOX=0. To turn it on anywhere else, use nativecad-mcp --sandbox --workspace <dir>, or set NATIVECAD_SANDBOX=1 and NATIVECAD_WORKSPACE. A server asked for sandbox mode with no workspace refuses to start.

Steps for your admin

Steps 1 and 2 run on a connected build host. Everything after that runs inside your boundary.

  1. Build the image. Run this from the repo root:
   docker build -f deploy/container/Dockerfile -t nativecad:govcloud .

The base is Red Hat UBI 9 nodejs-22-minimal, pinned by digest. UBI is freely redistributable and FIPS-capable: RHEL 9's OpenSSL is the FIPS 140-3 validated module, so on a FIPS-mode host crypto.getFips() reports 1 with no image change. To use an Iron Bank Node image instead, pass --build-arg BASE_IMAGE=registry1.dso.mil/ironbank/opensource/nodejs/nodejs22:<tag>@sha256:<digest>.

If the build host sits behind a TLS-inspecting proxy or uses an internal npm mirror, add any of these: --build-arg HTTPS_PROXY=…, --build-arg NPM_CONFIG_REGISTRY=https://nexus.example/npm/, --secret id=build_ca,src=corp-ca.pem. The CA is mounted for one build step and is never written into a layer.

  1. Prove it offline before it crosses. Run the container acceptance test. It runs the network-off session and the offline stack validation. Then scan the image with your own tooling and record its digest with docker inspect --format '{{index .RepoDigests 0}}'.
  2. Push it to a private ECR repository in your GovCloud account. Use your usual transfer path, for example docker save → media → docker load → docker push. The stack only pulls from ECR, through the VPC endpoint.
  3. Create the stack.
   aws cloudformation deploy --region us-gov-west-1 \
     --stack-name nativecad \
     --template-file deploy/govcloud/nativecad-govcloud.template.json \
     --capabilities CAPABILITY_IAM \
     --parameter-overrides \
       ImageUri=<acct>.dkr.ecr.us-gov-west-1.amazonaws.com/nativecad@sha256:<digest> \
       ClientCidr=<your enclave/VDI range> \
       CertificateArn=<ACM cert ARN for the internal ALB> \
       S3PrefixListId=<pl-… from: aws ec2 describe-managed-prefix-lists --filters Name=prefix-list-name,Values=com.amazonaws.us-gov-west-1.s3>

Two parameters you can set to fit your account. CreateCloudTrail=false skips the trail when your account already has an organization trail. ExpectedRegion=us-gov-east-1 targets the other GovCloud region.

  1. Connect your network to the VPC through your own Transit Gateway, Direct Connect or VPN attachment, so users in ClientCidr can reach the load balancer. The stack deliberately creates none of these. They belong to your boundary, not to this stack.
  2. Open the modeler at the ModelerUrl stack output.
  3. Run agent (MCP) sessions. The MCP server speaks stdio and has no port. Pick one of two patterns:
  4. Licence: set CADSOLVER_LICENSE_KEY, either as an ECS task environment value or from your secrets store. It is validated locally, with no licence server. See the licensing section of the air-gap deployment guide.

Updates: build a new image, run step 2 again, push it, then redeploy the stack with the new ImageUri digest. The service's deployment circuit breaker rolls back automatically if the new task fails its health check.

Model inside the boundary

A sandboxed CAD server is half the boundary. For CUI work the agent's model calls must stay in GovCloud too. The research behind this section, with dates and citations, is in our model-boundary research notes (checked 2026-10-11). Short version:

Agent host configuration (Claude Code or an Agent SDK host on an instance or task inside the VPC). Pin every model: unpinned, Claude Code defaults to Opus 5.5 and a Sonnet 4.5 background model, and Sonnet 4.5 is not in GovCloud.

export CLAUDE_CODE_USE_BEDROCK=1
export AWS_REGION=us-gov-west-1
export AWS_USE_FIPS_ENDPOINT=true
export ANTHROPIC_BEDROCK_BASE_URL=https://bedrock-runtime-fips.us-gov-west-1.amazonaws.com
export ANTHROPIC_MODEL=us-gov.anthropic.claude-sonnet-5-5
export ANTHROPIC_DEFAULT_SONNET_MODEL=us-gov.anthropic.claude-sonnet-5-5
export ANTHROPIC_DEFAULT_OPUS_MODEL=us-gov.anthropic.claude-opus-5-5
export ANTHROPIC_DEFAULT_HAIKU_MODEL=us-gov.anthropic.claude-sonnet-5-5   # keep background tasks on a model that exists in GovCloud
export DISABLE_TELEMETRY=1 DISABLE_ERROR_REPORTING=1 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 DISABLE_AUTOUPDATER=1

Verify the IDs your account can call before rollout: aws bedrock list-inference-profiles --region us-gov-west-1, then /status in Claude Code to confirm the provider and region.

What your ATO / boundary owns

The stack is a reference. It is designed to drop into an accredited boundary, and it does not replace that accreditation. Here is the split. For a requirement-by-requirement version against NIST SP 800-171 and CMMC Level 2, see the CMMC responsibility map. A CycloneDX SBOM for the bundle is in deploy/sbom/.

NativeCAD providesyour ATO / boundary owns
the image, its SBOM-able dependency closure (3 npm packages plus the staged kernel; see kernel/BUILD_INFO.json), and the Dockerfile that builds itthe image scan, approval and the registry it lives in
a stack that has no egress path and validates offlinethe AWS account, its SCPs, IAM boundaries and the GovCloud account itself
an internal load balancer with an optional FIPS TLS policy (ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04)the ACM certificate, DNS and the PKI behind it; user authentication in front of the modeler (your IdP, VDI or reverse proxy)
a VPC with no route outthe connectivity INTO it: Transit Gateway, Direct Connect or VPN, and the ClientCidr value
a KMS key, encrypted EFS, logs and trailkey administration policy, log retention beyond LogRetentionDays, SIEM forwarding and backup verification
CloudTrail and VPC flow logs switched oncontinuous monitoring, incident response and the SSP/POA&M entries
telemetry and sharing switched off in the imageyour policy on what users may export, and the media-transfer process for anything that crosses
sandbox mode: a workspace jail, an in-process egress block, and a hash-chained audit log with a verifiershipping /workspace/audit/ to WORM storage, reviewing it, and placing a current signed revoked.json on each media transfer

Files

pathwhat it is
deploy/container/Dockerfilethe one image: MCP stdio (mcp, the default) and the browser modeler (web)
deploy/container/Dockerfile.dockerignorebuild-context list. It starts from the air-gap list and keeps only the modeler's files from web/.
deploy/container/entrypoint.jsmode switch, workspace setup and the healthcheck
deploy/container/serve-modeler.jsstatic server for the modeler: GET/HEAD only, /healthz, CSP and a path-traversal guard
deploy/govcloud/nativecad-govcloud.template.jsonthe CloudFormation stack
deploy/sbom/nativecad-mcp-<version>.cdx.jsonthe CycloneDX SBOM for the staged MCP bundle, written by tools/sbom_cyclonedx.js
deploy/govcloud/validate.jsthe offline validator: structural checks, the no-egress contract, and cfn-lint when it is installed
the container acceptance testthe proof: an image build, a network-off MCP session, the modeler, and the stack validation
packages/mcp/src/sandbox/sandbox mode: the jail and gate (index.js), the egress guard (egress.js, preloaded by preload.js) and the audit chain (audit.js)
tools/audit_verify.jsverifies the audit hash chains
the sandbox acceptance testthe proof for sandbox mode: path escapes, egress attempts, inert bug-intake and update paths, and audit verification with tampering

Why CloudFormation and not Terraform: the repo had no infrastructure code before this. A CloudFormation template validates fully offline with cfn-lint. Terraform's validate needs terraform init to download the AWS provider first, which is awkward on a disconnected admin host. GovCloud supports CloudFormation natively.

Want this running inside your boundary? We will walk your team through the deployment and the map.

Talk to sales: sales@featureboard.ai