L’intégration de Miro avec Splunk permet aux clients Enterprise d’exporter deux types de données de journal vers Splunk pour une surveillance avancée de la sécurité, la conformité des rapports et l’analyse opérationnelle au sein de l’organisation. Cette intégration prend en charge :
- Journaux d’audit : capturer l’activité des utilisateurs et au niveau du système dans l’ensemble de votre organisation, telle que l’accès des utilisateurs, le partage de tableaux, les modifications des autorisations, les installations d’applications, les connexions et les actions administratives.
-
Journaux de contenu (module complémentaire Enterprise Guard) : capturez des activités détaillées au niveau du contenu à l'intérieur des tableaux Miro, telles que la création, la modification et la suppression d'objets de tableau (widgets, pense-bêtes, images, texte, cadres), ainsi que l'activité de commentaire.
Bonnes pratiques
- Utilisez des index séparés pour les journaux d’audit et les journaux de contenu.
- Planifier les périodes de conservation en fonction des besoins de conformité.
- Passez en revue les deux types de journaux ensemble pour une surveillance d'activité complète.
Prérequis
- Abonnement au forfait Enterprise.
- Le module complémentaire Enterprise Guard est nécessaire pour activer les journaux de contenu.
- Accès admin aux deux :
- Console d'administration Miro (pour activer le SIEM et générer des jetons)
- Instance Splunk (pour configurer les entrées de données)
Génération de jetons d’accès dans Miro
Les jetons de journal d'audit et de journal de contenu peuvent être générés depuis le même endroit dans Miro.
- Accédez à Intégrations Enterprise → Applications et intégrations dans votre console d'admin.
- Journaux d’audit : Activer le bouton SIEM.
Pour les journaux de contenu : Activez le bouton bascule eDiscovery.
Autrement, générez des jetons en enregistrant une application Miro personnalisée avec les portées : auditlogs:read, contentlogs:export.
⚠️ Les journaux d’audit et les journaux de contenu utilisent des jetons séparés. Sélectionnez le bon jeton pour chaque type d'entrée.
Vous aurez également besoin de votre ID d'organisation — cela peut être copié à partir de l'URL de votre console d'admin :https://miro.com/app/org/{organization_id}/...
Installation et configuration de l’application Splunk pour Miro
- Installez l’application Miro Splunk depuis Splunkbase.
- Dans votre instance Splunk, allez à Application Miro → Entrées.
- Cliquez sur Créer une nouvelle entrée.
- Sélectionnez le type de saisie souhaité : Journaux d’audit ou Journaux de contenu (pour les clients d’Enterprise Guard).
- Veuillez fournir les informations suivantes :
- Jeton — sélectionnez le jeton approprié en fonction du type d'entrée.
- Identifiant de l’organisation.
- Intervalle de temps — détermine la fréquence de récupération des nouveaux évènements par Splunk.
- Index — spécifiez quel index pour stocker les données de journal. Pour les journaux de contenu, un index séparé est recommandé en raison du volume élevé et de la sensibilité des données.
Une fois configuré, Splunk commencera à collecter des évènements de journal depuis Miro.
Résolution des problèmes
- Assurez-vous que les jetons sont correctement générés et attribués au bon type d'entrée.
- Vérifiez que l'identifiant de l’organisation correspond à votre console d’administration.
- Vérifiez que les index sont correctement créés et que les autorisations sont attribuées dans Splunk.
Comment effectuer des recherches dans les journaux de Splunk
Après avoir configuré les entrées de données, vous pouvez rechercher et analyser les journaux dans Splunk en utilisant les index que vous avez assignés pour les journaux d’audit et les journaux de contenu.
-
Journaux d’audit :
index="votre_index_d'audit" source="miro_audit_logs"
-
Journaux de contenu :
index="votre_index_contenu" source="journaux_de_contenu_miro"
Remplacez your_audit_index et your_content_index par les index que vous avez spécifiés lors de la configuration de l'entrée. Vous pouvez utiliser les fonctions standard de recherche, de filtrage et de visualisation de Splunk sur les deux types de journaux.
Visualisation des données dans Splunk
L'application Splunk pour Miro inclut des tableaux de bord préconçus pour les journaux d'audit afin de vous aider à surveiller l'activité des utilisateurs et du système. Après avoir configuré les journaux de contenu, vous pouvez créer des tableaux de bord personnalisés pour visualiser les changements de contenu au niveau du tableau en utilisant les outils de visualisation standard de Splunk.
Utilisez des filtres, des graphiques et des diagrammes chronologiques pour analyser les tendances telles que :
- Suppressions ou modifications du contenu du tableau au fil du temps
- Détection des pics pour les modifications massives de contenu
- Activité des utilisateurs sur les tableaux sensibles
✏️ Les tableaux de bord préconfigurés dans l'application Splunk sont actuellement conçus pour les journaux d'audit. Les journaux de contenu peuvent être analysés grâce à des requêtes de recherche personnalisées et des tableaux de bord en fonction des besoins de votre organisation.
<dashboard theme="light" version="1.1">
<label>Activité de l'utilisateur Miro</label>
<description>Aperçu des événements utilisateurs dans votre compte Miro.</description>
<search id="basesearch">
<query>source=miro_audit_logs | fields * | eval context.team.name = if(isnull('context.team'), 'context.team.name', "None") | search context.organization.name = "$form.organization$" context.team.name = "$form.team$"</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
</search>
<fieldset submitButton="false">
<input type="time" token="time">
<label>Plage horaire</label>
<default>
<earliest>-30d@d</earliest>
<latest>maintenant</latest>
</default>
</input>
<input type="dropdown" token="organization">
<label>Organisation</label>
<fieldForLabel>context.organization.name</fieldForLabel>
<fieldForValue>context.organization.name</fieldForValue>
<search base="basesearch">
<query>| table context.organization.name | dedup context.organization.name</query>
</search>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
</input>
<input type="dropdown" token="team">
<label>Équipe</label>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
<fieldForLabel>context.team.name</fieldForLabel>
<fieldForValue>context.team.name</fieldForValue>
<search base="basesearch">
<query>| table context.team.name | dedup context.team.name</query>
</search>
</input>
</fieldset>
<row>
<panel>
<single>
<title>Nombre total d’événements</title>
<search base="basesearch">
<query>| stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Évènements par date</title>
<search base="basesearch">
<query>| timechart count as Events</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.chart">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">aucun</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
<panel>
<chart>
<title>Évènements par équipe</title>
<search base="basesearch">
<query>| rename context.team.name as Team | stats count as "Events" by Team | sort - "Events"</query>
</search>
<option name="charting.chart">pie</option>
<option name="charting.chart.sliceCollapsingThreshold">0.03</option>
<option name="charting.drilldown">all</option>
<option name="refresh.display">progressbar</option>
<drilldown>
<set token="form.team">$click.value$</set>
</drilldown>
</chart>
</panel>
</row>
<row>
<panel>
<single>
<title>Évènements du tableau</title>
<search base="basesearch">
<query>| search event = board_* | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>Unique
<title>Tableaux créés</title>
<search base="basesearch">
<query>| search event = board_created | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>Unique
<title>Tableaux ouverts</title>
<search base="basesearch">
<query>| search event = board_opened | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Tableaux ouverts ou créés</title>
<search base="basesearch">
<query>| search event = board_created OR event = board_opened | timechart count as "Boards created" by event</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.chart">column</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.placement">right</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
</dashboard>
<dashboard theme="light" version="1.1">
<label>Activité de sécurité de Miro</label>
<description>Aperçu des événements de sécurité dans votre compte Miro.</description>
<search id="basesearch">
<query>source=miro_audit_logs | fields * | search context.organization.name = "$form.organization$"</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
</search>
<fieldset submitButton="false">
<input type="time" token="time">
<label>Plage horaire</label>
<default>
<earliest>-30j@j</earliest>
<latest>maintenant</latest>
</default>
</input>
<input type="dropdown" token="organization">
<label>Organisation</label>
<fieldForLabel>context.organization.name</fieldForLabel>
<fieldForValue>context.organization.name</fieldForValue>
<search base="basesearch">
<query>| table context.organization.name | dedup context.organization.name</query>
</search>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
</input>
<input type="dropdown" token="team">
<label>Team</label>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
<fieldForLabel>context.team.name</fieldForLabel>
<fieldForValue>context.team.name</fieldForValue>
<search base="basesearch">
<query>| table context.team.name | dedup context.team.name</query>
</search>
</input>
</fieldset>
<row>
<panel>
<single>
<title>Connexions réussies</title>
<search base="basesearch">
<query>| search event = sign_in_succeeded | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>
<title>Échecs de connexion</title>
<search base="basesearch">
<query>| search event = sign_in_failed | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Connexions par méthode d’authentification</title>
<search base="basesearch">
<query>| search event = sign_in_* | timechart count as Events by details.authType</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.chart">column</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<title>Événements de partage</title>
<search base="basesearch">
<query>| search event = *public_link* OR event = *sharing* | rename context.team.name as Team createdBy.name as User object.name as Board details.role as Details event as Event | table id _time Event Team User Board Details</query>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row>
<row>
<panel>
<table>
<title>Événements de fichiers</title>
<search base="basesearch">
<query>| search event = board_exported OR event = file_* | rename context.team.name as Team createdBy.name as User object.name as Board details.type as Type details.object as Object event as Event | table id _time Event Team User Board Type Object</query>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row>
</dashboard>
Figure 18 : Modifier le tableau de bord
Activité de l’utilisateur
La première visualisation est Activité de l'utilisateur, où vous trouverez un aperçu des événements de votre utilisateur dans Miro. Ces évènements comprennent :
- Le nombre d'événements au fil du temps, par équipe et au total.
-
Évènements relatifs aux tableaux : tableaux créés, tableaux ouverts et total.
Figure 19 : Activité des utilisateurs
<dashboard theme="light" version="1.1">
<label>Activité des utilisateurs Miro</label>
<description>Aperçu des événements utilisateurs dans votre compte Miro.</description>
<search id="basesearch">
<query>source=miro_audit_logs | fields * | eval context.team.name = if(isnull('context.team'), 'context.team.name', "None") | search context.organization.name = "$form.organization$" context.team.name = "$form.team$"</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
</search>
<fieldset submitButton="false">
<input type="time" token="time">
<label>Plage horaire</label>
<default>
<earliest>-30d@d</earliest>
<latest>maintenant</latest>
</default>
</input>
<input type="dropdown" token="organization">
<label>Organisation</label>
<fieldForLabel>context.organization.name</fieldForLabel>
<fieldForValue>context.organization.name</fieldForValue>
<search base="basesearch">
<query>| table context.organization.name | dedup context.organization.name</query>
</search>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
</input>
<input type="dropdown" token="team">
<label>Équipe</label>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
<fieldForLabel>context.team.name</fieldForLabel>
<fieldForValue>context.team.name</fieldForValue>
<search base="basesearch">
<query>| table context.team.name | dedup context.team.name</query>
</search>
</input>
</fieldset>
<row>
<panel>
<single>
<title>Évènements totaux</title>
<search base="basesearch">
<query>| stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Événements par date</title>
<search base="basesearch">
<query>| timechart count as Events</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.chart">area</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">aucun</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">none</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
<panel>
<chart>
<title>Événements par équipe</title>
<search base="basesearch">
<query>| rename context.team.name as Team | stats count as "Events" by Team | sort - "Events"</query>
</search>
<option name="charting.chart">pie</option>
<option name="charting.chart.sliceCollapsingThreshold">0.03</option>
<option name="charting.drilldown">all</option>
<option name="refresh.display">progressbar</option>
<drilldown>
<set token="form.team">$click.value$</set>
</drilldown>
</chart>
</panel>
</row>
<row>
<panel>
<single>
<title>Événements du tableau</title>
<search base="basesearch">
<query>| search event = board_* | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>
<title>Tableaux créés</title>
<search base="basesearch">
<query>| search event = board_created | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>
<title>Tableaux ouverts</title>
<search base="basesearch">
<query>| search event = board_opened | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Tableaux ouverts ou créés</title>
<search base="basesearch">
<query>| search event = board_created OR event = board_opened | timechart count as "Tableaux créés" by event</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.chart">column</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.placement">right</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
</dashboard>
Activité de sécurité
La deuxième visualisation est l'activité de sécurité, où vous pouvez trouver un aperçu de vos évènements d'utilisateur dans Miro. Ceux-ci sont :
- Activité de connexion : le nombre de connexions réussies et échouées.
-
Événements de partage : liste des événements des utilisateurs lors du partage des tableaux.
Figure 20: Activité de sécurité
<dashboard theme="light" version="1.1">
<label>Activité de sécurité Miro</label>
<description>Aperçu des événements de sécurité dans votre compte Miro.</description>
<search id="basesearch">
<query>source=miro_audit_logs | fields * | search context.organization.name = "$form.organization$"</query>
<earliest>$time.earliest$</earliest>
<latest>$time.latest$</latest>
</search>
<fieldset submitButton="false">
<input type="time" token="time">
<label>Plage horaire</label>
<default>
<earliest>-30d@d</earliest>
<latest>maintenant</latest>
</default>
</input>
<input type="dropdown" token="organization">
<label>Organisation</label>
<fieldForLabel>context.organization.name</fieldForLabel>
<fieldForValue>context.organization.name</fieldForValue>
<search base="basesearch">
<query>| table context.organization.name | dedup context.organization.name</query>
</search>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
</input>
<input type="dropdown" token="team">
<label>Équipe</label>
<choice value="*">Tout</choice>
<default>*</default>
<initialValue>*</initialValue>
<fieldForLabel>context.team.name</fieldForLabel>
<fieldForValue>context.team.name</fieldForValue>
<search base="basesearch">
<query>| table context.team.name | dedup context.team.name</query>
</search>
</input>
</fieldset>
<row>
<panel>
<single>
<title>Connexions réussies</title>
<search base="basesearch">
<query>| search event = sign_in_succeeded | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
<panel>
<single>unique
<title>Échecs de connexion</title>
<search base="basesearch">
<query>| search event = sign_in_failed | stats count</query>
</search>
<option name="drilldown">none</option>
</single>
</panel>
</row>
<row>
<panel>
<chart>
<title>Connexions par méthode d’authentification</title>
<search base="basesearch">
<query>| search event = sign_in_* | timechart count as Events by details.authType</query>
</search>
<option name="charting.axisTitleX.visibility">collapsed</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisY2.enabled">0</option>
<option name="charting.chart">column</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.stackMode">stacked</option>
<option name="charting.drilldown">none</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.mode">standard</option>
<option name="charting.legend.placement">right</option>
<option name="refresh.display">progressbar</option>
</chart>
</panel>
</row>
<row>
<panel>
<table>
<title>Événements de partage</title>
<search base="basesearch">
<query>| search event = *public_link* OR event = *sharing* | rename context.team.name as Team createdBy.name as User object.name as Board details.role as Details event as Event | table id _time Event Team User Board Details</query>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row>
<row>
<panel>
<table>
<title>Évènements de fichier</title>
<search base="basesearch">
<query>| search event = board_exported OR event = file_* | rename context.team.name as Team createdBy.name as User object.name as Board details.type as Type details.object as Object event as Event | table id _time Event Team User Board Type Object</query>
</search>
<option name="count">10</option>
<option name="drilldown">cell</option>
<option name="refresh.display">progressbar</option>
</table>
</panel>
</row>
</dashboard>