Skip to main content
CoreSDK
Deployment

Air-Gapped Deployments

Run CoreSDK with zero outbound connections — offline policy evaluation, local JWT validation, and manual artifact delivery for air-gapped and disconnected environments.

Air-Gapped Deployments

Phase 3. Air-gapped deployment mode (offline policy bundles, manual JWKS delivery, and disconnected license verification) ships Phase 3.

CoreSDK is designed for zero-trust environments where outbound internet access is restricted or prohibited. Every runtime decision — policy evaluation, JWT validation, license verification — happens locally. No request ever requires an outbound call to a CoreSDK service.

What runs locally

OperationHow
Policy evaluationRego engine (regorus) runs in-process; policy bundle loaded from local cache
JWT verificationJWK public keys cached locally; signature verified with ring crypto — no JWKS fetch per request
License verificationJWS token verified against embedded public key in the binary; no outbound check
Config / feature flagsLoaded from local file or HMAC-verified local cache
Audit logWritten to local sink (stdout, file, S3-compatible endpoint on your network)

Sidecar configuration for air-gapped mode

# coresdk-sidecar.yaml
control_plane:
  enabled: false          # disable all outbound sync

cache:
  policy_bundle_path: /etc/coresdk/policy-bundle.tar.gz
  config_path: /etc/coresdk/config.yaml
  jwks_path: /etc/coresdk/jwks.json

audit:
  sink: file
  file:
    path: /var/log/coresdk/audit.ndjson
    rotate_mb: 100

tls:
  mode: mtls
  ca_cert: /etc/coresdk/ca.crt
  server_cert: /etc/coresdk/server.crt
  server_key: /etc/coresdk/server.key

Set via environment variable:

CORESDK_CONTROL_PLANE_ENABLED=false \
CORESDK_POLICY_BUNDLE_PATH=/etc/coresdk/policy-bundle.tar.gz \
  coresdk-sidecar start

Delivering policy bundles

In a connected deployment, the sidecar pulls policy bundles from the control plane. In air-gapped mode, you push them manually using the CLI.

Build and sign a bundle

# Compile your Rego policies into a signed bundle
core policy bundle \
  --dir ./policies \
  --sign-key /etc/coresdk/signing-key.pem \
  --output policy-bundle.tar.gz

# Inspect the bundle before deploying
core policy bundle inspect policy-bundle.tar.gz
# → Bundle: policy-bundle.tar.gz
#   Policies: 6 (orders, reports, admin, tenant, config, data)
#   Signed: yes (ES256)
#   Created: 2026-03-19T12:00:00Z

Deploy to the sidecar

# Copy the bundle to each host
scp policy-bundle.tar.gz deploy@host1:/etc/coresdk/
scp policy-bundle.tar.gz deploy@host2:/etc/coresdk/

# Reload without restarting
core sidecar reload-policy --bundle /etc/coresdk/policy-bundle.tar.gz
# → Policy bundle loaded and verified. 6 policies active.

The sidecar verifies the bundle signature before loading. A tampered or unsigned bundle is rejected.

Automating bundle delivery via CI

#!/usr/bin/env bash
set -euo pipefail

# Build
core policy lint ./policies
core policy test ./policies --fixtures ./tests/policy-fixtures/ --ci
core policy bundle \
  --dir ./policies \
  --sign-key "$SIGNING_KEY_PEM" \
  --output dist/policy-bundle.tar.gz

# Push to your internal artifact registry
aws s3 cp dist/policy-bundle.tar.gz s3://internal-artifacts/coresdk/

# Notify hosts to pull and reload
ansible all -m shell -a \
  "aws s3 cp s3://internal-artifacts/coresdk/policy-bundle.tar.gz /etc/coresdk/ && \
   core sidecar reload-policy --bundle /etc/coresdk/policy-bundle.tar.gz"

Delivering JWKS

If your JWT issuer's JWKS endpoint is not reachable from the sidecar, pre-load the public keys:

# Download JWKS from your IdP (on a machine with internet access)
curl https://your-idp.example.com/.well-known/jwks.json -o jwks.json

# Transfer to air-gapped hosts
scp jwks.json deploy@host1:/etc/coresdk/
# coresdk-sidecar.yaml
auth:
  jwks_path: /etc/coresdk/jwks.json
  jwks_refresh: false   # disable automatic refresh attempts

When your IdP rotates keys, repeat the manual transfer. Set a reminder to rotate before the old key's exp or at your security team's key rotation schedule.

License tokens

CoreSDK license tokens are pre-signed JWS objects. They are verified against a public key embedded in the sidecar binary — no network call required.

# Deliver your license token (provided by CoreSDK)
cp coresdk-license.jwt /etc/coresdk/license.jwt
# coresdk-sidecar.yaml
license:
  token_path: /etc/coresdk/license.jwt

License tokens have a 1-year validity. CoreSDK logs a warning when fewer than 90 days remain. Renew by receiving a new JWS from CoreSDK and repeating the manual delivery.

Binary updates

In air-gapped mode, use the manual update channel:

# Download the new sidecar binary on a machine with internet access
curl -L https://releases.coresdk.io/sidecar/v1.5.0/coresdk-sidecar-linux-amd64 \
  -o coresdk-sidecar-v1.5.0

# Verify the signature
core verify binary coresdk-sidecar-v1.5.0 \
  --pubkey /etc/coresdk/release-signing-key.pub
# → Signature valid. Binary: coresdk-sidecar v1.5.0 (linux/amd64)

# Transfer and deploy
scp coresdk-sidecar-v1.5.0 deploy@host1:/usr/local/bin/coresdk-sidecar
ssh deploy@host1 "systemctl restart coresdk-sidecar"

Disable auto-update to prevent the sidecar from attempting to reach the update endpoint:

# coresdk-sidecar.yaml
auto_update:
  enabled: false
  channel: manual

Audit log export in air-gapped environments

Without cloud sink access, write audit logs to a local file and ship them via your existing log pipeline (Fluentd, Filebeat, etc.):

audit:
  sink: file
  file:
    path: /var/log/coresdk/audit.ndjson
    rotate_mb: 100
    compress: true      # gzip on rotation
    keep_rotated: 30    # keep 30 rotated files

Fluentd config to forward to an internal SIEM:

<source>
  @type tail
  path /var/log/coresdk/audit.ndjson
  pos_file /var/run/fluentd/coresdk-audit.pos
  tag coresdk.audit
  <parse>
    @type json
  </parse>
</source>

<match coresdk.audit>
  @type forward
  <server>
    host siem.internal
    port 24224
  </server>
</match>

Next steps

On this page