Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions internal-enrichment/metras/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__metadata__
**/__pycache__
**/__docs__
**/.venv
**/venv
**/logs
**/config.yml
**/*.egg-info
**/*.gql
.plan
tests
22 changes: 22 additions & 0 deletions internal-enrichment/metras/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM python:3.12-alpine

ENV CONNECTOR_TYPE=INTERNAL_ENRICHMENT
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY src /opt/opencti-connector-metras-enrichment

RUN apk update && apk upgrade --no-cache && \
apk --no-cache add libmagic libffi libxml2 libxslt && \
apk --no-cache add --virtual .build-deps git build-base libffi-dev libxml2-dev libxslt-dev && \
cd /opt/opencti-connector-metras-enrichment && \
pip3 install --no-cache-dir -r requirements.txt && \
apk del .build-deps

COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh && \
adduser -D -u 1000 connector && \
chown -R connector:connector /opt/opencti-connector-metras-enrichment
USER connector

ENTRYPOINT ["/entrypoint.sh"]
58 changes: 58 additions & 0 deletions internal-enrichment/metras/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# OpenCTI Metras Enrichment Connector (INTERNAL_ENRICHMENT)

Answers *"have I seen this in my fleet?"* by querying the [Metras](https://dashboard.metras.sa/)
platform when you enrich an observable in OpenCTI. Adds a context **Note** (and
**System identity** links to matched fleet endpoints) summarising local EDR/endpoint presence.

## Supported observables (`CONNECTOR_SCOPE`)

| Observable | Metras lookups | Output |
|---|---|---|
| **IPv4-Addr** | `/v1/edr/alerts?agent_ip=`, `/v1/endpoints?interface_ip=` | Note (alert + endpoint hits) + `related-to` **System identity** per matched endpoint |
| **StixFile** | `/v1/edr/binary/list?query=sha256:` / `?query=sha1:`, `/v1/edr/binary/details?md5=` | Note (publisher, signer, signature/runnability status, first/last seen) + System identity |

> Matched fleet endpoints are emitted as `Identity(identity_class="system")` (internal assets,
> not IOCs), consistent with the Feed connector and OpenCTI maintainer guidance (PR #6164).

> **Why only IPv4 + StixFile?** Metras exposes no value-lookup for domains or URLs, and
> `/v4/threats/detail` requires incident identifiers (title+direction+type), not an observable
> value. Domain/URL enrichment is therefore not offered.
>
> Fleet presence is conveyed via **Notes + relationships**, not STIX Sightings (the `stix2`
> library forbids a Sighting referencing an observable).

## Behavior & safety
- **Custom TLP check** (not `helper.check_max_tlp`) — skips observables above `METRAS_MAX_TLP`.
- **Refangs** values before querying Metras.
- **Partial results**: each lookup is wrapped; if at least one succeeds, results are sent.
If *all* lookups fail, a `ValueError` is raised so the failure is visible in the OpenCTI UI.
- Playbook-compatible (`playbook_compatible=True`, `entity_in_scope()` guard).

## Requirements
- OpenCTI **7.260529.0** (`pycti==7.260529.0`). A Metras API key.

## Configuration

| Env var | Required | Default | Description |
|---|---|---|---|
| `OPENCTI_URL` / `OPENCTI_TOKEN` / `CONNECTOR_ID` | yes | — | Standard connector settings |
| `CONNECTOR_NAME` | no | `Metras-Enrichment` | Connector name |
| `CONNECTOR_SCOPE` | no | `IPv4-Addr,StixFile` | Observable types to enrich |
| `CONNECTOR_AUTO` | no | `false` | Auto-enrich on observable creation |
| `CONNECTOR_LOG_LEVEL` | no | `error` | Log level |
| `METRAS_API_BASE_URL` | no | `https://api.metras.sa/api` | Metras API base URL |
| `METRAS_API_KEY` | yes | — | Metras API key |
| `METRAS_VERIFY_SSL` | no | `true` | Verify TLS certificates |
| `METRAS_MAX_TLP` | no | `amber+strict` | Max TLP to enrich (`clear`/`white`/`green`/`amber`/`amber+strict`/`red`) |

## Usage
Right-click an IPv4 or file-hash observable → **Enrich** → *Metras-Enrichment*, or set
`CONNECTOR_AUTO=true` to enrich automatically. Triggering via API uses
`stixCoreObjectEdit.askEnrichment(connectorId)` on OpenCTI 7.260529.0+.

## Troubleshooting
| Symptom | Cause / fix |
|---|---|
| "No Metras fleet data found" | The observable isn't present in your Metras fleet (expected for unknown IOCs) |
| Enrichment fails with auth error | Bad `METRAS_API_KEY` |
| File observable not enriched | Ensure `StixFile` is in `CONNECTOR_SCOPE` |
1 change: 1 addition & 0 deletions internal-enrichment/metras/VERSION
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.0.0
116 changes: 116 additions & 0 deletions internal-enrichment/metras/__metadata__/connector_config_schema.json
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://www.filigran.io/connectors/w_config.schema.json",
"type": "object",
"properties": {
"OPENCTI_URL": {
"description": "The base URL of the OpenCTI instance.",
"format": "uri",
"maxLength": 2083,
"minLength": 1,
"type": "string"
},
"OPENCTI_TOKEN": {
"description": "The API token to connect to OpenCTI.",
"type": "string"
},
"CONNECTOR_NAME": {
"default": "Metras-Enrichment",
"examples": [
"Metras-Enrichment"
],
"type": "string"
},
"CONNECTOR_SCOPE": {
"default": [
"IPv4-Addr",
"StixFile"
],
"description": "Entity types this connector enriches.",
"examples": [
[
"IPv4-Addr",
"StixFile"
]
],
"items": {
"type": "string"
},
"type": "array"
},
"CONNECTOR_LOG_LEVEL": {
"default": "error",
"description": "The minimum level of logs to display.",
"enum": [
"debug",
"info",
"warn",
"warning",
"error"
],
"type": "string"
},
"CONNECTOR_TYPE": {
"const": "INTERNAL_ENRICHMENT",
"default": "INTERNAL_ENRICHMENT",
"type": "string"
},
"CONNECTOR_AUTO": {
"default": false,
"examples": [
false
],
"type": "boolean"
},
"METRAS_API_BASE_URL": {
"default": "https://api.metras.sa/api",
"description": "Base URL of the Metras API.",
"examples": [
"https://api.metras.sa/api"
],
"format": "uri",
"maxLength": 2083,
"minLength": 1,
"type": "string"
},
"METRAS_API_KEY": {
"description": "Metras API key (X-API-KEY header).",
"examples": [
"ChangeMe"
],
"format": "password",
"type": "string",
"writeOnly": true
},
"METRAS_VERIFY_SSL": {
"default": true,
"description": "Verify TLS certificates.",
"examples": [
true
],
"type": "boolean"
},
"METRAS_MAX_TLP": {
"description": "Maximum TLP level the connector will enrich.",
"enum": [
"clear",
"white",
"green",
"amber",
"amber+strict",
"red"
],
"type": "string",
"default": "amber+strict",
"examples": [
"amber+strict"
]
}
},
"required": [
"OPENCTI_URL",
"OPENCTI_TOKEN",
"METRAS_API_KEY"
],
"additionalProperties": true
}
22 changes: 22 additions & 0 deletions internal-enrichment/metras/__metadata__/connector_manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"title": "Metras Enrichment Connector",
"slug": "metras-enrichment",
"description": "Enriches IPv4 and file-hash observables by querying Metras for fleet presence (EDR alerts, endpoint inventory, binary inventory), returning context Notes and system-identity links ('have I seen this in my environment?').",
"short_description": "Enrichment connector for Metras fleet presence lookups",
"logo": null,
"use_cases": ["Detection & Response Enablement"],
"solution_categories": ["Endpoint Detection & Response"],
"contact": null,
"license_type": "Commercial",
"verified": false,
"last_verified_date": null,
"playbook_supported": true,
"max_confidence_level": 50,
"support_version": ">=7.260529.0",
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
"subscription_link": null,
"source_code": "https://github.com/OpenCTI-Platform/connectors/tree/master/internal-enrichment/metras",
"manager_supported": false,
"container_version": "1.0.0",
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
"container_image": "opencti/connector-metras-enrichment",
"container_type": "INTERNAL_ENRICHMENT"
}
17 changes: 17 additions & 0 deletions internal-enrichment/metras/config.yml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
opencti:
url: 'http://localhost:8080'
token: 'ChangeMe'

