# Apono Query Language

The Apono Query Language (AQL) provides a simple, intuitive syntax for filtering cloud resources, integrations, and permissions.

<figure><img src="/files/jgcrlFjthoAYZFEeiDQ8" alt=""><figcaption><p>AQL query on the Inventory page</p></figcaption></figure>

This reference documents query construction, available components, and common filtering examples.

{% hint style="success" %}
When you are first starting to build queries, you can quickly learn how to build them by following these steps:

1. On the [**Inventory**](https://app.apono.io/inventory) page, click **Basic**.
2. [Filter the resources](/docs/inventory/inventory.md#filter-resources).
3. Click **AQL**. The AQL syntax will appear in the code box.
   {% endhint %}

***

### **Syntax**

The following is a basic AQL query.

```sql
resource_type = "aws-rds-mysql"
```

AQL uses a simple **field-operator-value** pattern.

```sql
field operator "value"
```

<table><thead><tr><th width="220">Component</th><th>Description</th></tr></thead><tbody><tr><td><a href="#field"><strong>field</strong></a></td><td>Attribute or tag to query</td></tr><tr><td><a href="#operator"><strong>operator</strong></a></td><td>Comparative logic</td></tr><tr><td><strong>value</strong></td><td><p>Expected value for the field</p><p>AQL values must be enclosed in double quotes (<code>""</code>). A backslash (<code>\</code>) can be used to escape special characters inside a string.</p><p>AQL does not support embedded newlines inside string values and rejects single quotes (<code>''</code>).</p></td></tr></tbody></table>

#### field

The `field` component specifies the attribute of your cloud resources to query.

{% tabs %}
{% tab title="Resource" %}
{% hint style="warning" %}
All resource field names are **case sensitive** and **strictly matched**.

For example, when querying for a resource type (`resource_type`), AQL rejects **`R`**`esource_`**`T`**`ype` because the casing is incorrect and `resource_type`**`s`** because it does not match a supported field name.
{% endhint %}

<table><thead><tr><th width="195">Field</th><th width="188">Description</th><th width="139.7864990234375">Supported operators</th><th>Example</th></tr></thead><tbody><tr><td><strong>resource_type</strong></td><td>Resource type</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_type = "aws-rds-mysql"</code></td></tr><tr><td><strong>resource_name</strong></td><td>Human-readable display name for the resource</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_name contains "prod"</code></td></tr><tr><td><strong>resource_path</strong></td><td>Hierarchical path within the integration</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_path contains "us-east-1"</code></td></tr><tr><td><strong>resource</strong></td><td>Apono internal resource identifier</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource = "res_12345"</code></td></tr><tr><td><strong>resource_status</strong></td><td>Current status</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_status = "active"</code></td></tr><tr><td><strong>resource_source_id</strong></td><td>Native identifier in the source system, such as an ARN</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_source_id = "arn:aws:iam::123:role/admin"</code></td></tr><tr><td><strong>resource_risk_level</strong></td><td>Associated risk level</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_risk_level = "high"</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Permission" %}
{% hint style="warning" %}
All permission field names are **case sensitive** and **strictly matched**.

For example, when querying for a permission name (`permission_name`), AQL rejects **`P`**`ermission_`**`N`**`ame` because the casing is incorrect and `permission_name`**`s`** because it does not match a supported field name.
{% endhint %}

<table><thead><tr><th width="211">Field</th><th width="188">Description</th><th>Supported operators</th><th>Example</th></tr></thead><tbody><tr><td><strong>permission_name</strong></td><td>Human-readable display name for the permission</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>permission_name = "ReadOnly"</code></td></tr><tr><td><strong>permission</strong></td><td>Apono internal permission identifier</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>permission = "perm_12345"</code></td></tr><tr><td><strong>permission_risk_level</strong></td><td>Permission risk level</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>permission_risk_level = "critical"</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Integration" %}
{% hint style="warning" %}
The integration field name is **case sensitive** and **strictly matched**.

For example, when querying for an integration (`integration`), AQL rejects **`I`**`ntegration` because the casing is incorrect and `integration`**`s`** because it does not match a supported field name.
{% endhint %}

<table><thead><tr><th width="193">Field</th><th width="188">Description</th><th>Supported operators</th><th>Example</th></tr></thead><tbody><tr><td><strong>integration</strong></td><td>Apono internal Integration identifier</td><td><a href="#comparison">Comparison</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>integration = "int_12345"</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Metadata" %}
{% hint style="warning" %}
All metadata field names are **case sensitive** and **strictly matched**.

For example, when querying for a resource tag (`resource_tag`), AQL rejects **`R`**`esource_`**`T`**`ag` because the casing is incorrect and `resource_tag`**`s`** because it does not match a supported field name.
{% endhint %}

<table><thead><tr><th width="245">Field</th><th width="176">Description</th><th>Supported operators</th><th>Example</th></tr></thead><tbody><tr><td><strong>resource_tag["key"]</strong></td><td>Resource tags</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_tag["environment"] = "prod"</code></td></tr><tr><td><strong>resource_context["key"]</strong></td><td>Resource context</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>resource_context["region"] = "us-east-1"</code></td></tr><tr><td><strong>permission_context["key"]</strong></td><td>Permission context</td><td><a href="#comparison">Comparison</a>, <a href="#string-matching">String Matching</a>, <a href="#lists">Lists</a>, <a href="#logic">Logic</a></td><td><code>permission_context["access"] = "write"</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

#### operator

The `operator` component defines how to evaluate the `field` against the specified `value`.

{% tabs %}
{% tab title="Comparison" %}
Basic operators that test for equality and inequality between values

<table><thead><tr><th width="151">Logic</th><th width="253">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>=</strong></td><td>Checks if values are the same</td><td><code>resource_type = "aws-account-dynamodb-table"</code></td></tr><tr><td><strong>!=</strong></td><td>Checks if values are different</td><td><code>integration != "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"</code></td></tr></tbody></table>
{% endtab %}

{% tab title="String Matching" %}
Operators that perform case-sensitive text comparisons against literal string values

{% hint style="warning" %}
All string matching operators are **case sensitive**.

For example, when checking if a literal string is contained (`contains`) as a substring, AQL rejects `CONTAINS` because the casing is incorrect.
{% endhint %}

<table><thead><tr><th width="151">Logic</th><th width="253">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>contains</strong></td><td>Checks if a value contains another literal string as a substring</td><td><code>(resource_tag["aws:cloudformation:stack-name"] contains "apono-cloudtrail")</code></td></tr><tr><td><strong>not_contains</strong></td><td>Checks if a value does NOT contain a literal string as a substring</td><td><code>permission_name not_contains "admin"</code></td></tr><tr><td><strong>starts_with</strong></td><td>Checks if a value begins with a specific string</td><td><code>resource_name starts_with "aws"</code></td></tr><tr><td><strong>ends_with</strong></td><td>Checks if a value ends with a specific string</td><td><code>(resource_tag["env"] ends_with "dev")</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Lists" %}
Operators that check if values exist within defined sets of options

{% hint style="warning" %}
All list operators are **case sensitive**.

For example, when checking if a value is in a list (`in`), AQL rejects `IN` because the casing is incorrect.
{% endhint %}

<table><thead><tr><th width="152">Logic</th><th width="252">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>in (_)</strong></td><td><p>Checks if the value is one of a list</p><p>Use a comma-separated list enclosed in parentheses. <strong>Do not</strong> add a comma after the final item.</p></td><td><code>resource_type in ("aws-account-dynamodb-table", "aws-account-s3", "aws-account-sns-topic")</code><br><br><code>resource_source_id in ("arn:aws:s3:::bucket-a", "arn:aws:s3:::bucket-b")</code></td></tr><tr><td><strong>not_in (_)</strong></td><td><p>Checks if the value is NOT one of a list</p><p>Use a comma-separated list enclosed in parentheses. <strong>Do not</strong> add a comma after the final item.</p></td><td><code>(resource_tag["aws:cloudformation:stack-name"] not_in ("apono-cloudtrail", "apono-doxy-dev"))</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Logic" %}
Operators that combine multiple conditions to create complex queries

{% hint style="info" %}
Logic operators are **not case** sensitive.
{% endhint %}

<table><thead><tr><th width="151">Logic</th><th width="252">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>and | AND</strong></td><td>Checks if both conditions are true</td><td><code>resource_type = "aws-account-s3" AND permission_name = "admin"</code></td></tr><tr><td><strong>or | OR</strong></td><td>Checks if either condition is true</td><td><code>resource_type = "aws-account-s3" OR resource_name contains "playground"</code></td></tr><tr><td><strong>not | NOT</strong></td><td>Negates a condition</td><td><code>integration = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" and not resource_type = "aws-account-sns-topic"</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

#### Unsupported

Operators not supported by AQL

<table><thead><tr><th width="144.85934448242188">Not supported</th><th width="252.06683349609375">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>*</strong></td><td>Wildcards</td><td><code>resource_name = "prod-*"</code></td></tr><tr><td><strong>&#x3C;</strong>, <strong>></strong>, <strong>&#x3C;=</strong>, <strong>>=</strong></td><td>Numeric comparison</td><td><code>resource_risk_level &#x3C;= "high"</code></td></tr><tr><td><strong>^</strong>, <strong>$</strong>, <strong>+</strong>, <strong>?</strong></td><td>Regular expressions (regex)</td><td><code>resource_name = "^prod"</code><br><code>resource_name = "prod-?s"</code></td></tr><tr><td><strong>between</strong></td><td>Ranges</td><td><code>between "2024-01-01" and "2024-12-31"</code></td></tr><tr><td><strong>exists</strong></td><td>Existence checks</td><td><code>exists(resource_tag["owner"])</code></td></tr><tr><td><strong>null</strong></td><td>Null checks</td><td><code>resource_tag["owner"] = null</code></td></tr></tbody></table>

***

### Common Queries

The following AQL queries demonstrate how to efficiently locate, audit, and manage cloud resources and permissions. They cover common use cases such as identifying high-risk assets, tracking access levels, and enforcing security policies.

Use these queries as a foundation and customize them to fit your specific environment and compliance requirements.

#### Resource Queries

Queries focused on locating and filtering cloud infrastructure resources

```sql
# Find production databases
resource_type = "aws-rds-mysql" and resource_name contains "prod"

# Find high-risk resources in specific region
resource_risk_level = "high" and resource_context["region"] = "us-east-1"

# Find resources by team ownership
resource_tag["team"] = "platform" and resource_tag["environment"] = "prod"
```

#### Permission Queries

Queries that manage and audit access control settings

{% code overflow="wrap" %}

```sql
# Find critical write permissions
permission_risk_level = "critical" and permission_context["access"] = "write"

# Find elevated permissions
permission_risk_level in ("high","critical") and not permission_name contains "readonly"
```

{% endcode %}

#### Combined Queries

Advanced patterns that merge resource and permission conditions for precise access control

```sql
# Find high-risk prod resources with write permissions
resource_name contains "prod"
and resource_risk_level = "high"
and permission_context["access"] = "write"
```

***

### Best Practices

Follow these best practices to write AQL queries that are clear, efficient, and easy to modify. These guidelines improve readability, execution speed, and adaptability.

#### Start with a specific condition

AQL processes conditions from left to right. Starting with a specific filter improves efficiency.

```sql
# Effective
resource_type = "aws-rds-mysql" and resource_name contains "prod"

# Less Efficient
resource_name contains "prod" and resource_type = "aws-rds-mysql"
```

#### Use lists instead of multiple OR conditions

When checking multiple values, `in (...)` is more concise and performs better than chaining multiple `or` conditions.

{% code overflow="wrap" %}

```sql
# Effective
resource_type in ("aws-rds-mysql", "aws-account-s3", "aws-ec2-ssh")

# Less efficient
resource_type = "aws-rds-mysql" or resource_type = "aws-account-s3" or resource_type = "aws-ec2-ssh"
```

{% endcode %}

#### Use parentheses to avoid ambiguity

Without parentheses, complex conditions can be misinterpreted and return unexpected results. Grouping conditions explicitly ensures the query evaluates as intended.

```sql
(resource_type = "aws-rds-mysql" and resource_name contains "prod")
or (resource_type = "aws-account-s3" and resource_name contains "backup")
```


---

# 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.apono.io/docs/inventory/apono-query-language.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.
