diff --git a/packages/@aws-cdk/aws-msk/README.md b/packages/@aws-cdk/aws-msk/README.md index 3ca501bfb4908..3702ca47e9b17 100644 --- a/packages/@aws-cdk/aws-msk/README.md +++ b/packages/@aws-cdk/aws-msk/README.md @@ -84,8 +84,6 @@ const cluster = msk.Cluster.fromClusterArn(this, 'Cluster', [MSK supports](https://docs.aws.amazon.com/msk/latest/developerguide/kafka_apis_iam.html) the following authentication mechanisms. -> Only one authentication method can be enabled. - ### TLS To enable client authentication with TLS set the `certificateAuthorityArns` property to reference your ACM Private CA. [More info on Private CAs.](https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html) @@ -151,6 +149,37 @@ const cluster = new msk.Cluster(this, 'cluster', { }); ``` + +### SASL/IAM + TLS + +Enable client authentication with [IAM](https://docs.aws.amazon.com/msk/latest/developerguide/iam-access-control.html) +as well as enable client authentication with TLS by setting the `certificateAuthorityArns` property to reference your ACM Private CA. [More info on Private CAs.](https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html) + +```ts +import * as acmpca from '@aws-cdk/aws-acmpca'; + +declare const vpc: ec2.Vpc; +const cluster = new msk.Cluster(this, 'Cluster', { + clusterName: 'myCluster', + kafkaVersion: msk.KafkaVersion.V2_8_1, + vpc, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.saslTls({ + iam: true, + certificateAuthorities: [ + acmpca.CertificateAuthority.fromCertificateAuthorityArn( + this, + 'CertificateAuthority', + 'arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111', + ), + ], + }), +}); +``` + + ## Logging You can deliver Apache Kafka broker logs to one or more of the following destination types: diff --git a/packages/@aws-cdk/aws-msk/lib/cluster.ts b/packages/@aws-cdk/aws-msk/lib/cluster.ts index 7b604deab2cd7..081593702f016 100644 --- a/packages/@aws-cdk/aws-msk/lib/cluster.ts +++ b/packages/@aws-cdk/aws-msk/lib/cluster.ts @@ -343,6 +343,11 @@ export interface TlsAuthProps { readonly certificateAuthorities?: acmpca.ICertificateAuthority[]; } +/** + * SASL + TLS authentication properties + */ +export interface SaslTlsAuthProps extends SaslAuthProps, TlsAuthProps { } + /** * Configuration properties for client authentication. */ @@ -361,6 +366,13 @@ export class ClientAuthentication { return new ClientAuthentication(undefined, props); } + /** + * SASL + TLS authentication + */ + public static saslTls(saslTlsProps: SaslTlsAuthProps): ClientAuthentication { + return new ClientAuthentication(saslTlsProps, saslTlsProps); + } + /** * @param saslProps - properties for SASL authentication * @param tlsProps - properties for TLS authentication @@ -616,6 +628,16 @@ export class Cluster extends ClusterBase { clientAuthentication = { sasl: { iam: { enabled: props.clientAuthentication.saslProps.iam } }, }; + if (props.clientAuthentication?.tlsProps) { + clientAuthentication = { + sasl: { iam: { enabled: props.clientAuthentication.saslProps.iam } }, + tls: { + certificateAuthorityArnList: props.clientAuthentication?.tlsProps?.certificateAuthorities?.map( + (ca) => ca.certificateAuthorityArn, + ), + }, + }; + } } else if (props.clientAuthentication?.saslProps?.scram) { clientAuthentication = { sasl: { diff --git a/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap b/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap index 2a5ae05e9f9cc..6791e85b252fc 100644 --- a/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap +++ b/packages/@aws-cdk/aws-msk/test/__snapshots__/cluster.test.js.snap @@ -492,3 +492,501 @@ Object { }, } `; + +exports[`MSK Cluster created with authentication enabled with sasl/iam auth and tls Snapshot test with all values set (iam/sasl) 1`] = ` +Object { + "Resources": Object { + "Vpc8378EB38": Object { + "Properties": Object { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc", + }, + ], + }, + "Type": "AWS::EC2::VPC", + }, + "VpcIGWD7BA715C": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc", + }, + ], + }, + "Type": "AWS::EC2::InternetGateway", + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": Object { + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": Object { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA", + }, + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500", + }, + "SubnetId": Object { + "Ref": "VpcPrivateSubnet1Subnet536B997A", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPrivateSubnet1RouteTableB2C5B500": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPrivateSubnet1Subnet536B997A": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Private", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Private", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPrivateSubnet2DefaultRoute060D2087": Object { + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": Object { + "Ref": "VpcPublicSubnet2NATGateway9182C01D", + }, + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet2RouteTableA678073B", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPrivateSubnet2RouteTableA678073B": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPrivateSubnet2RouteTableA678073B", + }, + "SubnetId": Object { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPrivateSubnet2Subnet3788AAA1": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Private", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Private", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PrivateSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": Object { + "DependsOn": Array [ + "VpcVPCGWBF912B6E", + ], + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "RouteTableId": Object { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPublicSubnet1EIPD7E02669": Object { + "Properties": Object { + "Domain": "vpc", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + }, + "Type": "AWS::EC2::EIP", + }, + "VpcPublicSubnet1NATGateway4D7517AA": Object { + "DependsOn": Array [ + "VpcPublicSubnet1DefaultRoute3DA9E72A", + "VpcPublicSubnet1RouteTableAssociation97140677", + ], + "Properties": Object { + "AllocationId": Object { + "Fn::GetAtt": Array [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId", + ], + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4", + }, + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + }, + "Type": "AWS::EC2::NatGateway", + }, + "VpcPublicSubnet1RouteTable6C95E38E": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPublicSubnet1RouteTableAssociation97140677": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E", + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPublicSubnet1Subnet5C2D37C4": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 0, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Public", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Public", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet1", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcPublicSubnet2DefaultRoute97F91067": Object { + "DependsOn": Array [ + "VpcVPCGWBF912B6E", + ], + "Properties": Object { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "RouteTableId": Object { + "Ref": "VpcPublicSubnet2RouteTable94F7E489", + }, + }, + "Type": "AWS::EC2::Route", + }, + "VpcPublicSubnet2EIP3C605A87": Object { + "Properties": Object { + "Domain": "vpc", + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + }, + "Type": "AWS::EC2::EIP", + }, + "VpcPublicSubnet2NATGateway9182C01D": Object { + "DependsOn": Array [ + "VpcPublicSubnet2DefaultRoute97F91067", + "VpcPublicSubnet2RouteTableAssociationDD5762D8", + ], + "Properties": Object { + "AllocationId": Object { + "Fn::GetAtt": Array [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId", + ], + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet2Subnet691E08A3", + }, + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + }, + "Type": "AWS::EC2::NatGateway", + }, + "VpcPublicSubnet2RouteTable94F7E489": Object { + "Properties": Object { + "Tags": Array [ + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::RouteTable", + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": Object { + "Properties": Object { + "RouteTableId": Object { + "Ref": "VpcPublicSubnet2RouteTable94F7E489", + }, + "SubnetId": Object { + "Ref": "VpcPublicSubnet2Subnet691E08A3", + }, + }, + "Type": "AWS::EC2::SubnetRouteTableAssociation", + }, + "VpcPublicSubnet2Subnet691E08A3": Object { + "Properties": Object { + "AvailabilityZone": Object { + "Fn::Select": Array [ + 1, + Object { + "Fn::GetAZs": "", + }, + ], + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": Array [ + Object { + "Key": "aws-cdk:subnet-name", + "Value": "Public", + }, + Object { + "Key": "aws-cdk:subnet-type", + "Value": "Public", + }, + Object { + "Key": "Name", + "Value": "Default/Vpc/PublicSubnet2", + }, + ], + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::Subnet", + }, + "VpcVPCGWBF912B6E": Object { + "Properties": Object { + "InternetGatewayId": Object { + "Ref": "VpcIGWD7BA715C", + }, + "VpcId": Object { + "Ref": "Vpc8378EB38", + }, + }, + "Type": "AWS::EC2::VPCGatewayAttachment", + }, + "kafka5BADF433": Object { + "DeletionPolicy": "Retain", + "Properties": Object { + "BrokerNodeGroupInfo": Object { + "ClientSubnets": Array [ + Object { + "Ref": "VpcPrivateSubnet1Subnet536B997A", + }, + Object { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1", + }, + ], + "InstanceType": "kafka.m5.large", + "SecurityGroups": Array [ + "sg-123", + "sg-456", + ], + "StorageInfo": Object { + "EBSStorageInfo": Object { + "VolumeSize": 100, + }, + }, + }, + "ClientAuthentication": Object { + "Sasl": Object { + "Iam": Object { + "Enabled": true, + }, + }, + "Tls": Object { + "CertificateAuthorityArnList": Array [ + "arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111", + ], + }, + }, + "ClusterName": "test-cluster", + "EncryptionInfo": Object { + "EncryptionAtRest": Object { + "DataVolumeKMSKeyId": "1234abc", + }, + "EncryptionInTransit": Object { + "ClientBroker": "TLS", + "InCluster": true, + }, + }, + "EnhancedMonitoring": "PER_TOPIC_PER_BROKER", + "KafkaVersion": "2.6.1", + "LoggingInfo": Object { + "BrokerLogs": Object { + "CloudWatchLogs": Object { + "Enabled": true, + "LogGroup": "a-log-group", + }, + "Firehose": Object { + "DeliveryStream": "a-delivery-stream", + "Enabled": true, + }, + "S3": Object { + "Bucket": "a-bucket", + "Enabled": true, + }, + }, + }, + "NumberOfBrokerNodes": 2, + "OpenMonitoring": Object { + "Prometheus": Object { + "JmxExporter": Object { + "EnabledInBroker": true, + }, + "NodeExporter": Object { + "EnabledInBroker": true, + }, + }, + }, + }, + "Type": "AWS::MSK::Cluster", + "UpdateReplacePolicy": "Retain", + }, + "sg1fromsg32181E6F4C07E": Object { + "Properties": Object { + "Description": "from sg3:2181", + "FromPort": 2181, + "GroupId": "sg-123", + "IpProtocol": "tcp", + "SourceSecurityGroupId": "sg-3", + "ToPort": 2181, + }, + "Type": "AWS::EC2::SecurityGroupIngress", + }, + "sg2fromsg32181884B3B9E": Object { + "Properties": Object { + "Description": "from sg3:2181", + "FromPort": 2181, + "GroupId": "sg-456", + "IpProtocol": "tcp", + "SourceSecurityGroupId": "sg-3", + "ToPort": 2181, + }, + "Type": "AWS::EC2::SecurityGroupIngress", + }, + }, +} +`; diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.assets.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.assets.json index 7dae708695e32..c472b41704175 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.assets.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.assets.json @@ -14,7 +14,7 @@ } } }, - "d4d546e07248e011111b5bfebbc8ee5e0f9c955454a8fc6571ea6053e4d57040": { + "cb5e0493d7a26e47c4deaeb7990a164366846c32f89649a02126aaab808016c3": { "source": { "path": "MskLoggingDefaultTestDeployAssertC2F074AF.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "d4d546e07248e011111b5bfebbc8ee5e0f9c955454a8fc6571ea6053e4d57040.json", + "objectKey": "cb5e0493d7a26e47c4deaeb7990a164366846c32f89649a02126aaab808016c3.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.template.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.template.json index b24db3acd839f..17175894fbb1f 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.template.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/MskLoggingDefaultTestDeployAssertC2F074AF.template.json @@ -30,7 +30,7 @@ } }, "flattenResponse": "false", - "salt": "1661970876829" + "salt": "1663236373089" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -51,7 +51,7 @@ ] }, "expected": "{\"$ObjectLike\":{\"KeyCount\":1}}", - "salt": "1661970876830" + "salt": "1663236373089" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -149,7 +149,7 @@ } }, "Outputs": { - "AssertionResultsAssertEqualsS3listObjectsV2": { + "AssertionResultsAssertEqualsS3listObjectsV2773d42ff5e69123d2a937459089e2352": { "Value": { "Fn::GetAtt": [ "AwsApiCallS3listObjectsV2AssertEqualsS3listObjectsV26A93E391", diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.assets.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.assets.json index 0ac21615afa2f..a9c3edc64ca31 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.assets.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.assets.json @@ -27,7 +27,7 @@ } } }, - "e78b5e231005a38236d928a77cdf100be5210512eb6c29ac1cad77234d020c49": { + "cfbe056d80d640f6fda522aaad2c3d4b4c1c66850a2478d379fbdd7f994a5d81": { "source": { "path": "aws-cdk-msk-integ.template.json", "packaging": "file" @@ -35,7 +35,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "e78b5e231005a38236d928a77cdf100be5210512eb6c29ac1cad77234d020c49.json", + "objectKey": "cfbe056d80d640f6fda522aaad2c3d4b4c1c66850a2478d379fbdd7f994a5d81.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.template.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.template.json index 3e1a054b22b98..703c137753c11 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.template.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/aws-cdk-msk-integ.template.json @@ -964,6 +964,226 @@ } ] } + }, + "CertificateAuthority": { + "Type": "AWS::ACMPCA::CertificateAuthority", + "Properties": { + "KeyAlgorithm": "RSA_2048", + "SigningAlgorithm": "SHA256WITHRSA", + "Subject": { + "CommonName": "MSK Cluster Root CA", + "Country": "DE", + "Locality": "Berlin", + "Organization": "Amazon Web Services", + "OrganizationalUnit": "AWS-CDK", + "State": "Berlin" + }, + "Type": "ROOT", + "KeyStorageSecurityStandard": "FIPS_140_2_LEVEL_3_OR_HIGHER" + } + }, + "Certificate": { + "Type": "AWS::ACMPCA::Certificate", + "Properties": { + "CertificateAuthorityArn": { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + }, + "CertificateSigningRequest": { + "Fn::GetAtt": [ + "CertificateAuthority", + "CertificateSigningRequest" + ] + }, + "SigningAlgorithm": "SHA256WITHRSA", + "Validity": { + "Type": "YEARS", + "Value": 1 + }, + "TemplateArn": "arn:aws:acm-pca:::template/RootCACertificate/V1" + } + }, + "CertificateActivation": { + "Type": "AWS::ACMPCA::CertificateAuthorityActivation", + "Properties": { + "Certificate": { + "Fn::GetAtt": [ + "Certificate", + "Certificate" + ] + }, + "CertificateAuthorityArn": { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + } + } + }, + "ClusterIAMTLSSecurityGroup57AD0504": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "MSK security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + }, + "DependsOn": [ + "CertificateActivation" + ] + }, + "ClusterIAMTLS84D04AEF": { + "Type": "AWS::MSK::Cluster", + "Properties": { + "BrokerNodeGroupInfo": { + "ClientSubnets": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "InstanceType": "kafka.m5.large", + "SecurityGroups": [ + { + "Fn::GetAtt": [ + "ClusterIAMTLSSecurityGroup57AD0504", + "GroupId" + ] + } + ], + "StorageInfo": { + "EBSStorageInfo": { + "VolumeSize": 1000 + } + } + }, + "ClusterName": "integ-test-iam-tls-auth", + "KafkaVersion": "2.8.1", + "NumberOfBrokerNodes": 2, + "ClientAuthentication": { + "Sasl": { + "Iam": { + "Enabled": true + } + }, + "Tls": { + "CertificateAuthorityArnList": [ + { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + } + ] + } + }, + "EncryptionInfo": { + "EncryptionInTransit": { + "ClientBroker": "TLS", + "InCluster": true + } + }, + "LoggingInfo": { + "BrokerLogs": { + "CloudWatchLogs": { + "Enabled": false + }, + "Firehose": { + "Enabled": false + }, + "S3": { + "Bucket": { + "Ref": "LoggingBucket1E5A6F3B" + }, + "Enabled": true + } + } + } + }, + "DependsOn": [ + "CertificateActivation" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsB831721C": { + "Type": "Custom::AWS", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWS679f53fac002430cb0da5b7982bd22872D164C4C", + "Arn" + ] + }, + "Create": { + "Fn::Join": [ + "", + [ + "{\"service\":\"Kafka\",\"action\":\"getBootstrapBrokers\",\"parameters\":{\"ClusterArn\":\"", + { + "Ref": "ClusterIAMTLS84D04AEF" + }, + "\"},\"physicalResourceId\":{\"id\":\"BootstrapBrokers\"}}" + ] + ] + }, + "Update": { + "Fn::Join": [ + "", + [ + "{\"service\":\"Kafka\",\"action\":\"getBootstrapBrokers\",\"parameters\":{\"ClusterArn\":\"", + { + "Ref": "ClusterIAMTLS84D04AEF" + }, + "\"},\"physicalResourceId\":{\"id\":\"BootstrapBrokers\"}}" + ] + ] + }, + "InstallLatestAwsSdk": true + }, + "DependsOn": [ + "CertificateActivation", + "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy508CF9CC" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy508CF9CC": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "kafka:GetBootstrapBrokers", + "Effect": "Allow", + "Resource": { + "Ref": "ClusterIAMTLS84D04AEF" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy508CF9CC", + "Roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + }, + "DependsOn": [ + "CertificateActivation" + ] } }, "Outputs": { @@ -1009,6 +1229,22 @@ "BootstrapBrokerStringSaslIam" ] } + }, + "BootstrapBrokers4": { + "Value": { + "Fn::GetAtt": [ + "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsB831721C", + "BootstrapBrokerStringTls" + ] + } + }, + "BootstrapBrokers5": { + "Value": { + "Fn::GetAtt": [ + "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsB831721C", + "BootstrapBrokerStringSaslIam" + ] + } } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/manifest.json index a78925d4c75b6..9611fa23c9236 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/manifest.json @@ -23,7 +23,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/e78b5e231005a38236d928a77cdf100be5210512eb6c29ac1cad77234d020c49.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/cfbe056d80d640f6fda522aaad2c3d4b4c1c66850a2478d379fbdd7f994a5d81.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -297,6 +297,68 @@ "data": "BootstrapBrokers3" } ], + "/aws-cdk-msk-integ/CertificateAuthority": [ + { + "type": "aws:cdk:logicalId", + "data": "CertificateAuthority" + }, + { + "type": "Description", + "data": "Signing authority for Certificates" + } + ], + "/aws-cdk-msk-integ/Certificate": [ + { + "type": "aws:cdk:logicalId", + "data": "Certificate" + }, + { + "type": "Description", + "data": "Certificate for signing requests from MSK-Cluster" + } + ], + "/aws-cdk-msk-integ/CertificateActivation": [ + { + "type": "aws:cdk:logicalId", + "data": "CertificateActivation" + } + ], + "/aws-cdk-msk-integ/ClusterIAMTLS/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterIAMTLSSecurityGroup57AD0504" + } + ], + "/aws-cdk-msk-integ/ClusterIAMTLS/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterIAMTLS84D04AEF" + } + ], + "/aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/Resource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsB831721C" + } + ], + "/aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/CustomResourcePolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy508CF9CC" + } + ], + "/aws-cdk-msk-integ/BootstrapBrokers4": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapBrokers4" + } + ], + "/aws-cdk-msk-integ/BootstrapBrokers5": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapBrokers5" + } + ], "/aws-cdk-msk-integ/BootstrapVersion": [ { "type": "aws:cdk:logicalId", @@ -328,7 +390,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d4d546e07248e011111b5bfebbc8ee5e0f9c955454a8fc6571ea6053e4d57040.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/cb5e0493d7a26e47c4deaeb7990a164366846c32f89649a02126aaab808016c3.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -360,7 +422,7 @@ "/MskLogging/DefaultTest/DeployAssert/AwsApiCallS3listObjectsV2/AssertEqualsS3listObjectsV2/AssertionResults": [ { "type": "aws:cdk:logicalId", - "data": "AssertionResultsAssertEqualsS3listObjectsV2" + "data": "AssertionResultsAssertEqualsS3listObjectsV2773d42ff5e69123d2a937459089e2352" } ], "/MskLogging/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ diff --git a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/tree.json b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/tree.json index 2a9bb117ea226..56c9ecd041b18 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/tree.json +++ b/packages/@aws-cdk/aws-msk/test/cluster.integ.snapshot/tree.json @@ -9,7 +9,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } }, "aws-cdk-msk-integ": { @@ -1115,7 +1115,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } }, "AWS679f53fac002430cb0da5b7982bd2287": { @@ -1444,6 +1444,311 @@ "fqn": "@aws-cdk/core.CfnOutput", "version": "0.0.0" } + }, + "CertificateAuthority": { + "id": "CertificateAuthority", + "path": "aws-cdk-msk-integ/CertificateAuthority", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ACMPCA::CertificateAuthority", + "aws:cdk:cloudformation:props": { + "keyAlgorithm": "RSA_2048", + "signingAlgorithm": "SHA256WITHRSA", + "subject": { + "commonName": "MSK Cluster Root CA", + "organization": "Amazon Web Services", + "organizationalUnit": "AWS-CDK", + "country": "DE", + "state": "Berlin", + "locality": "Berlin" + }, + "type": "ROOT", + "keyStorageSecurityStandard": "FIPS_140_2_LEVEL_3_OR_HIGHER" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-acmpca.CfnCertificateAuthority", + "version": "0.0.0" + } + }, + "Certificate": { + "id": "Certificate", + "path": "aws-cdk-msk-integ/Certificate", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ACMPCA::Certificate", + "aws:cdk:cloudformation:props": { + "certificateAuthorityArn": { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + }, + "certificateSigningRequest": { + "Fn::GetAtt": [ + "CertificateAuthority", + "CertificateSigningRequest" + ] + }, + "signingAlgorithm": "SHA256WITHRSA", + "validity": { + "type": "YEARS", + "value": 1 + }, + "templateArn": "arn:aws:acm-pca:::template/RootCACertificate/V1" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-acmpca.CfnCertificate", + "version": "0.0.0" + } + }, + "CertificateActivation": { + "id": "CertificateActivation", + "path": "aws-cdk-msk-integ/CertificateActivation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ACMPCA::CertificateAuthorityActivation", + "aws:cdk:cloudformation:props": { + "certificate": { + "Fn::GetAtt": [ + "Certificate", + "Certificate" + ] + }, + "certificateAuthorityArn": { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-acmpca.CfnCertificateAuthorityActivation", + "version": "0.0.0" + } + }, + "PrivateCA": { + "id": "PrivateCA", + "path": "aws-cdk-msk-integ/PrivateCA", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "ClusterIAMTLS": { + "id": "ClusterIAMTLS", + "path": "aws-cdk-msk-integ/ClusterIAMTLS", + "children": { + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "MSK security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::MSK::Cluster", + "aws:cdk:cloudformation:props": { + "brokerNodeGroupInfo": { + "instanceType": "kafka.m5.large", + "clientSubnets": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "securityGroups": [ + { + "Fn::GetAtt": [ + "ClusterIAMTLSSecurityGroup57AD0504", + "GroupId" + ] + } + ], + "storageInfo": { + "ebsStorageInfo": { + "volumeSize": 1000 + } + } + }, + "clusterName": "integ-test-iam-tls-auth", + "kafkaVersion": "2.8.1", + "numberOfBrokerNodes": 2, + "clientAuthentication": { + "sasl": { + "iam": { + "enabled": true + } + }, + "tls": { + "certificateAuthorityArnList": [ + { + "Fn::GetAtt": [ + "CertificateAuthority", + "Arn" + ] + } + ] + } + }, + "encryptionInfo": { + "encryptionInTransit": { + "clientBroker": "TLS", + "inCluster": true + } + }, + "loggingInfo": { + "brokerLogs": { + "cloudWatchLogs": { + "enabled": false + }, + "firehose": { + "enabled": false + }, + "s3": { + "enabled": true, + "bucket": { + "Ref": "LoggingBucket1E5A6F3B" + } + } + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-msk.CfnCluster", + "version": "0.0.0" + } + }, + "BootstrapBrokersBootstrapBrokerStringTls": { + "id": "BootstrapBrokersBootstrapBrokerStringTls", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls", + "children": { + "Provider": { + "id": "Provider", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/Provider", + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/Resource", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/Resource/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "CustomResourcePolicy": { + "id": "CustomResourcePolicy", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/CustomResourcePolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-msk-integ/ClusterIAMTLS/BootstrapBrokersBootstrapBrokerStringTls/CustomResourcePolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "kafka:GetBootstrapBrokers", + "Effect": "Allow", + "Resource": { + "Ref": "ClusterIAMTLS84D04AEF" + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "ClusterIAMTLSBootstrapBrokersBootstrapBrokerStringTlsCustomResourcePolicy508CF9CC", + "roles": [ + { + "Ref": "AWS679f53fac002430cb0da5b7982bd2287ServiceRoleC1EA0FF2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/custom-resources.AwsCustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-msk.Cluster", + "version": "0.0.0" + } + }, + "BootstrapBrokers4": { + "id": "BootstrapBrokers4", + "path": "aws-cdk-msk-integ/BootstrapBrokers4", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "BootstrapBrokers5": { + "id": "BootstrapBrokers5", + "path": "aws-cdk-msk-integ/BootstrapBrokers5", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } } }, "constructInfo": { @@ -1464,7 +1769,7 @@ "path": "MskLogging/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } }, "DeployAssert": { @@ -1484,7 +1789,7 @@ "path": "MskLogging/DefaultTest/DeployAssert/AwsApiCallS3listObjectsV2/SdkProvider/AssertionsProvider", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } } }, @@ -1524,7 +1829,7 @@ "path": "MskLogging/DefaultTest/DeployAssert/AwsApiCallS3listObjectsV2/AssertEqualsS3listObjectsV2/AssertionProvider/AssertionsProvider", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } } }, @@ -1602,7 +1907,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.102" } } }, diff --git a/packages/@aws-cdk/aws-msk/test/cluster.test.ts b/packages/@aws-cdk/aws-msk/test/cluster.test.ts index 7621c5563a80e..7a2fb87506517 100644 --- a/packages/@aws-cdk/aws-msk/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-msk/test/cluster.test.ts @@ -188,6 +188,65 @@ describe('MSK Cluster', () => { }); }); + describe('with sasl/iam auth and tls', () => { + test('Snapshot test with all values set (iam/sasl)', () => { + const cluster = new msk.Cluster(stack, 'kafka', { + clusterName: 'test-cluster', + kafkaVersion: msk.KafkaVersion.V2_6_1, + vpc, + securityGroups: [ + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg1', 'sg-123'), + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg2', 'sg-456'), + ], + ebsStorageInfo: { + volumeSize: 100, + encryptionKey: kms.Key.fromKeyArn( + stack, + 'kms', + 'arn:aws:kms:us-east-1:111122223333:key/1234abc', + ), + }, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.saslTls({ + iam: true, + certificateAuthorities: [ + acmpca.CertificateAuthority.fromCertificateAuthorityArn( + stack, + 'CertificateAuthority', + 'arn:aws:acm-pca:us-west-2:1234567890:certificate-authority/11111111-1111-1111-1111-111111111111', + ), + ], + }), + monitoring: { + enablePrometheusJmxExporter: true, + enablePrometheusNodeExporter: true, + clusterMonitoringLevel: msk.ClusterMonitoringLevel.PER_TOPIC_PER_BROKER, + }, + logging: { + s3: { + bucket: s3.Bucket.fromBucketName(stack, 'Bucket', 'a-bucket'), + }, + cloudwatchLogGroup: logs.LogGroup.fromLogGroupName( + stack, + 'LogGroup', + 'a-log-group', + ), + firehoseDeliveryStreamName: 'a-delivery-stream', + }, + }); + + cluster.connections.allowFrom( + ec2.SecurityGroup.fromSecurityGroupId(stack, 'sg3', 'sg-3'), + ec2.Port.tcp(2181), + ); + + // THEN + expect(Template.fromStack(stack)).toMatchSnapshot(); + }); + }); + describe('creates a customer master key', () => { beforeEach(() => { new msk.Cluster(stack, 'Cluster', { diff --git a/packages/@aws-cdk/aws-msk/test/integ.cluster.ts b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts index 177f06ba51e2c..b470c2bef55bc 100644 --- a/packages/@aws-cdk/aws-msk/test/integ.cluster.ts +++ b/packages/@aws-cdk/aws-msk/test/integ.cluster.ts @@ -1,3 +1,9 @@ +import { + CertificateAuthority, + CfnCertificate, + CfnCertificateAuthority, + CfnCertificateAuthorityActivation, +} from '@aws-cdk/aws-acmpca'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -56,6 +62,87 @@ class FeatureFlagStack extends cdk.Stack { // Test lazy instance of the AwsCustomResource new cdk.CfnOutput(this, 'BootstrapBrokers3', { value: cluster2.bootstrapBrokersSaslIam }); + + const certSigningAlgorithm = 'SHA256WITHRSA'; + const privateCA = new CfnCertificateAuthority( + this, + 'CertificateAuthority', + { + keyAlgorithm: 'RSA_2048', + signingAlgorithm: certSigningAlgorithm, + keyStorageSecurityStandard: 'FIPS_140_2_LEVEL_3_OR_HIGHER', + type: 'ROOT', + subject: { + commonName: 'MSK Cluster Root CA', + organization: 'Amazon Web Services', + organizationalUnit: 'AWS-CDK', + country: 'DE', + state: 'Berlin', + locality: 'Berlin', + }, + }, + ); + + privateCA.node.addMetadata( + 'Description', + 'Signing authority for Certificates', + ); + + const cert = new CfnCertificate(this, 'Certificate', { + certificateAuthorityArn: privateCA.attrArn, + certificateSigningRequest: privateCA.attrCertificateSigningRequest, + signingAlgorithm: certSigningAlgorithm, + templateArn: 'arn:aws:acm-pca:::template/RootCACertificate/V1', + validity: { + type: 'YEARS', + value: 1, + }, + }); + cert.node.addMetadata( + 'Description', + 'Certificate for signing requests from MSK-Cluster', + ); + + // Activating the certificate using the signing cert authority + const certActivation = new CfnCertificateAuthorityActivation( + this, + 'CertificateActivation', + { + certificateAuthorityArn: privateCA.attrArn, + certificate: cert.attrCertificate, + }, + ); + + const cluster3 = new msk.Cluster(this, 'ClusterIAMTLS', { + clusterName: 'integ-test-iam-tls-auth', + kafkaVersion: msk.KafkaVersion.V2_8_1, + vpc, + logging: { + s3: { + bucket: this.bucket, + }, + }, + encryptionInTransit: { + clientBroker: msk.ClientBrokerEncryption.TLS, + }, + clientAuthentication: msk.ClientAuthentication.saslTls({ + iam: true, + certificateAuthorities: [ + CertificateAuthority.fromCertificateAuthorityArn( + this, + 'PrivateCA', + privateCA.attrArn, + ), + ], + }), + removalPolicy: cdk.RemovalPolicy.DESTROY, + }); + + cluster3.node.addDependency(certActivation); + + // Test lazy instance of the AwsCustomResource + new cdk.CfnOutput(this, 'BootstrapBrokers4', { value: cluster3.bootstrapBrokersTls }); + new cdk.CfnOutput(this, 'BootstrapBrokers5', { value: cluster3.bootstrapBrokersSaslIam }); } }