Collecter les journaux Akamai EAA (Enterprise Application Access)
Ce document explique comment ingérer les journaux Akamai Enterprise Application Access (EAA) dans Google Security Operations à l'aide d'Akamai Unified Log Streamer (ULS) et de Bindplane. Akamai EAA génère des données opérationnelles sous la forme de journaux d'accès, de journaux d'audit des activités d'administration, d'informations d'authentification et de métriques sur l'état des connecteurs. L'analyseur extrait les champs des journaux JSON, effectue des transformations de données telles que des conversions de chaînes et l'extraction d'adresses IP, et mappe ces champs à l'UDM, en gérant différents types d'événements tels que NETWORK_HTTP et USER_UNCATEGORIZED en fonction de la présence de champs spécifiques. Il ajoute également des métadonnées telles que les noms du fournisseur et du produit à l'événement UDM.
Avant de commencer
Assurez-vous de remplir les conditions suivantes :
- Une instance Google SecOps
- Un hôte Windows 2016 ou version ultérieure, ou Linux avec
systemdpour exécuter l'agent Bindplane - Linux, macOS ou un environnement en conteneur (Docker/Kubernetes) pour exécuter Unified Log Streamer
- Si vous exécutez l'agent derrière un proxy, assurez-vous que les ports de pare-feu sont ouverts conformément aux exigences de l'agent Bindplane.
- Locataire Akamai EAA avec accès administrateur
- Identifiants de l'API Akamai (authentification EdgeGrid) :
- Jeton d'accès
- Jeton Client
- Code secret du client
- Nom d'hôte de base de l'API (par exemple,
akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net)
Obtenir le fichier d'authentification d'ingestion Google SecOps
- Connectez-vous à la console Google SecOps.
- Accédez à Paramètres du SIEM > Agents de collecte.
- Téléchargez le fichier d'authentification d'ingestion. Enregistrez le fichier de manière sécurisée sur le système sur lequel Bindplane sera installé.
Obtenir l'ID client Google SecOps
- Connectez-vous à la console Google SecOps.
- Accédez à Paramètres SIEM> Profil.
- Copiez et enregistrez le numéro client de la section Informations sur l'organisation.
Installer l'agent Bindplane
Installez l'agent Bindplane sur votre système d'exploitation Windows ou Linux en suivant les instructions ci-dessous.
Installation de fenêtres
- Ouvrez l'invite de commandes ou PowerShell en tant qu'administrateur.
Exécutez la commande suivante :
msiexec /i "https://github.com/observIQ/bindplane-agent/releases/latest/download/observiq-otel-collector.msi" /quiet
Installation de Linux
- Ouvrez un terminal avec les droits root ou sudo.
Exécutez la commande suivante :
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
Autres ressources d'installation
- Pour plus d'options d'installation, consultez ce guide d'installation.
Configurer l'agent Bindplane pour ingérer Syslog et l'envoyer à Google SecOps
Accédez au fichier de configuration :
- Recherchez le fichier
config.yaml. Il se trouve généralement dans le répertoire/etc/bindplane-agent/sous Linux ou dans le répertoire d'installation sous Windows. - Ouvrez le fichier à l'aide d'un éditeur de texte (par exemple,
nano,viou le Bloc-notes).
- Recherchez le fichier
Modifiez le fichier
config.yamlcomme suit :receivers: tcplog: listen_address: "0.0.0.0:5140" exporters: chronicle/chronicle_w_labels: compression: gzip creds_file_path: '/path/to/ingestion-authentication-file.json' customer_id: <CUSTOMER_ID> endpoint: malachiteingestion-pa.googleapis.com log_type: 'AKAMAI_EAA' raw_log_field: body ingestion_labels: source: akamai_eaa service: pipelines: logs/akamai_eaa: receivers: - tcplog exporters: - chronicle/chronicle_w_labels- Remplacez l'élément suivant :
- Remplacez
<CUSTOMER_ID>par le numéro client réel. - Mettez à jour
/path/to/ingestion-authentication-file.jsonen indiquant le chemin d'accès où le fichier d'authentification a été enregistré dans la section Obtenir le fichier d'authentification pour l'ingestion Google SecOps. 0.0.0.0:5140: adresse IP et port sur lesquels Bindplane doit écouter. Ajustez-les si nécessaire pour votre environnement.
- Remplacez
- Remplacez l'élément suivant :
Redémarrez l'agent Bindplane pour appliquer les modifications.
Pour redémarrer l'agent Bindplane sous Linux, exécutez la commande suivante :
sudo systemctl restart bindplane-agentPour redémarrer l'agent Bindplane sous Windows, vous pouvez utiliser la console Services ou saisir la commande suivante :
net stop BindPlaneAgent && net start BindPlaneAgent
Installer Akamai Unified Log Streamer
Unified Log Streamer (ULS) extrait les journaux d'Akamai EAA via l'API Enterprise Application Access et les diffuse vers Bindplane à l'aide de TCP ou UDP.
Installation de Linux
Téléchargez la dernière version d'ULS :
curl -LO https://github.com/akamai/uls/releases/latest/download/uls-linux-amd64Rendez le binaire exécutable :
chmod +x uls-linux-amd64Déplacez-le vers un emplacement standard :
sudo mv uls-linux-amd64 /usr/local/bin/uls
Installation sur macOS
Téléchargez la dernière version d'ULS :
curl -LO https://github.com/akamai/uls/releases/latest/download/uls-darwin-amd64Rendez le binaire exécutable :
chmod +x uls-darwin-amd64Déplacez-le vers un emplacement standard :
sudo mv uls-darwin-amd64 /usr/local/bin/uls
Installation de Docker
Extrayez l'image Docker ULS officielle :
docker pull akamai/uls:latest
Configurer les identifiants Akamai EdgeGrid
Créez le fichier d'identifiants EdgeGrid :
mkdir -p ~/.edgerc nano ~/.edgercAjoutez vos identifiants Akamai API au format suivant :
[default] client_secret = your-client-secret host = akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net access_token = your-access-token client_token = your-client-tokenSécurisez le fichier d'identifiants :
chmod 600 ~/.edgerc
Remplacez les éléments suivants :
your-client-secret: code secret client Akamai.your-access-token: votre jeton d'accès Akamai.your-client-token: votre jeton client Akamai.akab-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net: nom d'hôte de base de votre API Akamai.
Configurer ULS pour diffuser des journaux EAA vers BindPlane
Exécution de ligne de commande (tests)
Exécutez ULS avec une sortie TCP pour diffuser les journaux vers l'agent Bindplane :
uls --input eaa \
--feed access \
--output tcp \
--host <BINDPLANE_HOST> \
--port 5140 \
--edgerc ~/.edgerc \
--section default
- Remplacez l'élément suivant :
<BINDPLANE_HOST>: adresse IP ou nom d'hôte du serveur exécutant Bindplane5140: port configuré dans le récepteurtcplogde Bindplane
Pour diffuser plusieurs types de flux, exécutez des instances ULS distinctes :
```bash
# Access logs
uls --input eaa --feed access --output tcp --host <BINDPLANE_HOST> --port 5140 --edgerc ~/.edgerc --section default
# Admin audit logs
uls --input eaa --feed admin --output tcp --host <BINDPLANE_HOST> --port 5140 --edgerc ~/.edgerc --section default
# Connector health
uls --input eaa --feed conhealth --output tcp --host <BINDPLANE_HOST> --port 5140 --edgerc ~/.edgerc --section default
```
Service systemd (production)
Pour les déploiements en production, configurez ULS en tant que service systemd :
Créez un fichier de configuration ULS :
sudo mkdir -p /etc/uls sudo nano /etc/uls/eaa-access-tcp.confAjoutez la configuration suivante :
ULS_INPUT=eaa ULS_FEED=access ULS_OUTPUT=tcp ULS_HOST=<BINDPLANE_HOST> ULS_PORT=5140 ULS_EDGERC=/root/.edgerc ULS_SECTION=defaultCréez un fichier de service systemd :
sudo nano /etc/systemd/system/uls-eaa-access.serviceAjoutez le contenu suivant :
[Unit] Description=Unified Log Streamer - EAA Access Logs to BindPlane After=network.target [Service] Type=simple EnvironmentFile=/etc/uls/eaa-access-tcp.conf ExecStart=/usr/local/bin/uls --input ${ULS_INPUT} --feed ${ULS_FEED} --output ${ULS_OUTPUT} --host ${ULS_HOST} --port ${ULS_PORT} --edgerc ${ULS_EDGERC} --section ${ULS_SECTION} Restart=always RestartSec=10 User=root [Install] WantedBy=multi-user.targetActivez et démarrez le service :
sudo systemctl daemon-reload sudo systemctl enable uls-eaa-access.service sudo systemctl start uls-eaa-access.serviceVérifiez que le service est en cours d'exécution :
sudo systemctl status uls-eaa-access.serviceAffichez les journaux :
sudo journalctl -u uls-eaa-access.service -f
Répétez les étapes 1 à 7 pour chaque type de flux supplémentaire (admin, conhealth) en créant des fichiers de configuration et de service distincts avec des noms différents (par exemple, uls-eaa-admin.service, uls-eaa-conhealth.service).
Déploiement Docker
Créez un fichier Docker Compose :
nano docker-compose.ymlAjoutez la configuration suivante :
version: '3.8' services: uls-eaa-access: image: akamai/uls:latest container_name: uls-eaa-access restart: unless-stopped environment: - ULS_INPUT=eaa - ULS_FEED=access - ULS_OUTPUT=tcp - ULS_HOST=<BINDPLANE_HOST> - ULS_PORT=5140 volumes: - ~/.edgerc:/root/.edgerc:ro command: > --input eaa --feed access --output tcp --host "$${ULS_HOST}" --port "$${ULS_PORT}" --edgerc /root/.edgerc --section default uls-eaa-admin: image: akamai/uls:latest container_name: uls-eaa-admin restart: unless-stopped environment: - ULS_INPUT=eaa - ULS_FEED=admin - ULS_OUTPUT=tcp - ULS_HOST=<BINDPLANE_HOST> - ULS_PORT=5140 volumes: - ~/.edgerc:/root/.edgerc:ro command: > --input eaa --feed admin --output tcp --host "$${ULS_HOST}" --port "$${ULS_PORT}" --edgerc /root/.edgerc --section default uls-eaa-conhealth: image: akamai/uls:latest container_name: uls-eaa-conhealth restart: unless-stopped environment: - ULS_INPUT=eaa - ULS_FEED=conhealth - ULS_OUTPUT=tcp - ULS_HOST=<BINDPLANE_HOST> - ULS_PORT=5140 volumes: - ~/.edgerc:/root/.edgerc:ro command: > --input eaa --feed conhealth --output tcp --host "$${ULS_HOST}" --port "$${ULS_PORT}" --edgerc /root/.edgerc --section default- Remplacez
<BINDPLANE_HOST>par l'adresse IP ou le nom d'hôte de votre serveur Bindplane.
- Remplacez
Démarrez les conteneurs :
docker-compose up -dAffichez les journaux :
docker-compose logs -f
Table de mappage UDM
| Champ du journal | Mappage UDM | Logique |
|---|---|---|
app |
target.application |
Valeur après le deux-points dans le champ app. |
apphost |
target.hostname |
Mappé directement. |
browser |
network.http.user_agent |
Mappé directement. |
bytes_in |
network.received_bytes |
Mappé directement. |
bytes_out |
network.sent_bytes |
Mappé directement. |
cc |
principal.location.country_or_region |
Mappé directement. |
client_id |
additional.fields.key: "Client Id", additional.fields.value.string_value: client_id |
Mappé de manière conditionnelle si client_id est présent. |
clientip |
principal.ip |
Mappé directement. |
cloud_zone |
principal.cloud.availability_zone |
Mappé directement. |
connector_resp_time |
security_result.detection_fields.key: "Connector response time", security_result.detection_fields.value: connector_resp_time |
Mappé de manière conditionnelle si connector_resp_time n'est pas vide ou "-". |
content_type |
additional.fields.key: "Content type", additional.fields.value.string_value: content_type |
Mappé de manière conditionnelle si content_type est présent. |
datetime |
metadata.event_timestamp |
Analysé à partir du champ datetime au format RFC3339. |
deny_reason |
security_result.summary |
Mappé directement. |
device_type |
principal.platform, principal.platform_version |
Mappé sur WINDOWS, LINUX ou MAC en fonction de la correspondance de l'expression régulière. La valeur brute est mappée sur principal.platform_version. |
di |
metadata.ingestion_labels.key: "di", metadata.ingestion_labels.value: di |
Mappé directement en tant que libellé d'ingestion. |
error_code |
additional.fields.key: "Error code", additional.fields.value.string_value: error_code |
Mappé de manière conditionnelle si error_code est présent. |
event |
metadata.description |
Mappé directement. |
geo_city |
principal.location.city |
Mappé directement. |
geo_country |
principal.location.country_or_region |
Mappé directement. |
geo_state |
principal.location.state |
Mappé directement. |
groups |
principal.user.group_identifiers |
Mappé directement. |
http_method |
network.http.method |
Mappé directement. |
http_ver |
network.application_protocol, network.application_protocol_version |
Analysé à l'aide de grok pour extraire le protocole et la version. |
idpinfo |
additional.fields.key: "IDP Info", additional.fields.value.string_value: idpinfo |
Mappé de manière conditionnelle si idpinfo est présent. |
internal_host |
additional.fields.key: "Internal host", additional.fields.value.string_value: internal_host |
Mappé de manière conditionnelle si internal_host est présent. |
metadata.log_type |
metadata.log_type |
Codé en dur sur "AKAMAI_EAA". |
metadata.product_name |
metadata.product_name |
Codé en dur sur "AKAMAI_EAA". |
metadata.vendor_name |
metadata.vendor_name |
Codé en dur sur "AKAMAI_EAA". |
metadata.event_type |
metadata.event_type |
Déterminé par la logique : USER_UNCATEGORIZED si uid est présent, NETWORK_HTTP si principal.ip et target sont définis, ou GENERIC_EVENT dans le cas contraire. |
origin_host |
additional.fields.key: "Origin host", additional.fields.value.string_value: origin_host |
Mappé de manière conditionnelle si origin_host est présent. |
origin_resp_time |
security_result.detection_fields.key: "Origin response time", security_result.detection_fields.value: origin_resp_time |
Mappé de manière conditionnelle si origin_resp_time n'est pas vide ou "-". |
os |
principal.platform |
Mappé sur WINDOWS, MAC ou LINUX en fonction de la correspondance de l'expression régulière. |
port |
target.port |
Valeur après le deux-points dans le champ app. |
ral |
metadata.description |
Valeurs concaténées du tableau ral, séparées par des virgules. |
referer |
network.http.referral_url |
Mappé directement. |
resource |
principal.resource.attribute.labels.key: "Resource", principal.resource.attribute.labels.value: resource |
Mappé de manière conditionnelle si resource est présent. |
resource_type |
principal.resource.attribute.labels.key : "Resource Type", principal.resource.attribute.labels.value : resource_type |
Mappé de manière conditionnelle si resource_type est présent. |
rscd |
metadata.ingestion_labels.key : "rscd", metadata.ingestion_labels.value : rscd |
Mappé directement en tant que libellé d'ingestion. |
session_id |
network.session_id |
Mappé directement. |
session_info |
additional.fields.key: "Session info", additional.fields.value.string_value: session_info |
Mappé de manière conditionnelle si session_info est présent. |
state |
principal.location.state |
Mappé directement. |
status_code |
network.http.response_code |
Mappé directement. |
total_resp_time |
security_result.detection_fields.key: "Total response time", security_result.detection_fields.value: total_resp_time |
Mappé de manière conditionnelle si total_resp_time n'est pas vide ou "-". |
ts |
metadata.event_timestamp |
Analysé à partir du champ ts en tant que millisecondes ou secondes UNIX, le cas échéant, ou à partir du champ datetime. |
uid |
principal.user.userid |
Mappé directement. |
uip |
principal.ip |
Mappé directement. |
url_path |
target.url |
Mappé directement. |
user_agent |
network.http.user_agent, network.http.parsed_user_agent |
Mappé et analysé directement dans un champ parsed_user_agent structuré. |
username |
principal.user.email_addresses ou principal.user.userid |
Mappé sur email_addresses si cela ressemble à une adresse e-mail, sinon sur userid. |
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.