Skip to main content

The sidecar on the host

The sidecar is small and its footprint on a host is fixed. This page is the reference for the platforms it runs on, the network it needs, the Wazuh login it reads with, and the one place Wazuh 4.x and 5.x differ. A manager is added from Wazuh Fleet, which installs the sidecar as a plugin and manages its files. See Install the sidecar from Wazuh Fleet.

Supported platforms​

The Wazuh Fleet plugin runs on Linux amd64 and arm64 only. A native sidecar, installed on a host before Wazuh Fleet became the only way to add a manager, runs on Linux and macOS, on amd64 and arm64.

What a native sidecar keeps on the host​

A native sidecar keeps reporting and keeps updating itself. Every Pharos file lives under /etc/pharos/, and the binary in the standard place for a local program.

PathWhat it is
/usr/local/bin/pharos-sidecarThe static binary
/etc/pharos/sidecar.envThe configuration, including the Wazuh credentials it reads with. Readable by root only
/etc/pharos/*.pemThe certificate authorities the sidecar verifies against, when one was discovered or passed
/etc/systemd/system/pharos-sidecar.serviceThe service unit that runs the sidecar
/etc/systemd/system/pharos-sidecar-upgrade.service and .timerThe daily auto-upgrade timer, when it was left on. See Automatic updates
/var/lib/private/pharos-sidecarThe sidecar's own state, its credential and its read positions. The service runs under a dynamic system user, so this is not readable by ordinary accounts

No credential is written anywhere but the root-only /etc/pharos/sidecar.env, and none of it is sent to Pharos. Removing the manager from Pharos revokes its credential. The files above stay on the host until they are deleted there.

A native manager that loses its credential, because the host was rebuilt or its state was lost, is not re-keyed. It is removed from Pharos and added again from Wazuh Fleet.

Network​

The sidecar is outbound only. No port is opened on the host, and no Pharos address ever needs to reach it.

ConnectionWherePort
Pharos APIapi.pharos.wazuh.com443
Pharos download sitedl.pharos.wazuh.com, for the Fleet plugin and a native sidecar's daily upgrade443
The Wazuh indexerthe fleet's own indexerits API port, 9200 by default
The Wazuh manager server APIthe fleet's own manager, on Wazuh 4.x onlyits API port, 55000 by default

A proxy set through the standard HTTP_PROXY and HTTPS_PROXY environment variables is used for the connections to Pharos. It is not applied to the connection to the Wazuh indexer, which is treated as a host on the same network and reached directly.

Wazuh 4.x and 5.x​

The sidecar reads the same things from both, and one difference is worth knowing. On Wazuh 5.x the agent count and the agent list come from the indexer. On Wazuh 4.x there is no such index, so the agent census comes from the manager's server API and needs a read-only credential for it. Without one, a 4.x manager reports its agent count as unknown rather than as zero, and everything else it sends is unaffected. The credential and how to create it are in Counting agents on Wazuh 4.x.

A read-only indexer account​

The indexer half of the login typed at Add a manager, or later with Change Wazuh credentials, can be any account that reads the indexer. This section is for an environment that would rather the sidecar not hold a write-capable login such as the 5.x admin:admin default. Create a dedicated read-only account, map it to a least-privilege role, and type it as the indexer login. Pharos never creates this account. Creating one would be a write to the customer's cluster.

The account can carry any name, and this page uses pharos-readonly.

Wazuh 5.x​

The shipped wazuh_readonly role already grants everything the sidecar reads, so on 5.x create the account, give it that role, and use it. No custom role is needed. The role recipe below is the 4.x case, where no stock role is enough.

Wazuh 4.x​

There is no shipped read-only account on 4.x, so an admin creates one, and no stock backend role is sufficient on its own. The sidecar counts the state collections with _cat/indices, which needs both cluster:monitor/state and indices:monitor/settings/get. No stock role grants both to a read-only user: readall is refused, and so is readall_and_monitor.

The three commands below run against the customer's own indexer, and the admin credential in them is never given to Pharos.

Create the account, create the role, and map one to the other on the indexer, from any shell that reaches it. Fill in the admin credential <admin>:<password> and the indexer address <indexer> in each. Creating the role without mapping an account to it leaves the account with no permissions at all.

The -k in these commands skips TLS verification, the way Wazuh's own guides run one-off setup calls against the cluster's self-signed certificate. To run them verified instead, replace it with --cacert /etc/wazuh-indexer/certs/root-ca.pem on a host that has the cluster CA.

1. Create the account:

curl -sk -u "<admin>:<password>" -H "Content-Type: application/json" \
-X PUT "https://<indexer>:9200/_plugins/_security/api/internalusers/pharos-readonly" \
-d '{
"password": "...",
"description": "read-only account for the Pharos sidecar"
}'

2. Create the role:

curl -sk -u "<admin>:<password>" -H "Content-Type: application/json" \
-X PUT "https://<indexer>:9200/_plugins/_security/api/roles/pharos_sidecar" \
-d '{
"cluster_permissions": ["cluster_composite_ops_ro", "cluster_monitor"],
"index_permissions": [{
"index_patterns": ["wazuh-*", ".wazuh-cti-consumers*"],
"allowed_actions": ["read", "indices_monitor",
"indices:admin/mappings/get",
"indices:admin/resolve/index"]
}]
}'

3. Map the account to the role:

curl -sk -u "<admin>:<password>" -H "Content-Type: application/json" \
-X PUT "https://<indexer>:9200/_plugins/_security/api/rolesmapping/pharos_sidecar" \
-d '{
"users": ["pharos-readonly"]
}'

This role is verified read-only. It grants counting, not writing: with this credential, creating an index is still refused with indices:admin/create. The patterns are scoped rather than set to * on purpose, and they are two rather than one because the CTI consumer document lives at .wazuh-cti-consumers, outside the wazuh-* prefix. A role granting only wazuh-* refuses that read with a security_exception, and the deployment's CTI status then reads as unknown for good rather than as absent. An account that also carries a broad backend role hides the omission: readall cannot take the state census, but it does grant the CTI read, so an account holding both it and a wazuh-*-only role looks correct while a clean account mapped to that role alone does not. Check on an account carrying nothing but this role.

Without the role, the sidecar still enrols and still reports, but three panels on the manager's page stay empty for good: the collection census, coverage, and inventory sharing.

Counting agents on Wazuh 4.x​

On Wazuh 5.x the agent count comes from the indexer and the indexer login is all it takes. On 4.x there is no such index, so the count comes from the manager's own server API and needs a credential for it, typed as the Wazuh API half of the login. Without one the manager's page reports the agent count as unknown, rather than as zero, and says so.

Creating the account​

Neither Wazuh generation ships a read-only server API account, so this is an account an admin creates on the manager. Pharos cannot mint it: creating an account is a write to the customer's cluster, and the sidecar is read-only by construction.

The account is created against the server API as an administrator. Any name works, and this page uses pharos-readonly. These calls run against the customer's own manager, and the admin credential in them never reaches Pharos.

The -k here matches the server API's self-signed certificate. On the manager host, root can run these verified instead with --cacert /var/ossec/api/configuration/ssl/server.crt.

Authenticate as an administrator first:

TOKEN=$(curl -sk -u "<admin>:<password>" -X POST \
"https://localhost:55000/security/user/authenticate?raw=true")

1. Create the account:

curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-X POST "https://localhost:55000/security/users" \
-d '{"username": "pharos-readonly", "password": "..."}'

The API refuses weak passwords: it wants an uppercase letter, a lowercase letter, a digit and a symbol, and says so when it does not get them.

2. Grant it the stock agents_readonly role. Without the grant the account authenticates and can read nothing. The <id> is the user id from the creation call's response, or from GET /security/users:

curl -sk -H "Authorization: Bearer $TOKEN" \
-X POST "https://localhost:55000/security/users/<id>/roles?role_ids=4"

agents_readonly is the minimum: the sidecar calls exactly three endpoints, POST /security/user/authenticate, GET /agents/summary/status for the count and GET /agents for the per-agent roster, and the stock agents_readonly role covers all three. The stock readonly role also works but grants more. Its id is 4 on a stock install. Confirm it with GET /security/roles rather than trusting the number, since a manager with custom roles can number them differently.

Verify it by authenticating as the new account and calling the one endpoint the census uses. The second command returns the agent census. The third is a write that must fail, printing 403, which is the read-only claim checked rather than assumed. The write carries a body because the API validates the request before checking permissions: without one it prints 400 for any caller, an administrator included, and proves nothing. With it, the refusal comes before the placeholder password is judged, so the account never has to exist and never gets created:

TOKEN=$(curl -sk -u "pharos-readonly:<password>" -X POST \
"https://localhost:55000/security/user/authenticate?raw=true")
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/agents/summary/status"
curl -sk -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-X POST "https://localhost:55000/security/users" \
-d '{"username": "read-only-check", "password": "..."}'

Type the account as the Wazuh API half of the login at Add a manager, or with Change Wazuh credentials on a manager's Status tab.