diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.assets.json new file mode 100644 index 0000000000000..4843b48cdd9ff --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "b3c50c4e8378ff7782ea37244e92308e1c5724f88cbae2d1f9937061a00b454a": { + "source": { + "path": "integ-key-algorithm.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b3c50c4e8378ff7782ea37244e92308e1c5724f88cbae2d1f9937061a00b454a.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.template.json new file mode 100644 index 0000000000000..5b4005d39a339 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ-key-algorithm.template.json @@ -0,0 +1,98 @@ +{ + "Resources": { + "ECprime256v1A2C983CE": { + "Type": "AWS::CertificateManager::Certificate", + "Properties": { + "DomainName": "*.example.com", + "DomainValidationOptions": [ + { + "DomainName": "*.example.com", + "HostedZoneId": "Z23ABC4XYZL05B" + } + ], + "KeyAlgorithm": "EC_prime256v1", + "Tags": [ + { + "Key": "Name", + "Value": "integ-key-algorithm/EC_prime256v1" + } + ], + "ValidationMethod": "DNS" + } + }, + "ECsecp384r16CA95ECC": { + "Type": "AWS::CertificateManager::Certificate", + "Properties": { + "DomainName": "*.example.com", + "DomainValidationOptions": [ + { + "DomainName": "*.example.com", + "HostedZoneId": "Z23ABC4XYZL05B" + } + ], + "KeyAlgorithm": "EC_secp384r1", + "Tags": [ + { + "Key": "Name", + "Value": "integ-key-algorithm/EC_secp384r1" + } + ], + "ValidationMethod": "DNS" + } + }, + "RSA2048CD164E12": { + "Type": "AWS::CertificateManager::Certificate", + "Properties": { + "DomainName": "*.example.com", + "DomainValidationOptions": [ + { + "DomainName": "*.example.com", + "HostedZoneId": "Z23ABC4XYZL05B" + } + ], + "KeyAlgorithm": "RSA_2048", + "Tags": [ + { + "Key": "Name", + "Value": "integ-key-algorithm/RSA_2048" + } + ], + "ValidationMethod": "DNS" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ.json new file mode 100644 index 0000000000000..b5aec2f6f623f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "enableLookups": true, + "version": "36.0.0", + "testCases": { + "integ-test/DefaultTest": { + "stacks": [ + "integ-key-algorithm" + ], + "diffAssets": true, + "assertionStack": "integ-test/DefaultTest/DeployAssert", + "assertionStackName": "integtestDefaultTestDeployAssert24D5C536" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json new file mode 100644 index 0000000000000..3555eb95abb24 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integtestDefaultTestDeployAssert24D5C536.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/manifest.json new file mode 100644 index 0000000000000..525ce220fc4af --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/manifest.json @@ -0,0 +1,125 @@ +{ + "version": "36.0.0", + "artifacts": { + "integ-key-algorithm.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-key-algorithm.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-key-algorithm": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-key-algorithm.template.json", + "terminationProtection": false, + "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}/b3c50c4e8378ff7782ea37244e92308e1c5724f88cbae2d1f9937061a00b454a.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-key-algorithm.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-key-algorithm.assets" + ], + "metadata": { + "/integ-key-algorithm/EC_prime256v1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ECprime256v1A2C983CE" + } + ], + "/integ-key-algorithm/EC_secp384r1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ECsecp384r16CA95ECC" + } + ], + "/integ-key-algorithm/RSA_2048/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RSA2048CD164E12" + } + ], + "/integ-key-algorithm/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-key-algorithm/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-key-algorithm" + }, + "integtestDefaultTestDeployAssert24D5C536.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtestDefaultTestDeployAssert24D5C536.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtestDefaultTestDeployAssert24D5C536": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtestDefaultTestDeployAssert24D5C536.template.json", + "terminationProtection": false, + "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}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "metadata": { + "/integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/tree.json new file mode 100644 index 0000000000000..1ab152c1381db --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.js.snapshot/tree.json @@ -0,0 +1,223 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-key-algorithm": { + "id": "integ-key-algorithm", + "path": "integ-key-algorithm", + "children": { + "HostedZone": { + "id": "HostedZone", + "path": "integ-key-algorithm/HostedZone", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.118.0" + } + }, + "EC_prime256v1": { + "id": "EC_prime256v1", + "path": "integ-key-algorithm/EC_prime256v1", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-key-algorithm/EC_prime256v1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CertificateManager::Certificate", + "aws:cdk:cloudformation:props": { + "domainName": "*.example.com", + "domainValidationOptions": [ + { + "domainName": "*.example.com", + "hostedZoneId": "Z23ABC4XYZL05B" + } + ], + "keyAlgorithm": "EC_prime256v1", + "tags": [ + { + "key": "Name", + "value": "integ-key-algorithm/EC_prime256v1" + } + ], + "validationMethod": "DNS" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_certificatemanager.CfnCertificate", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.118.0" + } + }, + "EC_secp384r1": { + "id": "EC_secp384r1", + "path": "integ-key-algorithm/EC_secp384r1", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-key-algorithm/EC_secp384r1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CertificateManager::Certificate", + "aws:cdk:cloudformation:props": { + "domainName": "*.example.com", + "domainValidationOptions": [ + { + "domainName": "*.example.com", + "hostedZoneId": "Z23ABC4XYZL05B" + } + ], + "keyAlgorithm": "EC_secp384r1", + "tags": [ + { + "key": "Name", + "value": "integ-key-algorithm/EC_secp384r1" + } + ], + "validationMethod": "DNS" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_certificatemanager.CfnCertificate", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.118.0" + } + }, + "RSA_2048": { + "id": "RSA_2048", + "path": "integ-key-algorithm/RSA_2048", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-key-algorithm/RSA_2048/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CertificateManager::Certificate", + "aws:cdk:cloudformation:props": { + "domainName": "*.example.com", + "domainValidationOptions": [ + { + "domainName": "*.example.com", + "hostedZoneId": "Z23ABC4XYZL05B" + } + ], + "keyAlgorithm": "RSA_2048", + "tags": [ + { + "key": "Name", + "value": "integ-key-algorithm/RSA_2048" + } + ], + "validationMethod": "DNS" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_certificatemanager.CfnCertificate", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.118.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-key-algorithm/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.118.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-key-algorithm/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.118.0" + } + }, + "integ-test": { + "id": "integ-test", + "path": "integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.118.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.118.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.118.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.118.0-alpha.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.118.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.ts new file mode 100644 index 0000000000000..a928377ebcfba --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-certificatemanager/test/integ.certificate-key-algorithm.ts @@ -0,0 +1,50 @@ +import { PublicHostedZone } from 'aws-cdk-lib/aws-route53'; +import { App, Stack } from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { Certificate, CertificateValidation, KeyAlgorithm } from 'aws-cdk-lib/aws-certificatemanager'; + +/** + * In order to test this you need + * to have a valid public hosted zone that you can use + * to request certificates for. + * +*/ +const hostedZoneId = process.env.CDK_INTEG_HOSTED_ZONE_ID ?? process.env.HOSTED_ZONE_ID; +if (!hostedZoneId) throw new Error('For this test you must provide your own HostedZoneId as an env var "HOSTED_ZONE_ID". See framework-integ/README.md for details.'); +const hostedZoneName = process.env.CDK_INTEG_HOSTED_ZONE_NAME ?? process.env.HOSTED_ZONE_NAME; +if (!hostedZoneName) throw new Error('For this test you must provide your own HostedZoneName as an env var "HOSTED_ZONE_NAME". See framework-integ/README.md for details.'); +const domainName = process.env.CDK_INTEG_DOMAIN_NAME ?? process.env.DOMAIN_NAME; +if (!domainName) throw new Error('For this test you must provide your own DomainName as an env var "DOMAIN_NAME". See framework-integ/README.md for details.'); + +const app = new App(); +const stack = new Stack(app, 'integ-key-algorithm'); +const hostedZone = PublicHostedZone.fromHostedZoneAttributes(stack, 'HostedZone', { + hostedZoneId, + zoneName: hostedZoneName, +}); + +const validation = CertificateValidation.fromDns(hostedZone); + +new Certificate(stack, 'EC_prime256v1', { + domainName, + keyAlgorithm: KeyAlgorithm.EC_PRIME256V1, + validation, +}); + +new Certificate(stack, 'EC_secp384r1', { + domainName, + keyAlgorithm: KeyAlgorithm.EC_SECP384R1, + validation, +}); + +new Certificate(stack, 'RSA_2048', { + domainName, + keyAlgorithm: KeyAlgorithm.RSA_2048, + validation, +}); + +new IntegTest(app, 'integ-test', { + testCases: [stack], + diffAssets: true, + enableLookups: true, +}); \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-certificatemanager/README.md b/packages/aws-cdk-lib/aws-certificatemanager/README.md index 5c20e8fae88dd..8aa9a9467fc66 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/README.md +++ b/packages/aws-cdk-lib/aws-certificatemanager/README.md @@ -142,6 +142,7 @@ new acm.PrivateCertificate(this, 'PrivateCertificate', { subjectAlternativeNames: ['cool.example.com', 'test.example.net'], // optional certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(this, 'CA', 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + keyAlgorithm: acm.KeyAlgorithm.RSA_2048, // optional, default algorithm is RSA_2048 }); ``` @@ -156,6 +157,24 @@ new acm.Certificate(this, 'Certificate', { }); ``` +## Key Algorithms + +To specify the algorithm of the public and private key pair that your certificate uses to encrypt data use the `keyAlgorithm` property. + +Algorithms supported for an ACM certificate request include: + * `RSA_2048` + * `EC_prime256v1` + * `EC_secp384r1` + +```ts +new acm.Certificate(this, 'Certificate', { + domainName: 'test.example.com', + keyAlgorithm: acm.KeyAlgorithm.EC_PRIME256V1, +}); +``` + +> Visit [Key algorithms](https://docs.aws.amazon.com/acm/latest/userguide/acm-certificate.html#algorithms.title) for more details. + ## Importing If you want to import an existing certificate, you can do so from its ARN: diff --git a/packages/aws-cdk-lib/aws-certificatemanager/lib/certificate.ts b/packages/aws-cdk-lib/aws-certificatemanager/lib/certificate.ts index 37b5eb55b3511..db8cd1f783797 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/lib/certificate.ts +++ b/packages/aws-cdk-lib/aws-certificatemanager/lib/certificate.ts @@ -101,6 +101,47 @@ export interface CertificateProps { * @default the full, absolute path of this construct */ readonly certificateName?: string + + /** + * Specifies the algorithm of the public and private key pair that your certificate uses to encrypt data. + * + * @see https://docs.aws.amazon.com/acm/latest/userguide/acm-certificate.html#algorithms.title + * + * @default KeyAlgorithm.RSA_2048 + */ + readonly keyAlgorithm?: KeyAlgorithm; +} + +/** + * Certificate Manager key algorithm + * + * If you need to use an algorithm that doesn't exist as a static member, you + * can instantiate a `KeyAlgorithm` object, e.g: `new KeyAlgorithm('RSA_2048')`. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html#cfn-certificatemanager-certificate-keyalgorithm + */ +export class KeyAlgorithm { + /** + * RSA_2048 algorithm + */ + public static readonly RSA_2048 = new KeyAlgorithm('RSA_2048'); + + /** + * EC_prime256v1 algorithm + */ + public static readonly EC_PRIME256V1 = new KeyAlgorithm('EC_prime256v1'); + + /** + * EC_secp384r1 algorithm + */ + public static readonly EC_SECP384R1 = new KeyAlgorithm('EC_secp384r1'); + + constructor( + /** + * The name of the algorithm + */ + public readonly name: string, + ) { }; } /** @@ -259,6 +300,7 @@ export class Certificate extends CertificateBase implements ICertificate { domainValidationOptions: renderDomainValidation(validation, allDomainNames), validationMethod: validation.method, certificateTransparencyLoggingPreference, + keyAlgorithm: props.keyAlgorithm?.name, }); Tags.of(cert).add(NAME_TAG, props.certificateName || this.node.path.slice(0, 255)); diff --git a/packages/aws-cdk-lib/aws-certificatemanager/lib/dns-validated-certificate.ts b/packages/aws-cdk-lib/aws-certificatemanager/lib/dns-validated-certificate.ts index b3167087ae9d6..49e0c5b8e7b91 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/lib/dns-validated-certificate.ts +++ b/packages/aws-cdk-lib/aws-certificatemanager/lib/dns-validated-certificate.ts @@ -85,6 +85,12 @@ export class DnsValidatedCertificate extends CertificateBase implements ICertifi constructor(scope: Construct, id: string, props: DnsValidatedCertificateProps) { super(scope, id); + if (props.keyAlgorithm) { + cdk.Annotations.of(this) + .addWarningV2('@aws-cdk/aws-certificatemanager:keyAlgorithmIgnored', + 'keyAlgorithm is ignored for DnsValidatedCertificate construct.'); + } + this.region = props.region; this.domainName = props.domainName; // check if domain name is 64 characters or less diff --git a/packages/aws-cdk-lib/aws-certificatemanager/lib/private-certificate.ts b/packages/aws-cdk-lib/aws-certificatemanager/lib/private-certificate.ts index 78ddbf849f3fe..dd5696102c791 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/lib/private-certificate.ts +++ b/packages/aws-cdk-lib/aws-certificatemanager/lib/private-certificate.ts @@ -1,5 +1,5 @@ import { Construct } from 'constructs'; -import { ICertificate } from './certificate'; +import { ICertificate, KeyAlgorithm } from './certificate'; import { CertificateBase } from './certificate-base'; import { CfnCertificate } from './certificatemanager.generated'; import * as acmpca from '../../aws-acmpca'; @@ -28,6 +28,18 @@ export interface PrivateCertificateProps { * Private certificate authority (CA) that will be used to issue the certificate. */ readonly certificateAuthority: acmpca.ICertificateAuthority; + + /** + * Specifies the algorithm of the public and private key pair that your certificate uses to encrypt data. + * + * When you request a private PKI certificate signed by a CA from AWS Private CA, the specified signing algorithm family + * (RSA or ECDSA) must match the algorithm family of the CA's secret key. + * + * @see https://docs.aws.amazon.com/acm/latest/userguide/acm-certificate.html#algorithms.title + * + * @default KeyAlgorithm.RSA_2048 + */ + readonly keyAlgorithm?: KeyAlgorithm; } /** @@ -59,6 +71,7 @@ export class PrivateCertificate extends CertificateBase implements ICertificate domainName: props.domainName, subjectAlternativeNames: props.subjectAlternativeNames, certificateAuthorityArn: props.certificateAuthority.certificateAuthorityArn, + keyAlgorithm: props.keyAlgorithm?.name, }); this.certificateArn = cert.ref; diff --git a/packages/aws-cdk-lib/aws-certificatemanager/test/certificate.test.ts b/packages/aws-cdk-lib/aws-certificatemanager/test/certificate.test.ts index 6e383f30bb418..815661ef623fb 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/test/certificate.test.ts +++ b/packages/aws-cdk-lib/aws-certificatemanager/test/certificate.test.ts @@ -1,7 +1,7 @@ import { Template, Match } from '../../assertions'; import * as route53 from '../../aws-route53'; import { Aws, Duration, Lazy, Stack } from '../../core'; -import { Certificate, CertificateValidation } from '../lib'; +import { Certificate, CertificateValidation, KeyAlgorithm } from '../lib'; test('apex domain selection by default', () => { const stack = new Stack(); @@ -441,3 +441,43 @@ function hasTags(expectedTags: Array<{Key: string, Value: string}>) { }, }; } + +describe('Key Algorithm', () => { + test('key algorithm is undefined if not provided', () => { + const stack = new Stack(); + + new Certificate(stack, 'Certificate', { + domainName: 'test.example.com', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: Match.absent(), + }); + }); + + test('Can specify algorithm', () => { + const stack = new Stack(); + + new Certificate(stack, 'Certificate', { + domainName: 'test.example.com', + keyAlgorithm: KeyAlgorithm.EC_SECP384R1, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: 'EC_secp384r1', + }); + }); + + test('Can specify any arbitrary algorithm', () => { + const stack = new Stack(); + + new Certificate(stack, 'Certificate', { + domainName: 'test.example.com', + keyAlgorithm: new KeyAlgorithm('any value'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: 'any value', + }); + }); +}); diff --git a/packages/aws-cdk-lib/aws-certificatemanager/test/private-certificate.test.ts b/packages/aws-cdk-lib/aws-certificatemanager/test/private-certificate.test.ts index 550d26eb89515..75df50ea7b078 100644 --- a/packages/aws-cdk-lib/aws-certificatemanager/test/private-certificate.test.ts +++ b/packages/aws-cdk-lib/aws-certificatemanager/test/private-certificate.test.ts @@ -1,7 +1,7 @@ -import { Template } from '../../assertions'; +import { Match, Template } from '../../assertions'; import * as acmpca from '../../aws-acmpca'; import { Duration, Lazy, Stack } from '../../core'; -import { PrivateCertificate } from '../lib'; +import { KeyAlgorithm, PrivateCertificate } from '../lib'; test('private certificate authority', () => { const stack = new Stack(); @@ -100,3 +100,49 @@ test('metricDaysToExpiry', () => { renderingProperties: expect.anything(), }); }); + +describe('Key Algorithm', () => { + test('key algorithm is undefined if not provided', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: Match.absent(), + }); + }); + + test('Can specify algorithm', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + keyAlgorithm: KeyAlgorithm.EC_SECP384R1, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: 'EC_secp384r1', + }); + }); + + test('Can specify any arbitrary algorithm', () => { + const stack = new Stack(); + + new PrivateCertificate(stack, 'Certificate', { + domainName: 'test.example.com', + certificateAuthority: acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'CA', + 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/023077d8-2bfa-4eb0-8f22-05c96deade77'), + keyAlgorithm: new KeyAlgorithm('any value'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::CertificateManager::Certificate', { + KeyAlgorithm: 'any value', + }); + }); +});