Skip to content

Run Appliance


title: “Run Appliance” description: “Appliance Run information.” lead: “The appliance will need specific configuration variables to be set in order to run.” date: 2020-10-13T15:21:01+02:00 lastmod: 2026-08-04T00:00:00+00:00 draft: false images: [] menu: docs: parent: “how-to” weight: 203 toc: true

Section titled “title: “Run Appliance” description: “Appliance Run information.” lead: “The appliance will need specific configuration variables to be set in order to run.” date: 2020-10-13T15:21:01+02:00 lastmod: 2026-08-04T00:00:00+00:00 draft: false images: [] menu: docs: parent: “how-to” weight: 203 toc: true”

TAM can be deployed in three runtime variants. Each variant supports both online and offline policy loading modes.

Variant Description Typical use
Docker appliance Container image with HTTP REST API Kubernetes, ECS, Docker Compose, local dev
Embedded TAM Native shared library (CGO) In-process policy evaluation in Python, Java, C#
AWS Lambda Extension Lambda layer with local decision server Serverless authorization in Lambda functions

For FedRAMP and restricted-network deployments, see the dedicated FedRAMP guide.

Within the Docker appliance variant, you can integrate TAM in two ways:

  • REST API — your application calls the appliance decision API directly.
  • Envoy Authorization Filter — Envoy forwards requests to the appliance for external authorization decisions.

Additionally, you can run the Docker appliance as a container, ECS sidecar, or as part of a service mesh. Example configurations are provided below.

The appliance loads policy bundles in one of two modes, controlled by the OFFLINE_MODE environment variable.

Behavior Online (default) Offline (OFFLINE_MODE=true)
Bundle source TAM Command & Control (C&C) server Local file, s3:// URI, or HTTPS URL via BUNDLE_PATH
TAM C&C contact Yes — registration, bundle polling, status reporting No — no registration or status reporting
Bundle updates Automatic polling from C&C (60–120s) Manual upload to S3/local path, or OPA S3 polling
Remote data cache Received from C&C registration OFFLINE_CACHE_FILE or OFFLINE_CACHE_CONFIG
Trimble Identity Required for request validation Required for request validation
Reporting to TAM Enabled Disabled when OFFLINE_MODE=true

In online mode (the default), the appliance registers with the TAM C&C server, downloads policy bundles automatically, and reports status. This is the standard mode for Stage and Prod deployments with network access to TAM.

Required variables: ENVIRONMENT, CLIENT_ID, CLIENT_SECRET, API_PORT.

In offline mode, the appliance loads policy bundles from BUNDLE_PATH and does not contact TAM servers. Use this for FedRAMP, air-gapped, or restricted-network environments.

Required variables: all online variables plus OFFLINE_MODE=true and BUNDLE_PATH.

BUNDLE_PATH supports three forms:

Form Example Behavior
Local file /offline/bundle.tar.gz Loaded at startup; updates require file replacement and restart
S3 URI s3://bucket/policies/bundle.tar.gz OPA polls S3 for updates (60–120s interval)
HTTPS URL https://bucket.s3.amazonaws.com/bundle.tar.gz Downloaded to a temporary local file at startup

BUNDLE_PATH must point to a .tar.gz file. If the path is missing or invalid and OFFLINE_MODE=true, the appliance will not become ready.

