# Qcontrol (Beta)

## Introduction

Rulekit is the expression engine that powers Qcontrol's rule-based traffic management system. It allows you to define precise conditions for controlling network traffic using a simple, intuitive syntax. This guide will help you understand how to effectively use Rulekit expressions within Qcontrol to implement security policies and traffic controls.

## Understanding the Qcontrol Context

Qcontrol uses Rulekit to evaluate and enforce rules against network traffic, primarily focusing on:

* **Outbound connections**: Monitoring and controlling where your applications can connect
* **Process attribution**: Understanding which processes initiated connections
* **Security enforcement**: Allowing or denying traffic based on precise conditions

Rules are evaluated in order, with allow rules typically placed before deny rules to ensure critical services remain accessible.

## Expression Syntax

RuleKit expressions follow a straightforward pattern:

```
<field> <operator> <value>
```

{% hint style="info" %}
**Important**: RuleKit uses **dot notation** for accessing nested fields and map values, not square bracket notation:

* ✅ Correct: `src.pod.labels.app == "frontend"`
* ❌ Incorrect: `src.pod.labels["app"] == "frontend"`
  {% endhint %}

Multiple conditions can be combined using logical operators:

```
<field1> <operator1> <value1> and <field2> <operator2> <value2>
```

### Logical Operators

<table><thead><tr><th width="127.68023681640625">Operator</th><th width="104.2196044921875">Aliases</th><th width="148.3924560546875">Description</th><th>Example</th></tr></thead><tbody><tr><td>and</td><td>&#x26;&#x26;</td><td>Logical AND</td><td><code>dst.port == 443 and tls.version >= 1.3</code></td></tr><tr><td>or</td><td>||</td><td>Logical OR</td><td><code>dst.port == 80 or dst.port == 443</code></td></tr><tr><td>not</td><td>!</td><td>Logical NOT</td><td><code>not src.pod.namespace == "kube-system"</code></td></tr></tbody></table>

### Comparison Operators

<table><thead><tr><th width="106.488525390625">Operator</th><th width="101.33026123046875">Aliases</th><th width="246.0489501953125">Description</th><th>Example</th></tr></thead><tbody><tr><td><code>==</code></td><td>eq</td><td>Equal to</td><td><code>dst.port == 443</code></td></tr><tr><td><code>!=</code></td><td>ne</td><td>Not equal to</td><td><code>src.pod.namespace != "kube-system"</code></td></tr><tr><td><code>></code></td><td>gt</td><td>Greater than</td><td><code>dst.port > 1024</code></td></tr><tr><td><code>>=</code></td><td>ge</td><td>Greater than or equal to</td><td><code>tls.version >= 1.3</code></td></tr><tr><td><code>&#x3C;</code></td><td>lt</td><td>Less than</td><td><code>dst.port &#x3C; 1024</code></td></tr><tr><td><code>&#x3C;=</code></td><td>le</td><td>Less than or equal to</td><td><code>tls.version &#x3C;= 1.2</code></td></tr><tr><td><code>=~</code></td><td>matches</td><td>Matches regex pattern</td><td><code>dst.domain matches /.example.com$/</code></td></tr><tr><td><code>contains</code></td><td></td><td>Contains substring or element</td><td><code>dst.domain contains "example"</code></td></tr><tr><td><code>in</code></td><td></td><td>Is contained in array</td><td><code>dst.port in [80, 443, 8080]</code></td></tr></tbody></table>

### Value Types

**bool**

A boolean. For example: `true`, `false`.

```perl
tls.enabled || allow_insecure == true
```

**number**

An integer or floating-point number. For example: `8080`, `1.2`.

```perl
tls.version >= 1.2
```

**string**

A double-quoted string. For example: `"tcp"`, `"{\"content\": \"example\"}"`.

```perl
dst.domain == "example.com"
```

**regex pattern**

A Golang/RE2 regular expression surrounded by forwarded-slashes `/` or straight pipes `|`. Can only be compared against string values. For example: `\.domain\.com$`.

```perl
dst.domain matches /\.domain\.com$/
```

```perl
src.process.path matches |^/usr/local/|
```

**IP**

An IPv4, IPv6, or an IPv6 dual address. For example:

* `192.168.1.1`
* `2001:db8:3333:4444:cccc:dddd:eeee:ffff`

```perl
dst.ip != 10.0.0.1
```

**CIDR**

An IPv4 or IPv6 CIDR block. For example:

* `192.168.0.0/16`
* `2001:db8:3333:4444:cccc:dddd:eeee:0000/48`

