Skip to content

Conversation

@felipegonzalezmv
Copy link
Contributor

@felipegonzalezmv felipegonzalezmv commented Jan 8, 2026

Description

This PR implements SSL certificate support for Wazuh API connections in the dashboard. Previously, even though the Wazuh API could be configured in /var/ossec/api/configuration/api.yaml to use custom certificates, the Wazuh dashboard did not make use of them. This implementation allows the dashboard to connect to Wazuh API servers using SSL client certificates and CA certificate validation, matching the configuration in the Wazuh server API.

The implementation includes:

  • SSL client certificate authentication for Wazuh API hosts
  • CA certificate validation support
  • HTTPS agent configuration with client certificates and CA when provided
  • Certificate path resolution (absolute or relative to config directory)
  • Proper error handling for missing certificate files

This allows the dashboard to securely connect to Wazuh API servers configured with custom SSL certificates as specified in the Wazuh API configuration file.

Issues Resolved

#8002

Evidence

The API table now correctly displays a checkmark icon (✓) with a tooltip indicating "The Wazuh API is configured to use CA certificate" when key, cert ,ca are setting.

Api table image

Configuration Example:

The configuration in opensearch_dashboards.yml should match the certificate setup on the Wazuh Manager:

wazuh_core.hosts:
  manager-local:
    url: 'https://wazuh.manager.local'
    port: 55000
    username: wazuh-wui
    password: wazuh-wui
    run_as: false
    key: '/home/node/kbn/certs/dashboard-client.key' # Path to client private key
    cert: '/home/node/kbn/certs/dashboard-client.crt' # Path to client certificate
    ca: '/home/node/kbn/certs/manager-rootCA.pem' # Path to shared rootCA

Important Notes:

  • Certificate paths can be absolute (recommended) or relative to the OpenSearch Dashboards config directory
  • The client certificate (dashboard-client.crt) must be signed by the same rootCA used by the Wazuh Manager
  • The rootCA file (manager-rootCA.pem) must be the same one configured in the Wazuh Manager's api.yaml
  • When use_ca: true, certificate verification is enabled (rejectUnauthorized: true)
  • Critical: The server certificate on the Wazuh Manager must include the hostname/DNS used in the url field (e.g., wazuh.manager.local) in its Subject Alternative Names (SAN). If the hostname is not included, certificate verification will fail with "Hostname/IP does not match certificate's altnames"

UI Display:

  • When verify_ca: true (all certificates configured) → Shows ✓ icon with tooltip "CA certificate verification is enabled."
  • When verify_ca: false (partial certificate configuration) → Shows "-" with tooltip "CA certificate verification is disabled. Either certificate paths are not configured."
  • When verify_ca: null (no certificates configured) → Shows "-" with tooltip "CA certificate verification status is unknown."

Test

Prerequisites:

  • Wazuh Dashboard running
  • Wazuh Manager with API configured
  • Access to opensearch_dashboards.yml configuration file
  • Root access to Wazuh Manager server

Note

Deploy dev environment with a real manager ./dev.sh up --server-local 5.0.0

