API v1

Blueprint dedicated to the main API. It is composed of two namespaces, client and stats, that are used for the endpoints api/v1/stats and api/v1/client.

New namespaces are easily plugable via the file: api/v1/__init__.py.

Security model

First, an overview of the security model.

Clients needs to have an account on the Stats Service and a token in order to submit new stats and to query the API. New clients can be created with the dedicated command.

The token must be submitted in the headers of the requests with the key X-API-KEY, as explained below. It is not needed to submit an additional id, tokens are unique.

OpenAPI Specification

Specification also available at https://dashboard.monarc.lu/api/v1.

{
    "swagger": "2.0",
    "basePath": "/api/v1",
    "paths": {
        "/client/": {
            "post": {
                "responses": {
                    "201": {
                        "description": "Success",
                        "schema": {
                            "$ref": "#/definitions/Clients"
                        }
                    }
                },
                "summary": "Create a new client",
                "operationId": "client_create",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "$ref": "#/definitions/Clients"
                        }
                    },
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "client"
                ]
            }
        },
        "/client/me": {
            "get": {
                "responses": {
                    "200": {
                        "description": "Success",
                        "schema": {
                            "$ref": "#/definitions/Clients"
                        }
                    }
                },
                "operationId": "client_get",
                "parameters": [
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "client"
                ]
            },
            "patch": {
                "responses": {
                    "201": {
                        "description": "Success",
                        "schema": {
                            "$ref": "#/definitions/Clients"
                        }
                    }
                },
                "operationId": "client_patch",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "$ref": "#/definitions/Clients"
                        }
                    },
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "client"
                ]
            }
        },
        "/stats/": {
            "get": {
                "responses": {
                    "401": {
                        "description": "Authorization needed"
                    },
                    "200": {
                        "description": "Success",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/StatsList"
                            }
                        }
                    }
                },
                "summary": "List all stats",
                "operationId": "list_stats",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "anr": {
                                    "type": "string"
                                },
                                "type": {
                                    "type": "string"
                                },
                                "group_by_anr": {
                                    "type": "integer"
                                },
                                "date_from": {
                                    "type": "string"
                                },
                                "date_to": {
                                    "type": "string"
                                },
                                "anrs": {
                                    "type": "string"
                                },
                                "get_last": {
                                    "type": "boolean"
                                },
                                "offset": {
                                    "type": "integer"
                                },
                                "limit": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "stats"
                ]
            },
            "post": {
                "responses": {
                    "401": {
                        "description": "Authorization needed"
                    },
                    "201": {
                        "description": "Success",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/StatsList"
                            }
                        }
                    }
                },
                "summary": "Create a new stats",
                "operationId": "create_stats",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Stats"
                            }
                        }
                    },
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "stats"
                ]
            }
        },
        "/stats/processed/": {
            "get": {
                "responses": {
                    "200": {
                        "description": "Success",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Result"
                            }
                        }
                    }
                },
                "summary": "Return the result of the processor",
                "operationId": "processing_list",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "type": "object",
                            "properties": {
                                "type": {
                                    "type": "string"
                                },
                                "processor": {
                                    "type": "string"
                                },
                                "processor_params": {
                                    "type": "string"
                                },
                                "anrs": {
                                    "type": "string"
                                },
                                "date_from": {
                                    "type": "string"
                                },
                                "date_to": {
                                    "type": "string"
                                },
                                "local_stats_only": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "processed"
                ]
            }
        },
        "/stats/processed/list": {
            "get": {
                "responses": {
                    "200": {
                        "description": "Success"
                    }
                },
                "summary": "Return the list of available processors with their description",
                "operationId": "get_processor_list",
                "tags": [
                    "processed"
                ]
            }
        },
        "/stats/{anr}": {
            "parameters": [
                {
                    "in": "query",
                    "description": "The stats identifier",
                    "name": "uuid",
                    "type": "string"
                },
                {
                    "name": "anr",
                    "in": "path",
                    "required": true,
                    "type": "string"
                }
            ],
            "delete": {
                "responses": {
                    "404": {
                        "description": "Stats not found"
                    },
                    "204": {
                        "description": "Stats deleted"
                    }
                },
                "summary": "Delete stats by provided anr",
                "operationId": "delete_stats",
                "tags": [
                    "stats"
                ]
            },
            "get": {
                "responses": {
                    "404": {
                        "description": "Stats not found"
                    },
                    "200": {
                        "description": "Success",
                        "schema": {
                            "$ref": "#/definitions/Stats"
                        }
                    }
                },
                "summary": "Fetch a given resource by anr",
                "operationId": "get_stats",
                "parameters": [
                    {
                        "name": "X-Fields",
                        "in": "header",
                        "type": "string",
                        "format": "mask",
                        "description": "An optional fields mask"
                    }
                ],
                "tags": [
                    "stats"
                ]
            }
        }
    },
    "info": {
        "title": "MONARC Stats service - API v1",
        "version": "1.0",
        "description": "API v1 of the MONARC Stats service.",
        "license": {
            "name": "GNU Affero General Public License version 3",
            "url": "https://www.gnu.org/licenses/agpl-3.0.html"
        }
    },
    "produces": [
        "application/json"
    ],
    "consumes": [
        "application/json"
    ],
    "securityDefinitions": {
        "apikey": {
            "type": "apiKey",
            "in": "header",
            "name": "X-API-KEY"
        }
    },
    "security": [
        {
            "apikey": []
        }
    ],
    "tags": [
        {
            "name": "client",
            "description": "client related operations"
        },
        {
            "name": "stats",
            "description": "stats related operations"
        },
        {
            "name": "processed",
            "description": "Processing related operations on stats data."
        }
    ],
    "definitions": {
        "Clients": {
            "properties": {
                "name": {
                    "type": "string",
                    "description": "The client name."
                },
                "token": {
                    "type": "string",
                    "description": "The token of the client.",
                    "readOnly": true
                },
                "role": {
                    "type": "string",
                    "description": "The client role.",
                    "readOnly": true
                },
                "is_sharing_enabled": {
                    "type": "boolean",
                    "description": "If the statistics sharing is enabled or not.",
                    "readOnly": true
                }
            },
            "type": "object"
        },
        "Stats": {
            "properties": {
                "uuid": {
                    "type": "string",
                    "description": "The stats unique identifier",
                    "readOnly": true
                },
                "anr": {
                    "type": "string",
                    "description": "The ANR UUID related to this stats."
                },
                "type": {
                    "type": "string",
                    "description": "The type of this stats (risk, vulnerability, threat, cartography or compliance)."
                },
                "date": {
                    "type": "string",
                    "format": "date",
                    "description": "The stats date in format 'Y-m-d'"
                },
                "data": {
                    "type": "object",
                    "description": "The stats as a dynamic JSON object."
                }
            },
            "type": "object"
        },
        "StatsList": {
            "properties": {
                "metadata": {
                    "description": "Metada related to the result.",
                    "allOf": [
                        {
                            "$ref": "#/definitions/metadata"
                        }
                    ]
                },
                "data": {
                    "type": "array",
                    "description": "List of stats objects.",
                    "items": {
                        "$ref": "#/definitions/Stats"
                    }
                }
            },
            "type": "object"
        },
        "metadata": {
            "properties": {
                "count": {
                    "type": "string",
                    "description": "Total number of the items of the data.",
                    "readOnly": true
                },
                "offset": {
                    "type": "string",
                    "description": "Position of the first element of the data from the total data amount.",
                    "readOnly": true
                },
                "limit": {
                    "type": "string",
                    "description": "Requested limit data.",
                    "readOnly": true
                }
            },
            "type": "object"
        },
        "Result": {
            "properties": {
                "type": {
                    "type": "string",
                    "description": "Type of the processed stats data (risk, vulnerability, threat, cartography or compliance)."
                },
                "processor": {
                    "type": "string",
                    "description": "Processor used for the stats data processing."
                },
                "data": {
                    "type": "object",
                    "description": "Result of the selected processor applied to the resulting stats."
                }
            },
            "type": "object"
        }
    },
    "responses": {
        "ParseError": {
            "description": "When a mask can't be parsed"
        },
        "MaskError": {
            "description": "When any error occurs on mask"
        }
    }
}