```sql
dst.ip != 10.0.0.0/8
```

### Arrays

Arrays may be expressed using square bracket notation. Arrays may contain mixed types and can be used to make rules more readable.

```sql
dst.port in [80, 8080, 53]
-- instead of
dst.port == 80 or dst.port == 8080 or dst.port == 53
```

```sql
dst.ip != [10.0.0.0/8, 192.168.0.0/16, 1.2.3.4]
-- instead of
dst.ip != 10.0.0.0/8 and dst.ip != 192.168.0.0/16 and dst.ip != 1.2.3.4
```

```sql
dst.domain in ["example.com", /\.example\.com$/]
-- instead of
dst.domain == "example.com" or dst.domain matches /\.example\.com$/
```

### Comments and Whitespace

Expressions may contain single-line or multiline comments. Whitespace around values and operators will be ignored.

```sql
-- common services
dst.port == 80 /* http */ or dst.port == 53 /* dns */
-- database services
or dst.port in [
  3306,  -- MySQL
  5432,  -- PostgreSQL
  27017, -- MongoDB
  6379   -- Redis
]
```

## Qcontrol Field Reference

This document serves as a reference for the fields available in Qcontrol rules that can be used to monitor and control network traffic.

### Source Fields (src.\*)

| Field                 | Type               | Example                     | Description                  |
| --------------------- | ------------------ | --------------------------- | ---------------------------- |
| src.process.path      | string             | `/usr/bin/curl`             | Full path to the executable  |
| src.process.binary    | string             | `curl`                      | Binary name without path     |
| src.process.user.id   | int                | `1000`                      | Numeric user ID              |
| src.process.user.name | string             | `app-user`                  | Username                     |
| src.process.env       | map\[string]string | `{"HOME": "/home/user"}`    | Environment variables        |
| src.process.hostname  | string             | `worker-pod-1`              | Process hostname             |
| src.container.id      | string             | `a72dfe9c43a2`              | Container ID (short or full) |
| src.container.name    | string             | `app-frontend`              | Container name               |
| src.container.image   | string             | `nginx:1.21`                | Container image with tag     |
| src.container.labels  | map\[string]string | `{"app": "frontend"}`       | Container labels             |
| src.pod.name          | string             | `frontend-5d4d7d4b45-2jrvs` | Kubernetes pod name          |
| src.pod.namespace     | string             | `production`                | Kubernetes namespace         |
| src.pod.labels        | map\[string]string | `{"app": "frontend"}`       | Kubernetes pod labels        |
| src.ip                | IP                 | `10.0.0.1`                  | Source IP address            |
| src.port              | uint               | `55123`                     | Source port number           |

### Destination Fields (dst.\*)

<table><thead><tr><th>Field</th><th width="158.708251953125">Type</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>dst.ip</td><td>IP</td><td><code>192.168.1.10</code></td><td>Destination IP address</td></tr><tr><td>dst.port</td><td>uint</td><td><code>443</code></td><td>Destination port number</td></tr><tr><td>dst.domain</td><td>string</td><td><code>api.example.com</code></td><td>Destination domain name</td></tr></tbody></table>

### Connection Fields

<table><thead><tr><th width="162.258544921875">Field</th><th width="97.3526611328125">Type</th><th width="178.2222900390625">Example</th><th>Description</th></tr></thead><tbody><tr><td>protocol</td><td>string</td><td><code>http2</code></td><td><p>L7 protocol</p><p>values: <code>unknown</code>, <code>http1</code>, <code>http2</code>, <code>dns</code>, <code>grpc</code></p></td></tr><tr><td>type</td><td>string</td><td><code>tcp</code></td><td>Socket type<br>values: <code>tcp</code>, <code>udp</code>, <code>raw</code>, <code>icmp</code></td></tr><tr><td>direction</td><td>string</td><td><code>egress</code></td><td>Traffic direction<br>values: <code>egress-external</code>, <code>egress-internal</code>, <code>egress</code></td></tr></tbody></table>

### TLS Fields (tls.\*)

| Field       | Type      | Example              | Description                                   |
| ----------- | --------- | -------------------- | --------------------------------------------- |
| tls.enabled | bool      | `true`               | Whether TLS is enabled                        |
| tls.version | float     | `1.2`                | TLS protocol version                          |
| tls.sni     | string    | `api.example.com`    | TLS Server Name Indication                    |
| tls.alpn    | \[]string | `["h2", "http/1.1"]` | Application-Layer Protocol Negotiation values |

### Metadata Fields

