🕵️♂️ Scanner GitHub automatisé - Détection des clés AWS IAM exposées
Ceci est unSecOpsworkflow d'automatisation du domainecontenant 18 nœuds.Utilise principalement des nœuds comme If, Code, Wait, Slack, HttpRequest. Scanner automatique GitHub - Détection des clés AWS IAM exposées
- •Token Bot Slack ou URL Webhook
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (18)
Catégorie
{
"id": "Tcy2xebw2oGWMxUN",
"meta": {
"instanceId": "c62c01f3e843893075a10f252ec7d6d69e5ab593af019f50055d506cb3081b99",
"templateCredsSetupCompleted": true
},
"name": "🕵️♂️ Automated GitHub Scanner for Exposed AWS IAM Keys",
"tags": [
{
"id": "XuoVybTXeUXuim6G",
"name": "✅ Live",
"createdAt": "2025-06-08T07:59:43.586Z",
"updatedAt": "2025-06-08T07:59:43.586Z"
},
{
"id": "MbPHhZHgb39Syuoa",
"name": "🔐 SecOps",
"createdAt": "2025-04-20T05:18:20.689Z",
"updatedAt": "2025-06-08T08:01:56.494Z"
}
],
"nodes": [
{
"id": "84edf6c4-fc87-4b34-86c6-ad72c15cafe8",
"name": "Lors du clic sur 'Exécuter le workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-880,
75
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b2c1157f-c1eb-4d22-95d0-6ec166a93a4a",
"name": "Diviser les Utilisateurs pour Traitement",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-220,
75
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "ae5a0e4f-892c-4a75-bdcc-36253fbc7274",
"name": "Obtenir les Clés d'Accès Utilisateur",
"type": "n8n-nodes-base.httpRequest",
"position": [
0,
0
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "ListAccessKeys"
},
{
"name": "Version",
"value": "2010-05-08"
},
{
"name": "UserName",
"value": "={{ $json.username }}"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "0946f05d-11f0-480b-934a-c996bbb9551e",
"name": "Filtrer les Clés Actives Uniquement",
"type": "n8n-nodes-base.if",
"position": [
220,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "active-key-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].Status }}",
"rightValue": "Active"
}
]
}
},
"typeVersion": 2
},
{
"id": "8f9db031-245e-4c00-bdb9-4ed55e9b57b2",
"name": "Rechercher GitHub pour les Clés Exposées",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
0
],
"parameters": {
"url": "={{ $json.simpleSearch.searchUrl }}",
"options": {
"timeout": 10000,
"response": {
"response": {
"responseFormat": "json"
}
}
},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "githubApi"
},
"credentials": {
"githubApi": {
"id": "3fz93A0mgyxzXGOL",
"name": "GitHub account"
}
},
"typeVersion": 4.1
},
{
"id": "a6cd482c-86d2-49ac-aefe-6beec92c98af",
"name": "Agréger les Résultats de Recherche",
"type": "n8n-nodes-base.code",
"position": [
1100,
0
],
"parameters": {
"jsCode": "// Aggregate all search results\nconst allResults = [];\nconst accessKeyId = $input.first().json.accessKeyId;\nconst userName = $input.first().json.userName;\n\nfor (const item of $input.all()) {\n if (item.json.total_count > 0) {\n allResults.push(...item.json.items);\n }\n}\n\n// Remove duplicates based on repository and file path\nconst uniqueResults = allResults.filter((item, index, self) => \n index === self.findIndex(t => t.repository.full_name === item.repository.full_name && t.path === item.path)\n);\n\nreturn [{\n accessKeyId,\n userName,\n totalMatches: uniqueResults.length,\n repositories: uniqueResults,\n isCompromised: uniqueResults.length > 0\n}];"
},
"typeVersion": 2
},
{
"id": "75ed15ec-fdee-4644-a83c-6b47005dcac1",
"name": "Vérifier les Clés Compromises",
"type": "n8n-nodes-base.if",
"position": [
1320,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "ebf33a67-f8f3-4700-8579-1d33b7a642d5",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "isCompromised",
"rightValue": "={{ $json.isCompromised }}"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "57753be8-33d2-4172-94a2-0d5a4f7c73ec",
"name": "Générer un Rapport de Sécurité",
"type": "n8n-nodes-base.code",
"position": [
1540,
0
],
"parameters": {
"jsCode": "// Generate comprehensive security report - Notification Only (No Automatic Actions)\nconst data = $input.item.json;\n\nconst report = {\n timestamp: new Date().toISOString(),\n accessKeyId: data.accessKeyId,\n userName: data.userName,\n status: data.isCompromised ? 'COMPROMISED' : 'SAFE',\n totalRepositories: data.totalMatches,\n repositories: data.repositories.map(repo => ({\n name: repo.repository.full_name,\n url: repo.html_url,\n path: repo.path,\n score: repo.score\n })),\n actionTaken: data.isCompromised ? 'Security team notified - Manual review required' : 'No action required',\n riskLevel: data.totalMatches > 5 ? 'HIGH' : data.totalMatches > 0 ? 'MEDIUM' : 'LOW',\n notificationSent: data.isCompromised ? true : false,\n requiresManualAction: data.isCompromised ? true : false,\n recommendedActions: data.isCompromised ? [\n 'Manually disable the compromised access key',\n 'Generate new access keys for affected services',\n 'Remove exposed keys from repositories',\n 'Audit recent API usage for this key'\n ] : []\n};\n\nreturn [report];"
},
"typeVersion": 2
},
{
"id": "f2634090-b035-4592-ad56-b970c2bff14c",
"name": "Continuer l'Analyse",
"type": "n8n-nodes-base.noOp",
"position": [
2340,
80
],
"parameters": {},
"typeVersion": 1
},
{
"id": "158340f1-4dc4-4b4c-933f-95a28be524dc",
"name": "Slack",
"type": "n8n-nodes-base.slack",
"position": [
2020,
0
],
"webhookId": "47dc1fb0-71c0-40f6-8263-88880f01a436",
"parameters": {
"text": "={{ $json.message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "C08Q2H8SRUP"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "i1yhHILyYn12345678",
"name": "Slack account"
}
},
"typeVersion": 2.3
},
{
"id": "c0300832-418b-4fa8-98b6-2b799f2bcfe6",
"name": "Formater l'Alerte Slack",
"type": "n8n-nodes-base.code",
"position": [
1760,
0
],
"parameters": {
"jsCode": "/**\n * GitHub Scanner for Exposed AWS IAM Keys - Data Processor\n * \n * This script processes the results from the AWS IAM Key scanner workflow\n * and formats them for reporting and notification purposes.\n */\n\n// Main entry point - this is what n8n will call\n// Input: items array from n8n workflow\n// Output: Slack Block Kit UI format (blocks array only)\nconst items = $input.all();\n\n// Process the input data\nconst scanResults = items.map(item => item.json);\nconst processedResults = processIAMScanResults(scanResults);\n\n// Format for markdown notification\nconst markdownNotification = formatForMarkdownNotification(processedResults);\n// Return as array of objects for n8n\nreturn [{ message: markdownNotification }];\n\n/**\n * Process scan results and format them for reporting\n * @param {Array} scanResults - Array of scan result objects from the workflow\n * @returns {Array} Array of formatted result objects\n */\nfunction processIAMScanResults(scanResults) {\n if (!Array.isArray(scanResults) || scanResults.length === 0) {\n return [{\n status: 'NO_RESULTS',\n timestamp: new Date().toISOString(),\n message: 'No scan results to process'\n }];\n }\n\n // Process each scan result\n const processedResults = scanResults.map(result => {\n // Create a deep copy to avoid modifying the original data\n const processedResult = JSON.parse(JSON.stringify(result));\n \n // Ensure we have the required fields\n if (!processedResult.timestamp) {\n processedResult.timestamp = new Date().toISOString();\n }\n \n // Calculate risk metrics if not provided\n if (!processedResult.riskLevel) {\n processedResult.riskLevel = calculateRiskLevel(processedResult);\n }\n \n // Generate recommended actions if not provided\n if (!processedResult.recommendedActions || processedResult.recommendedActions.length === 0) {\n processedResult.recommendedActions = generateRecommendedActions(processedResult);\n }\n \n return processedResult;\n });\n\n return processedResults;\n}\n \n /**\n * Calculate risk level based on scan result data\n * @param {Object} result - Individual scan result\n * @returns {string} Risk level (HIGH, MEDIUM, LOW)\n */\n function calculateRiskLevel(result) {\n // Default to MEDIUM if we can't determine\n if (!result || !result.status) {\n return 'MEDIUM';\n }\n \n // Determine risk level based on status and other factors\n if (result.status === 'COMPROMISED') {\n // Public repositories or repositories with many contributors increase risk\n if (result.repositories && result.repositories.some(repo => {\n return repo.score >= 0.8; // High score indicates higher risk\n })) {\n return 'HIGH';\n }\n return 'MEDIUM';\n } else if (result.status === 'POTENTIAL_EXPOSURE') {\n return 'MEDIUM';\n } else {\n return 'LOW';\n }\n }\n \n /**\n * Generate recommended actions based on scan result\n * @param {Object} result - Individual scan result\n * @returns {Array} List of recommended actions\n */\n function generateRecommendedActions(result) {\n const commonActions = [\n 'Review the exposure details in the security report',\n 'Rotate affected access keys immediately'\n ];\n \n if (result.status === 'COMPROMISED') {\n return [\n ...commonActions,\n 'Disable the compromised access key',\n 'Generate new access keys for affected services',\n 'Remove exposed keys from repositories',\n 'Audit recent API usage for this key'\n ];\n } else if (result.status === 'POTENTIAL_EXPOSURE') {\n return [\n ...commonActions,\n 'Verify if the exposure is a false positive',\n 'Consider rotating keys as a precaution'\n ];\n } else {\n return [\n 'No immediate action required',\n 'Continue monitoring for potential exposures'\n ];\n }\n }\n \n /**\n * Format scan results for Slack-compatible markdown notification\n * @param {Array} processedResults - Processed scan results\n * @returns {string} Slack-compatible markdown formatted notification text\n */\n function formatForMarkdownNotification(processedResults) {\n if (!Array.isArray(processedResults) || processedResults.length === 0) {\n return `🔒 *AWS IAM Key Scan Completed*\\n\\nNo exposed AWS IAM keys were detected in this scan.`;\n }\n \n // Count compromised keys\n const compromisedCount = processedResults.filter(r => r.status === 'COMPROMISED').length;\n \n if (compromisedCount === 0) {\n return `🔒 *AWS IAM Key Scan Completed*\\n\\nNo exposed AWS IAM keys were detected in this scan.`;\n }\n \n // Create Slack-compatible notification for compromised keys\n let markdown = `⚠️ *ALERT: AWS IAM Keys Exposed*\\n\\n*${compromisedCount}* AWS IAM keys have been potentially exposed on GitHub. Immediate action required.\\n\\n`;\n \n // Add details for each compromised key\n processedResults.filter(r => r.status === 'COMPROMISED').forEach((result, index) => {\n markdown += `*Exposure ${index + 1}*\\n\\n`;\n \n // Add repository information in a cleaner format\n markdown += `*Exposure Details:*\\n`;\n result.repositories.forEach(repo => {\n markdown += `• *Repository:* ${repo.name}\\n`;\n markdown += `• *Path:* \\`${repo.path}\\`\\n`;\n markdown += `• *Risk Score:* ${repo.score.toFixed(2)}\\n\\n`;\n });\n \n // Add risk level and action taken in a compact format\n markdown += `*Risk Level:* ${result.riskLevel} | *Action Taken:* ${result.actionTaken || 'None'}\\n\\n`;\n \n // Add recommended actions with better formatting\n markdown += `*Recommended Actions:*\\n`;\n result.recommendedActions.forEach(action => {\n markdown += `• ${action}\\n`;\n });\n markdown += `\\n`;\n });\n \n return markdown;\n }\n\n \n // Export functions for use in n8n workflow\n module.exports = {\n processIAMScanResults,\n calculateRiskLevel,\n generateRecommendedActions,\n formatForMarkdownNotification\n };"
},
"typeVersion": 2
},
{
"id": "3ed685c7-27b5-4a00-840a-6f9dddff6d3f",
"name": "Préparer la Recherche Github",
"type": "n8n-nodes-base.code",
"position": [
440,
0
],
"parameters": {
"jsCode": "/**\n * Simplified GitHub Search for AWS Access Keys\n * This script generates optimized search queries for finding exposed AWS access keys on GitHub\n */\n\n/**\n * Generates a GitHub API search URL for a given AWS access key\n * @param {Object} inputData - The input data containing AWS access key information\n * @returns {Object} - Search information including URL and query\n */\nfunction generateGitHubSearchQuery(inputData) {\n try {\n // Extract access key information from input\n let accessKeyId;\n let userName;\n \n // Handle different input formats\n if (inputData && typeof inputData === 'object') {\n // Check for n8n workflow format\n if (inputData.ListAccessKeysResponse && \n inputData.ListAccessKeysResponse.ListAccessKeysResult && \n inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata && \n Array.isArray(inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata) && \n inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata.length > 0) {\n \n accessKeyId = inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].AccessKeyId;\n userName = inputData.ListAccessKeysResponse.ListAccessKeysResult.AccessKeyMetadata[0].UserName;\n } \n // Direct object format\n else if (inputData.accessKeyId) {\n accessKeyId = inputData.accessKeyId;\n userName = inputData.userName || 'unknown';\n }\n }\n \n // Validate we have an access key\n if (!accessKeyId) {\n console.error('No valid AWS access key ID found in input');\n return { error: 'No valid AWS access key ID found in input' };\n }\n \n // Create the most effective search query\n // Based on testing, the exact match with quotes is most reliable\n const searchQuery = `\"${accessKeyId}\" in:file`;\n \n // Generate the GitHub API search URL\n const searchUrl = `https://api.github.com/search/code?q=${encodeURIComponent(searchQuery)}`;\n \n return {\n accessKeyId,\n userName,\n searchQuery,\n searchUrl,\n note: 'A single exact match query is typically sufficient for finding exposed AWS keys'\n };\n } catch (error) {\n console.error('Error generating GitHub search query:', error);\n return { error: `Error generating GitHub search query: ${error.message}` };\n }\n}\n\n/**\n * For more comprehensive searches, this function generates multiple search patterns\n * This is optional and can be used if the simple search doesn't yield results\n * @param {string} accessKeyId - The AWS access key ID to search for\n * @returns {Array} - Array of search queries and URLs\n */\nfunction generateComprehensiveSearch(accessKeyId) {\n if (!accessKeyId) {\n return { error: 'No access key ID provided' };\n }\n \n // Search patterns for access keys (in order of effectiveness)\n const searchQueries = [\n `\"${accessKeyId}\" in:file`, // Exact match (most effective)\n `${accessKeyId} in:file`, // Without quotes (catches more results but may have false positives)\n `AWS_ACCESS_KEY_ID=${accessKeyId} in:file`, // Environment variable format\n `aws_access_key_id: ${accessKeyId} in:file`, // YAML/config format\n `accessKeyId: ${accessKeyId} in:file` // JavaScript/JSON format\n ];\n \n return searchQueries.map(query => ({\n searchQuery: query,\n searchUrl: `https://api.github.com/search/code?q=${encodeURIComponent(query)}`\n }));\n}\n\n// For n8n integration\nfunction processForN8n() {\n try {\n // Get input data\n const inputData = $input.item.json;\n \n // Generate the simplified search (recommended approach)\n const simpleSearch = generateGitHubSearchQuery(inputData);\n \n // For backward compatibility, also generate the comprehensive search\n // if an access key was successfully extracted\n let comprehensiveSearch = [];\n if (simpleSearch.accessKeyId) {\n comprehensiveSearch = generateComprehensiveSearch(simpleSearch.accessKeyId);\n }\n \n return {\n simpleSearch,\n comprehensiveSearch,\n recommendation: 'The simple search is recommended for most cases. Only use comprehensive search if simple search yields no results.'\n };\n } catch (error) {\n console.error('Error in n8n processing:', error);\n return { error: `Error in n8n processing: ${error.message}` };\n }\n}\n\n// For standalone usage\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = {\n generateGitHubSearchQuery,\n generateComprehensiveSearch\n };\n} else {\n // For n8n execution\n return processForN8n();\n}"
},
"typeVersion": 2
},
{
"id": "e58f0cd8-13df-41eb-9a9c-99efc7eba0c4",
"name": "Note Adhésive",
"type": "n8n-nodes-base.stickyNote",
"position": [
-900,
-680
],
"parameters": {
"width": 1120,
"height": 580,
"content": "# 🔐🕵️♂️ GitHub Scanner for Exposed AWS IAM Keys – Quick Overview\n\n## ⚙️ Workflow at a Glance\n\n1. 🔍 **Automated Discovery** \n Scans GitHub repositories for exposed AWS IAM access keys associated with your AWS account.\n\n2. 🧠 **Intelligent Filtering** \n Processes only active access keys and eliminates duplicate findings.\n\n3. 🚨 **Risk Assessment** \n Evaluates exposure severity and assigns risk levels (High/Medium/Low) based on findings.\n\n4. 📣 **Actionable Alerts** \n Sends detailed Slack notifications with interactive buttons for immediate response.\n\n5. 🛠️ **Remediation Guidance** \n Provides step-by-step instructions for securing compromised credentials.\n\n6. 🔄 **Continuous Monitoring** \n Maintains ongoing surveillance to detect new exposures quickly.\n\n---\n\n*🛡️ This workflow helps security teams quickly identify and respond to potential security breaches from exposed AWS credentials.*\n"
},
"typeVersion": 1
},
{
"id": "ef29b02b-f2a4-4642-a5c4-c9685b0e2c22",
"name": "Attente de Limite de Débit",
"type": "n8n-nodes-base.wait",
"position": [
660,
0
],
"webhookId": "850e337e-d261-456a-86c1-1725d77f9e52",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "714724b6-9aaf-4d17-97b7-1a3fd3dcaeae",
"name": "Lister les Utilisateurs AWS1",
"type": "n8n-nodes-base.httpRequest",
"position": [
-660,
80
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "ListUsers"
},
{
"name": "Version",
"value": "2010-05-08"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "a1448a68-81aa-4571-8f62-617c57daa6e6",
"name": "Extraire les Noms d'Utilisateur AWS",
"type": "n8n-nodes-base.code",
"position": [
-440,
75
],
"parameters": {
"jsCode": "// n8n Function node: Extract usernames from AWS ListUsersResponse\n\nconst allInputs = $input.all();\n\n// Find the ListUsersResponse input\nconst listUsersInput = allInputs.find(item => item.json.ListUsersResponse);\n\nif (!listUsersInput) {\n throw new Error('No ListUsersResponse found in input data');\n}\n\n// Extract users array from the response\nconst users = listUsersInput.json\n .ListUsersResponse\n .ListUsersResult\n .Users || [];\n\n// Extract usernames and return each as a separate item for looping\nconst usernameItems = users.map(user => ({\n json: { username: user.UserName }\n}));\n\n// Return array of individual username objects\nreturn usernameItems;"
},
"typeVersion": 2
},
{
"id": "2339c570-93a3-4c1a-ae0d-2eb9810eeee8",
"name": "Désactiver les Clés d'Accès",
"type": "n8n-nodes-base.httpRequest",
"disabled": true,
"position": [
1200,
-620
],
"parameters": {
"url": "https://iam.amazonaws.com",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "Action",
"value": "UpdateAccessKey"
},
{
"name": "AccessKeyId",
"value": "AKIAEXAMPLEACCESSKEY1"
},
{
"name": "UserName",
"value": "user@domain.com"
},
{
"name": "Status",
"value": "Inactive"
},
{
"name": "Version",
"value": "2010-05-08"
}
]
},
"nodeCredentialType": "aws"
},
"credentials": {
"aws": {
"id": "Y0EXCbx12345678",
"name": "AWS account"
}
},
"typeVersion": 4.1
},
{
"id": "99938eb1-580b-4a91-b7a7-83464b33053e",
"name": "Note Adhésive1",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
-680
],
"parameters": {
"color": 6,
"width": 1200,
"height": 580,
"content": "## 🚨 Automate Disable Access Keys\n\n### 1. Prerequisites\n\n- Configure AWS credentials in n8n with appropriate IAM permissions \n- Create an `Extract_Key_Info` node that provides the compromised key's ID and username \n\n### 2. Workflow Integration\n\n- Add this node after your key detection logic \n- Connect it to trigger when a compromised key is confirmed \n\n### 3. Security Considerations\n\n- Ensure your AWS credentials have the `iam:UpdateAccessKey` permission \n- Consider adding verification steps before automatic disabling \n- Implement notification steps after key disabling (e.g., Slack, email) \n\n---\n\nThis implementation enables **immediate remediation of security risks** by automatically disabling compromised AWS access keys as soon as they're discovered in GitHub repositories.\n"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "d96b586a-4739-4ef5-84c8-c71ff9f3e1e6",
"connections": {
"158340f1-4dc4-4b4c-933f-95a28be524dc": {
"main": [
[
{
"node": "f2634090-b035-4592-ad56-b970c2bff14c",
"type": "main",
"index": 0
}
]
]
},
"714724b6-9aaf-4d17-97b7-1a3fd3dcaeae": {
"main": [
[
{
"node": "a1448a68-81aa-4571-8f62-617c57daa6e6",
"type": "main",
"index": 0
}
]
]
},
"ef29b02b-f2a4-4642-a5c4-c9685b0e2c22": {
"main": [
[
{
"node": "8f9db031-245e-4c00-bdb9-4ed55e9b57b2",
"type": "main",
"index": 0
}
]
]
},
"f2634090-b035-4592-ad56-b970c2bff14c": {
"main": [
[
{
"node": "b2c1157f-c1eb-4d22-95d0-6ec166a93a4a",
"type": "main",
"index": 0
}
]
]
},
"c0300832-418b-4fa8-98b6-2b799f2bcfe6": {
"main": [
[
{
"node": "158340f1-4dc4-4b4c-933f-95a28be524dc",
"type": "main",
"index": 0
}
]
]
},
"ae5a0e4f-892c-4a75-bdcc-36253fbc7274": {
"main": [
[
{
"node": "0946f05d-11f0-480b-934a-c996bbb9551e",
"type": "main",
"index": 0
}
]
]
},
"a1448a68-81aa-4571-8f62-617c57daa6e6": {
"main": [
[
{
"node": "b2c1157f-c1eb-4d22-95d0-6ec166a93a4a",
"type": "main",
"index": 0
}
]
]
},
"3ed685c7-27b5-4a00-840a-6f9dddff6d3f": {
"main": [
[
{
"node": "ef29b02b-f2a4-4642-a5c4-c9685b0e2c22",
"type": "main",
"index": 0
}
]
]
},
"0946f05d-11f0-480b-934a-c996bbb9551e": {
"main": [
[
{
"node": "3ed685c7-27b5-4a00-840a-6f9dddff6d3f",
"type": "main",
"index": 0
}
]
]
},
"a6cd482c-86d2-49ac-aefe-6beec92c98af": {
"main": [
[
{
"node": "75ed15ec-fdee-4644-a83c-6b47005dcac1",
"type": "main",
"index": 0
}
]
]
},
"57753be8-33d2-4172-94a2-0d5a4f7c73ec": {
"main": [
[
{
"node": "c0300832-418b-4fa8-98b6-2b799f2bcfe6",
"type": "main",
"index": 0
}
]
]
},
"75ed15ec-fdee-4644-a83c-6b47005dcac1": {
"main": [
[
{
"node": "57753be8-33d2-4172-94a2-0d5a4f7c73ec",
"type": "main",
"index": 0
}
]
]
},
"b2c1157f-c1eb-4d22-95d0-6ec166a93a4a": {
"main": [
[],
[
{
"node": "ae5a0e4f-892c-4a75-bdcc-36253fbc7274",
"type": "main",
"index": 0
}
]
]
},
"8f9db031-245e-4c00-bdb9-4ed55e9b57b2": {
"main": [
[
{
"node": "a6cd482c-86d2-49ac-aefe-6beec92c98af",
"type": "main",
"index": 0
}
]
]
},
"84edf6c4-fc87-4b34-86c6-ad72c15cafe8": {
"main": [
[
{
"node": "714724b6-9aaf-4d17-97b7-1a3fd3dcaeae",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Opérations de sécurité
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Niranjan G
@niranjanCybersecurity leader turning complex workflows into seamless, AI-driven automations.
Partager ce workflow