Test Steps:

  1. Generate certificates on the Wazuh Manager:

    Follow the step-by-step guide from the Wazuh documentation to generate certificates on the manager:

    • Create a Certificate Authority (CA) on the Wazuh server
    • Generate an SSL certificate for the Wazuh manager signed by the CA
      • Important: When creating the certificate request configuration file (req.conf), ensure you include all DNS names and hostnames that will be used to connect to the manager. For example, if connecting via wazuh.manager.local, add it to the Subject Alternative Names:
    [req]
    distinguished_name = req_distinguished_name
    req_extensions = req_ext
    prompt = no
    [req_distinguished_name]
    C = US
    CN = 127.0.0.1
    [req_ext]
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = wazuh
    DNS.2 = wazuh.com
    DNS.3 = wazuh.manager.local  # Add your manager hostname here
    DNS.4 = localhost
    IP.1 = 127.0.0.1
    • Configure the Wazuh API to use the certificates in /var/ossec/api/configuration/api.yaml:
      https:
        enabled: yes
        key: 'server.key'
        cert: 'server.crt'
        use_ca: true
        ca: 'rootCA.pem'
        ssl_protocol: 'auto'
        ssl_ciphers: ''
    • Ensure the certificate includes the manager hostname in Subject Alternative Names (SAN)
    • Restart the Wazuh manager service
  2. Generate client certificate for the Dashboard:

    • Copy the rootCA and rootCA key from the manager to the dashboard (e.g., /home/node/kbn/certs/manager-rootCA.pem and /home/node/kbn/certs/manager-rootCA-key.pem)

    • Generate a client certificate for the dashboard using the same rootCA:

      # Generate private key
      openssl genrsa -out dashboard-client.key 2048
      
      # Create openssl config for client certificate
      cat > openssl-client.conf << EOF
      [req]
      distinguished_name = req_distinguished_name
      req_extensions = v3_req
      
      [req_distinguished_name]
      C = US
      L = California
      O = Wazuh
      OU = Wazuh Dashboard
      CN = dashboard-client
      
      [v3_req]
      basicConstraints = CA:FALSE
      keyUsage = digitalSignature, keyEncipherment
      extendedKeyUsage = clientAuth
      EOF
      
      # Create certificate signing request
      openssl req -new -key dashboard-client.key -out dashboard-client.csr \
          -config openssl-client.conf
      
      # Sign the certificate with manager's rootCA
      openssl x509 -req -in dashboard-client.csr \
          -CA manager-rootCA.pem \
          -CAkey manager-rootCA-key.pem \
          -CAcreateserial \
          -out dashboard-client.crt \
          -days 365 \
          -extensions v3_req \
          -extfile openssl-client.conf
      
      # Clean up temporary files
      rm dashboard-client.csr openssl-client.conf
  3. Configure API host in opensearch_dashboards.yml:

    • Open opensearch_dashboards.yml
    • Locate the wazuh_core.hosts section
    • Configure the host with SSL certificates:
      manager-local:
        url: 'https://wazuh.manager.local'
        port: 55000
        username: wazuh-wui
        password: wazuh-wui
        run_as: false
        key: '/home/node/kbn/certs/dashboard-client.key'
        cert: '/home/node/kbn/certs/dashboard-client.crt'
        ca: '/home/node/kbn/certs/manager-rootCA.pem'
  • Critical: Ensure the ca field in api.yaml points to the same rootCA file (rootCA.pem) that was used to sign both the server certificate and will be used to sign the dashboard client certificate
  1. Restart Dashboard And Manager :

    • Restart the Dashboards And Manager container to load the new configuration
    • Wait for the service to fully start
  2. Verify connection:

    • Navigate to Dashboard Management → Server Api
    • Click the "Check API" button for the configured host
    • Verify the connection is successful
  3. Expected Results:

    • PASS: The API connection check should succeed
    • PASS: The "Verify ca" column should display a checkmark icon (✓) when key, cert and ca
    • PASS: SSL/TLS connection should be established using the configured certificates
    • PASS: Certificate verification should work correctly with the shared rootCA
Expected Logs

When the dashboard starts and SSL certificates are configured for a host, you should see an info log indicating the SSL configuration:

[info][plugins][server-api-client][wazuhCore] SSL certificates configured for host manager-local: client certificates=enabled, CA verification=enabled

This log appears when the HTTPS agent is created for each configured host. It confirms that:

  • Client certificates are loaded and will be used for authentication
  • CA certificate verification is enabled (when use_ca: true)

Successful API connection:

When the API connection check succeeds, you should see in the healthcheck logs:

[info][healthcheck][server-api:connection-compatibility] Server API [manager-local] version [5.0.0] is compatible with the dashboard version

This indicates that the SSL connection was established successfully using the configured certificates and the API is responding correctly.

When certificate files are not found, you'll see warnings:

[warn][plugins][server-api-client][wazuhCore] Certificate files not found for host manager-local. Key: /path/to/key, Cert: /path/to/cert
[warn][plugins][server-api-client][wazuhCore] CA certificate file not found for host manager-local. CA: /path/to/ca

If there's an error reading certificates:

[error][plugins][server-api-client][wazuhCore] Error reading certificate files for host manager-local: [error message]

Check List

  • All tests pass
    • yarn test:jest
  • New functionality includes testing.
  • New functionality has been documented.
  • Update CHANGELOG.md
  • Commits are signed per the DCO using --signoff