For remote data in offline mode, provide cache configuration via OFFLINE_CACHE_FILE (local path or s3:// URI) or inline OFFLINE_CACHE_CONFIG JSON. See Remote Data for details.

When data.json is updated in offline mode, redeploy the policy bundle for changes to take effect.

The Docker appliance is a container image that exposes an HTTP REST API for policy decisions. Pull the image from Appliance Image.

Terminal window
docker run -it -p 8080:8080 \
-e ENVIRONMENT=Stage \
-e API_PORT=8080 \
-e CLIENT_ID=<<your_client_id>> \
-e CLIENT_SECRET=<<your_client_secret>> \
trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version

The appliance registers with TAM C&C, downloads the policy bundle, and begins serving decisions once /health/readyz returns 200.

Local file bundle:

Terminal window
docker run -it -p 8080:8080 \
-v "C:\path\to\bundle.tar.gz:/offline/bundle.tar.gz:ro" \
-e ENVIRONMENT=Stage \
-e API_PORT=8080 \
-e CLIENT_ID=<<your_client_id>> \
-e CLIENT_SECRET=<<your_client_secret>> \
-e OFFLINE_MODE=true \
-e DISABLE_REPORTING=true \
-e BUNDLE_PATH=/offline/bundle.tar.gz \
trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version

S3 bundle (FedRAMP):

Terminal window
docker run -it -p 8080:8080 \
-e ENVIRONMENT=Stage \
-e API_PORT=8080 \
-e CLIENT_ID=<<your_client_id>> \
-e CLIENT_SECRET=<<your_client_secret>> \
-e OFFLINE_MODE=true \
-e DISABLE_REPORTING=true \
-e BUNDLE_PATH=s3://your-bucket/policies/bundle.tar.gz \
-e OFFLINE_CACHE_FILE=s3://your-bucket/config/offline-cache.json \
-e AWS_EC2_METADATA_DISABLED=false \
-v ~/.aws:/root/.aws:ro \
trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version

On EC2 or ECS with an instance/task role, omit the ~/.aws volume and AWS_PROFILE. Set AWS_EC2_METADATA_DISABLED=false to use the instance role.

See FedRAMP guide for restricted-network deployment details.

The Embedded TAM SDK provides a native shared library for in-process policy evaluation in Python, Java, and C# applications. See Embedded TAM SDK Overview and SDK Location.

Set environment variables and call Initialize with your credentials:

TAM_CLIENT_ID, TAM_CLIENT_SECRET, TAM_TOKEN_URL, TAM_ENVIRONMENT

The library registers with TAM C&C as source EMBEDDED and polls for bundle updates every 60 seconds.

Set offline environment variables before calling Initialize:

OFFLINE_MODE=true
BUNDLE_PATH=s3://your-bucket/policies/bundle.tar.gz # or local path
AWS_PROFILE=profile-dev # for local S3 access
TAM_CLIENT_ID, TAM_CLIENT_SECRET, TAM_TOKEN_URL, TAM_ENVIRONMENT

No C&C registration or bundle refresh occurs in offline mode. Policy decisions use the bundle at BUNDLE_PATH only.

The TAM Lambda Extension runs as an AWS Lambda layer, starting a local decision server before your function handler executes. See Lambda Extension Overview and Extension Location.

Build the extension zip using build-extension.sh in the Appliance repository, or download the pre-built artifact from Artifactory.

Publish the layer and configure environment variables in your Lambda function:

ENVIRONMENT=stage
CLIENT_ID, CLIENT_SECRET, TOKEN_URL
API_PORT=9000

Your function handler sends decision requests to http://localhost:9000/v1/decision/{namespace}/{rule}.

Add offline variables to your Lambda function configuration:

OFFLINE_MODE=true
DISABLE_REPORTING=true
BUNDLE_PATH=s3://your-bucket/policies/bundle.tar.gz
OFFLINE_CACHE_FILE=s3://your-bucket/config/offline-cache.json

The Lambda execution role must have S3 read permissions. The extension does not trigger online bundle sync when OFFLINE_MODE=true.

The Appliance will need a port exposed for the REST API and/or the Envoy API. This will allow communication from your other containers that need to ask for authorization decisions through the Appliance API. The default ports for the appliance container are as follows:

  • API_PORT: 8080

Environment (See: Environment Endpoints):

  • Ex: ENVIRONMENT=Stage

REST / Envoy API Port:

  • Ex: API_PORT=8080

Application Client ID (from Trimble Cloud Console):

  • Ex: CLIENT_ID=b34857c1-6553-4909-beb3-5328e1810c48

Application Client Secret (from Trimble Cloud Console):

  • Ex: CLIENT_SECRET=6ff7cac0bb6a449eb8597ba1ba2952c3

Optional Redis Cache (for Remote Data Caching):

  • Ex: CACHE_TYPE=redis
  • Ex: REDIS_CONNECTION_URL=redis://default:password@redis:6379/0

Optional AWS Lambda invoke (invoke another Lambda for auth data):

  • Ex: ENABLE_LAMBDA_CLIENT=true
  • Ex: AUTH_DATA_LAMBDA={lambda_name_to_invoke}

A default AWS connection must be established for connectivity between the appliance host and your AWS account.

Optional Secret Manager (loading secrets from AWS SSM):

  • Ex: SECRET_MANAGER=ssm
  • Ex: CLIENT_ID=/iam/dev/client_id
  • Ex: CLIENT_SECRET=/iam/dev/client_secret

Optional Partition (for handling different stacks):

  • Ex: PARTITION=us-east

Optional log level:

  • Ex: LOG_LEVEL=DEBUG
  • Ex: OFFLINE_MODE=true
  • Ex: BUNDLE_PATH=/input/bundle.tar.gz or s3://bucket/policies/bundle.tar.gz
  • Ex: DISABLE_REPORTING=true (recommended defense-in-depth)
  • Ex: OFFLINE_CACHE_FILE=/offline/cache-config.json or s3://bucket/config/offline-cache.json
  • Ex: OFFLINE_CACHE_CONFIG='{"cacheEntries":[...]}' (inline JSON alternative)

AWS credentials for S3 access in offline mode:

  • Ex: AWS_PROFILE=profile-dev (local Docker with mounted ~/.aws)
  • Ex: AWS_EC2_METADATA_DISABLED=false (EC2/ECS/Lambda with instance/execution role)
  • Ex: BUNDLE_S3_REGION=us-east-1 (override bucket region detection)
  • Ex: AWS_REGION=us-east-1 (region fallback)

The appliance has a health endpoint on its API_PORT at /health.

GET /health/livez

  • This endpoint returns HTTP 200 OK once the appliance has started, regardless of whether the policy bundle has been downloaded or the OPA server is running.

  • This endpoint indicates that the appliance has successfully started and there are no infrastructure-level issues.

GET /health/readyz

  • Returns HTTP 200 OK only after the appliance has successfully loaded the policy bundle and is fully operational.

  • In online mode, this requires successful bundle download from TAM C&C. If the appliance cannot communicate with the server, this endpoint returns HTTP 503 Service Unavailable.

  • In offline mode, readiness depends on BUNDLE_PATH being valid and readable (local file or S3 preflight check). Returns 503 if the bundle cannot be loaded.

  • This endpoint confirms that the appliance is ready to serve requests based on the loaded policy.

The appliance can be run in your local Docker environment to test decisions against your policies without an associated API, Envoy Proxy, or other container. Both the Docker and Docker Compose examples below expose the appliance REST API on port 8080.

For offline local testing, see Docker appliance — offline.


Terminal window
docker run -it -p 8080:8080 \
-e ENVIRONMENT=Stage \
-e API_PORT=8080 \
-e CLIENT_ID=<<your_client_id>> \
-e CLIENT_SECRET=<<your_client_secret>> \
trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version

version: '3.4'
services:
appliance:
image: trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version
ports:
- 8080:8080
environment:
- ENVIRONMENT=Stage
- API_PORT=8080
- CLIENT_ID=<<your_client_id>>
- CLIENT_SECRET=<<your_client_secret>>
- PARTITION=<<partition>> (Optional)
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:8080/health/readyz || exit 1
interval: 10s
timeout: 10s
retries: 6

Additionally, you can also run with Docker Compose and your own container side-by-side.

The following example shows the configuration needed to launch an appliance and have its REST API be accessible as http://appliance:7001 to your API testwebservice:

version: '3.4'
services:
appliance:
image: trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version
ports:
- 7001:8080
environment:
- ENVIRONMENT=Stage
- API_PORT=8080
- CLIENT_ID=<<your_client_id>>
- CLIENT_SECRET=<<your_client_secret>>
- PARTITION=<<partition>> (Optional)
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:7001/health/readyz || exit 1
interval: 10s
timeout: 10s
retries: 6
testwebservice:
image: nginx # Your docker image here.
ports:
- "8082:80"
depends_on:
appliance:
condition: service_healthy

Or you can run with an Envoy proxy in front of your API testwebservice by providing the Docker Compose and a configuration for yaml.


version: '3.4'
services:
appliance:
image: ${DOCKER_REGISTRY-}appliance
build:
context: Appliance
dockerfile: Dockerfile
ports:
- "7001:8080"
environment:
- ENVIRONMENT=Stage
- API_PORT=8080
- CLIENT_ID=<<your_client_id>>
- CLIENT_SECRET=<<your_client_secret>>
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:7001/health/readyz || exit 1
interval: 10s
timeout: 10s
retries: 6
envoy:
image: envoyproxy/envoy:v1.26-latest
ports:
- "8000:8000"
volumes:
- ./envoy/envoy.yaml:/etc/envoy/envoy.yaml # Modify this as you see fit for your own Envoy config.
depends_on:
appliance:
condition: service_healthy
testwebservice:
image: nginx # Your docker image here.
ports:
- "8082:80"
depends_on:
appliance:
condition: service_healthy

Example Envoy configuration YAML:

static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: upstream
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: upstream-service
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
http_service:
server_uri:
uri: ext_authz
cluster: ext_authz-http-service
timeout: 0.250s
path_prefix: "/v1/envoy"
authorization_request:
headers_to_add:
- key: "Rego-Policy-Package-Namespace"
value: "<<package_namespace>>"
- key: "Rego-Policy-Rule"
value: "<<rule>>"
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: upstream-service
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: upstream-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: testwebservice
port_value: 8082
- name: ext_authz-http-service
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: ext_authz-http-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: appliance
port_value: 8080

An external authorization HTTP filter is used in the Envoy configuration above. The filter configuration adds headers (Rego-Policy-Package-Namespace and Rego-Policy-Rule) to specify the package namespace and rule that the appliance uses for the authorization decision. You will need to supply the package namespace and rule for the <<package_namespace>> and <<rule>> values respectively.

Now requests to the Envoy service (http://localhost:8000 in this example) will be filtered by the appliance before passing API calls to testwebservice.


Note: this example protects a web server from calls by allowing or denying calls, but does not allow API calls that produces lists by modfying data with rego.

  1. Docker Desktop installed
  2. Kubernetes enabled on Docker Desktop
  3. kubectl installed on your favorite cli. The previous link has information on Windows, or you may install it on wsl
  4. Istio installed with the demo profile on your local kubernetes cluster, along with istioctl
  5. TAM executable downloaded and available in your folder/cli

Protect server with TAM appliance using Istio

Section titled “Protect server with TAM appliance using Istio”
  1. Save istio.rego and istio_test.rego
istio.rego
package tam.istio.example
default allow := false
allow {
input.caller_auth.claims.iss == "https://stage.id.trimblecloud.com"
input.path == "/auth/allow.html"
input.method == "GET"
}
istio_test.rego
package tam.istio.example
import future.keywords
test_permission_denied if {
not allow
with input as {"method": "GET", "path": "/auth/deny.html", "caller_auth" : { "claims": {"iss": "https://stage.id.trimblecloud.com" } } }
}
test_permission_allowed if {
allow
with input as {"method": "GET", "path": "/auth/allow.html", "caller_auth" : { "claims": {"iss": "https://stage.id.trimblecloud.com" } } }
}
  1. Register Package with the files you just saved

    • Register your istio policy package. Customize package namespace in rego and the below command or use already registered policy. You will need to modify “Rego-Policy-Package-Namespace” set in the mesh configMap to be the right policy package namespace as well.
      ./tam package register --packageNamespace tam.istio.example --pathToFiles istio.rego --pathToTestFiles istio_test.rego --environment Stage --consumerKey <consumer_key_goes_here> --consumerSecret <consumer_secret_goes_here>
  2. Register Application

    • Register your application. Customize package namespace per package registered above.
      ./tam application register --namespaces tam.istio.example --environment Stage --consumerKey <consumer_key_goes_here> --consumerSecret <consumer_secret_goes_here>
  3. Create namespace for testing
    kubectl create ns foo

  4. Tell Istio to pay attention to your new namespace
    kubectl label ns foo istio-injection=enabled

  5. Save nginx-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
name: api-deployment
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/auth/allow.html
name: nginx-allow-conf
subPath: allow.html
- mountPath: /usr/share/nginx/html/auth/deny.html
name: nginx-deny-conf
subPath: deny.html
volumes:
- name: nginx-allow-conf
configMap:
name: nginx-allow-configmap
- name: nginx-deny-conf
configMap:
name: nginx-deny-configmap
---
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-allow-configmap
data:
allow.html: |
<html>You should be allowed to see this content</html>
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-deny-configmap
data:
deny.html: |
<html>You should NOT be allowed to see this content</html>
  1. Deploy an nginx server we can use for testing with the file you just saved
    kubectl apply -f nginx-deployment.yml -n foo

  2. Save appliance-deployment.yml

apiVersion: v1
kind: Service
metadata:
name: ext-authz
labels:
app: ext-authz
spec:
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app: ext-authz
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ext-authz
spec:
replicas: 1
selector:
matchLabels:
app: ext-authz
template:
metadata:
labels:
app: ext-authz
spec:
containers:
- image: trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version
name: ext-authz
ports:
- containerPort: 8080
env:
- name: ENVIRONMENT
value: "Dev"
- name: API_PORT
value: "8080"
- name: CLIENT_ID
value: "7a489063-8de0-46eb-aab4-63523e52e74c"
- name: CLIENT_SECRET
value: "fb72d7eaa3124ffa86538002dc368da1"
  1. Deploy the TAM appliance
    kubectl apply -n foo -f appliance-deployment.yml

  2. Verify TAM appliance is up and running
    kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz

  3. Save authorizer-service.yml

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-authz-http-local
spec:
hosts:
- "external-authz-http.local" # The service name to be used in the extension provider in the mesh config.
endpoints:
- address: "127.0.0.1"
ports:
- name: http
number: 8080 # The port number to be used in the extension provider in the mesh config.
protocol: HTTP
resolution: STATIC
  1. Register the service to the Istio mesh kubectl apply -n foo -f authorizer-service.yml

  2. Edit the mesh config kubectl edit configmap istio -n istio-system

    • Add the extension provider - depending on your setup you may have a few in here, or may have one. You’ll need to pay attention and only copy the appropriate chunk (maybe not all the text below).
data:
mesh: |-
# Add the following content to define the external authorizers.
extensionProviders:
- name: "sample-ext-authz-http"
envoyExtAuthzHttp:
service: "ext-authz.foo.svc.cluster.local"
port: "8080"
includeRequestHeadersInCheck: ["authorization"]
includeAdditionalHeadersInCheck:
"Rego-Policy-Package-Namespace": "tam.istio.example"
"Rego-Policy-Rule": "allow"
pathPrefix: "/v1/envoy"
  1. Save nginx-authz.yml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: ext-authz
spec:
selector:
matchLabels:
app: api
action: CUSTOM
provider:
name: sample-ext-authz-http
rules:
# The rules specify when to trigger the external authorizer.
- to:
- operation:
paths: ["/auth/*"]
  1. Enable Authorization on the nginx service
    kubectl apply -n foo -f nginx-authz.yml

  2. Save istio-gateway.yml

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: my-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: my-virtualservice
spec:
hosts:
- "*"
gateways:
- my-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
host: api-service
  1. Enable gateway to api
    kubectl apply -n foo -f istio-gateway.yml

  2. Get a JWT
    curl -d "grant_type=client_credentials&scope=tam-dev" -u <clientid>:<clientsecret> -H 'Content-Type: application/x-www-form-urlencoded' https://stage.id.trimblecloud.com/oauth/token

  3. Optional: view logs
    Open separate window to show logs for all requests using follow flag:
    kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz -f

  • NOTE: all curls should use linux or ps 7+
  1. Use the curl below to test nginx. You should see: Welcome to nginx!
    curl --location 'localhost/' --header 'Authorization: <Bearer your_token_here>

  2. Use curl to see success based on the rego policy. You should see : TODO
    curl --location 'localhost/auth/allow.html' --header 'Authorization: <Bearer your_token_here>

  3. Use curl to see a denial based on the rego policy. You should see: ‘Policy engine rejected the request’
    curl --location 'http://localhost/auth/something_not_allowed' --header 'Authorization: <Bearer your_token_here>


We recommend running the appliance in a Kubernetes or service mesh environment, which allows you the greatest control over ingress and network traffic.

The following example shows the configuration needed to launch an appliance and have its REST API be accessible as http://appliance:7001 to your API testwebservice:

apiVersion: v1
kind: Service
metadata:
name: appliance
spec:
selector:
app: appliance
ports:
- protocol: TCP
port: 7001
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: appliance
spec:
replicas: 1
selector:
matchLabels:
app: appliance
template:
metadata:
labels:
app: appliance
spec:
containers:
- name: appliance
image: trimblecloud-tam-appliance-core-docker-local.artifactory.trimble.tools/appliance:version
ports:
- containerPort: 8080
env:
- name: ENVIRONMENT
value: "Dev"
- name: API_PORT
value: "8080"
- name: CLIENT_ID
value: "<<your_client_id>>"
- name: CLIENT_SECRET
value: "<<your_client_secret>>"
readinessProbe:
httpGet:
path: /health/readyz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3

Of course the details of this will change based upon how you run ingress into your environment, so you would either need to expose a port manually or have an ingress controller manage traffic.

For offline Kubernetes deployments, add offline environment variables to the container spec:

env:
- name: OFFLINE_MODE
value: "true"
- name: DISABLE_REPORTING
value: "true"
- name: BUNDLE_PATH
value: "s3://your-bucket/policies/bundle.tar.gz"
- name: OFFLINE_CACHE_FILE
value: "s3://your-bucket/config/offline-cache.json"

Ensure the pod’s service account or node IAM role has S3 read permissions. See the FedRAMP guide for restricted-network details.

For FedRAMP and other restricted-network environments where TAM servers cannot be contacted, deploy in offline mode with S3-backed policy bundles. See the dedicated FedRAMP guide.

For appliance troubleshooting across all deployment modes, see the Troubleshooting guide. Key sections: