Repository: hashicorp/terraform-provider-aws
Pull request #42148: feat: add `bootstrap_brokers_sasl_iam` attribute for `aws_msk_serverless_cluster`
Author: login: stefanfreitag
Labels: name: documentation
description: Introduces or discusses updates to documentation.
name: size/M
description: Managed by automation to categorize the size of a PR.
name: tests
description: PRs: expanded test coverage. Issues: expanded coverage, enhancements to test infrastructure.
name: service/kafka
description: Issues and PRs that pertain to the kafka service.
name: external-maintainer
description: Contribution from a trusted external contributor.
Created: 2025-04-06T19:15:50Z | Merged: 2025-05-09T14:37:56Z

### Description

The [provisioned MSK cluster resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/msk_cluster) provides broker endpoint information for the various configurations (TLS, SASL/SCRAM, SASL/IAM, unauthenticated)

At the moment the resource [`aws_msk_serverless_cluster`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/msk_serverless_cluster)  does not expose the broker endpoint information at all.

This pull request adds the attribute for the SASL/IAM configuration - it is the only one supported by MSK serverless.

### Relations

* Relates #28005 
* Closes #42118 

### References

<!---
Optionally, provide any helpful references that may help the reviewer(s).
--->


### Output from Acceptance Testing

```console
❯ make testacc TESTS=TestAccKafkaServerlessCluster_basic PKG=kafka
make: Verifying source code with gofmt...
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.23.7 test ./internal/service/kafka/... -v -count 1 -parallel 20 -run='TestAccKafkaServerlessCluster_basic'  -timeout 360m -vet=off
2025/04/06 20:58:12 Initializing Terraform AWS Provider...
=== RUN   TestAccKafkaServerlessCluster_basic
=== PAUSE TestAccKafkaServerlessCluster_basic
=== CONT  TestAccKafkaServerlessCluster_basic
--- PASS: TestAccKafkaServerlessCluster_basic (210.10s)
PASS
ok      github.com/hashicorp/terraform-provider-aws/internal/service/kafka      210.331s
```


Linked issue #42118: aws_msk_serverless_cluster to return bootstrap server url
### Description

The `aws_msk_serverless_cluster` doesn't return the URL of the created cluster.

