JCC hardened mode (network isolation)
Restrict outbound network access from the JCC process on a Groundplex node so that Script Snaps and other pipeline code cannot reach unauthorized networks or cloud metadata services.
Overview
Network isolation applies OS-level egress filtering to a Groundplex JCC node, scoped to the
snapuser account (UID 1000 by default) that runs pipelines and Snaps. Using
iptables with the xt_owner match module, you can firewall
outbound connections by process owner rather than by network interface, so rules apply only
to traffic generated by the JCC process and not to root-owned system services such as
startup scripts or package management. This limits the blast radius of a Script Snap that
calls native Java functions to reach an unauthorized network, and it can block access to
cloud-provider instance metadata services that expose IAM credentials. This protection
applies to connections the JCC process makes directly; it does not by itself restrict
destinations reachable through a configured forward proxy (see Limitations).
Network isolation is a separate, customer-managed configuration from JCC hardened mode (file system isolation). File-system isolation hides sensitive host files from the JCC process; network isolation restricts what the JCC process can reach over the network. The two protections are independent and can be enabled together or separately.
Prerequisites
- A Groundplex node running on a Linux host with
iptablesinstalled. - The
xt_ownerkernel module loaded. Check withlsmod | grep xt_owner, and load it withmodprobe xt_ownerif it is not present. - Root or sudo access on the Groundplex host to configure firewall rules.
- Root/sudo access to confirm the UID of the account that runs the JCC process. These
examples assume the default
snapuseraccount, but every command below uses a$SNAPUSER_UIDshell variable rather than a hardcoded UID, set fromid -u snapuser(see Configure network isolation), so the rules apply correctly even if your host'ssnapuseraccount uses a UID other than the default 1000. - An inventory of the network endpoints your pipelines require: DNS, any private network
ranges, and the specific hosts or domains your integrations connect to. You will allow-list
these explicitly, so pipelines that reach undocumented endpoints will need those endpoints
added after the fact (see Allow-list specific endpoints). This inventory must also include the endpoints
the JCC itself requires for normal Groundplex operation. Groundplex requirements: Network
describes the required ports; Add the SnapLogic Platform to your
Allowlist is the maintained source for the actual control-plane and S3 IP
addresses to allow-list, since
iptablesfilters by IP address, not hostname. The final deny-all rule in this procedure blocks that traffic too if it is not allow-listed.
Configure network isolation
The xt_owner match filters outbound packets by the UID of the process that
created them.
Because iptables evaluates rules in order and stops at the first match,
the allow rules for snapuser must come before the final deny-all rule for
that user — and no earlier rule in the chain can already accept that traffic.
The examples below assume a clean OUTPUT chain: no pre-existing rules for
this UID, and no earlier ACCEPT rule that could match
snapuser traffic.
Scoping an earlier rule to an interface, protocol, or destination does not make it safe.
Only a rule that itself excludes this UID — for example, with -m owner !
--uid-owner "$SNAPUSER_UID" — or one that provably never carries
snapuser traffic can safely precede the rules below. For example, both of
these catch-all rules would break the procedure, even though the second is scoped to a
single interface:
iptables -A OUTPUT -j ACCEPT
iptables -A OUTPUT -o eth0 -j ACCEPT
Appending rules after either kind of rule has no effect, because iptables
stops evaluating once the earlier rule matches, so the chain never reaches the UID-specific
rules added here — including the final deny-all rule — and the isolation this procedure
describes is silently not enforced.
Run this command first and review every existing rule:
iptables -L OUTPUT -v -n --line-numbers
If your host already has rules for this UID, or a broad accept rule that could match
snapuser traffic, resolve that first — remove the conflicting rule, or
insert your rules ahead of it with -I — rather than appending on top of an
unknown configuration.
OUTPUT chain does not restrict the container's egress; see Limitations for containerized
deployments.Set a shell variable for the JCC user's UID, so every command below targets the correct
account even if your host's snapuser UID differs from the default. Run the
remaining commands in this section from the same shell session so the variable stays set:
SNAPUSER_UID=$(id -u snapuser)
- Allow loopback traffic for
snapuser. This example accepts all loopback traffic, which also accepts connections to any local TCP/UDP service listening on127.0.0.1— including a local forward proxy, SSH tunnel, or metadata/credential helper that itself relays traffic to remote networks. Such a service could be used to bypass the endpoint allow-list below entirely:
If you know the specific local ports the JCC requires — for example, a local health-check or metrics endpoint — restrict this rule to those ports instead of allowing all ofiptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -o lo -j ACCEPTlo. If you cannot enumerate every required local port, audit what listens on loopback on this host instead:
Remove or restrict any local service that could relay traffic externally onss -tulnpsnapuser's behalf. - Explicitly block the cloud metadata service endpoints, before adding any other allow
rule below. Placing this rule immediately after the loopback rule — ahead of the
established/related accept and every endpoint allow rule that follows — means no other
allow rule in this chain can accept traffic to these addresses before this rule is
reached. It also keeps the block in effect even if the final deny-all rule is later
removed or reordered:
iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 169.254.169.254 -j DROP iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 169.254.170.2 -j DROPNote: Because this rule precedes the established/related accept rule below, it also drops packets on a connection to these addresses that was already established before you added these rules —iptablesevaluates thisDROPfirst regardless of connection state. This is the one case in this procedure where an existing connection does not continue; see the next step for how established connections to other destinations are handled. - Allow established and related connections, so responses to requests the JCC already made
are not dropped:
iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTNote: This rule also keeps allowing responses on connections the JCC opened before you added these rules, even to destinations you don't allow-list below, until those connections close. Stop the JCC process before beginning this procedure for immediate enforcement, and restart it once Verify that isolation is active confirms the rules are correct. - Allow DNS resolution to only the resolver addresses your host is configured to use. A
rule that allows port 53 to any address lets
snapuserquery an arbitrary external resolver, bypassing the endpoint allow-list below. Find your configured resolvers:
Then add an allow rule for each resolver address returned (replacegrep nameserver /etc/resolv.conf203.0.113.53with your resolver's address, and repeat for each additional resolver):iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.53 -p udp --dport 53 -j ACCEPT iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.53 -p tcp --dport 53 -j ACCEPT - If your pipelines connect to endpoints on private network ranges, allow only the
specific host or subnet each integration actually uses rather than an entire RFC 1918
range. A rule for a full range such as
10.0.0.0/8grantssnapuseraccess to every address in that range, not just your pipeline's endpoints, which weakens the isolation this procedure is meant to provide:
Only allow a broad range such asiptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.0/24 -j ACCEPT10.0.0.0/8,172.16.0.0/12, or192.168.0.0/16in its entirety if you specifically intend forsnapuserto reach every host on that network, and document that this intentionally bypasses least-privilege filtering. - Allow the endpoints the JCC itself requires for normal Groundplex operation. The final
deny-all rule below blocks this traffic, along with pipeline traffic, if it is not
allow-listed here — verify these rules before proceeding, or you can strand the
Groundplex.
Control plane and S3: Groundplex requirements: Network lists the required ports (primarily 443), but not the destination IP addresses, and
iptablesfilters by IP address, not hostname. Get the current IP addresses for your SnapLogic environment and region — Production - Global, EMEA, Elastic2, or UAT — from Add the SnapLogic Platform to your Allowlist, the maintained source for these addresses. Add an allow rule for each address listed for your environment:iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 34.208.89.109/32 -p tcp --dport 443 -j ACCEPTRepeat for every IP address listed for your environment. Because these addresses can change, re-check that page and update your rules if a previously working control-plane connection starts failing.
Inter-node and FeedMaster traffic: These are the IP addresses of your own Snaplex nodes, not published SnapLogic addresses. For each peer node, allow the ports Groundplex requirements: Network lists for inter-node communication (8081, 8084, 8089) and health/monitoring (8090, 8091, or your reconfigured port):
iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.30 -p tcp --dport 8081 -j ACCEPTRepeat for each required port and each peer node in your Snaplex.
- Add allow rules for any specific external endpoints your integrations require. See Allow-list specific endpoints for examples.
- Add the default deny rule for
snapuserlast, after every allow rule above:iptables -A OUTPUT -m owner --uid-owner "$SNAPUSER_UID" -j DROP
-A (append) throughout. Because -A adds each rule to the
end of the chain, running these commands in order produces a chain that is evaluated
correctly: specific allow rules first, deny-all last. Inserting rules out of order at this
stage, or using -I (insert) without accounting for the chain you're
building, can silently reorder the deny-all rule ahead of an allow rule and block traffic
you intended to permit. Once the deny-all rule is in place, adding further endpoints
requires -I instead — see Allow-list specific endpoints.Allow-list specific endpoints
Add an explicit allow rule for each additional endpoint your pipelines require.
By the time you use this section, the deny-all rule for snapuser is
already the last rule in the chain, so appending a new rule with -A would
add it after the deny-all rule, where it can never match. Instead, find the deny-all rule's
current line number and insert (-I) the new allow rule immediately above
it:
iptables -L OUTPUT --line-numbers -n | grep "owner UID match $SNAPUSER_UID" | grep DROP
# 10 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1000
Use the line number from that output (10 in this example) as the insert position below. Re-run this check before each new insertion — the deny-all rule's line number increases each time you insert a rule above it.
Also check for any earlier ACCEPT rule above that insert position that
could match snapuser traffic. Scoping alone to an interface, protocol, or
destination does not exclude this UID — only a rule that itself excludes it is safe to leave
in place. If an unsafe rule exists, both the new allow rule and the deny-all rule below it
are silently skipped for traffic that already matched the earlier accept.
Because iptables matches on IP address rather than hostname, resolve the
hostname first and allow-list the resulting address:
A specific HTTPS endpoint
getent hosts api.example.com
# 203.0.113.10 api.example.com
iptables -I OUTPUT 10 -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.10 -p tcp --dport 443 -j ACCEPT
A database host
iptables -I OUTPUT 10 -m owner --uid-owner "$SNAPUSER_UID" -d 203.0.113.20 -p tcp --dport 5432 -j ACCEPT
Verify that isolation is active
List the OUTPUT chain with packet and byte counters to confirm the rules
are in place and matching traffic:
iptables -L OUTPUT -v -n --line-numbers
Test from a shell running as snapuser to confirm allowed and blocked
destinations behave as expected:
sudo -u snapuser curl -m 5 -I https://api.example.com
sudo -u snapuser curl -m 2 --noproxy '*' -X PUT \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \
http://169.254.169.254/latest/api/token
The first command should succeed for an allow-listed endpoint. For the second command, a
connection timeout, Connection refused, or No route to
host from curl — that is, no HTTP status code at all — confirms
the metadata service is unreachable. Do not judge this by the HTTP status code alone: when
AWS enforces IMDSv2, the metadata service returns 401 for a request that
omits a valid token, so a service that is still reachable can return an error status rather
than the requested data. Any HTTP response, including an error status, means the
destination was reached and the block is not in effect. For a protocol-independent check,
use a raw TCP probe instead: sudo -u snapuser nc -w 2 -z 169.254.169.254 80
&& echo reachable || echo blocked.
Limitations
- Requires the
xt_ownerkernel module. If the module is not available on your host or distribution, UID-based filtering cannot be applied. - Rule order is critical. Allow rules for
snapusermust precede the final deny-all rule, or traffic you intended to permit is dropped. - ICMP responses do not always carry the originating socket's UID. A rule that blocks all
ICMP traffic for
snapusercan drop responses needed for path MTU discovery and similar diagnostics. Avoid blanket ICMP deny rules scoped to this UID. - These rules use
iptables, which filters IPv4 traffic only. If the host has IPv6 enabled and can reach the network over IPv6, the JCC process can bypass this filtering entirely unless you apply equivalentip6tablesrules using the samext_ownermatch, or disable IPv6 on the host. - If the Snaplex is configured to use an HTTP/S forward proxy (see Groundplex Network Setup), these rules only see the JCC's connection to the proxy. The proxy can then connect to any destination on the JCC's behalf, so pipeline code routed through the proxy can reach a destination that isn't in this page's allow-list. Apply equivalent destination filtering on the proxy itself, or these rules do not fully prevent pipeline code from reaching unauthorized networks.
- These
iptablesrules are not persistent across a host reboot unless you separately configure a persistence mechanism for your distribution (for example,iptables-persistenton Debian-based systems, or saving rules with your distribution's equivalent). Confirm your rules are still active after any host restart. - Network isolation restricts what the JCC process can reach; it does not restrict what files the JCC process can read or write. For file-system isolation, see JCC hardened mode (file system isolation).
- A host administrator applies these rules to the host's network stack; the JCC process
itself does not need any special capability to be filtered by them. This works when the
JCC process runs directly on the Linux host, or in a container that uses host networking
and therefore shares the host's network namespace and
OUTPUTchain. Do not grant the JCC container theNET_ADMINcapability to try to satisfy this requirement — a JCC process withNET_ADMINcould modify or flush these firewall rules itself, defeating the isolation. A container that does not use host networking needs equivalent restrictions applied at the host or orchestration layer instead; see the note about network namespaces in Configure network isolation.
Troubleshooting
A pipeline fails to reach an endpoint after applying rules
Symptom: A pipeline or Snap that worked before the rules were applied now times out or fails to connect.
Fix: Run iptables -L OUTPUT -v -n --line-numbers and check whether
packet counters are increasing on the deny-all rule for snapuser's UID.
If so, identify the
destination address and port the pipeline needs and add an allow rule for it before the
deny-all rule (see Allow-list specific
endpoints).
Rules appear to have no effect
Symptom: Traffic that should be blocked is still reaching its destination.
Fix: Confirm the xt_owner module is loaded (lsmod | grep
xt_owner) and that the JCC process is actually running as the UID the rules
target (ps -o pid,uid,cmd -C jcc or equivalent). Rules written against the
wrong UID silently match nothing.
Roll back network isolation
Remove the rules you added for snapuser. List the chain with line numbers
(iptables -L OUTPUT -v -n --line-numbers) and delete each rule by number,
starting from the highest number so earlier line numbers don't shift:
iptables -D OUTPUT <line-number>
Re-run the verification steps to confirm the rules are removed and connectivity is restored.