Skip to content

MSK clusters should be encrypted in transit among broker nodes

Kafka broker nodes replicate partition data across the cluster continuously. Without TLS, that replication traffic travels in plaintext over the VPC network, exposing message payloads, consumer group metadata, and authentication tokens to anyone with network-level access. VPC traffic mirroring, compromised ENIs, or misconfigured routing can all expose unencrypted streams.

TLS between brokers adds minimal latency on modern instance types and removes an eavesdropping risk that network-layer controls alone cannot close.

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  = "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
}

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           = "pofix-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 in_cluster = true. While in_cluster defaults to true in the AWS provider, explicit configuration avoids ambiguity and prevents drift if provider defaults ever change. in_cluster = false fails this control, as it permits plaintext communication between brokers. The client_broker argument in the same block controls client-to-broker encryption and is evaluated separately; setting it to "TLS" is complementary but not what this control checks.

Common pitfalls

  • Encryption settings are immutable after creation

    Change in_cluster on an existing cluster and Terraform will destroy and recreate it, causing full downtime and data loss unless you've planned a blue-green migration. AWS doesn't expose a modify path for encryption_in_transit after cluster creation.

  • Default value masks missing configuration

    Explicitly set in_cluster = true in every cluster definition. The argument defaults to true, so omitting encryption_info entirely still passes this control, but relying on provider defaults is fragile. A future provider version change could silently introduce drift in clusters that never had the setting pinned.

  • client_broker setting is independent

    Setting client_broker to "TLS_PLAINTEXT" or "PLAINTEXT" has no effect on in_cluster. A cluster can pass this control while still accepting plaintext client connections. Both arguments represent separate encryption decisions and should be reviewed independently.

  • Custom configurations may conflict with TLS

    If you use a custom MSK configuration (aws_msk_configuration) with listener-related properties, validate compatibility with your cluster encryption mode. In-cluster encryption is governed by the cluster encryption_in_transit setting, not by custom configuration properties, so don't treat them as an override.

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

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

  • AWS Security Hub Control: MSK.1

  • KICS Query: 6db52fa6-d4da-4608-908a-89f0c59e743e

  • Trivy Check: AWS-0073

Last reviewed: 2026-03-09