Asset V2 Integration Guide#

Tip

To better understand the service and the terms covered in this guide please refer to the service lexicon

Warning

This integration guide targets the V2 of the Asset API, which replaces the deprecated V1 API. This guide is meant as a reference during testing and integration with the new API.

Detailed API documentation#

The Swagger API documentation is always up-to-date and lets you try out any query with your user session or an API-key.

Tip

Please read the General integration guide to learn the general concepts and common data structures used throughout the Argus API.

Integration Guide#

Note

The Asset service’s data model is highly interconnected. Make sure to get a decent understanding of the interdependencies before reading the rest of this guide.

Data Model#

All endpoints for fetching, searching/listing, updating and deleting assets return the same data model.

High level representation of the Asset V2 Model

See Swagger API documentation for details on the returned data model.

Creating Assets#

To create an asset you need to specify the shortName, name, criticality triad, and asset definition. The asset definition describes what components we can eventually attach to the asset and must already exist. The optional forceIndex (default=false) option when creating, updating, and deleting resources in the Asset service determines whether any changes are immediately pushed to the search index i.e. making the changes immediately searchable.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/asset -d '{
    "customer": "mnemonic",
    "shortName": "a1",
    "name": "asset1",
    "criticality": {
        "confidentiality": "low",
        "integrity": "high",
        "availability": "unknown"
    },
    "assetDefinition": "assetDefinition1",
    "components": [
      {
        "componentDefinition": "ipAddressComponentDefinition",
        "value": "10.0.0.1"
      }
    ]
}'

Asset Components#

Components, represent a piece of information about an Asset are defined by an Asset Component Definition. To be able to set a Component on an Asset it must be identifiable by its unique shortname or ID and defined on the Asset’s Definition.

Component Definitions include the following fields:

  • shortName - unique human readable identifier

  • name - non-unique display name

  • type - the expected/permitted data type of the value of components defined by this definition

  • visibility - whether components defined by this definition are appropriate for assets, vulnerabilities, or both

Important

The value of any component created with this definition will be validated against the type and rejected, if invalid.

When creating components, it’s possible to explicitly indicate that a component is to be considered unique. I.e. the Asset can only contain a single Component of that type. When creating or updating Assets, the service will reject the request if it contains multiple unique components of the same type, or any duplicate values. If the request is valid, the following outcomes are possible:

  • The Asset does not contain any active components, unique or otherwise, of the given type - the new unique component is added

  • The Asset contains active non-unique components of the given type - all existing components are expired and the new unique component is added

  • The Asset contains an active unique component of the given type - the existing component is expired and the new unique component is added

  • The Asset contains an active unique component of the given type while the submission is non-unique - the existing component is expired and the new component is added and flagged as unique

Fetching Assets#

We can fetch individual Assets by identifying them by their ID or unique (per customer) shortName field.

curl -H "Argus-API-Key: my/api/key" https://api.mnemonic.no/assets/v2/asset/{assetIdOrShortName}

If successful, the above invocation will return the Asset basic model:

{
  "data": {
    "id": "0005cd25-2be2-44fa-a260-b0f735c9797a",
    "customer": { "id":1, "shortName":"mnemonic", ...},
    "shortName":"a1",
    "name":"asset1",
    "description":"This is the description for this asset",
    "assetDefinition": {
        "id": "00000000-0000-0000-0000-000000000001",
            "domain": {
                "id": 1,
                "name": "MNEMONIC"
            },
        "shortName": "HostAsset",
        "name": "HostAsset"
    },
    "components": [...],
    ...
  }
}

Updating Assets#

Updating the basic fields of an asset is done with a PUT request to the Asset’s, identified by its ID or unique short name, endpoint. Asset components can also be added, and removed, via this request.

If no parameters are provided, no changes are performed. Similarly, for any parameter sent to this endpoint, a null value will cause no change to the current value.

curl -X PUT -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/asset/{assetIdOrShortName} -d '{
    "criticality": {
        "confidentiality": "high",
        "integrity": "low",
        "availability": "high"
    },
    "addComponents": [
        {
            "componentDefinition": "cd1",
            "value": "componentValue",
            "ttl": 0
        }
    ],
    "deleteComponents": [
        "0005cd25-2be2-44fa-a260-b0f735c9797a",
        "0005cd25-2be2-44fa-a260-b0f735c9797a"
    ]
}'

Importing Assets#

The endpoint should be used when importing a large number of assets where you don’t know if the assets are new or already exist in the database. A good example would be when importing a scanner report. It allows the ingestion of individual assets as well as their corresponding components and observations in a single request, and will handle eventual merge conflicts. The endpoint responds with the id of the asset, and whether it is new or already exists in the database, without a guarantee that processing has completed yet.

To import an asset you need to specify how the service should identify assets. This is specified in assetIdentification. assetDefinition is always required, but the other fields depend on the chosen identification strategy. If set to asset, the shortName or id of the asset must be given. If set to component, an identification component will be used. identificationComponent and identificationComponentValue is then required.

If no asset is identified with the given strategy, the resulting actions depend on the chosen strategy. If identifying by component or shortName we create a new asset, if identifying by id we reject the import request.

assetName is only used to set new assets’ display name, and if not given, the generated asset id will be used.

Asset components connected to the asset are not required, but can be added with the components field. Components added via imports are subject to the same validation as when adding/updating individual Assets via the add and update endpoints. I.e. the value must be appropriate for the type. The same applies to observed instances of Vulnerabilities on the asset which can be added with observations. The data model for the observations is best described in Creating Vulnerabilities.

customer and dataSource are always required. dataSource provides the merge strategy to be used when handling merge conflicts.

Note

This is an asynchronous endpoint. A response is given before the service is done processing the request. Therefore, if the returned id is used to look up the asset immediately, it is highly likely no changes have been made.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/asset -d '{
  "assetName": "myAsset",
  "dataSource": "datasource1",
  "customer": "mnemonic",
  "assetIdentification": {
    "strategy": "component",
    "asset": "",
    "assetDefinition": "assetDefinition1",
    "identificationComponent": "componentDefinition1",
    "identificationComponentValue": "identificationComponentValue1"
  },
  "components": [
    {
      "componentDefinition": "componentDefinition2",
      "value": "componentValue1"
    }
  ],
  "observations": [
    {
      "vulnerability": "COVID-19",
      "severity": "high",
      "rawOutput": "rawOutput",
      "cvss": 0,
      "observationDescription": "description",
      "observationReferences": [
        ""
      ],
      "components": [
        {
          "component": "string",
          "value": "string"
        }
      ]
    }
  ]
}'

Merge resolution strategies#

The strategies are defined by the sameSourceMergeResolutionStrategy and otherSourceMergeResolutionStrategy fields in the /assets/v2/datasource endpoint. We differentiate between conflicts from the same data source and different data sources.

The current strategies are:

  • append: the new data is added to the asset. The existing data is kept intact.

  • reject: the new data is ignored. The existing data is kept intact.

  • replace: the new data replaces the old data. The existing data is deleted.

  • expire: if the existing data has expired, meaning it’s time to live has passed, it is set expired. The new data is added - replacing the existing data. If the existing data has not expired, we reject the new data.

Searching for Assets#

Assets are searchable by their basic properties and their relationships with other resources in the Asset Service e.g. parent or ancestor group(s). All searches are restricted to assets belonging to customers for whom the current user has at least read permission.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/asset/search -d '{
    "sortBy": [
        "lastUpdatedTimestamp"
    ],
    "keywords": [
        "content"
    ],
    "keywordFieldStrategy": [
        "description"
    ]
    "parent": [
        "assetGroupShortName"
    ],
    ...
}'

Asset Statistics#

Warning

The Asset Statistics API is not completely stable i.e. new features are still under development. Please contact Mnemonic directly for clarification.

The Asset statistics endpoint allows a user to retrieve quantitative data about a set of assets that match certain search criteria.

The statistics request supports the same search criteria as the search endpoint; the statistics criteria then apply to the results of the search.

The statistics request itself is composed of 3 key components:

  • field aggregation - the field(s) by which we want to group the resulting assets and structure the response

  • range metrics - return counts for assets matching the defined timestamp filters

  • statistics metrics - return basic statistical data (min, max, median, avg, e.t.c) for asset numerical fields e.g. CVSS or vulnerability count

For example, we could ask for vulnerability statistics for assets created within the last month and also determine which of them have been updated during the same time period, aggregated by the types of assets and the groups to which they belong:

curl -X 'POST' \
  'https://api.mnemonic.no/assets/v2/asset/statistics' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Argus-API-Key: my/api/key' \
  -d '{
  "startTimestamp": "now-1month",
  "endTimestamp": "now",
  "timeFieldStrategy": [
    "createdTimestamp"
  ],
  "fieldAggregation": [
    {
      "field": "assetGroup",
      "limit": 25
    },
    {
      "field": "assetDefinition",
      "limit": 25
    }
  ],
  "rangeMetric": [
    {
      "name": "updatedThisWeek",
      "field": "lastUpdated",
      "startTimestamp": "now-1week",
      "endTimestamp": "now"
    }
  ],
  "statisticsMetric": [
    {
      "field": "vulnerabilities"
    }
  ],
  "includeDeleted": false
}'

The response’s structure is a unidirectional tree where the branches represent unique field aggregation values i.e. in this example groups and definitions.

Each branch consists of the count of assets within the branch and metadata containing

  • identifier - the unique ID of the object

  • shortName - the unique human/machine readable identifier

  • name - the human readable non-unique identifier

  • type - the type (assetGroup or assetDefinition in this example) of the metadata

Each branch then potentially contains buckets, which represent the next layer in the tree.

The leaves contain the actual metrics response e.g.:

{
  "metadata": {
    "identifier": "assetGroupUUID",
    "shortName": "assetGroupShortName",
    "name": "Asset Group Name",
    "type": "assetGroup"
  },
  "count": 291,
  "buckets": [
    {
      "metadata": {
        "identifier": "00000000-0000-0000-0000-000000000001",
        "shortName": "HostAsset",
        "name": "Host Asset",
        "type": "assetDefinition"
      },
      "count": 291,
      "buckets": [
      ],
      "rangeMetrics": [
        {
          "key": "updatedThisWeek",
          "count": 1,
          "startTimestamp": 1681198844900,
          "endTimestamp": 1681803644900
        }
      ],
      "statisticsMetrics": [
        {
          "key": "vulnerabilities",
          "count": 291,
          "min": 0,
          "max": 441,
          "avg": 48.67697594501718,
          "sum": 14165
        }
      ]
    }
  ],
  "rangeMetrics": [
  ],
  "statisticsMetrics": [
  ]
}

Creating Asset Groups#

To create an asset you need to specify the shortName, name, and criticality triad.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/group -d '{
    "customer": "mnemonic",
    "shortName": "ag1",
    "name": "assetGroup1",
    "criticality": {
        "confidentiality": "low",
        "integrity": "high",
        "availability": "unknown"
    }
}'

Attaching Assets to a Group#

To add Assets to a Group submit their IDs or short names to the group’s attach endpoint.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/group/groupShortNameOrID/assets -d '{
        "assets": [
            "asset1",
            "asset2"
        ]
    }
}'

Searching for Groups#

Similar to Assets, Groups are searchable by their basic properties and by their relationships to other objects in the Asset Service. groups e.g. parent, ancestor, or child group(s) and member assets. All searches are restricted to groups belonging to customers for whom the current user has at least read permission.

curl -X POST -H "Argus-API-Key: my/api/key" -H "Content-Type: application/json" https://api.mnemonic.no/assets/v2/group/search -d '{
    "sortBy": [
        "lastUpdatedTimestamp"
    ],
    "keywords": [
        "content"
    ],
    "keywordFieldStrategy": [
        "description"
    ]
    "parent": [
        "assetGroupIDOrShortName"
    ],
    "asset": [
        "assetIdOrShortName"
    ],
    "child": [
        "assetGroupIDOrShortName"
    ]
    ...
}'

