Security Groups¶
Security groups are virtual firewalls that control inbound and outbound traffic to compute instances. Each group holds a set of rules; a server can belong to one or more groups. Neutron automatically creates two default egress rules on every new group (allow all IPv4 egress and allow all IPv6 egress).
Concepts¶
- Group — a named container of rules, scoped to a project.
- Rule — a single allow entry specifying direction, protocol, port range, and traffic source or destination. Rules are immutable: to change a rule, delete it and create a new one.
- Attachment — a server references groups by name at creation time via the
security_groupsparameter. Changing the group list requires a server rebuild/recreate (server-level parameter).
Endpoints¶
| Method | Path | Description |
|---|---|---|
GET | /cloud/security-groups?project_id=<uuid> | List security groups |
POST | /cloud/security-groups?project_id=<uuid> | Create a security group |
GET | /cloud/security-groups/{id}?project_id=<uuid> | Show a security group |
PUT | /cloud/security-groups/{id}?project_id=<uuid> | Update name/description |
DELETE | /cloud/security-groups/{id}?project_id=<uuid> | Delete a security group |
GET | /cloud/security-groups/{id}/rules?project_id=<uuid> | List rules |
POST | /cloud/security-groups/{id}/rules?project_id=<uuid> | Add a rule |
DELETE | /cloud/security-groups/{id}/rules/{rule_id}?project_id=<uuid> | Remove a rule |
project_id is required on every request.
List security groups¶
Returns an envelope with data as an array of security group objects:
{
"metadata": {
"organization_id": "org-uuid",
"project_id": "proj-uuid",
"timestamp": "2026-06-05T10:00:00Z",
"count": 2
},
"data": [
{
"id": "sg-uuid-1",
"name": "default",
"description": "Default security group",
"security_group_rules": [...],
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}
]
}
Create a security group¶
POST /cloud/security-groups?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "web-tier",
"description": "Web servers — allow HTTP and HTTPS inbound"
}
name is required. description is optional.
Returns 201 Created with the new group in data. Neutron automatically adds two default egress rules (allow-all IPv4 egress + allow-all IPv6 egress) visible in data.security_group_rules.
Show a security group¶
Security group object fields:
| Field | Type | Description |
|---|---|---|
id | string | Security group UUID |
name | string | Display name |
description | string | Human-readable description |
security_group_rules | array | Embedded rules (see Rule object) |
created_at | ISO 8601 | Creation timestamp |
updated_at | ISO 8601 | Last update timestamp |
Update a security group¶
Updates name and/or description in-place. Rules are not affected.
PUT /cloud/security-groups/<id>?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "web-tier-v2",
"description": "Updated description"
}
Returns 200 OK with the updated group.
Delete a security group¶
Returns 204 No Content on success.
In-use groups return 422
If the group is still attached to one or more servers, the API returns 422 Unprocessable Entity with an error envelope. Detach all servers before deleting the group.
List rules¶
Returns the same rule objects embedded in the group's security_group_rules, including Neutron's auto-created default egress rules.
Add a rule¶
POST /cloud/security-groups/<id>/rules?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"direction": "ingress",
"ethertype": "IPv4",
"protocol": "tcp",
"port_range_min": 443,
"port_range_max": 443,
"remote_ip_prefix": "0.0.0.0/0"
}
Returns 201 Created with the new rule in data.
Rule create fields¶
| Field | Required | Type | Description |
|---|---|---|---|
direction | yes | ingress | egress | Traffic direction |
ethertype | no | IPv4 | IPv6 | Address family; defaults to IPv4 |
protocol | no | string | tcp, udp, icmp, icmpv6, or null for any |
port_range_min | no | integer | Start of port range (1–65535) |
port_range_max | no | integer | End of port range (1–65535) |
remote_ip_prefix | no | CIDR string | Source/destination CIDR; mutually exclusive with remote_group_id |
remote_group_id | no | UUID | Match traffic from/to another security group; mutually exclusive with remote_ip_prefix |
remote_ip_prefix and remote_group_id are mutually exclusive — setting both returns 422 Unprocessable Entity.
Remove a rule¶
Returns 204 No Content. Rules cannot be updated; delete and re-create to change a rule.
Rule object¶
| Field | Type | Description |
|---|---|---|
id | string | Rule UUID |
security_group_id | string | Parent security group UUID |
direction | ingress | egress | Traffic direction |
ethertype | IPv4 | IPv6 | Address family |
protocol | string | null | IP protocol, or null for any |
port_range_min | integer | null | Start of port range |
port_range_max | integer | null | End of port range |
remote_ip_prefix | string | null | Source/destination CIDR |
remote_group_id | string | null | Remote security group UUID |
created_at | ISO 8601 | Creation timestamp |
Error responses¶
| Status | When |
|---|---|
400 | Missing project_id or required body field |
403 | Forbidden (insufficient permissions) |
404 | Security group or rule not found |
422 | Validation failed — group in use on DELETE, or remote_ip_prefix+remote_group_id both set on rule create |
503 | OpenStack API unavailable |
See Response Envelope for the error shape.
Related pages¶
- Servers — attach security groups at server creation
- Networking — private networks and subnets
- Guide: Per-instance firewalling with security groups