OpenStack Neutron Security Group Audit

Driftmux can audit OpenStack Neutron security groups to detect public exposure of critical ports.

This mode does not scan virtual machines directly. Instead, it queries the OpenStack API and analyses Neutron security group rules.

It is useful when the cloud administrator does not have access to the guest operating systems but still wants to identify dangerous network exposure at the cloud layer.

What it detects

The OpenStack scanner detects ingress security group rules that expose critical ports to public CIDRs such as:

0.0.0.0/0
::/0

Examples of detected exposures:

SSH 22/tcp exposed to 0.0.0.0/0
RDP 3389/tcp exposed to 0.0.0.0/0
PostgreSQL 5432/tcp exposed to 0.0.0.0/0
Redis 6379/tcp exposed to 0.0.0.0/0
Elasticsearch/OpenSearch 9200/tcp exposed to 0.0.0.0/0
Docker API 2375/tcp exposed to 0.0.0.0/0
Kubernetes API 6443/tcp exposed to 0.0.0.0/0
All ports exposed to 0.0.0.0/0

By default, HTTP and HTTPS exposure on ports 80/tcp and 443/tcp is not reported as a high-risk finding.

What it does not do

The OpenStack scanner does not log into virtual machines.

It does not inspect:

Guest operating systems
Installed packages inside VMs
Local users
Processes
Rootkits
Filesystem integrity
Application logs inside the VM

It only analyses the cloud networking configuration available through the OpenStack API.

Requirements

The scanner requires:

openstacksdk
Valid OpenStack credentials
Permissions to list Neutron security group rules
Permissions to list Neutron ports
Permissions to read projects and servers, if usage enrichment is enabled

Install the Python dependency:

pip install openstacksdk

If you installed Driftmux in editable mode:

pip install -e .

Authentication

The scanner supports the usual OpenStack authentication methods.

Using clouds.yaml

Example:

driftmux --openstack-sg-audit --os-cloud openstack

Using an OpenRC file

Example:

source admin-openrc.sh
driftmux --openstack-sg-audit --format markdown

Basic usage

Run the OpenStack security group audit:

driftmux --openstack-sg-audit --os-cloud openstack --format markdown

Generate JSON output:

driftmux --openstack-sg-audit --os-cloud openstack --format json

Generate CSV output:

driftmux --openstack-sg-audit --os-cloud openstack --format csv

Output files

The OpenStack audit generates a dedicated report name:

reports/driftmux-openstack-neutron-security-groups.md
reports/driftmux-openstack-neutron-security-groups.json
reports/driftmux-openstack-neutron-security-groups.csv

This avoids mixing OpenStack findings with host-based scan reports.

Console output

The console output summarizes findings grouped by project.

Example:

OpenStack Neutron Security Group Audit
Checked rules: 3254
Findings: 340
Errors: 0

[project-a] total=12 critical=1 high=11
  - CRITICAL sg=default ports=all src=0.0.0.0/0 match=all_ports used_by=3
  - HIGH sg=k8s-master ports=22 src=0.0.0.0/0 match=22/SSH used_by=2

[project-b] total=2 critical=0 high=2
  - HIGH sg=elasticsearch ports=9200 src=0.0.0.0/0 match=9200/Elasticsearch/OpenSearch used_by=1

Markdown report

The Markdown report groups findings by project:

# Driftmux report

## Driftmux OpenStack Neutron Security Group Audit

- Checked rules: 3254
- Findings: 340
- Errors: 0

### Project: datalab-users `project-id`

- Total findings: 12
- Critical: 1
- High: 11
- Medium: 0
- Low: 0
- Info: 0

| Severity | Security group | Protocol | Ports | Source | Match | Used by ports | Used by servers | Rule ID |
|---|---|---|---|---|---|---:|---:|---|
| CRITICAL | default | any | all | 0.0.0.0/0 | all_ports | 3 | 2 | rule-id |
| HIGH | ssh-public | tcp | 22 | 0.0.0.0/0 | 22/SSH | 1 | 1 | rule-id |

