In Wazuh 5.0, every cloud log collector runs on a Wazuh agent. The AWS, Azure, Google Cloud, Microsoft 365, Microsoft Graph and GitHub modules are all configured in the agent’s ossec.conf, not in the manager configuration. Cloud events are decoded into the cloud-services category and routed to wazuh-events-v5-cloud-services, with matches in wazuh-findings-v5-cloud-services. The single most common reason a correct configuration produces nothing is that the cloud ruleset integration is disabled by default and has to be enabled from the dashboard.
What you need
- A Wazuh agent on a Linux host that can reach both your cloud provider’s API and the manager. See installing the agent on Linux.
- Credentials created in the cloud provider, with the least privilege each module needs.
- Dashboard access with rights over Security Analytics, to enable the integration. The same Security Analytics flow appears in malware detection with CTI and YARA, where content is promoted from Draft through Test to Custom.
- Python 3 on the collector agent for the Azure and Google Cloud modules, which ship as Python wodles.
Which cloud modules exist in 5.0
The agent configuration reference lists the collectors that survive. This is the whole set, and it is worth reading as a map before you pick one:
| Section | Collects |
|---|---|
wodle name="aws-s3" |
logs from supported AWS buckets, services and subscribers |
wodle name="azure-logs" |
Azure Log Analytics, Microsoft Graph and Azure Storage |
gcp-pubsub |
a Google Cloud Pub/Sub subscription |
gcp-bucket |
access logs from Google Cloud Storage buckets |
office365 |
Microsoft 365 audit logs via the Office 365 Management Activity API |
ms-graph |
logs through the Microsoft Graph API |
github |
GitHub organisation audit events |
Note what that table implies about placement. The Azure documentation says the Wazuh module for Azure and the Wazuh module for Microsoft Graph “run only on a Linux-based Wazuh agent”. The Office 365 module is supported on Windows, Linux and macOS, with an explicit warning to enable it on only one agent to avoid collecting duplicate events. That warning generalises: a cloud API is a single shared source, so two agents pulling the same subscription means two copies of everything.
Enable the integration before you configure anything
Do this first. The ruleset content for cloud providers ships disabled.
The Google Cloud documentation is unambiguous: “The GCP integration containing the Wazuh ruleset for Google Cloud is disabled by default.” You enable it on the dashboard at Security Analytics > Overview, search for gcp, select the integration, then Actions > Enable. The Azure documentation describes the same step through Ruleset Management > Overview, searching for the integration name Azure and selecting Actions > Enable.
Skip this and the symptom is confusing rather than obvious. The agent connects, the module runs, events reach the indexer, and no findings ever appear. You end up debugging credentials that were correct all along.
Collect AWS CloudTrail
CloudTrail is the worked example because it is the one most deployments start with, and because it exercises the bucket path that every other AWS bucket type reuses.
Create the trail
In the AWS console, open CloudTrail and create a trail. Choose whether to create a new S3 bucket or point at an existing one, and note the bucket name: you need it in the agent configuration.
Configure the agent
Add the module to /var/ossec/etc/ossec.conf on the collector agent:
<wodle name="aws-s3">
<disabled>no</disabled>
<interval>30m</interval>
<run_on_start>yes</run_on_start>
<skip_on_error>no</skip_on_error>
<bucket type="cloudtrail">
<name><AWS_BUCKET_NAME></name>
<aws_profile><AWS_PROFILE_NAME></aws_profile>
</bucket>
</wodle>
Restart the agent:
sudo systemctl restart wazuh-agent
That is the whole module. Everything else is tuning, and the reference page for wodle name="aws-s3" carries the full option list. The ones that matter in practice:
intervaldefaults to10m. Thirty minutes is a reasonable starting point for CloudTrail, because CloudTrail itself batches delivery and a shorter interval mostly buys you empty polls.only_logs_aftertakes a date inYYYY-MMM-DDformat, for example2026-AUG-21. Without it the module starts from the date of execution at 00:00:00. Set it deliberately on first run or you will either miss history or ingest a year of it.regionsandaws_account_idtake comma-separated lists and work only with CloudTrail buckets. Use them to keep a multi-region trail from flooding you.discard_regextakes a mandatoryfieldattribute naming the event field to test. The documented example drops events from a specific principal:
<discard_regex field="userIdentity.principalID">EXAMPLE6E4XEGITWATV6R</discard_regex>
remove_from_bucketdefaults tono. Leave it there. Deleting log objects after collection means your SIEM becomes the only copy, and your SIEM is not an archive of record.
Available bucket types are cloudtrail, guardduty, vpcflow, config, custom, cisco_umbrella, waf, alb, clb, nlb and server_access. Service types are cloudwatchlogs and inspector. Subscriber types are security_lake, buckets and security_hub. Multiple buckets, services and subscribers can sit inside the same aws-s3 section.
Credentials and least privilege
access_key and secret_key are deprecated in the reference as of 4.4.0. Use aws_profile against a shared credentials file, or iam_role_arn with an optional iam_role_duration between 900 and 3600 seconds.
Test it
Generate an event that CloudTrail records, such as creating an IAM user. The documentation notes that findings appear as soon as Wazuh receives the logs from the bucket, which is bounded by two delays you do not control: CloudTrail’s own delivery latency to S3, and your interval. Then the detector schedule adds its own. Expect minutes, not seconds, and do not conclude the pipeline is broken before you have waited out all three.
View the results at Cloud security > Amazon Web Services > Findings.
Collect Microsoft 365 audit logs
Microsoft 365 needs an app registration before anything on the Wazuh side matters.
Register the application
In the Azure portal, create an app registration and note the application (client) ID and the directory (tenant) ID. Create a client secret under Manage > Certificates & secrets and copy the value immediately, because the portal does not display it again.
Then add API permissions against the https://manage.office.com resource. Under API permissions > Add a permission, choose Office 365 Management APIs, then Application permissions, and add from the ActivityFeed group:
ActivityFeed.Readfor general activity monitoringActivityFeed.ReadDlpfor visibility into DLP policy violations
Administrator consent is required for API permission changes.
Configure the agent
<office365>
<enabled>yes</enabled>
<interval>1m</interval>
<curl_max_size>1M</curl_max_size>
<only_future_events>yes</only_future_events>
<api_auth>
<tenant_id><YOUR_TENANT_ID></tenant_id>
<client_id><YOUR_CLIENT_ID></client_id>
<client_secret><YOUR_CLIENT_SECRET></client_secret>
<api_type>commercial</api_type>
</api_auth>
<subscriptions>
<subscription>Audit.AzureActiveDirectory</subscription>
<subscription>Audit.General</subscription>
</subscriptions>
</office365>
The subscription types are Audit.AzureActiveDirectory, Audit.Exchange, Audit.SharePoint, Audit.General and DLP.All. api_type accepts commercial, gcc and gcc-high, and picking the wrong one points the module at the wrong API root.
Two details worth knowing. client_secret_path is an alternative to client_secret and points at a file containing the secret, which is the better choice if the configuration is distributed through an agent group. And the api_auth block can be repeated, so one agent can serve several tenants. On an invalid configuration the module generates a warning in the log and triggers an alert after the third scan attempt, which is a useful signal to watch for.
Collect Azure logs
The Azure module needs Python dependencies installed on the collector agent before it will run. The documentation gives version-pinned pip3 commands for Python 3.8 to 3.13, including the --break-system-packages handling for newer releases, on the Azure platform and services page. Install them there rather than improvising.
Credentials go in a file, not in the configuration. Create the directory and write field = value pairs:
sudo mkdir -p /var/ossec/wodles/credentials
For Log Analytics and Graph the file holds two lines, application_id and application_key. For Storage it holds account_name and account_key. Lock it down:
sudo chown root:wazuh /var/ossec/wodles/credentials/<SERVICE_NAME_CREDENTIALS>
sudo chmod 640 /var/ossec/wodles/credentials/<SERVICE_NAME_CREDENTIALS>
Then reference the file with <auth_path> regardless of which Azure service you monitor:
<wodle name="azure-logs">
<disabled>no</disabled>
<run_on_start>yes</run_on_start>
<log_analytics>
<auth_path>/var/ossec/wodles/credentials/<LOG_ANALYTICS_CREDENTIALS></auth_path>
<tenantdomain><YOUR_TENANT_DOMAIN></tenantdomain>
<request>
<query>AzureActivity</query>
<workspace><WORKSPACE_ID></workspace>
<time_offset>1d</time_offset>
</request>
</log_analytics>
</wodle>
More than one <request> block can sit in the same configuration, and the module processes each one in sequence. That sequencing matters at scale: a slow query delays every query behind it.
Collect Google Cloud logs
Google Cloud collection runs through Pub/Sub. Logs are routed into a topic by a sink, and the agent pulls from a subscription on that topic.
Set up the pipeline in Google Cloud
Create a topic and a subscription with Pull delivery. Then create a sink at Logging > Log Router > Create Sink, pointing at the Pub/Sub topic, with an inclusion filter for the logs you want:
| Log type | Inclusion filter |
|---|---|
| Cloud Audit Logs | logName:"cloudaudit.googleapis.com" |
| VPC Flow Logs | resource.type="gce_subnetwork" |
| Firewall rule logs | logName="projects/<YOUR_PROJECT_ID>/logs/compute.googleapis.com%2Ffirewall" |
| DNS query logs | resource.type="dns_query" |
Combine them with OR to feed several log types into one sink. Admin Activity audit logs are enabled by default for every Google Cloud service and cannot be turned off.
After creating the sink, grant its writer identity the Pub/Sub Publisher role on the destination topic. The identity has the form service-<PROJECT_NUMBER>@gcp-sa-logging.iam.gserviceaccount.com and is shown on the sink’s page. Forgetting this step produces a sink that looks healthy and delivers nothing.
Create the service account
Create a service account and give it the roles the module needs. For Pub/Sub that is Pub/Sub Publisher and Pub/Sub Subscriber. For the Cloud Storage bucket module it is Storage Object User and Storage Insights Collector Service. Create a JSON key, transfer it to the agent, and set ownership:
sudo chown root:wazuh /var/ossec/wodles/gcloud/<AUTHENTICATION_FILE_NAME>.json
Configure the agent
<gcp-pubsub>
<pull_on_start>yes</pull_on_start>
<interval>1m</interval>
<project_id><YOUR_PROJECT_ID></project_id>
<subscription_name><YOUR_SUBSCRIPTION_ID></subscription_name>
<credentials_file>/var/ossec/wodles/gcloud/<AUTHENTICATION_FILE_NAME>.json</credentials_file>
</gcp-pubsub>
max_messages defaults to 100 per iteration and num_threads to 1, with the thread count truncated to five times the number of physical cores. On a busy project the default pull of 100 messages a minute will fall behind, and the queue depth in Pub/Sub is where you will see it first.
One hard constraint: the module supports only one gcp-pubsub section per configuration file. A second subscription needs a second agent.
Results appear at Cloud Security > Google Cloud.
How cloud events are categorised
An integration in 5.0 is a grouping of decoders, KVDBs and rules, and every integration is assigned exactly one of seven categories:
access-management, applications, cloud-services, network-activity, security, system-activity, other.
The category is written to wazuh.integration.category on every event that integration decodes, and the output stage uses it to route the event to the right data stream. Cloud provider events therefore land in wazuh-events-v5-cloud-services, with matches in wazuh-findings-v5-cloud-services.
There is no per-provider data stream in the documented model. If you need to slice AWS from Azure from GCP, filter on wazuh.integration.name rather than expecting separate indices. That also shapes your retention thinking, since one category means one lifecycle policy for all cloud logs. See index retention for changing it.
Common errors
Events arrive but no findings appear
The ruleset integration is disabled. Enable it from Security Analytics > Overview, search for the provider name, then Actions > Enable. Confirm events are arriving by querying wazuh-events-v5-cloud-services in Discover before you touch credentials.
Attention: This documentation covers an upcoming release
Not an error, but worth naming: the 5.0-beta cloud pages carry this banner and several of them moved during the beta. The AWS section under cloud-security/amazon/ is not present in the beta documentation tree at all. The authoritative AWS reference in the beta is the wodle name="aws-s3" configuration page, with a worked CloudTrail example in the proof of concept guide.
Duplicate cloud events
Two agents are running the same module against the same source. The Office 365 documentation states the rule explicitly: enable it on only one agent. Check every group’s shared agent.conf as well as the local files, because a cloud module inherited from a group applies to every agent in it. Agent groups covers the merge order.
The Azure module does nothing after a configuration change
Check the Python dependencies first. The module is a Python wodle and the documented dependency list is version-pinned. A pip3 upgrade elsewhere on the host can break it without touching Wazuh at all. The documentation also warns that if you install into a virtual environment you must update the shebang of /var/ossec/wodles/azure/azure-logs to point at that interpreter.
The GCP sink exists but the subscription stays empty
The sink’s writer identity has not been granted Pub/Sub Publisher on the topic. This is the single most common Google Cloud mistake, and neither the sink page nor the subscription page flags it.
An AWS bucket collects nothing on first run
only_logs_after defaults to the date of execution at 00:00:00, so a bucket full of history is ignored. Set it explicitly, in YYYY-MMM-DD form, and be aware that a wide value on a large trail is an ingest spike. Size it against system requirements before you set it.
Next: Monitoring Docker and Kubernetes with Wazuh.
Files for this lesson
Every file this lesson refers to, exactly as used. Open a file to read it in the browser, or download the set as a zip. Download wazuh-cloud-logs.zip. The full set for all lessons is at wazuh-tutorial-files.zip.
Frequently asked questions
Can the Wazuh manager still collect cloud logs in 5.0?
No. Every cloud module runs on a Wazuh agent. The Azure documentation states it directly: starting with Wazuh 5.0 the manager no longer collects Azure Log Analytics logs directly. The same applies to the Office 365 module, which can only be configured on the agent from 5.0 onwards. Nominate one agent as your cloud collector.
Where do cloud events land in the Wazuh indexer?
In the cloud-services category. An integration is assigned one of seven categories, and that value is written to wazuh.integration.category on every event it decodes and used to route the event. Cloud provider events go to wazuh-events-v5-cloud-services and matches to wazuh-findings-v5-cloud-services.
Why am I getting no findings from my AWS or GCP logs?
Most often because the ruleset integration is disabled. Wazuh ships cloud provider integrations switched off in 5.0. Enable the one you need from Security Analytics or Ruleset Management, find the integration by name, then Actions and Enable. Until you do, events are collected but no rule matches them.
Which AWS services does the aws-s3 module support?
As bucket types: cloudtrail, guardduty, vpcflow, config, custom, cisco_umbrella, waf, alb, clb, nlb and server_access. As service types: cloudwatchlogs and inspector. As subscriber types: security_lake, buckets and security_hub. Every one is configured inside a single wodle name=aws-s3 block on the agent.
Can one agent collect from several cloud tenants?
It depends on the module. The Office 365 module accepts multiple api_auth blocks in one configuration, so several tenants share one agent. The Google Cloud Pub/Sub module supports only one gcp-pubsub section per configuration file, so a second subscription needs a second agent.