Ce guide explique comment écrire un plugin New Application Risk Exchange pour extraire le maximum de valeur de l'écosystème du risque client en tirant parti de la fonctionnalité fournie par le module Application Risk Exchange. En suivant ce guide, le développeur devrait être en mesure d'écrire un plugin New de manière autonome sans aucun problème technique.
Conditions préalables
- Expérience en programmation Python 3.x (niveau intermédiaire).
- Accès à la plateforme Netskope Cloud Exchange.
- Accès à l'API ou au SDK Python du produit ou de la solution pour lequel vous devez écrire le plugin.
- Un compte avec une autorisation minimale pour le produit.
Module d'échange sur les risques liés à l'application
La plateforme Cloud Exchange, et son module Application Risk Exchange, est dotée d'un riche ensemble de caractéristiques et de fonctionnalités qui permettent un haut degré de personnalisation. Nous vous recommandons donc de vous familiariser avec les différents aspects de la plateforme énumérés ci-dessous. Ce module permet de partager les données de Netskope avec un outil tiers.
Concepts et terminologie de Netskope
- Le noyau : Le moteur central de CE gère les plugins tiers et leurs méthodes de cycle de vie. Il dispose de points d'extrémité API permettant d'interagir avec la plateforme pour effectuer diverses tâches.
- Module : Le code fonctionnel est tel qu'il invoque des plugins spécifiques aux modules pour accomplir différents flux de travail. Application Risk Exchange est l'un des modules de Cloud Exchange.
- Plugin : Les plugins sont des paquets Python dont la logique permet de récupérer les utilisateurs et les scores de risque des systèmes Threat Intel tiers, qui seront ensuite stockés dans l'Application Risk Exchange. Il peut également effectuer des actions.
- Configurations de plugin : Les configurations de plugin sont les objets de la classe de plugin qui sont configurés avec les paramètres requis et sont programmés par le moteur central de Cloud Exchange pour récupérer les utilisateurs et les scores.
- Applications (événements d'application) : détails de l'application à partir des événements d'application d'un locataire Netskope, qui sont ensuite partagés avec d'autres plugins configurés pour l'échange de risques d'application.
Lignes directrices pour le développement
- Utilisez la structure du répertoire du paquet pour tout le code Python.
- Assurez-vous que toutes les bibliothèques tierces fournies avec le plugin ont été vérifiées pour détecter les vulnérabilités connues.
- Veillez à respecter les conventions de code Python standard. (https://peps.python.org/pep-0008/)
- Exécutez et vérifiez que le contrôle lint de flake8 passe avec le contrôle docstring activé. La longueur maximale d'une ligne doit être de 80.
- Convertissez les valeurs de l'horodatage au format lisible par l'homme (de l'époque à l'objet DateTime). Assurez-vous que l'heure affichée sur l'interface utilisateur correspond au fuseau horaire local.
- Si possible, ajoutez une valeur par défaut lors de l'ajout d'un paramètre de configuration dans le plugin.
- Pour les scripts/intégrations écrits en Python, veillez à créer des tests unitaires. Veuillez vous référer à la section ci-dessous : Tests unitaires.
- L'architecture du plugin permet de stocker des états, mais il faut éviter de stocker des objets volumineux pour la gestion des états.
- Vérifiez que votre code python ne présente pas de vulnérabilités.
- L'icône du plugin doit être inférieure à 10kb. Veillez à utiliser le logo de l'entreprise (et non celui du produit) sur un fond transparent. La taille recommandée pour le logo est de 300×50 ou un rapport d'aspect similaire.
- Veillez à utiliser tous les champs possibles disponibles dans le modèle de données de l'application lorsque vous transmettez les détails de l'application au produit tiers.
- Suivez la structure du répertoire des plugins.
- Si la description contient un lien, il doit s'agir d'un lien hypertexte et non d'un texte en clair.
- Utilisez une validation appropriée pour les paramètres transmis à la méthode validate et fournissez le texte d'aide approprié pour tous les paramètres.
- Utilisez un objet notificateur pour déclencher une notification en cas d'échec ou de situation critique (comme la limitation du débit ou le dépassement de la taille de la charge utile) afin d'informer l'utilisateur de l'état du plugin.
- Veillez à mettre en place un mécanisme de journalisation approprié avec l'objet logger transmis par la plateforme Cloud Exchange. Veillez à ce que la journalisation soit suffisante pour aider l'équipe d'exploitation à résoudre les problèmes. Assurez-vous que les données sensibles ne sont pas enregistrées ou divulguées dans la notification.
- Les messages du logger et les messages Toast ne doivent pas contenir les valeurs des champs de type API Token et Password.
- La pagination doit toujours être prise en compte lors du développement d'une fonctionnalité dans un plugin.
- Veillez à ajouter un mécanisme de relance pour le code de statut 429.
- Utilisez un objet notificateur pour déclencher une notification en cas d'échec ou de situation critique (comme la limitation du débit ou le dépassement de la taille de la charge utile) afin d'informer l'utilisateur de l'état du plugin.
- Veillez à mettre en place un mécanisme de journalisation approprié avec l'objet logger transmis par la plateforme Cloud Exchange. Veillez à ce que la journalisation soit suffisante pour aider l'équipe d'exploitation à résoudre les problèmes. Assurez-vous que les données sensibles ne sont pas enregistrées ou divulguées dans la notification.
- Fournissez le texte d'aide approprié (infobulle) pour tous les paramètres. Si possible, veillez à expliquer la signification du paramètre dans l'infobulle.
- Veillez à donner un nom et une description significatifs aux paramètres de configuration du plugin.
- Veillez à fournir un type de configuration approprié (texte, nombre, mot de passe, choix, multi-choix) aux paramètres.
- Assurez-vous d'utiliser la configuration du proxy et le drapeau de validation du certificat SSL qui est transmis par la plateforme Cloud Exchange lors de toute requête sortante (API/SDK).
- Veillez à collecter la valeur d'un paramètre non obligatoire à l'aide de la fonction .get() et fournir une valeur par défaut lors de l'utilisation de .get() méthode.
- Les champs Tokens API et Password ne doivent pas utiliser strip().
- The log messages should start with “<module> <app name> Plugin [configuration_name]: “. Example: “ARE Bitsight Plugin [Bitsight Configuration Name]: <log_message>“. [This is a suggestion, we can avoid configuration name]. (logger.info(“<module> <plugin_name> Plugin: <message>”))
- Lors de l'enregistrement d'un journal d'erreurs, nous devrions, si possible, ajouter une trace de l'exception. USE :self.logger.error(error, details=traceback.format_exc()).
- The Toast message should not contain the <app_name> <module> Plugin: in the message.
- Assurez-vous d'attraper les exceptions et les codes d'état appropriés pendant et après les appels à l'API. Si possible, les développeurs peuvent créer une méthode d'aide à partir de laquelle les demandes seront faites et cette méthode peut être appelée avec les paramètres appropriés lorsque cela est nécessaire.
- Le fichier CHANGELOG.md doit être mis à jour avec les balises appropriées telles que Added, Changed et Fixed ainsi qu'un message convivial approprié. Assurez-vous que le nom du fichier correspond exactement à CHANGELOG.md.
- Assurez-vous que le nom du répertoire du plugin (sample_plugin) correspond à celui du fichier manifest.json. Champ ID.
- L'agent utilisateur doit être ajouté aux en-têtes lors de tout appel à l'API. Format pour l'agent utilisateur : Netskope-ce-<ce_version>-<module>-<plugin_name>-<plugin_version>.Note : La version du plugin doit être récupérée dynamiquement et pour récupérer Netskope-ce-<version> string utilisez la méthode définie par core.
- La pagination doit toujours être prise en compte lors du développement d'une fonctionnalité dans un plugin.
- Toutes les déclarations de l'enregistreur doivent respecter ce format :
logger.info(“<module> <plugin_name> Plugin: <message>”)
Écrire un plugin
Cette section explique le processus d'écriture d'un plugin à partir de zéro.
Téléchargez le plugin d’exemple depuis le dépôt public NetskopeOSS sur Github ou depuis la base de connaissances Cloud Exchange disponible ici : https://support.netskope.com/hc/en-us/articles/360052128734-Cloud-Threat-Exchange.
Développement de l'installation
Python
Notre système utilise Python3 (v3.7 et plus). Veillez à installer python3 dans votre environnement de développement. Pytest est utilisé pour exécuter des tests unitaires.
Bibliothèques Python incluses
Les bibliothèques Python suivantes sont incluses dans la plateforme Netskope Cloud Exchange.
| Nom de la bibliothèque | Version |
|---|---|
| aiofiles | 22.1.0 |
| amqp | 5.1.1 |
| anyio | 3.6.2 |
| asgiref | 3.6.0 |
| attrs | 22.2.0 |
| azure-core | 1.26.2 |
| azure-storage-blob | 12.14.1 |
| bcrypt | 4.0.1 |
| boto3 | 1.26.51 |
| botocore | 1.29.51 |
| billiard | 3.6.4.0 |
| celery | 5.2.7 |
| cabby | 0.1.23 |
| cachetools | 5.2.1 |
| celerybeat-mongo | 0.2.0 |
| certifi | 2022.12.7 |
| cffi | 1.15.1 |
| chardet | 5.1.0 |
| charset-normalizer | 3.0.1 |
| click | 8.1.3 |
| click-didyoumean | 0.3.0 |
| click-plugins | 1.1.1 |
| click-repl | 0.2.0 |
| colorama | 0.4.6 |
| colorlog | 6.7.0 |
| cryptography | 39.0.0 |
| cybox | 2.1.0.21 |
| defusedxml | 0.7.1 |
| dnspython | 2.3.0 |
| docker | 6.0.1 |
| fastapi | 0.89.1 |
| furl | 2.1.3 |
| google-api-core | 2.11.0 |
| google-auth | 2.16.0 |
| google-cloud-core | 2.3.2 |
| google-cloud-pubsub | 2.13.12 |
| google-cloud-pubsublite | 1.6.0 |
| google-cloud-storage | 2.7.0 |
| google-crc32c | 1.5.0 |
| google-resumable-media | 2.4.0 |
| googleapis-common-protos | 1.58.0 |
| grpc-google-iam-v1 | 0.12.6 |
| grpcio | 1.51.1 |
| grpcio-status | 1.51.1 |
| gunicorn | 20.1.0 |
| h11 | 0.14.0 |
| idna | 3.4 |
| importlib-metadata | 6.0.0 |
| isodate | 0.6.1 |
| jmespath | 1.0.1 |
| jsonpath | 0.82 |
| jsonschema | 4.17.3 |
| kombu | 5.2.4 |
| libcst | 0.3.21 |
| libtaxii | 1.1.119 |
| lxml | 4.9.2 |
| mongoengine | 0.25.0 |
| more-itertools | 9.0.0 |
| MarkupSafe | 2.1.2 |
| memory-profiler | 0.61.0 |
| mixbox | 1.0.5 |
| mongoquery | 1.4.2 |
| msrest | 0.7.1 |
| multidict | 6.0.4 |
| mypy-extensions | 0.4.3 |
| netskopesdk | 0.0.25 |
| numpy | 1.23.5 |
| oauthlib | 3.2.2 |
| onelogin | 3.1.0 |
| ordered-set | 4.1.0 |
| orderedmultidict | 1.0.1 |
| overrides | 6.5.0 |
| pandas | 1.5.0 |
| packaging | 23.0 |
| passlib | 1.7.4 |
| pycparser | 2.21 |
| prompt-toolkit | 3.0.36 |
| proto-plus | 1.22.2 |
| protobuf | 4.21.12 |
| psutil | 5.9.4 |
| pydantic | 1.10.4 |
| pyasn1 | 0.4.8 |
| pyasn1-modules | 0.2.8 |
| PyJWT | 2.6.0 |
| pymongo | 4.3.3 |
| pyparsing | 3.0.9 |
| python-dateutil | 2.8.2 |
| pyrsistent | 0.19.3 |
| python-multipart | 0.0.5 |
| python3-saml | 1.15.0 |
| pytz | 2022.7.1 |
| PyYAML | 6.0 |
| requests | 2.28.2 |
| requests-oauthlib | 1.3.1 |
| rsa | 4.9 |
| six | 1.16.0 |
| starlette | 0.22.0 |
| sniffio | 1.3.0 |
| s3transfer | 0.6.0 |
| stix | 1.2.0.11 |
| taxii2-client | 2.3.0 |
| typing-inspect | 0.8.0 |
| typing-utils | 0.1.0 |
| typing_extensions | 4.4.0 |
| urllib3 | 1.26.14 |
| uvicorn | 0.20.0 |
| vine | 5.0.0 |
| wcwidth | 0.2.6 |
| weakrefmethod | 1.0.3 |
| websocket-client | 1.4.2 |
| Werkzeug | 2.2.2 |
| xmlsec | 1.3.11 |
| zipp | 3.11.0 |
| requests-mock | 1.7.0 |
Inclure des bibliothèques de plugins personnalisés
Netskope conseille de regrouper toutes les bibliothèques python tierces dont votre plugin aura besoin dans le paquetage du plugin lui-même. Utilisez le programme d'installation pip pour réaliser ce regroupement ; il fournit un commutateur qui prend un répertoire en entrée. Si le répertoire est fourni, pip installera les paquets dans ce répertoire.
For example, the command shown below will install the cowsay package into the directory lib.
> pip install cowsay --target ./lib
Pour la documentation officielle à ce sujet, consultez https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-t.
Lors de l’importation des modules depuis le dossier de la bibliothèque ci-dessus, nous devrions utiliser l’importation relative plutôt que l’import absolu.
IDE
Les IDE recommandés sont PyCharm ou Visual Studio Code.
Structure du répertoire des plugins
Cette section présente la structure de répertoire typique d'un plugin d'échange de risques d'application.
/sample_plugin/ ├── __init__.py ├── Changelog.md ├── icon.png ├── main.py └── manifest.json
- __init__.py : Chaque paquet de plugins est considéré comme un module python par le code d'échange de risques d'application. Assurez-vous que chaque paquet de plugins contient le fichier vide "__init__.py" fichier.
- CHANGELOG.md : Ce fichier contient les détails des mises à jour du plugin et doit être mis à jour avec les balises appropriées telles que Added, Changed, et Fixed ainsi qu'un message convivial approprié.
- icon.png : Logo de l'icône du plugin, qui sera visible dans le chiclet du plugin et dans les cartes de configuration de l'interface utilisateur. Le logo doit avoir un fond transparent et la taille recommandée est de 300*50 pixels ou un rapport d'aspect similaire.
- main.py : Ce fichier python contient la classe Plugin contenant l'implémentation concrète des méthodes push, validate et get_target_fields.
- manifest.json : Fichier manifeste pour le paquet de plugins, contenant des informations sur tous les paramètres configurables et leurs types de données. Ce fichier contient également plus d'informations sur l'intégration du plugin.
Les fichiers énumérés ici sont obligatoires pour toute intégration de plugin, mais les développeurs peuvent ajouter d'autres fichiers en fonction des exigences d'intégration spécifiques.
Note
Assurez-vous que le nom du répertoire du plugin (sample_plugin) correspond à celui du fichier manifest.json. Champ ID.
CHANGELOG.md
Il s'agit d'un fichier qui contient des détails sur les mises à jour du plugin et qui doit être mis à jour avec les balises appropriées telles que Added, Changed, et Fixed ainsi qu'un message convivial approprié.
- Ajouté : à utiliser lorsque les fonctionnalités de New sont ajoutées.
- Corrigé : A utiliser lorsqu'un bogue/une erreur est corrigé(e).
- Changed : à utiliser en cas de changement dans l'implémentation existante du plugin.
# 1.0.1 ## Fixed - Fixed pagination when there are more than 10k Logs. # 1.0.0 ## Added - Initial release.
Manifest.json
Il s'agit d'un fichier JSON qui stocke les méta-informations relatives au plugin, qui sont ensuite lues par le module Application Risk Exchange pour rendre le plugin dans l'interface utilisateur, ainsi que pour permettre au module Application Risk Exchange d'en savoir plus sur le plugin, y compris les paramètres de configuration requis, l'identifiant du plugin, le nom du plugin, etc.
- Chaque plugin doit contenir ce fichier avec les informations nécessaires pour que Application Risk Exchange puisse instancier l'objet Plugin correctement.
- Les paramètres courants de manifest.json sont les suivants
- name : (string) Nom du plugin. (Obligatoire)
- description : (string) Description du plugin. Fournissez une description détaillée qui mentionne les capacités et les instructions d'utilisation du plugin, (ex. Recherche d'utilisateurs et de scores d'utilisateurs et effectue des actions pour les membres d'un groupe/de groupes). Cette description apparaît sur la carte de configuration du plugin. (Obligatoire)
- ID : (chaîne) ID du paquet de plugins. Assurez-vous qu'il est unique pour tous les plugins installés dans le Cloud Exchange. L'ID doit correspondre au nom du répertoire du paquet de plugins. (Obligatoire
- version : (string) Version du plugin. Utilisation d'un MAJOR.MINOR.PATCH (ex. 1.0.1) est encouragé, bien qu'il n'y ait pas de restrictions. (Obligatoire)
- configuration : (array) Array of JSON objects that contains information about all the parameters required by the plugin - their name, type, id, etc. Les paramètres communs des objets JSON imbriqués sont expliqués ci-dessous.
- label : Nom du paramètre. Ceci sera affiché sur la page de configuration du plugin. (Obligatoire)
- key : Clé unique du paramètre, qui sera utilisée comme clé dans l'objet dict python où la configuration du plugin est utilisée. (Obligatoire)
- type : Type de valeur du paramètre. Les valeurs autorisées sont "texte", "mot de passe", "nombre", "choix" et "multichoix". (Obligatoire) Pour plus de détails, reportez-vous aux types de paramètres de la configuration du plugin ci-dessous.
- default : La valeur par défaut de ce paramètre. Cette valeur apparaîtra dans la page de configuration du plugin sur l'interface utilisateur ARE. Les types de données pris en charge sont "texte", "nombre" et "liste" (pour les types à choix multiples). (Obligatoire)
- obligatoire : Booléen qui indique si ce paramètre est obligatoire ou non. Si un paramètre est obligatoire, ARE UI ne vous laissera pas passer une valeur vide pour ce paramètre. Les valeurs autorisées sont `true` et `false`. (Obligatoire)
- description : Description du paramètre au niveau du texte d'aide qui peut donner plus de détails sur le paramètre et la valeur attendue. Cette chaîne apparaîtra dans la page de configuration du plugin en tant que texte d'aide. (Obligatoire)
- choix : Une liste d’objets JSON contenant une clé et une valeur sous forme de clés JSON. Ce paramètre n'est pris en charge que par ‘type’: ‘choice and multichoice`.
Plugin Configuration Parameter Types
Assurez-vous que tous les paramètres de configuration du plugin sont listés dans la section de configuration de manifest.json pour le plugin.
Password Parameter
Utilisez ce paramètre pour stocker les secrets/mots de passe pour l'authentification avec les points d'extrémité de l'API. Les paramètres dont le mot de passe est un type auront une zone de texte de mot de passe dans la page de configuration du plugin et seront obscurcis et cryptés par la plateforme.
Exemple de JSON
"configuration": [
{
"label": "API Token",
"key": "api_token",
"type": "password"
},
]
Vue de la configuration du plugin :

Text Parameter
Utilisez ce paramètre pour stocker des informations sous forme de chaîne, telles que base-url, nom d'utilisateur, etc. Ce paramètre aura une entrée de texte normale sur la page de configuration du plugin.
Exemple de JSON
"configuration": [
{
"label": "Tenant Name",
"key": "user_name",
"type": "text"
},
]
Vue de la configuration du plugin

Number Parameter
Utilisez ce paramètre pour stocker des valeurs numériques ou flottantes. Ce paramètre aura un champ de saisie numérique sur la page de configuration du plugin. (Notez que la liste des hachages se trouve dans le module Threat Exchange).
Exemple de JSON
"configuration": [
{
"label": "Maximum File hash list size in MB.",
"key": "max_size",
"type": "number"
},
]
Vue de la configuration du plugin

Choice Parameter
Utilisez ce paramètre pour stocker les valeurs des paramètres d'énumération. Ce paramètre aura une liste déroulante sur la page de configuration du plugin.
Exemple de JSON
"configuration": [
{
"label": "Base URL",
"key": "base_url",
"type": "choice",
"choices": [
{
"key": "Commercial cloud (api.crowdstrike.com)",
"value": "https://api.crowdstrike.com"
},
{
"key": "US 2 (api.us-2.crowdstrike.com)",
"value": "https://api.us-2.crowdstrike.com"
},
{
"key": "Falcon on GovCloud (api.laggar.gcw.crowdstrike.com)",
"value": "https://api.laggar.gcw.crowdstrike.com"
},
{
"key": "EU cloud (api.eu-1.crowdstrike.com)",
"value": "https://api.eu-1.crowdstrike.com"
}
],
"default": "https://api.crowdstrike.com",
"mandatory": true,
"description": "API Base URL."
},
Vue de configuration du plugin

Après avoir sélectionné l'entrée :

Multichoice Parameter
Utilisez ce paramètre pour stocker des valeurs à choix multiples. Ce paramètre aura une liste déroulante sur la page de configuration du plugin avec la possibilité de sélectionner plusieurs valeurs. (Notez que la gravité se trouve dans le module Threat Exchange).
Exemple de JSON
"configuration": [
{
"label": "Severity",
"key": "severity",
"type": "multichoice",
"choices": [
{
"key": "Unknown",
"value": "unknown"
},
{
"key": "Low",
"value": "low"
},
{
"key": "Medium",
"value": "medium"
},
{
"key": "High",
"value": "high"
},
{
"key": "Critical",
"value": "critical"
}
],
"default": [
"critical",
"high",
"medium",
"low",
"unknown"
],
"mandatory": false,
"description": "Only indicators with matching severity will be saved."
}
]
Vue de la configuration du plugin

Toggle Parameter
Ce paramètre stocke une valeur booléenne, la bascule activée est vraie et la bascule désactivée est fausse.
Utiliser le proxy du système ("proxy") :
Use system proxy configured in Settings.(Default: False)
Vue de la configuration du plugin

Note
Ce paramètre est fourni par Core, et il n'est pas autorisé à être ajouté à partir du fichier manifest.json du plugin.
main.py
Ce fichier python contient l'implémentation de base du plugin.
Importations standard
from netskope.integrations.grc.plugin_base import (
PluginBase,
ValidationResult,
PushResult,
)
from netskope.integrations.grc.models.configuration import (
TargetMappingFields,
MappingType,
)
Variables de PluginBase
PluginBase donne accès à des variables qui peuvent être utilisées au cours du cycle de vie du plugin Méthodes. Voici la liste des variables.
| Nom de la variable | Usage | Description |
|---|---|---|
| self.logger | self.logger.error("Message") self.logger.warn("Message") self.logger.info("Message") | Poignée du logger fournie par le noyau. Utilisez cet objet pour enregistrer les événements importants. Les journaux seront visibles dans les journaux d'audit de Cloud Exchange. Reportez-vous à la documentation de l'objet Logger. |
| self.configuration | self.configuration.get(<nom-clé-attribut>)<attribute-key-name> | Représentation JSON de l'objet de configuration d'une instance de plugin. Utilisez-le pour accéder aux attributs de configuration tels que les informations d'authentification, les détails du serveur, etc. Utilisez le nom de la clé de l'attribut mentionné dans manifest.json. |
| self.last_run_at | Si self.last_run_at : self.last_run_at.timestamp() Utilisez ce format pour convertir la dernière durée d'exécution en format d'époque. | Fournit l'horodatage de la dernière exécution réussie de la méthode d'extraction du plugin. Le noyau de Cloud Exchange maintient l'heure du point de contrôle après chaque exécution réussie de pull(). Pour la première exécution, la valeur sera None. Le type de données de l'objet est datetime. |
| self.storage | Cloud Exchange fournit au plugin un mécanisme pour maintenir l'état. Utilisez cet objet pour conserver tout état qui serait nécessaire lors d'appels ultérieurs. Le type de données de cet objet est python dict. | |
| self.notifier | self.notifier.info(“message”) self.notifier.warn(“message”) self.notifier.error(“message”) | Cet objet fournit l'identifiant du notificateur du noyau Cloud Exchange. Utilisez cet objet pour envoyer une notification à la plateforme. Les notifications seront visibles dans l'interface utilisateur de l'Application Risk Exchange. Veillez à ce que le message contienne des informations résumées pour que l'utilisateur puisse les lire et prendre les mesures nécessaires. Notification utilisée dans le plugin Netskope si la méthode push() dépasse la limite de 8MB du produit. |
| self.proxy | requests.get(url=url, proxies=self.proxy) | Gestion des paramètres proxy du système s'ils sont configurés, sinon {}. |
| self.ssl_validation | requests.get(url=url, verify=self.ssl_validation) | Valeur booléenne qui indique si la validation ssl est appliquée pour les appels à l'API REST. |
Classe de plugin
- La classe Plugin doit être héritée de la classe PluginBase. La classe PluginBase est définie dans Netskope.integrations.grc.plugin_base.
- Assurez-vous que la classe Plugin fournit une implémentation pour les méthodes validate, get_target_fields et push.
- La classe du plugin contiendra tous les paramètres nécessaires pour établir la connexion et l'authentification avec l'API tierce.
"""Sample plugin implementation.
This is a sample implementation of base PluginBase class. Which explains the concrete implementation
of the base class.
"""
from netskope.integrations.grc.plugin_base import (
PluginBase,
ValidationResult,
PushResult,
)
from netskope.common.utils import add_user_agent
from netskope.integrations.grc.models.configuration import (
TargetMappingFields,
MappingType,
)
from typing import List
from datetime import datetime
import requests
PLUGIN_NAME = “<module> <plugin_name> Plugin”
class SamplePlugin(PluginBase):
"""SamplePlugin class having concrete implementation for fetching information and performing actions.
This class is responsible for implementing pull, perform actions and validate methods with proper return types, so that its lifecycle execution can be scheduled by the ARE core engine.
"""
Def get_target_fields()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode doit renvoyer la liste des champs à afficher dans l'interface utilisateur lorsqu'une cible est sélectionnée dans la liste déroulante.
- Cette méthode doit être appelée après que l'utilisateur a validé avec succès les paramètres de configuration et sélectionné les informations de mappage lors de la configuration du plugin.
def get_target_fields(self, plugin_id, plugin_parameters):
"""Get available Target fields."""
return [
TargetMappingFields(
label="Company Name",
type=MappingType.STRING,
value="name",
),
TargetMappingFields(
label="Company Legal Name",
type=MappingType.STRING,
value="company_legal_name",
),
]
Def validate()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode valide la configuration du plugin et les paramètres d'authentification transmis lors de la création d'une configuration de plugin.
- Cette méthode n'est appelée que lorsqu'une configuration New est créée ou mise à jour.
- Validez tous les paramètres obligatoires qui sont transmis avec le type de données approprié.
- Validez les paramètres d'authentification et le point de terminaison de l'API pour garantir le bon déroulement du cycle de vie du plugin.
- Retourne l'objet ValidationResult (voir le modèle de données ValidationResult) avec un drapeau de réussite indiquant le succès ou l'échec de la validation et le message de validation contenant la raison de l'échec de la validation.
def validate(self, data):
""Validate the Plugin configuration parameters.
Validation for all the parameters mentioned in the manifest.json for the existence and
data type. Method returns the netskope.integrations.grc.plugin_base.ValidationResult object with success = True in the case of successful validation and success = False and an error message in the case of failure.
Args:
data (dict): Dict object having all the Plugin configuration parameters.
Returns:
netskope.integrations.grc.plugin_base.ValidateResult: ValidateResult object with success flag and message.
"""
self.logger.info(f”PLUGIN_NAME}: Executing validate method for Sample plugin")
if (
"secret_field_id1" not in data
or not data["secret_field_id1"]
or type(data["secret_field_id1"]) != str
):
self.logger.error(
f"{PLUGIN_NAME}: Validation error occurred Error: Secret Field1 is required with type string."
)
return ValidationResult(
success=False, message="Invalid Secret Field 1 provided.",
Poussée déf.
- Cette méthode met en œuvre la logique permettant d'envoyer les détails de l'application aux points d'extrémité de l'API du produit ou aux connexions Socket.
- Il reçoit toutes les données et les transmet. Vous pouvez utiliser n'importe quel type de stratégie pour diffuser des données. Qu'il s'agisse d'une connexion par socket ou d'une API REST.
- Cette méthode sera invoquée lorsque la plateforme Cloud Exchange recevra des données d'application.
- Veillez à gérer le cas où la taille maximale de la charge utile prise en charge par le point de terminaison de l'API est dépassée. Il peut y avoir plusieurs façons de traiter ce cas.
- Si le point de terminaison de l'API prend en charge plusieurs demandes avec une taille de charge utile fixe, envoyez les données par morceaux.
- Si le point de terminaison de l'API ne prend pas en charge les demandes multiples (c'est-à-dire nous pouvons le pousser en un seul appel API), soit le plugin peut ignorer les journaux restants et envoyer une notification à l'utilisateur pour qu'il ajuste les filtres de partage, soit il peut échouer avec l'erreur de dépassement de la taille de la charge utile.
- Traitez toutes les exceptions avec la connexion et le code de réponse HTTP et levez les exceptions avec les messages d'erreur ainsi que les enregistreurs en cas d'erreurs.
- L'agent utilisateur doit être ajouté aux en-têtes lors de tout appel à l'API. Format de l'agent utilisateur : Netskope-ce-<ce_version>-<module>-<plugin_name>-.<plugin_version>
- Dans cette méthode, la variable "proxy" pour l'option "Use System Proxy" doit être utilisée lors d'un appel à l'API.
- Renvoyer l'objet PushResult (voir le modèle de données PushResult) avec un drapeau de réussite indiquant si l'opération Push a réussi ou non.
Modèles de données
Cette section énumère les modèles de données et leurs propriétés.
Modèle d'application
- Ce modèle contient 15 champs : applicationId, applicationName, vendor, cci, ccl, categoryName, deepLink, users, customTags, discoveryDomains, steeringDomains, createdTime, updatedTime, firstSeen et lastSeen.
- Vous interagirez avec le modèle dans la méthode "push" lorsque vous transmettrez les détails de l'application à un tiers.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| applicationId | int | Identifiant unique de la demande. |
| applicationName | String | Nom de l'application. |
| vendor | String | Valeur du champ. |
| cci | int | Il peut s'agir de n'importe quel nombre entier positif. |
| ccl | String | Il peut s'agir de l'une des valeurs suivantes [médiocre, faible, moyen, élevé, excellent, inconnu]. |
| categoryName | String | Nom de la catégorie. |
| deepLink | String | Lien vers la page d'un tiers où les détails de la demande partagée peuvent être consultés. |
| users | Listr[string] | Liste des utilisateurs. |
| customTags | Listr[string] | List of custom tags. |
| discoveryDomains | Listr[string] | Liste des domaines de découverte. |
| steeringDomains | Listr[string] | Liste des domaines de pilotage. |
| createdTime | datetime | Date et heure de création. |
| updatedTime | datetime | Date et heure de la mise à jour. |
| firstSeen | datetime | Date et heure de la première observation. |
| lastSeen | datetime | Date et heure de la dernière visite. |
Modèle TargetMappingFields
- Ce modèle contient 3 champs : étiquette, type et valeur.
- Vous interagirez avec le modèle dans la méthode get_target_fields en renvoyant une liste de Target. Domaines
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| label | string | Étiquette du champ qui est affichée dans l'interface utilisateur. |
| type | MappingType | Type de données du champ. |
| value | string | Valeur du champ. |
from netskope.integrations.grc.models import Application
Application(
applicationId=0,
applicationName="string",
vendor="string",
cci=100,
ccl="poor",
categoryName="string",
deepLink="",
source="string",
createdTime="2023-03-20T06:02:15.893Z",
updatedTime="2023-03-20T06:02:15.893Z",
users=[],
customTags=[],
discoveryDomains=[],
steeringDomains=[],
firstSeen="2023-03-20T06:02:15.893Z",
lastSeen="2023-03-20T06:02:15.893Z",
)
MappingType
Il s'agit d'une énumération composée de 3 valeurs : liste, chaîne, entier.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| list | List | Peut être une liste de chaînes de caractères ou d'entiers. |
| string | string | Peut être une chaîne. |
| integer | Integer | Peut être un nombre entier positif. |
Classe PushResult
- Cette classe contient le résultat de l'opération de transfert des détails de l'application vers le point de terminaison de l'API produit.
- L'indicateur de réussite indique le résultat de l'opération "push" et l'indicateur de message doit contenir un message d'erreur approprié en cas d'échec. (En cas de succès, un simple message de succès avec l'indicateur de succès True doit être renvoyé).
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| success | bool | Le drapeau de réussite indique le résultat d'une opération de poussée, qu'elle ait réussi ou échoué. |
| message | string | Le champ message indique l'erreur en cas d'échec. En cas de succès, il peut s'agir d'un simple message de réussite. |
from netskope.integrations.grc.plugin_base import PushResult
PushResult(
success=True,
message="Successfully pushed data to 3rd party."
)
Classe ValidationResult
- Cette classe contient le résultat du processus de validation des paramètres de configuration du plugin transmis à l'objet Plugin lors de la création d'une configuration New pour le plugin.
- Assurez-vous que tous les paramètres transmis à la méthode validate sont validés par rapport au type de données et à la valeur.
- La méthode Validate renvoie l'objet de cette classe avec un drapeau de réussite indiquant le résultat de l'opération de validation et un champ de message contenant le message d'erreur approprié en cas d'échec de la validation. (En cas de succès, un simple message de succès avec l'indicateur de succès True doit être renvoyé).
- Notez que l'action Validate renvoie également l'objet de cette classe.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| success | bool | indique le résultat de l'opération de validation, qu'elle ait réussi ou échoué. |
| message | string | Le champ message indique l'erreur en cas d'échec. En cas de succès, il peut s'agir d'un simple message de réussite. |
from netskope.integrations.cre.plugin_base import ValidationResult
ValidationResult(
success=True,
message="Validation Successful for Sample plugin"
)
Enregistrement
Application Risk Exchange fournit une poignée d'un objet logger pour la journalisation.
- Évitez les instructions d'impression dans le code.
- Cet objet s'enregistre dans la base de données centrale de Cloud Exchange avec le champ horodatage. Les niveaux de journalisation pris en charge sont info, warn et error.
- Assurez-vous que le secret d'authentification de l'API ou toute autre information sensible n'est pas exposé dans les messages du journal.
- Veillez à mettre en place un mécanisme de journalisation approprié avec l'objet logger transmis par la plateforme Cloud Exchange.
- Assurez-vous que la journalisation est suffisante pour aider l'équipe d'exploitation à résoudre les problèmes.
- Assurez-vous que les données sensibles ne sont pas enregistrées ou divulguées dans la notification ou les journaux.
self.logger.error(
f"{PLUGIN_NAME}: Error log-message goes here."
)
self.logger.warn(
f"{PLUGIN_NAME}: Warning log-message goes here."
)
self.logger.info(
f"{PLUGIN_NAME}: Info log-message goes here."
)
Notifications
Application Risk Exchange fournit une poignée d'objets de notification, qui peuvent être utilisés pour générer des notifications dans l'interface utilisateur d'Application Risk Exchange.
- Cet objet est transmis de la plateforme Cloud Exchange à l'objet Plugin. Chaque intégration de plugin peut utiliser cet objet chaque fois qu'il y a un cas d'échec qui doit être notifié à l'utilisateur immédiatement. L'horodatage de la notification est géré par la plateforme Cloud Exchange.
- Cet objet déclenche une notification dans l'interface utilisateur avec un code couleur correspondant à la gravité de l'échec. Les niveaux de notification pris en charge sont info, avertissement et erreur.
- Assurez-vous que le secret d'authentification de l'API ou toute autre information sensible n'est pas exposé dans les messages de notification.
- Utilisez un objet notificateur pour déclencher une notification en cas d'échec ou de situation critique (comme la limitation du débit ou le dépassement de la taille de la charge utile) afin d'informer l'utilisateur de l'état du plugin.
self.notifier.info(
f"{PLUGIN_NAME}: Info notification-message goes here."
)
self.notifier.error(
f"{PLUGIN_NAME}: Error notification-message goes here."
)
self.notifier.warn(
f"{PLUGIN_NAME}: Warning notification-message goes here."
)
Testing
Linting
Dans le cadre du processus de construction, nous exécutons quelques linters pour détecter les erreurs de programmation courantes, les erreurs stylistiques et les éventuels problèmes de sécurité.
Flake8
Il s'agit d'un linter de base. Il peut être exécuté même sans que toutes les dépendances soient disponibles et détectera les erreurs courantes. Nous utilisons également ce linter pour imposer le style de formatage standard pep8 de Python. Dans de rares cas, vous pourriez avoir besoin de désactiver une erreur ou un avertissement renvoyé par ce linter. Pour ce faire, ajoutez un commentaire en ligne du type suivant sur la ligne où vous souhaitez désactiver l'erreur :
# noqa : <error-id>
Par exemple :
example = lambda : 'example' # noqa : E731
Lorsque vous ajoutez un commentaire en ligne, incluez toujours également le code d'erreur pour lequel vous désactivez la fonctionnalité. Ainsi, si d'autres erreurs se produisent sur la même ligne, elles seront signalées.
Pour plus d'informations, consultez : https://flake8.pycqa.org/en/latest/user/violations.html#in-line-ignoring-errors
La vérification des chaînes de documentation au format PEP8 est également activée avec le linter flake8. Assurez-vous donc que chaque fonction/module possède une documentation appropriée.
Tests unitaires
Assurer des tests unitaires pour tester de petites unités de code de manière isolée et déterministe. Veillez à ce que les tests unitaires évitent de communiquer avec des API externes et à ce qu'ils utilisent la technique du "mocking". Assurez-vous que les tests unitaires garantissent une couverture du code supérieure à 70%.
Configuration de l'environnement
Afin de travailler avec les tests unitaires, le script d'intégration ou d'automatisation doit être développé dans la structure du répertoire des plugins. Nous utilisons PIP pour installer toutes les dépendances du module Python nécessaires à l'exécution de l'installation. Avant d'exécuter les tests, assurez-vous d'installer toutes les dépendances requises mentionnées dans le fichier requirements.txt du référentiel Application Risk Exchange.
Écrire vos tests unitaires
Assurez-vous que les tests unitaires sont écrits dans un fichier Python séparé nommé : <your_plugin_name>_test.py. Dans le fichier de test unitaire, chaque fonction de test unitaire doit porter le nom : test_.<your test case> Plus d’informations sur la rédaction de tests unitaires et leur format sont disponibles sur PyTest Docs.
Mocking
Nous utilisons pytest-mock pour la simulation. pytest-mock est activé par défaut et installé dans l'environnement de base mentionné ci-dessus. Pour utiliser un objet mocker, il suffit de le passer en paramètre à votre fonction de test. Le simulateur peut alors être utilisé pour simuler à la fois l'objet de classe du plugin et les API externes.
Exemple:
ef test_netskope_push(mocker):
mocker.patch("grc.plugins.sample.main.SamplePlugin")
Push_return_result = PushResult(
success=True,
message="Successfully pushed data to third_party.",
)
samplePlugin.push.return_value = Push_return_result
sp = samplePlugin(None, None, None, logger)
application = [Application(objectId="64116b18969c9579c080c5ac",
applicationId=0,
applicationName="Postman",
vendor="Nexus Venture Partners",
cci=100,
ccl="poor",
categoryName="Desktop",
deepLink="",
createdTime="2023-03-15T06:52:08.374000",
updatedTime="2023-03-15T06:52:08.374000",
source="netskope",
users=[],
customTags=[],
discoveryDomains=[],
steeringDomains=[],
firstSeen="2023-03-15T06:52:08.374000",
lastSeen="2023-03-15T06:52:08.374000"
)]
mappings = {
"jsonQuery": {
"and": [
{
"==": [
{
"var": "name"
},
"applicationName"
]
}
]
},
"query": "name == \"applicationName\""
}
actual_push = sp.push(application,mappings)
assert push_return_result == actual_push
Pour simuler la réponse du module de demande pour les appels API (le plugin requests_mock Pytest est installé avec toutes les dépendances).
def test_fetch_users(requests_mock):
endpoint_url = "https://example-api.com"
mock_response_json = {
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#directoryObjects",
"value": [
{
"@odata.type": "#microsoft.graph.user",
"id": "48a97c4b-65af-4cb7-90f9-c7835d5ecd8b",
"userPrincipalName": "adaml@xyz.com"
}
]
}
requests_mock.get(endpoint_url, json=mock_response_json)
config_dict = {
"tenant_name": "ecre-ccec-jpvasq",
"client_id": "ue4y-3id8-mnx87q",
"client_secret": "d9oe-ple7-nfi34w",
"api_token": "token",
}
sp = SamplePlugin(config_dict, None, None, logger)
actual_users_lists = sp.fetch_users(
endpoint_url,
config_dict['api_token']
)
users_mock = [
Record(uid="a@def.com", type=Record.user, score=400),
Record(uid="b@pqr.com", type=Record.user, score=300),
Record(uid="c@xyz.com", type=Record.user, score=750),
]
assert len(actual_users_lists) == len(users_mock)
for i in range(len(actual_users_lists)):
assert actual_ind_lists[i].value == users_mock[i].value
Exécuter vos tests unitaires
$ PYTHONPATH=. pytest
Déploiement de plugins sur Cloud Exchange
Paqueter le plugin
Cloud Exchange attend le plugin développé au format zip et tar.gz.
Exécutez cette commande pour compresser le paquet :
zip -r sample_plugin.zip sample_plugin
Exécutez cette commande pour générer le paquet tar.gz :
tar -zcvf sample_plugin.tar.gz sample_plugin
Télécharger le plugin
Pour déployer ce zip ou tar.gz sur la plateforme Cloud Exchange, suivez ces étapes :
- Connectez-vous à la plateforme Cloud Exchange.
- Va sur Settings > Plugin.

- Cliquez Add New Plugin.

- Cliquez sur Browse.
- Select votre fichier zip ou tar.gz.

- Cliquez sur Upload.
Add a Repo
Pour déployer votre plugin sur la plateforme Cloud Exchange, vous pouvez ajouter votre repo dans la plateforme Cloud Exchange en suivant ces étapes :
- Connectez-vous à la plateforme Cloud Exchange.
- Va sur Settings > Plugin Repository.

- Cliquez Configure New Repository.

- Fournissez un nom de référentiel, une URL de référentiel, un nom d'utilisateur et un jeton d'accès personnel.
- Cliquez sur Save.

- Allez sur Settings > Plugins.
- Select un nom de référentiel dans la liste déroulante Référentiel.

Deliverables
Plugin Guide
- Veillez à mettre à jour le guide du plugin à chaque version.
- Le guide du plugin doit contenir ce contenu :
- Compatibility
- Notes de mise à jour
- Description
- Conditions préalables
- Permissions
- Autorisation du produit
- Configuration du plugin Netskope Application Risk Exchange
- Configuration du plugin Application Risk Exchange que nous avons développé.
- Configuration de la règle de gestion
- Configuration de l'ajout Configuration du partage
- Validation
Vidéo de démonstration
Après le développement réussi du plugin Application Risk Exchange, créez une vidéo de démonstration et montrez le plugin de bout en bout workflow.

