<a id="ansible-encrypt"></a>

# Configure Encryption for Confluent Platform with Ansible Playbooks

Ansible Playbooks for Confluent Platform supports the PLAINTEXT (no encryption) and TLS encryption methods with
PLAINTEXT being the default.

<a id="ansible-encryption-tls"></a>

## TLS encryption

### Configure TLS for all components

To enable TLS encryption for all components, add the following in the
`hosts.yml` file.

```none
all:
  vars:
    ssl_enabled: true
```

### Configure TLS for individual components

To selectively enable or disable TLS encryption for specific components, set the
following settings to `true` or `false` in addition to the global
`ssl_enabled` setting.

* `kafka_controller_ssl_enabled`
* `kafka_connect_ssl_enabled`
* `kafka_rest_ssl_enabled`
* `schema_registry_ssl_enabled`
* `control_center_next_gen_ssl_enabled`
* `ksql_ssl_enabled`

For example, if you want TLS enabled for all components except for Schema Registry, set:

```none
all:
  vars:
    ssl_enabled: true
    schema_registry_ssl_enabled: false
```

By default, the certs for this configuration are self-signed. To deploy custom
certificates, you can provide either custom certs or custom keystores and
truststores.

### Disable SNI validation

Starting in Confluent Platform 8.0, Server Name Indication (SNI) validation is enabled by
default. Any client that does not pass SNI headers cannot communicate
communicate with Confluent Platform components.

