Ce document explique comment créer un plugin New Cloud Log Shipper qui permet de transformer et de pousser ou d'ingérer des données en s'appuyant sur les fonctionnalités fournies par le module CLS. 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 CE.
- 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 Log Shipper
La plateforme Cloud Exchange, et son module Cloud Log Shipper, est dotée d'un ensemble riche 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.
Remarque : ce module permet de partager les données de Netskope avec des outils tiers.
Concepts de Netskope & Terminologie
- Core : CE core engine 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 : Les zones de code fonctionnel qui invoquent des plugins spécifiques aux modules pour accomplir différents flux de travail. CLS est l'un des modules de Cloud Exchange fonctionnant sous Cloud Exchange.
- Plugin : Les plugins sont des paquets Python qui ont une logique pour transformer et pousser ou ingérer des informations/logs collectés par le locataire Netskope à des tiers.
- 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 l'EC pour transformer et pousser ou ingérer des informations.
- Cartographie : Le format des données que vous souhaitez envoyer à la plateforme, appelé "mapping".
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 de lint de flake8 passe avec le contrôle de doc string 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 évite de stocker d'énormes objets pour la gestion des états.
- Si la description du plugin contient un lien, il doit s'agir d'un lien hypertexte redirigeant vers la page de documentation. Reportez-vous au plugin CTE Trend Micro Vision One pour plus de détails.
- 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 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 œuvre un mécanisme de journalisation approprié avec l'objet logger transmis par la plate-forme CE. 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.
- Veillez à utiliser la configuration du proxy et l'indicateur de validation du certificat SSL transmis par la plateforme CE 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.
- Assurez-vous que le nom du répertoire du plugin (par exemple sample_plugin) correspond à celui du fichier manifest.json. champ id
- L’Agent utilisateur doit être ajouté aux en-têtes lors de tout appel API. Format de l'agent utilisateur : Netskope-ce-
– – – Consultez le plugin URE Microsoft Azure AD ou URE CrowdStrike Identity Protect pour plus de détails. Remarque : La version du plugin doit être récupérée dynamiquement et pour récupérer Netskope-ce- utiliser la méthode définie par le noyau. - Les champs Tokens API et Password ne doivent pas utiliser strip().
- Les messages de journalisation doivent commencer par «
Plugin [nom_de_configuration] : « . Exemple : « Plugin CLS Chronicle [Nom de la configuration Chronicle] : ". [Ceci est une suggestion, nous pouvons éviter le nom de la configuration]. (logger.info(" Plugin : ")) - 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())
- Le message Toast ne doit pas contenir le
Plugin : dans le 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é. Veillez à ce que le nom du fichier corresponde exactement à CHANGELOG.md.
- Vérifiez que votre code python ne présente pas de vulnérabilités.
Écrire un plugin
Cette section illustre le processus d'écriture d'un plugin à partir de zéro.
Téléchargez le plugin d’exemple depuis le dépôt public Github NetskopeOSS.
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 plate-forme Netskope CE.
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.
Par exemple, la commande ci-dessous installera le paquet "cowsay" dans le répertoire "lib".
> pip install cowsay --target ./lib
Vous trouverez la documentation officielle à ce sujet à l'adresse suivante : https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-t.
Lors de l'importation de modules à partir du dossier lib ci-dessus, nous devrions utiliser l'importation relative au lieu de l'importation absolue. Comme indiqué ci-dessous
from .lib import cowsay
IDE
Les IDE recommandés sont PyCharm ou Visual Studio Code.
Structure du répertoire des plugins
Cette section présente la structure typique des répertoires d'un plugin Log Shipper.
/sample_plugin/ ├── /utils/ ├── syslog_cef_generator.py ├── syslog_constants.py ├── syslog_exceptions.py ├── syslog_helper.py ├── syslog_ssl.py ├── syslog_validator.py ├── __init__.py ├── CHANGELOG.md ├── icon.png ├── main.py ├── mappings.json └── manifest.json
- __init__.py : Chaque package de plugin est considéré comme un module Python par le code CE. Assurez-vous que chaque package de plugin contienne le fichier vide « __init__.py ». déposer.
- 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 une taille recommandée de 300*50 pixels ou un rapport d'aspect similaire.
- CHANGELOG.md : Ce fichier contient les détails de la mise à jour du plugin et doit être mis à jour avec les balises appropriées telles que Added, Changed, Fixed (Ajouté, Modifié, Corrigé) ainsi qu'un message convivial approprié.
- main.py : Ce fichier python contient la classe Plugin contenant l'implémentation concrète de la méthode transform, push et validate.
- 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.
- Mappings.json : Ce fichier contient le fichier de mapping par défaut que nous devons utiliser pour le plugin. S'il n'est pas spécifié, il utilisera les mappings par défaut spécifiés dans le fichier manifest.json et Cloud Exchange lancera une erreur, étant donné qu'aucun fichier de mapping de ce type n'est trouvé.
- utils/ : Ce répertoire est utilisé pour écrire des fonctions utilitaires et contient différents fichiers en fonction des besoins du plugin. Les fichiers spécifiques au plugin syslog sont affichés ici.
- syslog_cef_generator.py : Le fichier générateur contient la logique permettant de convertir les données json de Netskope en un type de données pris en charge par une tierce partie, sur la base du fichier de mappage sélectionné pour le plugin.
- syslog_constants.py : Ce fichier contient les constantes qui peuvent être utilisées dans l'ensemble du plugin, comme BASE_URL, Severity maps, etc.
- syslog_exceptions.py : Ce fichier contient les exceptions personnalisées que peut générer le plugin, telles que les exceptions de validation de mappage et les exceptions spécifiques au format de données.
- syslog_helper.py : Ce fichier contient les fonctions d'aide qui peuvent être utilisées pour valider le schéma de mappage ou pour obtenir un fichier de mappage basé sur le type de données.
- syslog_ssl.py : Ce fichier contient la logique permettant de créer une connexion avec une plateforme tierce.
- syslog_validator.py : Ce fichier contient la validation des paramètres de configuration ainsi que certaines validations liées au mappage ou à la connexion.
Les fichiers énumérés , à l'exception du dossier "utils" et de "mappings.json", sont obligatoires pour toute intégration de plugin, mais les développeurs peuvent ajouter d'autres fichiers en fonction des exigences spécifiques de l'intégration.
Remarque : assurez-vous que le nom du répertoire du plugin (par exemple, sample_plugin) corresponde à celui du fichier manifest.json. champ d'identification
CHANGELOG.md
Il s'agit d'un fichier qui contient les détails de la mise à jour du plugin et qui doit être mis à jour avec les balises appropriées telles que Added, Changed, Fixed (ajouté, modifié, corrigé) ainsi qu'un message convivial approprié.
- Ajouté : utilisez-le lorsque les fonctionnalités de New sont ajoutées
- Corrigé : utilisez-le lorsqu'un bug/une erreur est corrigé(e).
- Changed : à utiliser en cas de modification de l'implémentation existante du plugin.
Exemple de Changelog.md
# 1.0.1 ## Fixed - Fixed pagination when there are more than 10k Logs # 1.0.0 ## Added - Initial release.
Mappings.json
Il s'agit d'un fichier JSON qui contient le fichier de correspondance du plugin, qui est ensuite lu par le module CLS lors de la transformation des données Netskope vers le type de données pris en charge par le plugin.
- Les paramètres courants pour mappings.json sont les suivants :
- name : (string) Nom du fichier de mappage. (Obligatoire)
- jsonData : (string) field mapping of all fields as Json escaped string. (Obligatoire)
- isDefault : (booléen) Indique si ce fichier de mappage est par défaut ou non. Les utilisateurs ne peuvent pas supprimer/modifier les mappages par défaut. (Valeur par défaut : False) (Facultatif)
- Vous devez toujours créer un fichier de correspondance pour les plugins Log Shipper. Le mapping doit contenir le type et le sous-type que le plugin supporte, même si nous ne faisons pas de transformation, le plugin doit définir les sous-types. Par exemple :
{ "taxonomy": { "json": { "events": { "application": [], "page": [] } } } } - Exemple de fichier mappings.json.
{ "name": "Default Mappings", "jsonData": "{\"delimiter\":\"|\",\"syslog_map_version\":\"2.0.3\",\"cef_version\":\"0\",\"validator\":\"valid_extensions.csv\",\"taxonomy\":{\"logs\":{\"info\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"warning\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"error\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}}},\"webtx\":{\"v2\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}}},\"alerts\":{\"anomaly\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"dlp\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"malware\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"policy\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"CompromisedCredential\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"LegalHold\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"Malsite\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"Quarantine\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"Remediation\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"SecurityAssessment\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"Watchlist\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"uba\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}}},\"events\":{\"infrastructure\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"page\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"application\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"audit\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}},\"network\":{\"header\":{\"Target_Field\":{\"default_value\":\"Netskope\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}},\"extension\":{\"Target_Field\":{\"default_value\":\"default_value\",\"mapping_field\":\"Netskope_Field\",\"transformation\":\"String\"}}}},\"json\":{\"alerts\":{\"anomaly\":[],\"dlp\":[],\"malware\":[],\"policy\":[],\"CompromisedCredential\":[],\"LegalHold\":[],\"Malsite\":[],\"Quarantine\":[],\"Remediation\":[],\"SecurityAssessment\":[],\"Watchlist\":[],\"uba\":[]},\"events\":{\"application\":[],\"audit\":[],\"infrastructure\":[],\"page\":[],\"network\":[]}}}}"
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 CLS pour rendre le plugin dans l'interface utilisateur et permettre au module CLS 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 CLS puisse instancier correctement l'objet Plugin.
- Les paramètres courants du fichier manifest.json sont les suivants
- name : (string) Nom du plugin. (Obligatoire)
- id : (string) 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é, mais il n'y a pas de restrictions. (Obligatoire)
- types : (tableau) Types de données pris en charge par le plugin. Les types de données possibles sont "alertes", "événements", "webtx" et "journaux".
- description : (string) Description du plugin. Fournissez une description détaillée qui mentionne les capacités et les instructions d'utilisation du plugin. (Ex. - Ce plugin est utilisé pour ingérer des données dans la plateforme SIEM). La description apparaît sur la carte de configuration du plugin. (obligatoire). Si la description contient un lien, il doit s'agir d'un lien hypertexte et non d'un texte en clair.
- Mapping : Le type de format de données que l'on veut envoyer. (Obligatoire) (ce paramètre doit être identique au paramètre "name" dans le fichier de correspondance du plugin).
- 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 à la section Types de paramètres de 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 dans l'interface utilisateur CLS. 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, l'interface utilisateur CLS ne vous permet pas de lui attribuer une valeur vide. 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": "tenant_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. (Note : Ceci est tiré du guide de développement du plugin Cloud 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
Use this parameter for storing any enumeration parameter values. This parameter will have a dropdown box on the plugin configuration page.
Exemple de JSON
{
"label": "Syslog Protocol",
"key": "syslog_protocol",
"type": "choice",
"choices": [
{
"key": "TLS",
"value": "TLS"
},
{
"key": "UDP",
"value": "UDP"
},
{
"key": "TCP",
"value": "TCP"
}
],
"default": "UDP",
"mandatory": true,
"description": "Protocol to be used while ingesting data."
},
Vue de la 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. (Note : Ceci est tiré du guide de développement du plugin Cloud Threat Exchange).
Lors de l’utilisation du paramètre « multichoix » dans le fichier manifest, le paramètre « obligatoire » doit être maintenu comme Faux.
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.
Transformez les données brutes ("transformData") :
If enabled, Raw logs will be transformed using selected mapping file, else raw logs will be sent to SIEM. The ingestion may be affected if the SIEM does not accept raw logs format.(Default: True)
Utiliser le proxy du système ("proxy") :
Use system proxy configured in Settings.(Default: False)
Vue de la configuration du plugin :
Remarque: Ce paramètre est fourni par le noyau et ne peut pas être ajouté à partir du fichier manifest.json des plugins.
main.py
Ce fichier python contient l'implémentation de base du plugin.
Standard Imports
from netskope.integrations.cls.plugin_base import ( PluginBase, ValidationResult, PushResult, )
PluginBase Variables
PluginBase donne accès à des variables qui peuvent être utilisées pendant les méthodes du cycle de vie du plugin. Vous trouverez ci-dessous la liste des variables.
Nom de la variable | Usage | Description |
Self.name, | self.logger.error(“Message”) self.logger.warn("Message") self.logger.info(“Message”) | Les poignées de l'enregistreur sont fournies par le noyau. Utilisez cet objet pour enregistrer les événements importants. Les journaux seraient visibles dans les journaux d'audit de CE. Pour plus d'informations, reportez-vous à la section Journalisation. |
self.configuration | self.configuration. obtenir( | Représentation JSON de l'objet de configuration de l'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. | Valeur temporelle qui contient l'heure à laquelle le plugin s'est exécuté avec succès. |
self.storage | Log Shipper fournit au plugin un mécanisme de maintien de 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 une poignée pour le notificateur du noyau CE. Utilisez cet objet pour envoyer des notifications à la plateforme. Les notifications seraient visibles sur l'interface utilisateur de CLS. Veillez à ce que le message contienne des informations résumées permettant à l'utilisateur de les lire et d'entreprendre les actions nécessaires. Par exemple : utilisez un notificateur dans le plugin Netskope si la méthode push() dépasse la limite de 8 Mo du produit. |
self.use_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. |
self.source | helper.get_tenant_cls(self.source) | Chaîne contenant le nom du plugin source à partir duquel les données seront extraites. |
self.mappings | obtenir_syslog_mappings( self.mappings, type_de_données) | Chaîne Json contenant la cartographie du plugin. |
Classe de plugin
- La classe Plugin doit être héritée de la classe PluginBase. La classe PluginBase est définie dans Netskope.integrations.cls.plugin_base.
- Assurez-vous que la classe Plugin fournit une implémentation pour les fonctions push et transform. Vous pouvez mettre en œuvre des méthodes de tirage, de validation, de mappage ou de source, en fonction de votre cas d'utilisation.
- La pagination doit toujours être prise en compte lors du développement d'une fonctionnalité dans un plugin.
- La classe du plugin contiendra tous les paramètres nécessaires pour établir la connexion et l'authentification avec l'API tierce.
- Les constantes telles que PLUGIN_NAME, LIMIT, etc. doivent être déclarées.
"""Sample plugin implementation.
This is a sample implementation of base PluginBase class. Which explains the concrete implementation of the base class.
"""
from netskope.common.utils import AlertsHelper
from netskope.integrations.cls.plugin_base import (
PluginBase,
ValidationResult,
PushResult,
)
PLUGIN_NAME = "<module> <plugin_name> Plugin"
class SamplePlugin(PluginBase):
"""SamplePlugin class having concrete implementation for transforming and pushing logs.
This class is responsible for implementing transform, push and validate methods with proper return types,
so that it's lifecycle execution can be scheduled by the CLS core engine.
"""
Def Transform()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode met en œuvre la logique de transformation des journaux pour les envoyer à une autre plateforme.
- Vous pouvez créer des fonctions d'aide et de génération pour transformer les événements/alertes de Netskope.
- Dans cette méthode, la variable "transformData" pour la bascule "Transformer les journaux bruts" doit être gérée correctement comme indiqué dans la section Paramètres de la bascule.
def transform(self, raw_data, data_type, subtype) -> List:
"""To Transform the raw netskope JSON data into target platform supported data formats."""
try:
# Get the mapping file content
except Exception as err:
self.logger.error(f”{PLUGIN_NAME}: An error occurred while getting mapping. Error: {str(err)}"
)
raise
# Initialize generator/helper objects if required
transformed_data = []
for data in raw_data:
# Map headers and extensions as per mapping file
# append transformed data in the transformed_data list
return transformed_data
Def Push()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode met en œuvre la logique permettant d'envoyer les journaux transformés par la plateforme CE vers les points d'extrémité de l'API du produit ou les connexions Socket.
- Il reçoit toutes les données que les données transformées et ensuite il pousse. 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 plate-forme CE recevra des données transformées.
- 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 le message d'erreur et les journaux en cas d'erreurs.
- L'agent utilisateur doit être ajouté aux en-têtes lors de tout appel API. Format de l'agent utilisateur : Netskope-ce-
– – – . - Dans cette méthode, la variable "proxy" pour l'option "Use System Proxy" doit être utilisée lors de l'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.
def push(self, transformed_data, data_type, subtype) -> PushResult:
""Push the logs to the 3rd party systems.
This method will be invoked while pushing the logs with 3rd party systems.It takes in transformed_data, data_type and subtype as arguments while pushing this data via sockets to the 3rd party platform.
"""
try:
# API Calls or Socket write operations to push the data
except Exception as err:
self.logger.error(f”{PLUGIN_NAME}: Error occurred during pushing data. Error: {str(err)}"
)
raise
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.
- Des validations séparées doivent être effectuées pour la validation des champs vides et la validation des contrôles de type dans la méthode de validation de la configuration du plugin.
- Valide que tous les paramètres obligatoires 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.
- Lors de la validation, utilisez strip() pour les paramètres de configuration tels que l'URL de base, l'email, le nom d'utilisateur, etc. à l'exception des champs Jetons API et Mot de passe.
- Renvoyer l'objet ValidationResult (se référer au 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.cls.plugin_base.ValidationResult object with success = True in the case
of successful validation and success = False and a error message in the case of failure.
Args:
data (dict): Dict object having all the Plugin configuration parameters.
Returns:
netskope.integrations.cls
.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(
Modèles de données
Cette section énumère les modèles de données et leurs propriétés.
Classe PushResult
- Cette classe contient le résultat de l'opération de poussée des indicateurs 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é).
Data Model Properties
Nom | Type | Description |
success | bool | 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.cls.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é).
Data Model Properties
Nom | Type | Description |
success | bool | Le drapeau de réussite indique le résultat d'une 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. |
rom netskope.integrations.cls.plugin_base import ValidationResult
ValidationResult(
success=True,
message="Validation Successful for Sample plugin"
)
Enregistrement
L'expéditeur de logs 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 l'EC 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 œuvre un mécanisme de journalisation approprié avec l'objet logger transmis par la plate-forme CE.
- 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
Log Shipper fournit un objet de notification qui peut être utilisé pour générer des notifications sur l'interface utilisateur de Log Shipper.
- Cet objet est transmis de la plate-forme CE à 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 CE.
- Cet objet lèvera la 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é sans que toutes les dépendances soient disponibles et il détectera les erreurs les plus courantes. Nous utilisons également ce linter pour appliquer le style de formatage standard python pep8. En de rares occasions, vous pouvez être amené à désactiver une erreur/un avertissement renvoyé(e) par ce lecteur. Pour ce faire, ajoutez un commentaire en ligne de ce type sur la ligne où vous souhaitez désactiver l'erreur :
# noqa:
Par exemple :
example = lambda: 'example' # noqa: E731
Lorsque vous ajoutez un commentaire en ligne, indiquez toujours le code d'erreur pour lequel vous désactivez la fonction. Ainsi, si d'autres erreurs apparaissent sur la même ligne, elles seront signalées.
Plus d'infos : https://flake8.pycqa.org/en/latest/user/violations.html#in-line-ignoring-errors.
La vérification des chaînes de documentation à la manière de PEP8 est également activée avec le linter flake8. Veillez donc à ce que chaque fonction/module soit accompagné d'une docstring 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
Pour pouvoir utiliser les tests unitaires, le script d'intégration ou d'automatisation doit être développé dans une structure de plugin (répertoire). Nous utilisons PIP pour installer toutes les dépendances du module Python nécessaires à l'exécution de l'installation. Avant de lancer les tests, assurez-vous d'installer toutes les dépendances requises mentionnées dans le fichier requirements.txt du dépôt CE core.
Écrire vos tests unitaires
Assurez-vous que les tests unitaires sont écrits dans un fichier Python séparé nommé
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.
Par exemple :
def test_push(mocker, common_config):
"""To test push method of CLSPlugin."""
cls_plugin = CLS_Plugin(
<name>,
common_config,
None,
None,
logger,
source="<source_name>",
mappings=<mapping_json_string>,
)
# Initialize required classes
syslogger = logging.getLogger(
"SYSLOG_LOGGER_{}".format(threading.get_ident())
)
mocker.patch(
"netskope.plugins.Default.cls.main.CLSPlugin.init_handler",
return_value=syslogger,
)
try:
cls_plugin.push(data, data_type, subtype)
except Exception as e:
assert False, f"Push raised exception: {e}"
Exécuter vos tests unitaires
$ PYTHONPATH=. pytest
Déployer le plugin sur Cloud Exchange
Paqueter le plugin
CE attend le plugin développé au format zip et tar.gz.
Exécutez la commande ci-dessous pour zipper le paquet :
zip -r sample_plugin.zip sample_plugin
Exécutez la commande ci-dessous 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 dans Cloud Exchange :
- Connectez-vous à Cloud Exchange.
- Allez sur Settings > Plugins.
- Cliquez sur Add New Plugin.

- Cliquez sur Browse.

- Select le fichier zip ou tar.gz.

- Cliquez sur Upload.
Add a Repo
Pour déployer votre plugin, ajoutez votre répertoire dans Cloud Exchange :
- Connectez-vous à Cloud Exchange.
- Allez sur Settings > Plugin Repository.
- Cliquez sur 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 le nom de votre référentiel dans la liste déroulante Référentiel.


