Skip to main content
Version: Next 🚧

External Policies

External policies allow you to control capabilities for modules you don't own - third-party libraries, legacy code, and overly permissive dependencies.

Overview​

jGuard supports three types of policies:

Policy TypeLocationPurpose
EmbeddedInside JAR (META-INF/jguard/policy.bin)Module author's policy
ExternalExternal directory (policies/*.bin)Deployment-time overrides
GlobalExternal directory (policies/_global.bin)Applies to ALL modules

Grant/Deny Semantics​

External policies can both grant and deny capabilities:

security module com.vendor.library {
// Grant capabilities the library needs
entitle module to fs.read("config", "**");
entitle module to system.property.read;

// Deny dangerous capabilities
deny module to network.outbound;
deny module to native.load;
}

Merge Formula​

The effective policy is computed as:

effective = (embedded ∪ external_grants ∪ global_grants)
- (external_denials ∪ global_denials)

Key rules:

  • Denials always win over grants
  • More specific subjects don't override less specific (both apply)
  • Global policies merge with module-specific (not replace)

Example: Restricting an Overly Permissive Library​

Embedded policy (in library JAR):

security module com.vendor.library {
entitle module to network.outbound;
entitle module to threads.create;
entitle module to native.load; // DANGEROUS!
entitle module to fs.read("config", "**");
}

External override (policies/com.vendor.library.jguard):

security module com.vendor.library {
deny module to native.load;
deny module to threads.create;
}

Effective policy:

  • network.outbound - ALLOWED (embedded, not denied)
  • fs.read("config", "**") - ALLOWED (embedded, not denied)
  • native.load - BLOCKED (denied by external)
  • threads.create - BLOCKED (denied by external)

Legacy Library Support​

For non-JPMS libraries without embedded policies, jGuard uses the auto-module name derived from the JAR filename.

Auto-Module Name Derivation​

JAR FilenameAuto-Module Name
legacy-library-1.2.3.jarlegacy.library
commons-io-2.11.0.jarcommons.io
guava-31.1-jre.jarguava

Example: Restricting a Legacy Library​

Given legacy-library.jar with no embedded policy:

External policy (policies/legacy.library.jguard):

security module legacy.library {
// Grant only what's needed
entitle module to fs.read("config", "**");
entitle module to system.property.read;

// Everything else denied by default
}

Since jGuard is deny-by-default, the library is automatically blocked from:

  • Network access
  • Thread creation
  • Native code loading
  • Environment variable access
  • File writes

Global Policies​

Global policies apply to all modules in the JVM.

File Location​

Place global policies in policies/_global.jguard:

security module _global {
// Block native code loading for all modules
deny module to native.load;

// Block system property writes
deny(defensive) module to system.property.write;
}

Defensive Denials​

Use deny(defensive) to suppress warnings when denying capabilities that weren't explicitly granted:

security module _global {
// Normal deny - warns if capability wasn't granted
deny module to native.load;

// Defensive deny - no warning even if not granted
deny(defensive) module to system.property.write;
}

Use cases for defensive denials:

  • Proactive security (deny even if not currently granted)
  • Defense in depth
  • Avoiding redundant warnings in logs

Directory Structure​

/etc/myapp/policies/
├── _global.bin # Applies to ALL modules
├── com.example.app.bin # Your app's policy overrides
├── com.vendor.library.bin # Third-party library restrictions
└── legacy.library.bin # Legacy library policy

Subject Pattern Matching​

When using deny statements, subject patterns match entitlements:

Denial SubjectMatches Entitlements
moduleAny subject in the module
pkg..pkg.., pkg.*, pkg, or any descendant
pkg.*pkg.* or direct children
pkgOnly exact pkg match

Example: Precise Denial Targeting​

// Embedded policy grants multiple subjects
security module com.example.app {
entitle module to network.outbound;
entitle com.example.app.http.. to network.outbound;
}

// External policy - deny at module level
security module com.example.app {
deny module to network.outbound; // Revokes BOTH grants!
}

// To keep the specific grant, re-grant it
security module com.example.app {
deny module to network.outbound;
entitle com.example.app.http.. to network.outbound; // Re-grant specific
}

Configuration​

Gradle Plugin​

jguardPolicy {
externalPoliciesSourceDir = file("policies-src")
externalPoliciesOutputDir = file("policies")
}

Agent System Properties​

PropertyDefaultDescription
jguard.policy.override—Directory for external policy files
java -Djguard.policy.override=/etc/myapp/policies \
-javaagent:jguard-agent.jar \
-jar app.jar

Hot Reload​

External policies support zero-downtime updates:

jguardPolicy {
hotReload = true
hotReloadInterval = 5 // seconds
externalPoliciesSourceDir = file("policies-src")
externalPoliciesOutputDir = file("policies")
}

Or via system properties:

java -Djguard.reload=true \
-Djguard.reload.interval=5 \
-Djguard.policy.override=/etc/myapp/policies \
-javaagent:jguard-agent.jar \
-jar app.jar

Workflow:

  1. Edit policy source: policies-src/com.vendor.library.jguard
  2. Compile: ./gradlew compileExternalPolicies
  3. Agent detects change and reloads atomically
  4. New policy takes effect within poll interval

Error handling:

  • Syntax errors caught at compile time
  • Corrupted files keep old policy in effect
  • Atomic swap via AtomicReference<PolicyEnforcer>

Validation​

Validate that external policies are valid overrides:

jguard validate-override --jar vendor.jar --override policies/com.vendor.library.bin

Valid overrides can only:

  • Deny capabilities that were granted
  • Grant capabilities (additive)

Invalid overrides:

  • Grant capabilities outside the module's code
  • Reference unknown capabilities

Best Practices​

  1. Start restrictive - Grant only what's needed, add more if required
  2. Use global policies sparingly - Prefer module-specific restrictions
  3. Prefer defensive denials - Use deny(defensive) for proactive security
  4. Version control policies - Track changes to security configuration
  5. Audit before enforce - Use AUDIT mode to discover requirements
  6. Separate concerns - One policy file per module

Next Steps​