This was reported in the past (https://github.com/hashicorp/terraform-provider-aws/issues/28005) but **not** implemented.

What was implemented to get the original issue closed is a workaround: instantiate a data source `aws_msk_bootstrap_broker` and get the information from there.


### Affected Resource(s) or Data Source(s)

* `aws_msk_serverless_cluster`

### Potential Terraform Configuration

```hcl
aws_msk_serverless_cluster.client_information
```


### References

_No response_

### Would you like to implement the enhancement?

No
Linked issue comments: user: login: github-actions[bot]
created_at: 2025-04-03T22:02:23Z
body: ### Community Guidelines

This comment is added to every new Issue to provide quick reference to how the Terraform AWS Provider is maintained. Please review the information below, and thank you for contributing to the community that keeps the provider thriving! :rocket:

#### Voting for Prioritization

* Please vote on this Issue by adding a :+1: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original post to help the community and maintainers prioritize it.
* Please see our [prioritization guide](https://hashicorp.github.io/terraform-provider-aws/prioritization/) for additional information on how the maintainers handle prioritization.
* Please **do not** leave +1 or other comments that do not add relevant new information or questions; they generate extra noise for others following the Issue and do not help prioritize the request.

### Volunteering to Work on This Issue

* If you are interested in working on this issue, please leave a comment.
* If this would be your first contribution, please review the [contribution guide](https://hashicorp.github.io/terraform-provider-aws/).
* For new resources and data sources, use [skaff](https://hashicorp.github.io/terraform-provider-aws/skaff/) to generate scaffolding with comments detailing common expectations.


author_association: CONTRIBUTOR
user: login: stefanfreitag
created_at: 2025-04-04T20:00:45Z
body: Good evening @heitorPB 👋 ,

thank you for raising the issue!
If I understood you right, the resource `aws_msk_serverless_cluster` should be enhanced by exposing the connection details for the Kafka brokers as attributes  (same as we have for the "normal"  MSK cluster).
Let me have a look into this.

---
One follow up question I have:
The serverless MSK seems only to support SASL/IAM,  would the broker endpoints for this be sufficient or would you expect also other broker endpoint details (SASL/SCRAM,...) ?
author_association: CONTRIBUTOR
user: login: heitorPB
created_at: 2025-04-07T12:50:30Z
body: Hey @stefanfreitag 👋

> If I understood you right, the resource `aws_msk_serverless_cluster` should be enhanced by exposing the connection details for the Kafka brokers as attributes (same as we have for the "normal" MSK cluster).

That's correct. When I instantiate a new cluster in Terraform, I expect to be able to retrieve information about that resource "directly" from it. In this case of the serverless MSK, I'd expect to be able to get the connection details for the Kafka brokers.

> The serverless MSK seems only to support SASL/IAM, would the broker endpoints for this be sufficient or would you expect also other broker endpoint details (SASL/SCRAM,...) ?

In our case, we are using only SASL/IAM, but if there are other details I'd expect those to be available as well.
author_association: NONE
user: login: stefanfreitag
created_at: 2025-04-07T12:54:10Z
body: Hi @heitorPB ,

thanks for the feedback. 

As you mentioned "but if there are other details I'd expect those to be available as well.": yes,  for sure. But to my understanding SASL/IAM is the only option. I wanted to check with you if I maybe missed something.
 
 
author_association: CONTRIBUTOR
user: login: heitorPB
created_at: 2025-04-07T13:05:21Z
body: The workaround I'm using is to get a [data source `aws_msk_bootstrap_brokers`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/msk_bootstrap_brokers) and from it the `bootstrap_brokers_sasl_iam` attribute. If you look at the docs page, you see there are more attributes, including `bootstrap_brokers_sasl_scram`.

So, there are more details to get than only the SASL/IAM endpoints.
author_association: NONE
user: login: stefanfreitag
created_at: 2025-04-07T15:14:48Z
body: Hi @heitorPB ,
Yes the data source contains more attributes, but for msk serverless all the attributes except for the SASL I AM one will be empty.
At least this is my understanding from local tests with the serverless cluster. You cannot enable other authentication methods.

With this in mind, I added only the endpoint SASL IAM configuration as a new attribute.

(The data source can also be used with provisioned msk clusters, then the other broker configuration details should be filled accordingly.)
author_association: CONTRIBUTOR
user: login: heitorPB
created_at: 2025-04-07T15:28:41Z
body: Aah, got it. That makes sense now.

Thank you for looking into it!
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-09T14:38:19Z
body: > [!WARNING]
> This Issue has been closed, meaning that any additional comments are much easier for the maintainers to miss. Please assume that the maintainers will not see them.
>
> Ongoing conversations amongst community members are welcome, however, the issue will be locked after 30 days. Moving conversations to another venue, such as the [AWS Provider forum](https://discuss.hashicorp.com/c/terraform-providers/tf-aws/33), is recommended. If you have additional concerns, please open a new issue, referencing this one where needed.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-16T13:53:39Z
body: This functionality has been released in [v5.98.0 of the Terraform AWS Provider](https://github.com/hashicorp/terraform-provider-aws/blob/v5.98.0/CHANGELOG.md).  Please see the [Terraform documentation on provider versioning](https://www.terraform.io/docs/configuration/providers.html#provider-versions) or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a [new GitHub issue](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose) following the template. Thank you!
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-06-16T02:30:38Z
body: I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
author_association: CONTRIBUTOR

Diff:
diff --git a/.changelog/42148.txt b/.changelog/42148.txt
new file mode 100644
index 000000000000..b5329125733d
--- /dev/null
+++ b/.changelog/42148.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+resource/aws_msk_serverless_cluster: Add `bootstrap_brokers_sasl_iam` attribute. This functionality requires the `kafka:GetBootstrapBrokers` IAM permission
+```
\ No newline at end of file
diff --git a/internal/service/kafka/bootstrap_brokers_data_source.go b/internal/service/kafka/bootstrap_brokers_data_source.go
index b5b6ac95ad55..50ffd30395b6 100644
--- a/internal/service/kafka/bootstrap_brokers_data_source.go
+++ b/internal/service/kafka/bootstrap_brokers_data_source.go
@@ -81,16 +81,16 @@ func dataSourceBootstrapBrokersRead(ctx context.Context, d *schema.ResourceData,
 	}
 
 	d.SetId(clusterARN)
-	d.Set("bootstrap_brokers", SortEndpointsString(aws.ToString(output.BootstrapBrokerString)))
-	d.Set("bootstrap_brokers_public_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslIam)))
-	d.Set("bootstrap_brokers_public_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslScram)))
-	d.Set("bootstrap_brokers_public_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicTls)))
-	d.Set("bootstrap_brokers_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
-	d.Set("bootstrap_brokers_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslScram)))
-	d.Set("bootstrap_brokers_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringTls)))
-	d.Set("bootstrap_brokers_vpc_connectivity_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslIam)))
-	d.Set("bootstrap_brokers_vpc_connectivity_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslScram)))
-	d.Set("bootstrap_brokers_vpc_connectivity_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivityTls)))
+	d.Set("bootstrap_brokers", sortEndpointsString(aws.ToString(output.BootstrapBrokerString)))
+	d.Set("bootstrap_brokers_public_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslIam)))
+	d.Set("bootstrap_brokers_public_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslScram)))
+	d.Set("bootstrap_brokers_public_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicTls)))
+	d.Set("bootstrap_brokers_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
+	d.Set("bootstrap_brokers_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslScram)))
+	d.Set("bootstrap_brokers_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringTls)))
+	d.Set("bootstrap_brokers_vpc_connectivity_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslIam)))
+	d.Set("bootstrap_brokers_vpc_connectivity_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslScram)))
+	d.Set("bootstrap_brokers_vpc_connectivity_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivityTls)))
 
 	return diags
 }
diff --git a/internal/service/kafka/cluster.go b/internal/service/kafka/cluster.go
index eb9d95e44549..cbd95bbe6cad 100644
--- a/internal/service/kafka/cluster.go
+++ b/internal/service/kafka/cluster.go
@@ -653,16 +653,16 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta any)
 
 	clusterARN := aws.ToString(cluster.ClusterArn)
 	d.Set(names.AttrARN, clusterARN)
-	d.Set("bootstrap_brokers", SortEndpointsString(aws.ToString(output.BootstrapBrokerString)))
-	d.Set("bootstrap_brokers_public_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslIam)))
-	d.Set("bootstrap_brokers_public_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslScram)))
-	d.Set("bootstrap_brokers_public_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicTls)))
-	d.Set("bootstrap_brokers_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
-	d.Set("bootstrap_brokers_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslScram)))
-	d.Set("bootstrap_brokers_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringTls)))
-	d.Set("bootstrap_brokers_vpc_connectivity_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslIam)))
-	d.Set("bootstrap_brokers_vpc_connectivity_sasl_scram", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslScram)))
-	d.Set("bootstrap_brokers_vpc_connectivity_tls", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivityTls)))
+	d.Set("bootstrap_brokers", sortEndpointsString(aws.ToString(output.BootstrapBrokerString)))
+	d.Set("bootstrap_brokers_public_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslIam)))
+	d.Set("bootstrap_brokers_public_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicSaslScram)))
+	d.Set("bootstrap_brokers_public_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringPublicTls)))
+	d.Set("bootstrap_brokers_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
+	d.Set("bootstrap_brokers_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslScram)))
+	d.Set("bootstrap_brokers_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringTls)))
+	d.Set("bootstrap_brokers_vpc_connectivity_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslIam)))
+	d.Set("bootstrap_brokers_vpc_connectivity_sasl_scram", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivitySaslScram)))
+	d.Set("bootstrap_brokers_vpc_connectivity_tls", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringVpcConnectivityTls)))
 	if cluster.BrokerNodeGroupInfo != nil {
 		if err := d.Set("broker_node_group_info", []any{flattenBrokerNodeGroupInfo(cluster.BrokerNodeGroupInfo)}); err != nil {
 			return sdkdiag.AppendErrorf(diags, "setting broker_node_group_info: %s", err)
@@ -717,8 +717,8 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta any)
 		d.Set("open_monitoring", nil)
 	}
 	d.Set("storage_mode", cluster.StorageMode)
-	d.Set("zookeeper_connect_string", SortEndpointsString(aws.ToString(cluster.ZookeeperConnectString)))
-	d.Set("zookeeper_connect_string_tls", SortEndpointsString(aws.ToString(cluster.ZookeeperConnectStringTls)))
+	d.Set("zookeeper_connect_string", sortEndpointsString(aws.ToString(cluster.ZookeeperConnectString)))
+	d.Set("zookeeper_connect_string_tls", sortEndpointsString(aws.ToString(cluster.ZookeeperConnectStringTls)))
 
 	setTagsOut(ctx, cluster.Tags)
 
diff --git a/internal/service/kafka/cluster_data_source.go b/internal/service/kafka/cluster_data_source.go
index 67220ed04a77..ea9f20ee1416 100644
--- a/internal/service/kafka/cluster_data_source.go
+++ b/internal/service/kafka/cluster_data_source.go
@@ -236,13 +236,13 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta any
 
 	d.SetId(clusterARN)
 	d.Set(names.AttrARN, clusterARN)
-	d.Set("bootstrap_brokers", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerString)))
-	d.Set("bootstrap_brokers_public_sasl_iam", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicSaslIam)))
-	d.Set("bootstrap_brokers_public_sasl_scram", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicSaslScram)))
-	d.Set("bootstrap_brokers_public_tls", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicTls)))
-	d.Set("bootstrap_brokers_sasl_iam", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringSaslIam)))
-	d.Set("bootstrap_brokers_sasl_scram", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringSaslScram)))
-	d.Set("bootstrap_brokers_tls", SortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringTls)))
+	d.Set("bootstrap_brokers", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerString)))
+	d.Set("bootstrap_brokers_public_sasl_iam", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicSaslIam)))
+	d.Set("bootstrap_brokers_public_sasl_scram", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicSaslScram)))
+	d.Set("bootstrap_brokers_public_tls", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringPublicTls)))
+	d.Set("bootstrap_brokers_sasl_iam", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringSaslIam)))
+	d.Set("bootstrap_brokers_sasl_scram", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringSaslScram)))
+	d.Set("bootstrap_brokers_tls", sortEndpointsString(aws.ToString(bootstrapBrokersOutput.BootstrapBrokerStringTls)))
 	if cluster.BrokerNodeGroupInfo != nil {
 		if err := d.Set("broker_node_group_info", []any{flattenBrokerNodeGroupInfo(cluster.BrokerNodeGroupInfo)}); err != nil {
 			return sdkdiag.AppendErrorf(diags, "setting broker_node_group_info: %s", err)
@@ -255,8 +255,8 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta any
 	d.Set("cluster_uuid", clusterUUID)
 	d.Set("kafka_version", cluster.CurrentBrokerSoftwareInfo.KafkaVersion)
 	d.Set("number_of_broker_nodes", cluster.NumberOfBrokerNodes)
-	d.Set("zookeeper_connect_string", SortEndpointsString(aws.ToString(cluster.ZookeeperConnectString)))
-	d.Set("zookeeper_connect_string_tls", SortEndpointsString(aws.ToString(cluster.ZookeeperConnectStringTls)))
+	d.Set("zookeeper_connect_string", sortEndpointsString(aws.ToString(cluster.ZookeeperConnectString)))
+	d.Set("zookeeper_connect_string_tls", sortEndpointsString(aws.ToString(cluster.ZookeeperConnectStringTls)))
 
 	if err := d.Set(names.AttrTags, KeyValueTags(ctx, cluster.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
 		return sdkdiag.AppendErrorf(diags, "setting tags: %s", err)
diff --git a/internal/service/kafka/exports_test.go b/internal/service/kafka/exports_test.go
index 5b024556a29a..97d6388fffe3 100644
--- a/internal/service/kafka/exports_test.go
+++ b/internal/service/kafka/exports_test.go
@@ -22,4 +22,6 @@ var (
 	FindSingleSCRAMSecretAssociationByTwoPartKey = findSingleSCRAMSecretAssociationByTwoPartKey
 	FindServerlessClusterByARN                   = findServerlessClusterByARN
 	FindVPCConnectionByARN                       = findVPCConnectionByARN
+
+	SortEndpointsString = sortEndpointsString
 )
diff --git a/internal/service/kafka/serverless_cluster.go b/internal/service/kafka/serverless_cluster.go
index 0cb770f0ae67..1aaf4c89f1fa 100644
--- a/internal/service/kafka/serverless_cluster.go
+++ b/internal/service/kafka/serverless_cluster.go
@@ -15,6 +15,7 @@ import (
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
 	"github.com/hashicorp/terraform-provider-aws/internal/conns"
+	"github.com/hashicorp/terraform-provider-aws/internal/errs"
 	"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
 	"github.com/hashicorp/terraform-provider-aws/internal/flex"
 	tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
@@ -45,6 +46,10 @@ func resourceServerlessCluster() *schema.Resource {
 				Type:     schema.TypeString,
 				Computed: true,
 			},
+			"bootstrap_brokers_sasl_iam": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
 			"client_authentication": {
 				Type:     schema.TypeList,
 				Required: true,
@@ -184,6 +189,17 @@ func resourceServerlessClusterRead(ctx context.Context, d *schema.ResourceData,
 		return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
 	}
 
+	output, err := findBootstrapBrokersByARN(ctx, conn, d.Id())
+
+	switch {
+	case errs.IsA[*types.ForbiddenException](err):
+		d.Set("bootstrap_brokers_sasl_iam", nil)
+	case err != nil:
+		return sdkdiag.AppendErrorf(diags, "reading MSK Cluster (%s) bootstrap brokers: %s", clusterARN, err)
+	default:
+		d.Set("bootstrap_brokers_sasl_iam", sortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
+	}
+
 	setTagsOut(ctx, cluster.Tags)
 
 	return diags
diff --git a/internal/service/kafka/serverless_cluster_test.go b/internal/service/kafka/serverless_cluster_test.go
index 32a74e5f4c9d..a0b11c4c7139 100644
--- a/internal/service/kafka/serverless_cluster_test.go
+++ b/internal/service/kafka/serverless_cluster_test.go
@@ -37,6 +37,7 @@ func TestAccKafkaServerlessCluster_basic(t *testing.T) {
 				Check: resource.ComposeAggregateTestCheckFunc(
 					testAccCheckServerlessClusterExists(ctx, resourceName, &v),
 					acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "kafka", regexache.MustCompile(`cluster/.+$`)),
+					resource.TestCheckResourceAttrSet(resourceName, "bootstrap_brokers_sasl_iam"),
 					resource.TestCheckResourceAttr(resourceName, "client_authentication.#", "1"),
 					resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.#", "1"),
 					resource.TestCheckResourceAttr(resourceName, "client_authentication.0.sasl.0.iam.#", "1"),
diff --git a/internal/service/kafka/sort.go b/internal/service/kafka/sort.go
index 1ee7450938fb..6961948228d6 100644
--- a/internal/service/kafka/sort.go
+++ b/internal/service/kafka/sort.go
@@ -12,8 +12,8 @@ const (
 	endpointSeparator = ","
 )
 
-// SortEndpointsString sorts a comma-separated list of endpoints.
-func SortEndpointsString(s string) string {
+// sortEndpointsString sorts a comma-separated list of endpoints.
+func sortEndpointsString(s string) string {
 	parts := strings.Split(s, endpointSeparator)
 	slices.Sort(parts)
 	return strings.Join(parts, endpointSeparator)
diff --git a/website/docs/r/msk_serverless_cluster.html.markdown b/website/docs/r/msk_serverless_cluster.html.markdown
index e3b96231b820..f5a8468580a8 100644
--- a/website/docs/r/msk_serverless_cluster.html.markdown
+++ b/website/docs/r/msk_serverless_cluster.html.markdown
@@ -64,6 +64,7 @@ This resource supports the following arguments:
 This resource exports the following attributes in addition to the arguments above:
 
 * `arn` - The ARN of the serverless cluster.
+* `bootstrap_brokers_sasl_iam` - One or more DNS names (or IP addresses) and SASL IAM port pairs. For example, `boot-abcdefg.c2.kafka-serverless.eu-central-1.amazonaws.com:9098`. The resource sorts the list alphabetically. AWS may not always return all endpoints so the values may not be stable across applies.
 * `cluster_uuid` - UUID of the serverless cluster, for use in IAM policies.
 * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block).
 


Reviews:
user: login: ewbankkit
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:50:32Z
user: login: stefanfreitag
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T19:12:33Z
user: login: ewbankkit
body: LGTM :rocket:.

```console
% make testacc TESTARGS='-run=TestAccKafkaServerlessCluster_basic' PKG=kafka
make: Verifying source code with gofmt...
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go1.23.8 test ./internal/service/kafka/... -v -count 1 -parallel 20  -run=TestAccKafkaServerlessCluster_basic -timeout 360m -vet=off
2025/05/08 08:36:07 Initializing Terraform AWS Provider...
=== RUN   TestAccKafkaServerlessCluster_basic
=== PAUSE TestAccKafkaServerlessCluster_basic
=== CONT  TestAccKafkaServerlessCluster_basic
--- PASS: TestAccKafkaServerlessCluster_basic (163.83s)
PASS
ok  	github.com/hashicorp/terraform-provider-aws/internal/service/kafka	168.504s
```
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T14:30:16Z
user: login: jar-b
body: LGTM 🚀
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-09T13:45:45Z
user: login: ewbankkit
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T14:37:30Z

Review comments:
diff_hunk: @@ -184,6 +188,12 @@ func resourceServerlessClusterRead(ctx context.Context, d *schema.ResourceData,
 		return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
 	}
 
+	output, err := findBootstrapBrokersByARN(ctx, conn, d.Id())
path: internal/service/kafka/serverless_cluster.go
user: login: ewbankkit
body: As this is introducing a new API call (and hence required IAM permission) for this resource, could you please do something similar to the fix in https://github.com/hashicorp/terraform-provider-aws/pull/42117 and ignore any authorization errors from the new call? Thanks.
created_at: 2025-04-09T22:50:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -184,6 +188,12 @@ func resourceServerlessClusterRead(ctx context.Context, d *schema.ResourceData,
 		return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
 	}
 
+	output, err := findBootstrapBrokersByARN(ctx, conn, d.Id())
path: internal/service/kafka/serverless_cluster.go
user: login: stefanfreitag
body: Good evening!
Thanks for looking into the code changes.

I think I understood the change in #42117, but do not understand how I can apply it here.
In the linked pull request it is an extra call that requires the additional IAM permissions. If the extra call  is failing, it is not nice, but also not critical. Hence suppressing the authorization error is ok.

The situation I see here:
If we are hitting an authorization error when calling `findBootstrapBrokersByARN`  (`GetBootstrapBrokers`) we would not be able to fill in the value to `bootstrap_brokers_sasl_iam`:

```golang
d.Set("bootstrap_brokers_sasl_iam", SortEndpointsString(aws.ToString(output.BootstrapBrokerStringSaslIam)))
```
 I would consider this then as functionality not working as expected. In my view, surfacing the authorization error would make sense.

Does it makes sense to update the documentation and provide a hint on the additionally required permission?

Let me know your thoughts - maybe I misunderstood something.

created_at: 2025-04-10T19:12:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -184,6 +189,17 @@ func resourceServerlessClusterRead(ctx context.Context, d *schema.ResourceData,
 		return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
 	}
 
+	output, err := findBootstrapBrokersByARN(ctx, conn, d.Id())
+
+	switch {
+	case errs.IsA[*types.ForbiddenException](err):
+		d.Set("bootstrap_brokers_sasl_iam", nil)
path: internal/service/kafka/serverless_cluster.go
user: login: jar-b
body: Can we open a follow up issue to remove this handling in a future major version? (e.g. `kafka:GetBootstrapBrokers` will be explicitly required).


created_at: 2025-05-09T13:44:52Z
author_association: MEMBER
diff_hunk: @@ -184,6 +189,17 @@ func resourceServerlessClusterRead(ctx context.Context, d *schema.ResourceData,
 		return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
 	}
 
+	output, err := findBootstrapBrokersByARN(ctx, conn, d.Id())
+
+	switch {
+	case errs.IsA[*types.ForbiddenException](err):
+		d.Set("bootstrap_brokers_sasl_iam", nil)
path: internal/service/kafka/serverless_cluster.go
user: login: ewbankkit
body: https://github.com/hashicorp/terraform-provider-aws/issues/42555
created_at: 2025-05-09T14:37:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-06T19:16:03Z
body: ### Community Guidelines

This comment is added to every new Pull Request to provide quick reference to how the Terraform AWS Provider is maintained. Please review the information below, and thank you for contributing to the community that keeps the provider thriving! :rocket:

#### Voting for Prioritization

* Please vote on this Pull Request by adding a :+1: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original post to help the community and maintainers prioritize it.
* Please see our [prioritization guide](https://hashicorp.github.io/terraform-provider-aws/prioritization/) for additional information on how the maintainers handle prioritization.
* Please **do not** leave +1 or other comments that do not add relevant new information or questions; they generate extra noise for others following the Pull Request and do not help prioritize the request.

### Pull Request Authors

* Review the [contribution guide](https://hashicorp.github.io/terraform-provider-aws/) relating to the type of change you are making to ensure all of the necessary steps have been taken.
* Whether or not the branch has been rebased will **not** impact prioritization, but doing so is always a welcome surprise.


author_association: CONTRIBUTOR
user: login: ewbankkit
created_at: 2025-05-09T14:37:51Z
body: @stefanfreitag Thanks for the contribution :tada: :clap:.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-09T14:38:14Z
body: > [!WARNING]
> This Issue has been closed, meaning that any additional comments are much easier for the maintainers to miss. Please assume that the maintainers will not see them.
>
> Ongoing conversations amongst community members are welcome, however, the issue will be locked after 30 days. Moving conversations to another venue, such as the [AWS Provider forum](https://discuss.hashicorp.com/c/terraform-providers/tf-aws/33), is recommended. If you have additional concerns, please open a new issue, referencing this one where needed.
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-16T13:53:36Z
body: This functionality has been released in [v5.98.0 of the Terraform AWS Provider](https://github.com/hashicorp/terraform-provider-aws/blob/v5.98.0/CHANGELOG.md).  Please see the [Terraform documentation on provider versioning](https://www.terraform.io/docs/configuration/providers.html#provider-versions) or reach out if you need any assistance upgrading.

For further feature requests or bug reports with this functionality, please create a [new GitHub issue](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose) following the template. Thank you!
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-06-16T02:31:44Z
body: I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
author_association: CONTRIBUTOR