Creating Vulnerabilities#

To create a Vulnerability you need to specify the asset (identified by its UUID or shortname) on which the vulnerability was observed, its vulnerability definition.

CVSS and Severity values are optional when creating a vulnerability. If these are not specified, the values from the relevant Vulnerability Definition are used. If it is necessary to manually put in different values for the specific observation, the observation will be marked with flags overwrittenDefinitionCVSS or overwrittenDefinitionSeverity depending on which value is adjusted. Please note that ‘overwritten’ value will no longer be updated when the Vulnerability Definition values change. If only CVSS is provided the Severity is calculated based on CVSS value.

CVSS/Severity - Mapping

CVSS

Severity

0

INFO

< 4

LOW

< 7

MEDIUM

< 9

HIGH

<= 10

CRITICAL

The optional forceIndex option (default=false) will instruct the service to refresh the search index such that new vulnerabilities are immediately searchable. Like Assets, Vulnerabilities can be created bound to specific components.

The time to live (TTL) field determines how long the component information is considered valid. Ideally it should be longer than the scan interval so that component information is not invalidated before it can be updated. Please see the Swagger API for how the other fields are handled or determined if not provided.

Specify Customer#

NB: If the request does not explicitly specify the Customer who owns the Asset on which the Vulnerability was detected and the Asset was defined by its short name then the service will attempt to resolve the Asset based on the requesting user’s Customer. As Asset shortNames are unique per customer it’s possible that this request might fail.

curl -X POST -H "Argus-API-Key: my/api/key" -H "accept: application/json" 
"https://api.mnemonic.no/assets/v2/vulnerability" -d '{
    "customer": "mnemonic",
    "asset": "internalAsset",
    "vulnerability": "vulnerabilityDefinition",
    "components": [
        {
            "componentDefinition": "cpeComponentDefinition",
            "value": "cpe:2.3:o:microsoft:windows:2008:r2",
            "ttl": 0
        }
    ],
    "cvss": 3,
    "severity": "low",
    "rawOutput": "output from scanner",
    "ttl": 0
}'

Fetching Vulnerabilities#

To fetch a single Vulnerability you need to provide its UUID:

curl -H "Argus-API-Key: my/api/key" https://api.mnemonic.no/assets/v2/vulnerability/53477c72-f4c8-4929-bc05-3a8c7d4ba7a2

A successful request will return the Vulnerability’s data model:

{
    "id": "53477c72-f4c8-4929-bc05-3a8c7d4ba7a2",
    "customer": {
        "id": 1,
        "name": "mnemonic",
        "shortName": "mnemonic",
        "domain": {
            "id": 1,
            "name": "MNEMONIC"
        }
    },
    "asset": {
        "id": "4cb3797b-35f6-4ca7-8102-46e8a3946829",
        "customer": {
            ...
        },
        "shortName": "GraphQLAsset_2",
        "name": "Asset 2 - Asset V2 Test"
    },
    "vulnerabilityID": "COVID-19",
    "vulnerabilityDefinition": null,
    "components": [],
    "cvss": 8.8,
    "severity": "high",
    "resolution": "unresolved",
    "resolutionTimestamp": 0,
    "resolvedByUser": null,
    "resolutionComment": null,
    "rawOutput": null,
    "firstSeenTimestamp": 1596539880803,
    "lastSeenTimestamp": 1596539880803,
    "firstSeenByUser": {
        "id": 8982,
        "shortName": "testUser",
        "name": "Test User",
        "domain": null,
        "customer": {
            ...
        },
        "type": "user"
    },
    "lastSeenByUser": {...},
    "ttl": 0,
    "expireTimestamp": 0,
    "createdTimestamp": 1596539880803,
    "createdByUser": {...},
    "lastUpdatedTimestamp": 1596539880803,
    "lastUpdatedByUser": {...},
    "deletedTimestamp": 0,
    "deletedByUser": null,
    "flags": []
}