- Updated opensearch_dashboards.yml to include SSL settings: key, cert, use_ca, ca, ssl_protocol, and ssl_ciphers.
- Enhanced api-table.js to display CA certificate usage status in the API settings table.
- Added new constants for SSL/TLS settings in constants.ts and updated settings-adapter.ts to handle optional fields.
- Modified manage-hosts.ts to incorporate SSL/TLS settings in the host management process.
@felipegonzalezmv felipegonzalezmv linked an issue Jan 8, 2026 that may be closed by this pull request
1 task
@felipegonzalezmv felipegonzalezmv self-assigned this Jan 8, 2026
- Added functionality to resolve relative certificate paths based on the OpenSearch Dashboards configuration directory.
- Implemented a method to create HTTPS agents with optional certificate verification based on provided host configurations.
- Updated the ServerAPIClient constructor to accept a configuration directory for improved certificate handling.
- Removed outdated comments regarding SSL certificate handling to improve clarity.
- Ensured consistency in the code by maintaining relevant comments while eliminating unnecessary ones.
- Updated the WazuhCorePlugin to streamline the configuration directory usage for the ServerAPIClient.
- Implement SSL client certificate authentication for Wazuh API hosts
- Add support for CA certificate validation (use_ca configuration)
- Configure HTTPS agent with client certificates and CA when provided
- Enable certificate verification when CA is configured (rejectUnauthorized: true)
- Resolve certificate paths (absolute or relative to config directory)
- Add proper error handling for missing certificate files

This allows the dashboard to connect to Wazuh API servers configured with
custom SSL certificates as specified in the Wazuh API configuration.

Related to: #8002
- Removed unnecessary comment regarding certificate settings to enhance code clarity.
- Maintained relevant code structure while improving readability.
- Add INFO level logs in server-api-client.ts to show when SSL certificates are configured for API hosts
- Log shows client certificates and CA verification status
- Improve visibility of SSL certificate configuration without requiring debug mode
@felipegonzalezmv felipegonzalezmv marked this pull request as ready for review January 13, 2026 15:19
- Remove trailing whitespace to comply with prettier rules
- Add type checking for key, cert, and ca fields
- Validate that certificate paths are non-empty strings
- Prevent processing of undefined, null, or empty string values
- Improves robustness when certificate configuration is missing or incomplete
…ndling

- Removed redundant comments regarding SSL certificate configuration checks.
- Enhanced code clarity by streamlining the documentation within the ServerAPIClient class.
…uh API connections

- Documented the addition of SSL certificate support, enabling the dashboard to use client certificates and CA certificate validation for Wazuh Manager APIs with custom SSL configurations.
…ons table

- Documented the addition of a new column in the API Connections table that indicates whether CA certificate verification is enabled for each API host, enhancing clarity on SSL certificate configurations.
- Add SSL certificate configuration support (key, cert, ca) in opensearch_dashboards.yml
- Implement dynamic use_ca calculation based on opensearch.ssl.verificationMode
- Add certificate loading and HTTPS agent configuration in server-api-client.ts
- Remove redundant SSL configuration fields (use_ca, ssl_protocol, ssl_ciphers) from config
- Add logging for SSL certificate configuration and loading
- Update manage-hosts.ts to calculate use_ca dynamically
- Update constants.ts and settings-adapter.ts to remove deprecated fields
- Update plugin.ts to pass initializerContext to ManageHosts

Related to: #8015
- Rename use_ca to verify_ca in IAPIHostRegistry interface
- Rename calculateUseCa() to calculateVerifyCa() method
- Update all references from use_ca to verify_ca in server-api-client.ts
- Improve SSL certificate logging (info level first time, debug afterwards)
- Respect verify_ca value when loading CA certificates
- Only load CA certificate if verify_ca is true

The name 'verify_ca' is more descriptive and clearly indicates
that it controls CA certificate verification.

Related to: #8015
…tion

- Refactor API connection logic to separate cluster_info from allow_run_as and verify_ca.
- Update ApiTable component to reflect changes in data structure for SSL verification.
- Simplify calculateVerifyCa method to focus solely on certificate paths.
- Remove unused OpenSearch verification mode logic from ManageHosts class.
- Enhance clarity in comments regarding SSL certificate verification.

These changes improve the organization of API connection data and streamline the verification process for SSL certificates.
… support

- Revised the description of SSL certificate support for Wazuh API connections to clarify the automatic calculation of the `verify_ca` value based on certificate paths.
- Updated the "Use ca" column to "Verify CA" in the API Connections table, emphasizing the automatic determination of CA certificate verification status based on configuration.
…rification

- Changed opensearch.ssl.verificationMode from 'none' to 'certificate' to enhance security by requiring SSL certificate validation for connections.
- Removed a comment that was no longer relevant regarding the use of CA certificates based on the `verify_ca` value.
- Added `verify_ca`, `ca`, `cert`, and `key` fields to mock registry data in ManageHosts tests.
- Updated assertions to reflect the new structure of cluster_info and ensure proper handling of SSL certificate configurations.
…tests