JSON output

Each finding is represented using the common Driftmux finding model.

Example:

{
  "scanner": "openstack",
  "host": "openstack:neutron",
  "title": "OpenStack security group exposure: datalab/default exposes all ports to 0.0.0.0/0 (all_ports) [active, servers=2]",
  "severity": "critical",
  "description": "OpenStack Neutron security group rule exposes a critical port or port range to a public CIDR.",
  "evidence": "rule_id=... sg=default project=datalab direction=ingress protocol=None ports=None-None remote_ip_prefix=0.0.0.0/0 used_by_ports=3 used_by_servers=2 exposure_status=active",
  "confidence": "high",
  "port": null,
  "service": "neutron-security-group",
  "metadata": {
    "event_type": "openstack_security_group_exposure",
    "project_id": "project-id",
    "project_name": "datalab",
    "security_group_id": "security-group-id",
    "security_group_name": "default",
    "remote_ip_prefix": "0.0.0.0/0",
    "matched": [
      "all_ports"
    ],
    "used_by_count": 3,
    "used_by_server_count": 2,
    "exposure_status": "active"
  }
}

Active and unused exposures

The OpenStack scanner distinguishes between two states:

active
unused

Active exposure

A finding is marked as active when the security group is attached to at least one Neutron port.

Example:

SSH 22/tcp exposed to 0.0.0.0/0 and applied to one or more VM ports

Unused exposure

A finding is marked as unused when the rule exists but the security group is not currently attached to any Neutron port.

Example:

SSH 22/tcp exposed to 0.0.0.0/0 but the security group is not used by any port

Unused exposures are still reported because they may become dangerous if the security group is later attached to a server.

Severity model

The default severity model is:

Condition

Active SG

Unused SG

All ports exposed to 0.0.0.0/0 or ::/0

Critical

High

Critical service exposed to 0.0.0.0/0 or ::/0

High

Medium

HTTP/HTTPS only

Info or ignored

Info or ignored

Examples:

0.0.0.0/0 -> all ports -> active -> CRITICAL
0.0.0.0/0 -> 22/tcp -> active -> HIGH
0.0.0.0/0 -> 22/tcp -> unused -> MEDIUM
0.0.0.0/0 -> 80/tcp -> ignored by default
0.0.0.0/0 -> 443/tcp -> ignored by default

Critical ports

By default, Driftmux checks for common administrative, database and infrastructure ports.

Port

Service

22

SSH

3389

RDP

3306

MySQL/MariaDB

5432

PostgreSQL

6379

Redis

27017

MongoDB

9200

Elasticsearch/OpenSearch

5601

Kibana/OpenSearch Dashboards

8080

HTTP alternative/Tomcat

8443

HTTPS alternative

9092

Kafka

11211

Memcached

2049

NFS

445

SMB

389

LDAP

636

LDAPS

2375

Docker API without TLS

2376

Docker API with TLS

6443

Kubernetes API

10250

Kubelet

5900-5999

VNC

Security group usage enrichment

Driftmux tries to determine whether each affected security group is currently used.

It builds the following relationship:

security_group_rule
        |
        v
security_group
        |
        v
neutron port.security_group_ids
        |
        v
port.device_id
        |
        v
nova server

The scanner enriches findings with:

used_by_count
used_by_server_count
used_by_ports
used_by_servers
exposure_status

Example metadata:

{
  "used_by_count": 2,
  "used_by_server_count": 1,
  "used_by_servers": [
    {
      "server_id": "server-id",
      "server_name": "vm-01",
      "status": "ACTIVE",
      "project_id": "project-id"
    }
  ],
  "exposure_status": "active"
}

Important limitation

exposure_status=active means that the security group is attached to at least one Neutron port.

It does not prove that traffic has actually reached the VM.

To know whether the exposed rule is receiving traffic, you need network telemetry such as:

Neutron security group logging
OVN/OVS flow logs
Suricata
Zeek
Firewall logs
Router logs