If you need to run clients without SNI validation, set the specified property
using [custom properties](ansible-configure.md#ansible-custom-properties) as below:

* Kafka
  ```yaml
  all:
    vars:
      kafka_broker_custom_properties:
        confluent.http.server.sni.host.check.enabled: false
  ```
* MDS
  ```yaml
  all:
    vars:
      kafka_broker_custom_properties:
        confluent.metadata.server.sni.host.check.enabled: false
  ```
* Control Center
  ```yaml
  all:
    vars:
      control_center_next_gen_custom_properties:
        confluent.controlcenter.rest.sni.host.check.enabled: false
  ```
* REST Proxy
  ```yaml
  all:
    vars:
      kafka_rest_custom_properties:
        confluent.http.server.sni.host.check.enabled: false
  ```
* Schema Registry, Connect, any other Confluent Platform components
  ```yaml
  all:
    vars:
      <component>_custom_properties:
        sni.host.check.enabled: false
  ```

### Certificates

You can enable TLS encryption using one of the following.

* **Self-signed certs**: A Certificate Authority will be generated by the
  Ansible playbooks and used to sign the certs for each host.

  Use self-signed certificates only for test and development environments.
  Due to security concerns, self-signed certificates are not recommended for
  production environments.
* **Custom certs**: You provide signed certs and keys for each host as
  well as the Certificate Authority Certificate used to sign the certs. See
  [Use custom certs for TLS](#ansible-use-custom-certs).
* **Custom certs existing on the hosts**: You use the signed certs and keys
  already existing on the hosts. See [Use custom certs already existing on hosts](#ansible-use-existing-certs).
* **Custom keystores and truststores**: You provide keystores and truststores
  for each host on the control node. See [Use custom keystores and truststores for TLS](#ansible-use-custom-keystores).
* **Custom keystores and truststores existing on the hosts**: You use the
  keystores and truststores already existing on the hosts. See
  [Use custom keystores and truststores already existing on hosts](#ansible-use-existing-keystores).

To speed up the certificate and key store creations, you can install and run the
random number generator service (`rng-tools`) on all hosts.

<a id="ansible-use-custom-certs"></a>

#### Use custom certs for TLS

To provide custom certs for each host, you need to have the the following on the
Ansible control node:

* The Certificate Authority certificate
* The signed certificates
* The keys for each host

Complete the following steps to update `hosts.yml`.

1. Specify that custom certs are provided.
   ```none
   all:
     vars:
       ssl_custom_certs: true
   ```
2. Enter the path to the Certificate Authority Certificate used to sign each host
   certificate. For example:
   ```none
   all:
     vars:
       ssl_ca_cert_filepath: "/tmp/certs/ca.crt"
   ```
3. Set the signed certificate path and key file path for each host. For example:
   ```none
   all:
     vars:
       ssl_signed_cert_filepath: "/tmp/certs/{{inventory_hostname}}-signed.crt"
       ssl_key_filepath: "/tmp/certs/{{inventory_hostname}}-key.pem"
   ```

   The `{{inventory_hostname}}` internal variable holds the host names set
   in the inventory file. You can use the variable to keep the inventory file
   shorter in the filename for each signed certificate and key file.

   As an alternative, you can set the variables directly under a host. For
   example:
   ```none
   schema_registry:
      hosts:
         ip-192-24-10-207.us-west.compute.internal:
            ssl_signed_cert_filepath: "/tmp/certs/192-24-10-207-signed.crt
            ssl_key_filepath: "/tmp/certs/192-24-10-207-key.pem
   ```

The certificate file specified in `ssl_signed_cert_filepath` must include one of the following certificate combinations:

* Leaf and intermediate certificates: Use this combination when an organization has one or more intermediate certificates before the root certificate.
* Leaf and root certificates: Use this combination when there are no intermediate certificates in the certificate chain.
* Full chain of leaf certificate -> intermediate certificate(s) -> root
  certificate.

  For example, leaf certificate -> intermediate certificate 1 -> intermediate certificate 2 -> root certificate.

<a id="ansible-use-existing-certs"></a>

#### Use custom certs already existing on hosts

You can set up TLS in Ansible Playbooks for Confluent Platform with the custom certs that are
already present on the Confluent Platform components hosts.

You need the Certificate Authority certificate, the signed certificates, and
keys existing on each host.

Complete the following steps to update `hosts.yml`.

1. Specify that you are using the custom certs existing on the hosts.
   ```yaml
   all:
     vars:
       ssl_custom_certs: true
       ssl_custom_certs_remote_src: true
   ```
2. Enter the path to the Certificate Authority Certificate used to sign each host
   certificate.
   ```yaml
   ssl_ca_cert_filepath:
   ```
3. Set the signed certificate path and key file path for each host.
   ```yaml
   ssl_signed_cert_filepath:
   ssl_key_filepath:
   ```

   For example:
   ```yaml
   schema_registry:
      hosts:
         ip-192-24-10-207.us-west.compute.internal:
            ssl_ca_cert_filepath: "/tmp/certs/ca.crt"
            ssl_signed_cert_filepath: "/tmp/certs/192-24-10-207-signed.crt
            ssl_key_filepath: "/tmp/certs/192-24-10-207-key.pem
   ```

<a id="ansible-use-custom-keystores"></a>

#### Use custom keystores and truststores for TLS

To provide custom keystores and truststores for each host, you need to have
keystores and truststores (and their passwords) for each host on the Ansible
control node and their passwords.

Complete the following steps to update `hosts.yml`.

1. Specify that custom keystores and truststores are provided.
   ```none
   all:
     vars:
       ssl_provided_keystore_and_truststore: true
   ```
2. Provide the keystore and truststore filepaths and passwords. For example:
   ```none
   all:
     vars:
       ssl_keystore_filepath: "/tmp/certs/{{inventory_hostname}}-keystore.jks"
       ssl_keystore_key_password: mystorepassword
       ssl_keystore_store_password: mystorepassword
       ssl_truststore_filepath: "/tmp/certs/truststore.jks"
       ssl_truststore_password: truststorepass
   ```

   The `{{inventory_hostname}}` internal variable holds the hostnames set in
   the inventory file. Using the `{{inventory_hostname}}` variable and setting
   the same password for each host, you can set these variable only once in the
   `hosts.yml` file.

   As an alternative, you can set these variables under each host. For example:
   ```none
   schema_registry:
     hosts:
       ip-192-24-10-207.us-west.compute.internal:
         ssl_keystore_filepath: "/tmp/certs/{{inventory_hostname}}-keystore.jks"
         ssl_keystore_key_password: mystorepassword
         ssl_keystore_store_password: mystorepassword
         ssl_truststore_filepath: "/tmp/certs/truststore.jks"
         ssl_truststore_password: truststorepass
   ```

<a id="ansible-use-existing-keystores"></a>

#### Use custom keystores and truststores already existing on hosts

You can set up TLS in Ansible Playbooks for Confluent Platform with the keystores and truststores that are
already present on the Confluent Platform components hosts.

In this scenario, you fully own the keystore and truststore and take
responsibility to ensure the correct certificates are in place and to set and
manage the JKS password. If you are using the certificates for mTLS
authentication, ensure that the correct SANs are in the certificates and that
the principal name is correctly set.

To use existing keystores and truststores:

1. Create the keystore and truststore JKS files, a separate one per component.
   You put these files on the component hosts and provide the file path for each
   file per component in the inventory as shown in the third step below.

   Keystores and truststores must be configured as follows:
   * Keystores and truststores should be in the PKCS12 format. If it’s
     in the JKS format, Ansible internally copies and converts it to a temporary
     `pem` file to enable the extraction of key/certs.
   * Keystore and truststore must have the read permission
     (permissions >= 0640).
   * Keystore and truststore must be owned by the relevant user and group.

   #### NOTE
   The `ssl_keystore_alias` variable is only honored for keystores in the
   JKS format. It is ignored for keystores in the PKCS12 format. Set
   `ssl_keystore_alias` only when you provide a JKS keystore that contains
   multiple certificates and you need to select a specific one. For
   certificate rotation, prefer a keystore that contains only the new
   certificate rather than relying on `ssl_keystore_alias` to
   disambiguate. For the recommended approach, see
   [Rotate certificates signed by a new CA without downtime](ansible-reconfigure.md#ansible-rotate-ca-certs).
2. Set the following variables in the inventory.

   In addition to the variables mentioned in
   [Use custom keystores and truststores for TLS](#ansible-use-custom-keystores), you need to set
   `ssl_provided_keystore_and_truststore_remote_src: true`.
   ```yaml
   all:
     vars:
       ssl_enabled: true
       ssl_mutual_auth_enabled: true
       ssl_client_authentication: required
       ssl_provided_keystore_and_truststore: true
       ssl_provided_keystore_and_truststore_remote_src: true
   ```
3. Set the following variables for each host separately in the inventory:
   ```yaml
   ssl_keystore_filepath:
   ssl_keystore_key_password:
   ssl_keystore_store_password:
   ssl_keystore_alias:
   ssl_truststore_filepath:
   ssl_truststore_password:
   ssl_truststore_ca_cert_alias:
   ```

   For example:
   ```yaml
   schema_registry:
     hosts:
       ip-192-24-10-207.us-west.compute.internal:
         ssl_keystore_filepath: "/tmp/certs/{{inventory_hostname}}-keystore.jks"
         ssl_keystore_key_password: mystorepassword
         ssl_keystore_store_password: mystorepassword
         ssl_keystore_alias: <alias for host specific certificate, only required if multiple certs are in the provided keystore>
         ssl_truststore_filepath: "/tmp/certs/truststore.jks"
         ssl_truststore_password: truststorepass
         ssl_truststore_ca_cert_alias: <alias for the CA certificate in the truststore>
   ```

   The internal variable `{{inventory_hostname}}` holds the hostnames set
   in the inventory file.
4. (For RBAC only) To use existing keystores and truststores for the mTLS
   authentication with RBAC, the following are the additional steps you need to
   perform.
   1. Generate `pem` files in addition to keystores/truststores and copy them
      to the hosts.

      PEM files must be 2048 bits in size.
   2. Set the following variables in the inventory under each host:
      ```yaml
      create_mds_certs: false
      token_services_public_pem_file: # Path to public.pem on the host node
      token_services_private_pem_file: # Path to tokenKeypair.pem
      ```

<a id="ansible-fips"></a>

## Enable FIPS in Confluent Platform

Federal Information Processing Standards (FIPS) compliance ensures that Confluent Platform uses cryptographic modules that meet government and industry security requirements.
Confluent Platform 8.2 and later support FIPS 140-3 compliance.

You can use Ansible Playbooks for Confluent Platform to enable FIPS mode on Confluent Platform clusters that run on Red Hat Enterprise Linux (RHEL). For detailed FIPS requirements and prerequisites, see [FIPS 140-3 Prerequisites](https://docs.confluent.io/platform/current/security/compliance/overview.html#prerequisites).
When you enable FIPS in Confluent Ansible, the playbooks automatically does the following:

* Configure Kafka brokers and controllers with `enable.fips=true` and the appropriate `enable.fips.mode`. `fips-140-3` is the by default for Confluent Platform 8.2 and later.
* Install the FIPS-certified Bouncy Castle FIPS providers and configure TLS to use only FIPS-approved cipher suites and protocols.
* Use the FIPS-compliant OpenSSL libraries provided by RHEL for TLS certificates and key material handling.

#### NOTE
* FIPS mode with Confluent Ansible is supported only on Red Hat–based operating systems.
* FIPS support is available on RHEL 8, 9, and 10. RHEL 7 is not supported for FIPS deployments.
* For LDAP-based RBAC, FIPS 140-2 and FIPS 140-3 modes require LDAP provider URLs that use the `ldaps://` protocol. Plain `ldap://` is rejected in FIPS mode.

### Requirements

To run Confluent Platform in FIPS mode with Confluent Ansible, you need:

* A FIPS-enabled RHEL 8, 9, or 10 system on all control and managed nodes.
* FIPS mode enabled at the operating system level. On RHEL, use the system-wide cryptographic policies to enable FIPS mode as described in the [Red Hat documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/security_hardening/switching-rhel-to-fips-mode_security-hardening).
* Java 17 or Java 21 installed on the hosts running Confluent Platform.
* TLS enabled for all Confluent Platform components that communicate over the network.
* For RBAC deployments that use LDAP, an LDAPS endpoint and an LDAP directory that is FIPS-compliant.

### FIPS mode variables

Confluent Ansible exposes the following variables to control FIPS behavior:

* `fips_enabled` – Enables or disables FIPS mode for the deployment. Set this to `true` to configure Confluent Platform to run in FIPS mode.
* `fips_mode` – (Confluent Platform 8.2 and later) Specifies the FIPS level for Kafka brokers and controllers:
  * `fips-140-3` – Default for Confluent Platform 8.2 and later. Recommended for new deployments.
  * `fips-140-2` – Use for existing deployments (8.1 and earlier) that are already running FIPS 140-2.

  Confluent Ansible validates that `fips_mode` is set to either `fips-140-2` or `fips-140-3` when `fips_enabled` is `true`.

Example inventory snippet:

```yaml
all:
  vars:
    ansible_connection: ssh
    ansible_user: ec2-user
    ansible_become: true
    fips_enabled: true
    fips_mode: fips-140-3
    ssl_enabled: true
    ssl_mutual_auth_enabled: true

zookeeper:
  hosts:
    ip1.us-west-2.compute.amazonaws.com:

kafka_broker:
  hosts:
    ip2.us-west-2.compute.amazonaws.com:

schema_registry:
  hosts:
    ip3.us-west-2.compute.amazonaws.com:

kafka_connect:
  hosts:
    ip4.us-west-2.compute.amazonaws.com:
```

For more information about enabling and using FIPS 140-2 and FIPS 140-3 in Confluent Platform, including OS-level prerequisites and the full list of security properties
that Confluent Ansible configures (`enable.fips`, `enable.fips.mode`, TLS protocols, and cipher suites), see [FIPS compliance in Confluent Platform](https://docs.confluent.io/platform/current/security/compliance/overview.html).

To configure Confluent Platform to run in FIPS mode with Confluent Ansible:

1. Ensure that FIPS mode is enabled on all RHEL nodes (controlled and managed) using the appropriate Red Hat tooling.
2. If you use role-based access control (RBAC) with LDAP, verify that your LDAP URLs use `ldaps://` and that the directory is configured to operate in a FIPS-compliant way.
3. In your Ansible inventory file:
   * Set `fips_enabled: true`.
   * Optionally set `fips_mode` to `fips-140-2` if you must remain on FIPS 140-2, otherwise omit it or set it to `fips-140-3` (Confluent Platform 8.2 and later).
4. Run the playbook:
   ```bash
   ansible-playbook -i <inventory.yml> confluent.platform.all
   ```

## Next steps

* [Configure Authentication for Confluent Platform with Ansible Playbooks](ansible-authenticate.md#ansible-authenticate).
* [Configure Authorization for Confluent Platform with Ansible Playbooks](ansible-authorize.md#ansible-authorize).
* [Configure Advanced Confluent Platform Settings with Ansible Playbooks](ansible-adv-deployments.md#ansible-adv-deployments).
* [Install Confluent Platform with Ansible Playbooks](ansible-install.md#ansible-install).