- Eliminated `ca`, `cert`, and `key` fields from the ManageHosts service and associated tests to streamline the data structure.
- Updated mock registry data and assertions to reflect the removal of these fields, ensuring consistency in the handling of SSL certificate configurations.
- Removed `ca`, `cert`, and `key` fields from the ManageHosts service implementation to simplify the data structure.
- Updated the ManageHosts tests to reflect these changes, ensuring consistency in the handling of SSL configurations.
Comment on lines +48 to +58
const fieldSetting = options[key] as TPluginSetting;
const fieldSchema = schemaMapper(fieldSetting);
if (
optionalFields.includes(key) ||
fieldSetting.defaultValue === '' ||
fieldSetting.defaultValue === undefined
) {
mappedSchema[key] = schema.maybe(fieldSchema);
} else {
mappedSchema[key] = fieldSchema;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why is it required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s required because key/cert/ca are optional. We must accept hosts without TLS or with partial TLS config, and also allow empty/undefined defaults without failing schema validation.

Comment on lines 212 to 234
const registryData = updatedRegistry[id] || {};
const { allow_run_as, verify_ca, ca, cert, key, ...cluster_info } =
registryData;
return {
...host,
allow_run_as,
verify_ca,
cluster_info,
};
});
}

return hosts.map(host => {
const { id } = host;

return { ...host, cluster_info: registry[id] || {} };
const registryData = registry[id] || {};
const { allow_run_as, verify_ca, ca, cert, key, ...cluster_info } =
registryData;
return {
...host,
allow_run_as,
verify_ca,
cluster_info,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: consider defining a function that enhances the host data instead of duplicating the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this commit 6731ceb

Comment on lines 356 to 370
(async () => {
try {
return [
host.id,
await this.getRegistryDataByHost(host, { throwError: false }),
];
} catch (error) {
this.logger.warn(
`Failed to get registry data for host [${
host.id
}] during startup: ${error.message || error}`,
);
return [host.id, null];
}
})(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why is it required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right 433d6bb

headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + token,
...(token ? { Authorization: 'Bearer ' + token } : {}),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why is it required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this commit d0e481e

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this commit d0e481e

@Desvelao
Copy link
Member

question: the verify CA in the UI is enabled despite the configuration points to non-existent files. Is this ok?

image

@Desvelao
Copy link
Member

Test

image

@Desvelao
Copy link
Member

Desvelao commented Jan 15, 2026

🟡 The cert files are read in each creation of the https agent, that is in each request. I guess we could cache this data to avoid accessing to the filesystem in each request.

Note

Update in this commits e5e3817 , 5cfe9b7

@Desvelao
Copy link
Member

Desvelao commented Jan 15, 2026

Add docs for the configuration.

Note

Update in this commit dc84ebb

@Desvelao
Copy link
Member

Desvelao commented Jan 15, 2026

🟡 In a meeting with @felipegonzalezmv , we saw in the first requests used by the api-compatibility-connection check it could not use the CA cert despite it is configured.

Note

Update: This was change in this commit e5e3817

…s and ServerAPIClient

- Added resolveVerifyCa method in ManageHosts to determine the verify_ca value from the cache or host config.
- Updated ServerAPIClient to utilize resolveVerifyCa for fetching verify_ca, improving clarity and consistency in SSL certificate verification logic.
- Adjusted HTTPS agent configuration to enforce rejectUnauthorized based on verify_ca status, enhancing security for HTTPS connections.
…erverAPIClient

- Introduced a cache for HTTPS agents in ServerAPIClient to optimize SSL certificate handling.
- Added methods to resolve configuration paths and build signatures for HTTPS agents based on certificate files.
- Introduced a new function, enhanceHostWithRegistry, to encapsulate the logic for enriching host data with registry information.
- Replaced Promise.allSettled with Promise.all for improved performance in fetching registry data for hosts.
- Simplified the logic for handling registry data retrieval, enhancing code clarity and efficiency.
@github-actions
Copy link
Contributor

Wazuh Core plugin code coverage (Jest) test % values
Statements 27.16% ( 201 / 740 )
Branches 13.05% ( 50 / 383 )
Functions 20.11% ( 36 / 179 )
Lines 27.24% ( 200 / 734 )

@github-actions
Copy link
Contributor

Wazuh Check Updates plugin code coverage (Jest) test % values
Statements 78.72% ( 185 / 235 )
Branches 62.72% ( 69 / 110 )
Functions 61.7% ( 29 / 47 )
Lines 78.72% ( 185 / 235 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Wazuh API custom certificates

3 participants