Resolving Vulnerabilities#

Although actually resolving a Vulnerability is not handled by Argus, updating a Vulnerability’s resolution status is an important step in the Vulnerability management process.

When resolving a Vulnerability permitted resolution statuses are:

  • accepted - the Vulnerability is known and will not be handled

  • temporarilyAccepted - the Vulnerability is known and will be handled at a later date

  • falsePositive - not a Vulnerability

  • serviceNotAvailable

  • noLongerVulnerable - the Vulnerability has been handled

To resolve a vulnerability simply submit a resolution request to the vulnerability’s resolution endpoint:

curl -X PUT -H "Argus-API-Key: my/api/key" "accept: application/json" -H "Content-Type: application/json" \
    "https://devapi.mnemonic.no/assets/v2/vulnerability/4cb3797b-35f6-4ca7-8102-46e8a3946829/resolve" -d \
    '{ 
        "resolution": "accepted",
        "comment": "cannot resolve now"
    }'

Searching for Vulnerabilities#

Vulnerability are searchable by their basic properties and their direct relationship with the asset on which they were detected. All searches are restricted to Vulnerabilities on Assets belonging to the customer(s) for whom the requesting user has permission to access. Unlike Asset and Asset Groups, Vulnerabilities currently have no keyword fields. Only exact matches will return results.

{
  "sortBy": [
    "vulnerabilityID"
  ],
  "startTimestamp": 0,
  "endTimestamp": 0,
  "timeFieldStrategy": [
    "all"
  ],
  "timeMatchStrategy": "any",
  "userFieldStrategy": [
    "lastUpdatedByUser"
  ],
  "user": [
    "testUser"
  ],
  "asset": [
    "myVeryImportantAsset"
  ],
  "customer": [
    "mnemonic"
  ],
  "severity": "info",
  "resolution": "unresolved",
  "minimumCvss": 1,
  "maximumCvss": 2,
  "includeRawOutput": false,
  "limit": 0,
  "offset": 0,
  "includeDeleted": false
}

To, for example, retrieve all open Vulnerabilities created on Assets belong to a particular Customer for the last week you could submit the following query:

{
  "sortBy": [
    "createdTimestamp"
  ],
  "customer": [
    "customerIdOrShortName"
  ],
  "resolution": "unresolved",
  "startTimestamp": "startOfWeek - 1 week",
  "endTimestamp": "startOfWeek"
}

Creating Vulnerability Definitions#

A Vulnerability Definition is a general description of a Vulnerability. It contains a subset of CVE data as well as other Mnemonic generated data. Vulnerability observations are instances of a Vulnerability Definition. Vulnerability definitions are not specific to a particular asset or customer and contain globally available unrestricted information.

To create a Vulnerability Definition you need to specify its source (identified by its UUID or shortname) and vulnerability definition identifier (for example plugin ID from vulnerability scanner). It is also required to provide CVSS for the vulnerability definition. If a severity is not specified, it will be assigned based on the submitted CVSS value using the following mapping:

CVSS/Severity - Mapping

CVSS

Severity

0

INFO

< 4

LOW

< 7

MEDIUM

< 9

HIGH

<= 10

CRITICAL

Permissions required: addVulnerabilityDefinition

curl -X 'POST' \
  'https://api.mnemonic.no/assets/v2/vulnerability/definition?forceIndex=false' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H "Argus-API-Key: my/api/key" \
  -d '{
    "vulnerabilitySource": "string",
    "vulnerabilityID": "string",
    "name": "string",
    "description": "string",
    "solution": "string",
    "conclusion": "string",
    "references": [
     "string"
    ],
    "exploitAvailable": true,
    "exploitAvailableTimestamp": 0,
    "severity": "info",
    "cvss": 0
  }'

Additional note on Severity and CVSS: Values in the vulnerability definition will be used to populate newly created vulnerabilities (observations) relevant to the given definition. The changes on vulnerability definition update for Severity and CVSS values will be propagated in an async manner to the relevant observations.