| Field | Type      | Example                        | Description            |
| ----- | --------- | ------------------------------ | ---------------------- |
| tags  | \[]string | `["app:frontend", "env:prod"]` | List of key-value tags |

## Common Security Use Cases

### Allow Essential Services

Place allow rules at the top of your configuration to ensure critical services remain accessible:

```yaml
- name: allow essential services
  expr: dst.domain in ["registry.k8s.io", "k8s.gcr.io", "gcr.io", "docker.io"]
  actions: [allow]
  
- name: allow documentation sites
  expr: dst.domain in ["kubernetes.io", "helm.sh", "prometheus.io"]
  actions: [allow]
```

### Enforce TLS Security

Block connections using outdated TLS versions:

```yaml
- name: block legacy tls
  expr: tls.enabled and tls.version <= 1.2
  actions: [deny]
```

### Protect Internal Services

Control access to internal network services:

```yaml
- name: restrict sensitive ports
  expr: dst.port in [22, 3306, 6379, 27017] and dst.ip != 10.0.0.0/8
  actions: [deny]
```

### Control Process Access

Restrict what specific applications can connect to:

```yaml
- name: restrict curl
  expr: src.process.binary == "curl" and not dst.domain in ["api.example.com", "updates.example.com"]
  actions: [deny]
```

### Prevent Data Exfiltration

Block access to cloud storage services except from authorized sources:

```yaml
- name: block cloud storage
  expr: dst.domain matches /(\.s3\.amazonaws\.com|\.storage\.googleapis\.com|\.blob\.core\.windows\.net)$/ and not src.pod.namespace == "backup"
  actions: [deny]
```

## Best Practices

### Rule Organization

* **Put allow rules first**: Define what should be explicitly allowed before setting up blocking rules
* **Order by priority**: Most critical rules should be evaluated first
* **Group related rules**: Keep similar rules together for easier management

### Rule Writing

* **Be specific**: Write targeted rules that address particular security concerns
* **Use descriptive names**: Make rule names clear and self-explanatory
* **Comment complex rules**: Add YAML comments to explain reasoning behind rules
* **Test thoroughly**: Validate rules in a non-production environment first
* **Readability:** Use whitespace and comments within rule expressions for clarity

### Performance Tips

* **Use exact matching**: Prefer `==` and `in` over regex patterns when possible
* **Limit regex complexity**: Simple patterns are more efficient

## Comprehensive Production Example

Here's an example of a production rule set for Kubernetes environments:

```yaml
control:
  rules:
    # Allow rules (highest priority)
    - name: allow essential services
      expr: dst.domain in ["registry.k8s.io", "k8s.gcr.io", "gcr.io", "docker.io"]
      actions: [allow]
      
    - name: allow documentation sites
      expr: dst.domain in ["kubernetes.io", "helm.sh", "prometheus.io", "pypi.org"]
      actions: [allow]
    
    - name: allow monitoring traffic
      expr: dst.port in [9090, 9100, 3000]
      actions: [allow]
    
    # Internal service protection
    - name: restrict sensitive ports
      expr: dst.port in [22, 3306, 6379, 27017] and dst.ip != 10.0.0.0/8
      actions: [deny]
    
    - name: enforce secure communications
      expr: tls.enabled and tls.version <= 1.2
      actions: [deny]
    
    # Prevent data exfiltration
    - name: block cloud storage 
      expr: dst.domain matches /(\.s3\.amazonaws\.com|\.storage\.googleapis\.com|\.blob\.core\.windows\.net)$/ and src.pod.namespace != "backup"
      actions: [deny]
    
    # Additional security rules
    - name: block cryptocurrency mining
      expr: dst.domain in ["pool.minergate.com", "cryptonight.net", "coinhive.com", "crypto-loot.com"]
      actions: [deny]
    
    - name: restrict database connections
      expr: |
        dst.port in [
          3306,  -- MySQL
          5432,  -- PostgreSQL
          27017, -- MongoDB
          6379   -- Redis
        ]
        and not src.pod.namespace in ["api", "backend", "monitoring"]
      actions: [deny]
```

## Troubleshooting

If your rules aren't working as expected:

* **Check rule ordering**: Rules are evaluated in order - earlier rules take precedence
* **Verify field names**: Ensure fields referenced in rules match the actual data
* **Test rule patterns**: Validate regex patterns against sample data
* **Check logs**: Look for logs showing which rules were matched
* **Simplify and iterate**: Start with simple rules and build complexity gradually


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.qpoint.io/appendix/qcontrol-beta.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