Detailed examples with the API

Getting stats for a client

$ curl -X GET "http://127.0.0.1:5000/api/v1/stats" -H  "accept: application/json" -H  "X-API-KEY: rddPRk9_t-Z4GOgmY2UL2blKB1DxWB_0yhDlqcsF9p63eXs-oLCdm2c9YgP7cOqGz71GK1tc8lrCenD8AvEr-g"
{
  "metadata": {
    "count": "0",
    "offset": "0",
    "limit": "0"
  },
  "data": []
}

Specify a type of stats:

$ curl --location --request GET \
-H 'X-API-KEY: rddPRk9_t-Z4GOgmY2UL2blKB1DxWB_0yhDlqcsF9p63eXs-oLCdm2c9YgP7cOqGz71GK1tc8lrCenD8AvEr-g' \
-H "Content-type: application/json" \
-H "Accept: application/json" \
-d '{"type":"threat"}' \
'http://127.0.0.1:5000/api/v1/stats'

Invoking a processor

Processors are utilities to process stats data. Processors are currently defined in statsservice/lib/processors.py. They operate on different kind of stats:

  • risks;
  • threats;
  • vulnerabilities.

They can do a lot of things, like evaluate different averages based on user requirements. The result of the processor is sent in the response from the API.

You can get the list of available processors:

$ curl http://127.0.0.1:5000/api/v1/stats/processed/list
[
    {
        "name": "risk_averages",
        "description": "Evaluates the averages for the risks. Averages are evaluated per categories\n    (current/residual, informational/operational, low/medium/high)."
    },
    {
        "name": "risk_averages_on_date",
        "description": "Evaluates the averages for the risks per date. Averages are evaluated per categories\n    (current/residual, informational/operational, low/medium/high).\n    Supported parameters:\n    - risks_type: informational or operational\n    - risks_state: current or residual."
    },
    {
        "name": "threat_average_on_date",
        "description": "Aggregation and average of threats per date for each threat (accross all risk\n    analysis).\n    "
    },
    {
        "name": "vulnerability_average_on_date",
        "description": "Aggregation and average of vulnerabilities per date for each vulnerability\n    (accross all risk analysis).\n    "
    }
]

Some processors can use dedicated parameters. For this purpose the parameter processor_params can be used to transfer these parameters directly to the concerned processor. These parameters will affect the behaviour of the processor.

For example you might want to call the processor risk_averages_on_date but you want that this processor only evaluates the averages for residual risks that are also operational risks (and not informational risks). The request will look like:

curl -X GET "http://127.0.0.1:5000/api/v1/stats/processed/" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{  \"type\": \"risk\",  \"processor\": \"risk_averages_on_date\",  \"local_stats_only\": 0, \"date_from\":\"2020-06-12\",\"processor_params\": {\"risks_type\":\"operational\",\"risks_state\":\"residual\"}}"

Internally the processor processor_params will honor the value provided with the parameters risks_type and risks_state.

  • risks_type can be informational or operational;
  • risks_state can be current or residual.

Generally, you can get information about a processor:

$ echo -e `curl -s http://127.0.0.1:5000/api/v1/stats/processed/list | jq '.[] | select(.name=="risk_averages_on_date") | .description'`
"Evaluates the averages for the risks per date. Averages are evaluated per categories
 (current/residual, informational/operational, low/medium/high).
 Supported parameters:
 - risks_type: informational or operational
 - risks_state: current or residual."