This document describes MidoNet’s implementation of logging for firewall rules.
FWaaS v2.0 will be implemented in newton, However, first of all we implement MidoNet for mitaka with FWaaS v1.0 because development schedule between networking-midonet and neutron does not match.
Note that eventually we aim to unify this spec and spec for upstream [1]. Thus, this spec is written following spec for upstream. In addition, we should keep on watch spec for upstream because the spec have not completed yet.
In Neutron, traffic accepted/denied on routers are managed by FWaaS. However, logging is currently a missing feature in FWaaS. Thus, requirements above cannot be satisfied.
The scope of this spec:
How tenants can consume outputted logs are out of scope. Logging format that will be sent to tenants are out of scope. Where the logs are generated is also out of scope.
Add ‘logging-resource’ extension alias in the supported extension aliases list.
MidoNet plugin implement the CRUD methods for logging resource and firewall log objects.
The events related to firewall rules will collect:
- ACCEPT event
- DROP event
Operators and tenants can specify what kind of events they want to log. Note that only logging of firewall rules that are created explicitly are gathered.
- ACCEPT/DROP or ALL (collect all ACCEPT/DROP events of firewalls).
- firewall uuid.
In this spec, two resources are newly defined.
LoggingResource is root resource for logging. This model defines policy of logging. e.g. how can we see logs, where logs are going to be collected.
FirewallLog is logging resource for specific resource. Though this spec proposes only FWaaS, many logging resources for specific resource will be supported in the future. (e.g. security group)
In addition, firewall can be associated with multiple logging resource only when the tenant_ids are different to allow operators and tenants to specify same firewall as logging resource. This allows operators to gather log in all of system.
Note that there is no difference in outputted format between tenant’s logging resource and operator’s logging resource. If operator wants to operate description above, some validations are needed to solve why the log is outputted.
The rough sketch that contains future consideration is following;
TenantA---------LoggingResourceA------FirewallLogA-----------
| |
|--------------SecurityGroupLogA |------firewallA
|
AdminTenant-----LoggingResourceB------FirewallLogB-----------
|
|--------------FirewallLogC
|
|--------------SecurityGroupLogB
LoggingResource
Attribute Name | Type | CRUD | Required | Description |
---|---|---|---|---|
id | string (UUID) | CR | generated | ID of the LoggingResource |
name | string | CRU | No | Defined LoggingResource name |
description | string | CRU | No | Description for the LoggingResource |
tenant_id | string | CR | No | Tenant ID of LoggingResource object owner |
enabled | string | CRU | No | Enable/disable for the LoggingResource. log is gathered only when this flag is enable. |
FirewallLog
Attribute Name | Type | CRUD | Required | Description |
---|---|---|---|---|
id | string (UUID) | CR | generated | ID of the FirewallLog |
description | string | CRU | No | Description for FirewallLog |
tenant_id | string | CR | No | Tenant ID of FirewallLog object owner |
fw_event | string | CRU | No | Event of firewall. ACCEPT/DROP/ALL can be specified. ALL is set as default. |
firewall_id | string (UUID) | CR | Yes | ID of firewall instance |
API list is as follows. Note that api path prefix ‘logging’ may conflict with upstream. However, we keep this prefix to keep consitency with upstream. To avoid confusion, we should do following things.
- Separate our plugin configuration from upstream.
- Note to user that not to use both plugins together.
Object | URI | Type |
---|---|---|
logging-resource | /logging/logging_resources | POST |
logging-resource | /logging/logging_resources | GET |
logging-resource | /logging/logging_resources/{id} | GET |
logging-resource | /logging/logging_resources/{id} | DELETE |
logging-resource | /logging/logging_resources/{id} | PUT |
firewall-log | /logging/logging_resources/{id}/firewall_logs | POST |
firewall-log | /logging/logging_resources/{id}/firewall_logs | GET |
firewall-log | /logging/logging_resources/{id}/firewall_logs/{id} | GET |
firewall-log | /logging/logging_resources/{id}/firewall_logs/{id} | DELETE |
firewall-log | /logging/logging_resources/{id}/firewall_logs/{id} | PUT |
To Create a LoggingResource to manage security event log, following API can be used:
JSON Request
POST /v2.0/logging/logging_resources
{
"logging_resource": {
"name": "firewall_log",
"description": "Get traffic flow of firewall",
"enabled": True
}
}
Response:
Response:
{
"logging_resource": {
"id": "46ebaec0-0570-43ac-82f6-60d2b03168c4",
"tenant_id": "8d4c70a21fed4aeba121a1a429ba0d04",
"name": "firewall_log",
"description": "Get traffic flow of firewall",
"enabled": True
}
}
To Create a FirewallLog to collect security event of the firewall, following API can be used:
JSON Request
POST /v2.0/logging/logging_resources/46ebaec0-0570-43ac-82f6-60d2b03168c4/firewall_logs
{
"firewall_log": {
"description": "Collecting all traffic passing the firewall",
"fw_event": "ALL",
"firewall_id: "21aeda2a-a52f-4e81-9e64-7edeb59fa25b"
}
}
Response:
{
"firewall_log": {
"id": "5f126d84-551a-4dcf-bb01-0e9c0df0c793",
"tenant_id": "8d4c70a21fed4aeba121a1a429ba0d04",
"logging_resource_id": "46ebaec0-0570-43ac-82f6-60d2b03168c4",
"description": "Collecting all traffic passing the firewall",
"fw_event": "ALL",
"firewall_id": "21aeda2a-a52f-4e81-9e64-7edeb59fa25b"
}
}
The new resources:
LOGGING_PREFIX = '/logging'
FW_EVENT_ACCEPT = 'ACCEPT'
FW_EVENT_DROP = 'DROP'
FW_EVENT_ALL = 'ALL'
FW_EVENTS = [FW_EVENT_ACCEPT, FW_EVENT_DROP, FW_EVENT_ALL]
LOG_COMMON_FIELDS = {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True, 'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True, 'is_visible': True},
'logging_resource_id': {'allow_post': False, 'allow_put': False,
'is_visible': True}
}
RESOURCE_ATTRIBUTE_MAP = {
'logging_resources': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True, 'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': attr.NAME_MAX_LEN},
'default': '', 'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': attr.LONG_DESCRIPTION_MAX_LEN},
'default': '', 'is_visible': True},
'enabled': {'allow_post': True, 'allow_put': True,
'is_visible': True, 'default': False,
'convert_to': attr.convert_to_boolean},
'firewall_logs': {'allow_post': False, 'allow_put': False,
'is_visible': True}
}
}
SUB_RESOURCE_ATTRIBUTE_MAP = {
'firewall_logs': {
'parent': {'collection_name': 'logging_resources',
'member_name': 'logging_resource'},
'parameters': dict((LOG_COMMON_FIELDS),
**{
'description': {
'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'default': None, 'is_visible': True},
'firewall_id': {
'allow_post': True, 'allow_put': False,
'is_visible': True,
'validate': {'type:uuid': None}},
'fw_event': {
'allow_post': True, 'allow_put': True,
'is_visible': True,
'validate': {'type:values': FW_EVENT},
'default': 'ALL'}
})
},
}
Following items can be shown as follows. Eventually, we catch up neutron behavior that agent collects logs and sends logs to specified location from user. Therefore, outputted items should be unified with neutron after supporting function in neutron.
Item | Description |
---|---|
tenant_id | Tenant ID of targeted firewall |
timestamp | Time of the event is happened The time is based on ISO8601, time zone is UTC |
firewall UUID | UUID of neutron firewall |
firewall rule UUID | UUID of neutron firewall rule |
router UUID | UUID of neutron router |
source IP address | Source IP address of the communication |
destination IP address | Destination IP address of the communication |
source L4 port | Source L4 port of the communication |
destination L4 port | Destination L4 port of the communication |
protocol | IANA protocol number |
action | ACCEPT/DROP |
Currently, operators can only access directly to file on host that midolman is running to consume log-data. File location has format: /var/log/midolman/logging/fw-<firewall-log-uuid>.log How generated log files are sent to tenants is up to the operator. Backend implementation and/or log collector are expected to handle log rotation. In the case with MidoNet, log rotation policy can be configured using its configuration tool.
To avoid competition of table name with upstream, we add specific initial to head of table names. Note that upstream DB will be reused in newton or later and DB in networking-midonet will be deleted.
The LoggingResource model has the following attributes:
midonet_logging_resources
Attribute Name | Type | Access | Default Value | Validation/ Conversion | Description |
---|---|---|---|---|---|
id | uuid | RO | generated | uuid | Identity |
tenant_id | uuid | RO | N/A | uuid | Id of tenant that created this LoggingResource |
name | string | RW | N/A | none | LoggingResource name |
description | string | RW | N/A | none | LoggingResource description |
enabled | bool | RW | False | Boolean | Enable/disable log |
The FirewallLog model would look like:
midonet_firewall_logs
Attribute Name | Type | Access | Default Value | Validation/ Conversion | Description |
---|---|---|---|---|---|
id | uuid | RO | generated | uuid | Identity |
logging_resource_id | uuid | RO | N/A | uuid | LoggingResource UUID |
tenant_id | uuid | RO | generated | uuid | Tenant creates logging |
description | string | RW | N/A | none | FirewallLogging description |
fw_event | enum | RW | N/A | enum | ACCEPT/DROP & ALL (collect all ACCEPT/DROP events) |
firewall_id | uuid | RW(No update) | N/A | uuid | Firewalls UUID is enabled logging |
Firewall log is managed by Quota. Default value of firewall log is 10 that is same number as firewall. Basically, both Quota value for firewall and firewall log should be aligned.
Additional methods will be added to python-neutronclient to create, update, delete, list, get logging resource and firewall logging.
Checking support resource logging
For logging resource:
neutron logging-create --name <logging-resource-name>
[--enable <True/False>]
[--description <logging-resource-description>]
neutron logging-list
neutron logging-update <logging-resource-name-or-id>
[--name ...]
[--description ...]
[--enable <True/False>]
neutron logging-show <logging-resource-name-or-id>
neutron logging-delete <logging-resource-name-or-id>
For firewalls logging:
neutron logging-firewall-create <logging-resource-name-or-id> <firewall-id>
[--description <firewall-log description>]
[--fw-event <ACCEPT/DROP/ALL>]
neutron logging-firewall-list <logging-resource-name-or-id>
neutron logging-firewall-update <logging-resource-name-or-id> <firewall-log-id>
[--description ...]
[--fw-event ...]
neutron logging-firewall-show <logging-resource-name-or-id> <firewall-log-id>
neutron logging-firewall-delete <logging-resource-name-or-id> <firewall-log-id>
Set quota for firewall log in quotas section of neutron.conf.
quota_firewall_log = 10