Security Policies
Overview
Security policies define the runtime behavior permitted for your CI/CD pipelines and deployments. The Runtime Sensor enforces these policies at the kernel level using eBPF technology, intercepting and validating security-relevant operations before they execute.
What Are Security Policies?
A security policy is a JSON document that specifies:
- Allowed operations: Which processes can execute, what files can be accessed, which network connections are permitted
- Enforcement mode: Whether to observe, enforce, or derive policy rules
- Security boundaries: Constraints on containers, kernel operations, memory access, and inter-process communication
Policies follow a deny-by-default model—operations not explicitly permitted are blocked when enforcement is enabled.
Key Concepts
Policy Domains
Security policies cover multiple security domains:
| Domain | Description | Examples |
|---|---|---|
| File System | File and directory operations | Process execution, file reads/writes/overwrites, path creation/deletion, renaming, linking, mounting |
| Networking | TCP/IP, Unix sockets, raw sockets | Outbound connections, listening ports, packet sniffing |
| Containers | Container runtime operations | Image execution, socket access |
| Memory | Memory-related operations | Memory mapping, W+X protection |
| Process | Process management | Process termination, resource limits, scheduling |
| Kernel | Kernel-level operations | eBPF programs, kernel modules, direct memory access |
| IPC | Inter-process communication | Unix sockets, System V shared memory, message queues |
Enforcement Modes
Policies operate in one of three modes:
| Mode | Behavior | Use Case |
|---|---|---|
derive | Monitor all behavior and generate policy rules | Initial setup—run your pipeline to capture baseline behavior |
observe | Log violations without blocking operations | Testing and refinement—validate policy before enforcement |
enforce | Block unauthorized operations and fail builds | Production—active protection against policy violations |
Rule Format
Most policy rules follow a pipe-delimited format that specifies actors and targets:
actor|target
actor|target|additional_contextFor example, an IP connection rule:
/usr/bin/curl|api.example.com|443This permits the curl binary to connect to api.example.com on port 443.
Wildcards and Patterns
Policies support several pattern matching features:
| Pattern | Description | Example |
|---|---|---|
all | Matches any value | "all" permits all values for that field |
{a,b,c} | Brace expansion | {80,443} matches port 80 or 443; {%workspace%,%tmpdir%}/bin matches either path |
%home% | Home directory of the user running the pipeline | %home%/.config/myapp |
%hostname% | Hostname of the machine running the Sensor | %hostname% |
%tmpdir% | Temporary directory ($TMP, $TMPDIR, $TEMP, or $TEMPDIR) | %tmpdir%/build-cache |
%uid% | UID of the user running the pipeline | %uid% |
%user% | Username of the user running the pipeline | %user% |
%workspace% | Job workspace directory | %workspace%/build/output |
Policy Lifecycle
The recommended workflow for creating and deploying security policies:
1. Derive
Start with a policy in derive mode and run your pipeline:
{
"mode": "derive"
}After the build completes, the Runtime Sensor outputs a derived policy containing rules for all observed behavior. The Sensor automatically consolidates path-based rules by removing entries that are subpaths of other entries in the same rule group, reducing policy size before output.
2. Refine
Review the derived policy and refine it before moving to observe or enforce mode. The derive output captures exact behavior from your pipeline run, which often needs to be generalized to account for dynamic values or broader valid ranges.
Consolidate dynamic file paths
Build processes frequently generate files with dynamic, unpredictable names. The derived policy captures each specific filename observed during the run, but those names will differ on every execution. Replace them with their parent directory.
Note: Directory-prefix path matching is supported for most, but not all, path positions. Consult the Specification for the specific operation to confirm which arguments support this technique.
For example, derive may produce:
"/usr/bin/bash|/opt/myapp/tmp/custom_script12345",
"/usr/bin/bash|/opt/myapp/tmp/custom_script67890"These represent the same program (/usr/bin/bash) operating in the same temporary directory—only the filename suffix differs. Refine this to:
"/usr/bin/bash|/opt/myapp/tmp"At runtime, any file under /opt/myapp/tmp (including dynamically named scripts) satisfies this rule. The policy remains precise about where the operation is permitted while accommodating filenames that cannot be known in advance.
Review and broaden IP address ranges
The Runtime Sensor operates at the kernel level and works exclusively with IP addresses. When derive captures an outbound connection, it records the specific IP with a /32 mask (IPv4) or /128 mask (IPv6). Domain name resolution is best-effort and may not always succeed, so the derived policy often contains raw IPs.
A derived policy might look like:
"ip": {
"connect": [
"all|127.0.0.1/32|53",
"all|127.0.0.53/32|53",
"all|::1/128|53",
"/usr/bin/python3.6|192.168.1.100/32|443",
"/usr/bin/python3.6|192.168.1.101/32|443",
"/usr/bin/python3.6|192.168.1.102/32|443",
"/usr/bin/python3.6|192.168.1.103/32|53"
]
}When refining, consider:
- DNS traffic (
port 53) — entries likeall|127.0.0.1/32|53andall|127.0.0.53/32|53represent local DNS resolvers. These are typically safe to leave as-is or consolidate into a subnet. - Application connections — the
/32entries for192.168.1.100–192.168.1.103may represent a load-balanced service or CDN. If those IPs belong to a known address range, replace the individual entries with the appropriate CIDR block (e.g.,192.168.1.0/24). - Completeness — the derive run captures only the IPs contacted during that specific run. Verify that the full set of valid IPs for each service is represented, especially for services that rotate addresses.
Other refinement techniques
- Brace expansion — consolidate rules with a common prefix using
{a,b,c}notation:"/usr/bin/node|/app/{src,dist,node_modules}" - Remove one-time entries — derived policies may include paths from install steps or first-run initialization that won’t recur. Remove entries that don’t apply to steady-state pipeline execution.
Policy too large to load
If a derived policy is applied without sufficient refinement, the Sensor may emit the following error:
Argument list too long (os error 7)This means the policy has too many rules to load. Return to the derive output and apply the techniques above—particularly collapsing dynamic paths into parent directories and consolidating IP ranges into CIDR blocks—until the policy is compact enough to load successfully.
3. Observe
Deploy the refined policy in observe mode:
{
"mode": "observe"
}Run several builds and review any violations in Team Server. Adjust the policy as needed.
4. Enforce
Once builds run cleanly in observe mode, switch to enforce:
{
"mode": "enforce"
}The Runtime Sensor now actively blocks unauthorized operations.
Policy Management
Security policies are managed through Team Server:
- Create policies: Define policies using the built-in editor with JSON schema validation
- Assign policies: Link policies to pipelines for enforcement
- Monitor violations: View and investigate policy violations
- Version history: Track policy changes with audit logging
To create a policy in Team Server:
- Navigate to Policies in the main menu
- Click Create
- Enter a Name, Description, and Version
- Write or paste your policy JSON
- Click Create
To assign a policy to a pipeline:
- Navigate to Policies
- Click the Assign Policy (link icon) for your policy
- Search and select the pipeline(s) to protect
- Click Assign
Next Steps
- Specification — Full reference for policy format and all available rules
- Example Policies — Real-world policy examples for common use cases