compliance.tf

MSK clusters should require TLS for client-broker connections

Kafka clients send message payloads, consumer group metadata, and credentials to the brokers. If the cluster accepts plaintext client connections, that traffic crosses the VPC network unencrypted and is exposed to anyone with network-level access, through traffic mirroring, a compromised ENI, or misconfigured routing.

Requiring TLS for all client connections removes that eavesdropping risk. TLS_PLAINTEXT is not enough, because any client can still choose the plaintext listener.

Retrofit consideration

Changing the in_cluster encryption setting on an existing MSK cluster requires creating a new cluster. AWS does not support modifying encryption-in-transit settings after cluster creation. Plan for data migration and client reconnection.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "msk_kafka_cluster" {
  source  = "soc2.compliance.tf/terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3
}
module "msk_kafka_cluster" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3
}
module "msk_kafka_cluster" {
  source  = "iso27001.compliance.tf/terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3
}
module "msk_kafka_cluster" {
  source  = "nis2.compliance.tf/terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3
}
module "msk_kafka_cluster" {
  source  = "nistcsf.compliance.tf/terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3
}

This control is enforced automatically with Compliance.tf modules. Start free trial

If you use terraform-aws-modules/msk-kafka-cluster/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "msk_kafka_cluster" {
  source  = "terraform-aws-modules/msk-kafka-cluster/aws"
  version = ">=3.0.0"

  broker_node_client_subnets  = ["subnet-12345678", "subnet-12345678", "subnet-12345678"]
  broker_node_instance_type   = "kafka.t3.small"
  broker_node_security_groups = ["sg-12345678"]
  client_authentication = {
    sasl = {
      iam = true
    }
  }
  kafka_version          = "3.6.0"
  name                   = "abc123"
  number_of_broker_nodes = 3

  encryption_in_transit_in_cluster = true
}

Use AWS provider resources directly. See docs for the resources involved: aws_msk_cluster.

resource "aws_msk_cluster" "this" {
  broker_node_group_info {
    client_subnets  = [element(["subnet-abc123", "subnet-def456"], 0), element(["subnet-abc123", "subnet-def456"], 1)]
    instance_type   = "kafka.t3.small"
    security_groups = ["sg-abc12345"]
  }

  client_authentication {
    sasl {
      iam = true
    }
  }

  cluster_name           = "example-abc123"
  kafka_version          = "3.5.1"
  number_of_broker_nodes = 2

  encryption_info {
    encryption_in_transit {
      in_cluster = true
    }
  }
}

What this control checks

In Terraform, aws_msk_cluster must include an encryption_info block containing encryption_in_transit with client_broker = "TLS". client_broker = "TLS_PLAINTEXT" and "PLAINTEXT" fail. TLS is the provider default, but set it explicitly so a reviewer can see it. The in_cluster argument controls encryption between brokers and is not evaluated by this control. The control applies to provisioned clusters.

Common pitfalls

TLS_PLAINTEXT still fails

client_broker = "TLS_PLAINTEXT" is often used during migrations so old clients keep working. It leaves the plaintext listener open, so the control fails until you switch to "TLS".

Clients need TLS bootstrap brokers

After the switch, clients must connect with the TLS bootstrap string (bootstrap_brokers_tls on aws_msk_cluster, port 9094) and security.protocol=SSL or SASL_SSL. Clients still pointed at the plaintext port 9092 lose connectivity.

Broker-to-broker encryption is separate

This control does not look at in_cluster. A cluster can pass with in_cluster = false, which sends replication traffic between brokers in plaintext. Keep in_cluster = true, and note that it cannot be changed after the cluster is created.

Custom configurations may conflict with TLS

If you use a custom MSK configuration (aws_msk_configuration) with listener-related properties, validate compatibility with your encryption mode. Encryption in transit is governed by the cluster's encryption_in_transit block, not by custom configuration properties.

Audit evidence

An auditor expects AWS Config rule evaluation results showing MSK clusters with in-cluster TLS enabled, or output from aws kafka describe-cluster where EncryptionInfo.EncryptionInTransit.InCluster is true for each cluster. Console screenshots of the MSK cluster's "Encryption" settings panel with "Within the cluster" set to TLS are also valid.

For continuous coverage, AWS Config conformance pack results or scanner output from Prowler or Steampipe that explicitly evaluate this property across all regions provide the strongest evidence of ongoing compliance.

Framework-specific interpretation

SOC 2: Under SOC 2 audit, TLS between brokers helps demonstrate that information in transit is protected within internal network boundaries, not just at the perimeter. The Common Criteria covering logical access and data protection in transit both apply.

PCI DSS v4.0: Requirement 4.2.1 mandates strong cryptography for cardholder data in transit. In-cluster TLS is a defense-in-depth measure that can help reduce exposure when sensitive data traverses internal environments that may not be fully isolated.

ISO/IEC 27001:2022: A.8.24 requires applying cryptography to protect data confidentiality and integrity, which in-cluster TLS satisfies directly. A.8.20 covers cryptographic protection of internal service communication channels, making both controls relevant to broker-to-broker traffic.

NIS2 Directive (EU 2022/2555): Article 21 calls for encryption policies and technical measures proportionate to interception risk. Encrypting intra-cluster traffic falls within that scope, particularly for managed infrastructure where portions of the network path are outside direct operator control.

NIST Cybersecurity Framework v2.0: PR.DS-2 covers protection of data in transit. Inter-broker TLS is the mechanism that satisfies it at the MSK layer: Kafka replication runs continuously inside the cluster, and without it there are no authenticated channels at the broker level regardless of what client-facing encryption is configured.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: msk_cluster_encryption_in_transit_with_tls_enabled
  • AWS Config Managed Rule: MSK_IN_CLUSTER_NODE_REQUIRE_TLS
  • Checkov Check: CKV_AWS_81
  • Powerpipe Control: aws_compliance.control.msk_cluster_encryption_in_transit_with_tls_enabled
  • Prowler Check: kafka_cluster_in_transit_encryption_enabled
  • KICS Query: 6db52fa6-d4da-4608-908a-89f0c59e743e
  • Trivy Check: AWS-0073

Last reviewed: 2026-10-03

On this page

Ask AI about this

Help improve this page