Policy Engine (Gatekeeper FSM plugin) Framework for DNS, URL, IP, App Lookup
Design
As part of this feature, we are monotoring network activities using these attributes:
DNS requests
WAN IPs (inbound and outbound)
Application names, URL/SNI host names bound to an IP flow
The controller reply provides the action to take (block/allow/redirect) and the requirement to report.
The controller also provides a TTL for the attribute, builds an action map, and the node caches the mapping on a per-device base.
The controller communicates node cache entries to validate the policy changes.
The node reports HERO stats periodically per device.
Data Presentation
The data is presented using protobuf structure.
A message (request/reply) envelops a "typed" message. A "typed" message refers to a specific message (FQDN, URL, IPv[4,6], IP tuples). Fields that are present in all messages are factorized in GatekeeperCommon[Request,Reply].
The protobuff structure is available here: https://github.com/plume-design/opensync/blob/osync_2.4.0/interfaces/gatekeeper.proto.
OVSDB Configuration
A plugin presents the FSM_Policy engine a flow attribute and gets in return the action to apply to the flow.
As currently designed, the FSM policy engine processes the object in 3 folds:
Optionally requests a 3rd party plugin further properties of the flow attributes (web categories such as shopping, news, etc.).
Compare the flow attribute properties to a provisioned set of properties and return the action to take to the requesting plugin when a match is found.
Report the action taken if requested so.
The indication is provided through a new action label called "gatekeeper".
Here is a configuration example:
## FSM policy settings. This shows the option to create various gatekeeper policies
$ ovsh s FSM_Policy -w action==gatekeeper
--------------------------------------------------------
_uuid | cf1d~9bbc | ec54~6ee8 |
_version | ab48~c4b4 | 48a7~f53d |
action | gatekeeper | gatekeeper |
fqdn_op | ["set",[]] | ["set",[]] |
fqdncat_op | ["set",[]] | ["set",[]] |
fqdncats | ["set",[]] | ["set",[]] |
fqdns | ["set",[]] | ["set",[]] |
idx | 9 | 10 |
ipaddr_op | ["set",[]] | ["set",[]] |
ipaddrs | ["set",[]] | ["set",[]] |
log | all | all |
mac_op | out | out |
macs | ["set",[]] | ["set",[]] |
name | dev_rule_dns | dev_rule_sni |
next | ["map",[]] | ["map",[]] |
other_config | ["map",[]] | ["map",[]] |
policy | dev_gatekeeper_dns | dev_gatekeeper_sni |
redirect | ["set",[]] | ["set",[]] |
risk_level | ["set",[]] | ["set",[]] |
risk_op | ["set",[]] | ["set",[]] |
--------------------------------------------------------
## The FUT gatekeeper plugin:
# ovsh -j s Flow_Service_Manager_Config -w handler==dev_gatekeeper
[
{
"if_name": "",
"_version": [
"uuid",
"ebc6b5cb-d187-470d-a443-9ff6b87343b7"
],
"other_config": [
"map",
[
[
"cacert",
"/usr/opensync/tools/cacert.pem"
],
[
"dso_init",
"gatekeeper_plugin_init"
],
[
"gk_url",
"https://[]"
],
[
"wc_health_stats_interval_secs",
"30"
],
[
"wc_health_stats_topic",
"dev-test/WC/Stats/Health/futs/xxxx8002B3/xxxx9f5acbb22513f0ae5e17"
]
]
],
"type": "web_cat_provider",
"plugin": "/usr/osync/lib/libfsm_gatekeeper.so",
"_uuid": [
"uuid",
"c2c69b7f-1182-42f7-a3dc-226eb505c7ce"
],
"pkt_capt_filter": "",
"handler": "dev_gatekeeper"
}
]
## The FUT DNS plugin settings for gatekeeper:
$ ovsh s Flow_Service_Manager_Config -w handler==dev_dns
------------------------------------------------------------------------------------------------
_uuid | a484~baf0 |
_version | 7c2f~3081 |
handler | dev_dns |
if_name | br-home.devdns |
other_config | ["map",[["dso_init","dns_plugin_init"],["mqtt_v", |
: "dev-test/DNS/Queries/opensync/xxxx8002B3/xxxx9f5acbb22513f0ae5e17"], :
: ["policy_table","dev_gatekeeper_dns"],["provider_plugin","dev_gatekeeper"]]] :
pkt_capt_filter | |
plugin | /usr/opensync/lib/libfsm_dns.so |
type | parser |
------------------------------------------------------------------------------------------------
## The FUT SNI plugin settings for gatekeeper:
$ ovsh s Flow_Service_Manager_Config -w handler==dev_dpi_sni
------------------------------------------------------------------------------------------------
_uuid | 325f~31b4 |
_version | 5996~5745 |
handler | dev_dpi_sni |
if_name | |
other_config | ["map",[["dpi_plugin","walleye_dpi"],["dso_init","dpi_sni_plugin_init"], |
: ["flow_attributes","${dev_sni_attrs}"],["mqtt_v", :
: "dev-test/SNI/Requests/opensync/xxxx8002B3/xxxx9f5acbb22513f0ae5e17"], :
: ["policy_table","dev_gatekeeper_sni"],["provider_plugin","dev_gatekeeper"]]] :
pkt_capt_filter | |
plugin | /usr/opensync/lib/libfsm_dpi_sni.so |
type | dpi_client |
------------------------------------------------------------------------------------------------ |
MQTT Report Format
With the settings above, the following reports will be produced when executing the command curl for https://www.lemonde.fr.
The first report is a DNS report, the second is a SNI report:
{
"dnsQueries": [
{
"action": "allowed",
"deviceMac": "00:E0:4C:20:9F:85",
"dnsAddress": "www.lemonde.fr",
"dnsCategorization": {
"categoryId": 100,
"confidenceLevel": 30,
"gatekeeperFilter": "dev_rule_dns_from_gk",
"source": "dev_gatekeeper"
},
"fromCache": "false",
"policy": "dev_gatekeeper_dns",
"policyIndex": 9,
"ruleName": "dev_rule_dns"
}
],
"locationId": "xxxx9f5acbb22513f0ae5e17",
"nodeId": "xxxx8002B3",
"reportedAt": "2021-02-12T10:32:50.237Z",
"version": "1.0.0"
}
Waiting for the next message for 90 seconds
2021-02-12 10:32:51,642 - __main__ - INFO - got message from emqtt-dog1-0af01323.dogfood.us-west-2.aws.osync.tech:dev-test/SNI/Requests/dog1/4C718002B3/59f39f5acbb22513f0ae5e17
{
"httpsSniQueries": [
{
"action": "allowed",
"deviceMac": "00:E0:4C:20:9F:85",
"fromCache": "false",
"httpsSni": "www.lemonde.fr",
"httpsSniCategorization": {
"categoryId": 100,
"confidenceLevel": 30,
"gatekeeperFilter": "dev_rule_sni_from_gk",
"source": "dev_gatekeeper"
},
"policy": "dev_gatekeeper_sni",
"policyIndex": 10,
"ruleName": "dev_rule_sni"
}
],
"locationId": "xxxx9f5acbb22513f0ae5e17",
"nodeId": "xxxx8002B3",
"reportedAt": "2021-02-12T10:32:50.791Z",
"version": "1.0.0"
} |
Clearing the Gatekeeper Cache Entries
Gatekeeper cache entries can be flushed using Node_Config. Gatekeeper cache can be cleared by running the below command:
ovsh i Node_Config module:=fsm key:=clear_gatekeeper_cache value:=clear |
Configuring the Gatekeeper Service URL and Certificates
The Gatekeeper plugin should have the information of Gatekeeper Service URL and the certificates required to access it. This can be configured using the Gatekeeper plugin's other_config using the key gk_url and cacert.
"other_config":
["map",[
["dso_init","gatekeeper_plugin_init"],
["gk_url","https://[]:443"],
["cacert","/tmp/cacert.pem"]
]] |
Connectivity Issues
FSM uses libcurl to connect to the Gatekeeper Service. After a request is sent the execution is blocked until the response is received from the Gatekeeper Service.
CURL time stats for retrieving data from the Gatekeeper Service (Docker Instance).
DNS lookup : 0.000181 sec
TCP Connection: 0.000184 sec
TLS Handshake: 0.000578 sec
Server Processing: 0.000607 sec
Total Time: 0.028594 sec
To avoid blocking while waiting for the response from the controller, these time-out timers are used:
Connection timeout: maximum time allowed for the connection to be established. The libcurl uses CURLOPT_CONNECTTIMEOUT option for this timer.
Curl timeout: maximum time allowed after the connection is established to get the data from the server. Libcurl uses CURLOPT_TIMEOUT for this timer.
Logs:
When connection timer expires:
Feb 18 22:55:37 FSM[10669]: <NOTICE> MISC: gk_send_curl_request(): curl_easy_perform failed: ret code: 28 (Connection timed out after 2001 milliseconds)
When operation timer expires:
Feb 18 22:45:11 FSM[5581]: <NOTICE> MISC: gk_send_curl_request(): curl_easy_perform failed: ret code: 28 (Operation timed out after 2001 milliseconds with 0 bytes received)
Published Content
https://www.opensync.io/s/EDE-021-030-501_FSM_Plugins.pdf
https://www.opensync.io/s/ERE-021-061-701_FSM_Plugin_Requirements.pdf