connector:
type: 'INTERNAL_ENRICHMENT'
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
id: 'ChangeMe' # UUIDv4
name: 'Metras-Enrichment'
scope: 'IPv4-Addr,StixFile'
log_level: 'info'
auto: false

metras:
api_base_url: 'https://api.metras.sa/api'
api_key: 'ChangeMe'
verify_ssl: true
max_tlp: 'amber+strict'
29 changes: 29 additions & 0 deletions internal-enrichment/metras/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
services:
connector-metras-enrichment:
build:
context: .
dockerfile: Dockerfile
Comment thread
Khidr6G marked this conversation as resolved.
Outdated
image: opencti/connector-metras-enrichment:1.0.0
environment:
- OPENCTI_URL=http://opencti:8080
- OPENCTI_TOKEN=${OPENCTI_ADMIN_TOKEN}
- CONNECTOR_ID=${CONNECTOR_METRAS_ENRICHMENT_ID}
- CONNECTOR_TYPE=INTERNAL_ENRICHMENT

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never configurable, always hardcoded - should de removed

- CONNECTOR_NAME=Metras-Enrichment
- CONNECTOR_SCOPE=IPv4-Addr,StixFile
- CONNECTOR_LOG_LEVEL=info
- CONNECTOR_AUTO=false
- METRAS_API_BASE_URL=https://api.metras.sa/api
- METRAS_API_KEY=${METRAS_API_KEY}
- METRAS_VERIFY_SSL=true
- METRAS_MAX_TLP=amber+strict
restart: always
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
mem_limit: 512m
pids_limit: 100
3 changes: 3 additions & 0 deletions internal-enrichment/metras/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
cd /opt/opencti-connector-metras-enrichment
exec python3 main.py
5 changes: 5 additions & 0 deletions internal-enrichment/metras/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[tool.coverage.run]
source = ["connector", "metras_client"]

[tool.coverage.report]
show_missing = true
4 changes: 4 additions & 0 deletions internal-enrichment/metras/src/connector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from connector.connector import MetrasEnrichmentConnector
from connector.settings import ConnectorSettings

__all__ = ["MetrasEnrichmentConnector", "ConnectorSettings"]
Loading
Loading