Fetching Vulnerability Definitions#

To fetch a single Vulnerability Definition it’s necessary to provide definition UUID or identifier of vulnerability (for example “MV301-OS-CIS-2.3.10.3-129”)

Permissions required: viewVulnerabilityDefinition

curl -X 'GET' \
  'https://api.mnemonic.no/assets/v2/vulnerability/definition/MV301-OS-CIS-2.3.10.3-129' \
  -H 'accept: application/json' \
  -H "Argus-API-Key: my/api/key" 

A successful request will return the Vulnerability Definition’s data model:

Vulnerability Definition - data model
{
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "vulnerabilitySource": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "shortName": "string",
      "name": "string"
    },
    "vulnerabilityID": "string",
    "name": "string",
    "description": "string",
    "solution": "string",
    "conclusion": "string",
    "references": [
      "string"
    ],
    "exploitAvailableTimestamp": 0,
    "createdTimestamp": 0,
    "createdByUser": {
      "id": 0,
      "shortName": "string",
      "name": "string",
      "domain": {
        "id": 0,
        "name": "string"
      },
      "customer": {
        "id": 0,
        "name": "string",
        "shortName": "string",
        "domain": {
          "id": 0,
          "name": "string"
        }
      },
      "type": "user"
    },
    "lastUpdatedTimestamp": 0,
    "lastUpdatedByUser": {
      "id": 0,
      "shortName": "string",
      "name": "string",
      "domain": {
        "id": 0,
        "name": "string"
      },
      "customer": {
        "id": 0,
        "name": "string",
        "shortName": "string",
        "domain": {
          "id": 0,
          "name": "string"
        }
      },
      "type": "user"
    },
    "deletedTimestamp": 0,
    "deletedByUser": {
      "id": 0,
      "shortName": "string",
      "name": "string",
      "domain": {
        "id": 0,
        "name": "string"
      },
      "customer": {
        "id": 0,
        "name": "string",
        "shortName": "string",
        "domain": {
          "id": 0,
          "name": "string"
        }
      },
      "type": "user"
    },
    "flags": [
      "deleted"
    ],
    "severity": "info",
    "cvss": 0
}

Updating Vulnerability Definition#

It’s possible to update the Vulnerability Definition by providing its UUID or identifier of vulnerability (for example “MV301-OS-CIS-2.3.10.3-129”)

Permissions required: updateVulnerabilityDefinition

curl -X 'PUT' \
  'https://api.mnemonic.no/assets/v2/vulnerability/definition/MV301-OS-CIS-2.3.10.3-12?forceIndex=false' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H "Argus-API-Key: my/api/key" \
  -d '{
    "name": "string",
    "description": "string",
    "solution": "string",
    "conclusion": "string",
    "addReferences": [
      "string"
    ],
    "deleteReferences": [
      "string"
    ],
    "exploitAvailable": true,
    "exploitAvailableTimestamp": 0,
    "cvss": 10,
    "severity": "info"
  }'

The forceIndex option should be set to true only if the use case requires the definition to be immediately searchable. Without this option the change should be visible within seconds.

Deleting Vulnerability Definition#

It’s possible to delete the Vulnerability Definition by providing its UUID or identifier of vulnerability (for example “MV301-OS-CIS-2.3.10.3-129”)

Permissions required: deleteVulnerabilityDefinition

curl -X 'DELETE' \
  'https://api.mnemonic.no/assets/v2/vulnerability/definition/MV301-OS-CIS-2.3.10.3-12?forceIndex=false' \
  -H 'accept: application/json' \
  -H "Argus-API-Key: my/api/key" 

The forceIndex option, should be set to true only if the use case requires the definition’s status change to be immediately reflected in the search results. Without this option the change should be visible within seconds.

Searching for Vulnerabilities#

Vulnerability Definitions are searchable by keywords. Searching for vulnerability definitions can be done using the simple search GET endpoint or the advanced search POST endpoint.

Please read the General integration guide to learn about general concepts for search endpoints. Permissions required: viewVulnerabilityDefinition.