From cf6d63461d266b9310551f89fe9edacf0f2c2984 Mon Sep 17 00:00:00 2001 From: Naumel <104374999+Naumel@users.noreply.github.com> Date: Mon, 20 Mar 2023 10:47:02 +0100 Subject: [PATCH 1/9] chore: Minor updates for the used deployment methods (#24649) > [CONTRIBUTING GUIDE]: https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md > [DESIGN GUIDELINES]: https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md This work is tangential to code I am editing, splitting the function from non-functional changes. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk/lib/cdk-toolkit.ts | 22 +++++++++------------- packages/aws-cdk/lib/cli.ts | 14 ++++++++++---- packages/aws-cdk/lib/import.ts | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 012da02865bfb..e2b11284c54c8 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -86,7 +86,7 @@ export enum AssetBuildTime { * Build assets just-in-time, before publishing */ JUST_IN_TIME, -}; +} /** * Toolkit logic @@ -489,11 +489,7 @@ export class CdkToolkit { roleArn: options.roleArn, toolkitStackName: options.toolkitStackName, tags, - deploymentMethod: { - method: 'change-set', - changeSetName: options.changeSetName, - execute: options.execute, - }, + deploymentMethod: options.deploymentMethod, usePreviousParameters: true, progress: options.progress, rollback: options.rollback, @@ -612,16 +608,16 @@ export class CdkToolkit { /** * Bootstrap the CDK Toolkit stack in the accounts used by the specified stack(s). * - * @param environmentSpecs environment names that need to have toolkit support - * provisioned, as a glob filter. If none is provided, - * all stacks are implicitly selected. - * @param toolkitStackName the name to be used for the CDK Toolkit stack. + * @param userEnvironmentSpecs environment names that need to have toolkit support + * provisioned, as a glob filter. If none is provided, all stacks are implicitly selected. + * @param bootstrapper Legacy or modern. + * @param options The name, role ARN, bootstrapping parameters, etc. to be used for the CDK Toolkit stack. */ public async bootstrap(userEnvironmentSpecs: string[], bootstrapper: Bootstrapper, options: BootstrapEnvironmentOptions): Promise { // If there is an '--app' argument and an environment looks like a glob, we - // select the environments from the app. Otherwise use what the user said. + // select the environments from the app. Otherwise, use what the user said. - // By default glob for everything + // By default, glob for everything const environmentSpecs = userEnvironmentSpecs.length > 0 ? [...userEnvironmentSpecs] : ['**']; // Partition into globs and non-globs (this will mutate environmentSpecs). @@ -1085,7 +1081,7 @@ export interface ImportOptions extends CfnDeployOptions { readonly recordResourceMapping?: string; /** - * Path to a file with with the physical resource mapping to CDK constructs in JSON format + * Path to a file with the physical resource mapping to CDK constructs in JSON format * * @default - No mapping file */ diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 0715386fdf3b7..3b8761490aabd 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -470,7 +470,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise Date: Mon, 20 Mar 2023 10:26:49 +0000 Subject: [PATCH 2/9] docs(cfnspec): update CloudFormation documentation (#24694) --- .../spec-source/cfn-docs/cfn-docs.json | 223 ++++++++++++++---- 1 file changed, 181 insertions(+), 42 deletions(-) diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json index f5f9f8aa37cdc..6f25a36973931 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json @@ -5487,6 +5487,20 @@ "WorkGroupConfiguration": "The configuration of the workgroup, which includes the location in Amazon S3 where query results are stored, the encryption option, if any, used for query results, whether Amazon CloudWatch Metrics are enabled for the workgroup, and the limit for the amount of bytes scanned (cutoff) per query, if it is specified. The `EnforceWorkGroupConfiguration` option determines whether workgroup settings override client-side query settings." } }, + "AWS::Athena::WorkGroup.AclConfiguration": { + "attributes": {}, + "description": "Indicates that an Amazon S3 canned ACL should be set to control ownership of stored query results. When Athena stores query results in Amazon S3, the canned ACL is set with the `x-amz-acl` request header. For more information about S3 Object Ownership, see [Object Ownership settings](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html#object-ownership-overview) in the *Amazon S3 User Guide* .", + "properties": { + "S3AclOption": "The Amazon S3 canned ACL that Athena should specify when storing query results. Currently the only supported canned ACL is `BUCKET_OWNER_FULL_CONTROL` . If a query runs in a workgroup and the workgroup overrides client-side settings, then the Amazon S3 canned ACL specified in the workgroup's settings is used for all queries that run in the workgroup. For more information about Amazon S3 canned ACLs, see [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) in the *Amazon S3 User Guide* ." + } + }, + "AWS::Athena::WorkGroup.CustomerContentEncryptionConfiguration": { + "attributes": {}, + "description": "Specifies the KMS key that is used to encrypt the user's data stores in Athena.", + "properties": { + "KmsKey": "The KMS key that is used to encrypt the user's data stores in Athena." + } + }, "AWS::Athena::WorkGroup.EncryptionConfiguration": { "attributes": {}, "description": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE_KMS` or `CSE_KMS` ) and key information.", @@ -5507,7 +5521,9 @@ "attributes": {}, "description": "The location in Amazon S3 where query and calculation results are stored and the encryption option, if any, used for query and calculation results. These are known as \"client-side settings\". If workgroup settings override client-side settings, then the query uses the workgroup settings.", "properties": { + "AclConfiguration": "Indicates that an Amazon S3 canned ACL should be set to control ownership of stored query results. Currently the only supported canned ACL is `BUCKET_OWNER_FULL_CONTROL` . This is a client-side setting. If workgroup settings override client-side settings, then the query uses the ACL configuration that is specified for the workgroup, and also uses the location for storing query results specified in the workgroup. For more information, see `WorkGroupConfiguration$EnforceWorkGroupConfiguration` and [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", "EncryptionConfiguration": "If query results are encrypted in Amazon S3, indicates the encryption option used (for example, `SSE_KMS` or `CSE_KMS` ) and key information. This is a client-side setting. If workgroup settings override client-side settings, then the query uses the encryption configuration that is specified for the workgroup, and also uses the location for storing query results specified in the workgroup. See `EnforceWorkGroupConfiguration` and [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", + "ExpectedBucketOwner": "The AWS account ID that you expect to be the owner of the Amazon S3 bucket specified by `ResultConfiguration$OutputLocation` . If set, Athena uses the value for `ExpectedBucketOwner` when it makes Amazon S3 calls to your specified output location. If the `ExpectedBucketOwner` AWS account ID does not match the actual owner of the Amazon S3 bucket, the call fails with a permissions error.\n\nThis is a client-side setting. If workgroup settings override client-side settings, then the query uses the `ExpectedBucketOwner` setting that is specified for the workgroup, and also uses the location for storing query results specified in the workgroup. See `WorkGroupConfiguration$EnforceWorkGroupConfiguration` and [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", "OutputLocation": "The location in Amazon S3 where your query results are stored, such as `s3://path/to/query/bucket/` . To run a query, you must specify the query results location using either a client-side setting for individual queries or a location specified by the workgroup. If workgroup settings override client-side settings, then the query uses the location specified for the workgroup. If no query location is set, Athena issues an error. For more information, see [Working with Query Results, Output Files, and Query History](https://docs.aws.amazon.com/athena/latest/ug/querying.html) and `EnforceWorkGroupConfiguration` ." } }, @@ -5515,9 +5531,12 @@ "attributes": {}, "description": "The configuration of the workgroup, which includes the location in Amazon S3 where query results are stored, the encryption option, if any, used for query results, whether Amazon CloudWatch Metrics are enabled for the workgroup, and the limit for the amount of bytes scanned (cutoff) per query, if it is specified. The `EnforceWorkGroupConfiguration` option determines whether workgroup settings override client-side query settings.", "properties": { + "AdditionalConfiguration": "Specifies a user defined JSON string that is passed to the notebook engine.", "BytesScannedCutoffPerQuery": "The upper limit (cutoff) for the amount of bytes a single query in a workgroup is allowed to scan. No default is defined.\n\n> This property currently supports integer types. Support for long values is planned.", + "CustomerContentEncryptionConfiguration": "Specifies the KMS key that is used to encrypt the user's data stores in Athena.", "EnforceWorkGroupConfiguration": "If set to \"true\", the settings for the workgroup override client-side settings. If set to \"false\", client-side settings are used. For more information, see [Workgroup Settings Override Client-Side Settings](https://docs.aws.amazon.com/athena/latest/ug/workgroups-settings-override.html) .", "EngineVersion": "The engine version that all queries running on the workgroup use. Queries on the `AmazonAthenaPreviewFunctionality` workgroup run on the preview engine regardless of this setting.", + "ExecutionRole": "Role used in a session for accessing the user's resources.", "PublishCloudWatchMetricsEnabled": "Indicates that the Amazon CloudWatch metrics are enabled for the workgroup.", "RequesterPaysEnabled": "If set to `true` , allows members assigned to a workgroup to reference Amazon S3 Requester Pays buckets in queries. If set to `false` , workgroup members cannot query data from Requester Pays buckets, and queries that retrieve data from Requester Pays buckets cause an error. The default is `false` . For more information about Requester Pays buckets, see [Requester Pays Buckets](https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html) in the *Amazon Simple Storage Service Developer Guide* .", "ResultConfiguration": "Specifies the location in Amazon S3 where query results are stored and the encryption option, if any, used for query results. For more information, see [Working with Query Results, Output Files, and Query History](https://docs.aws.amazon.com/athena/latest/ug/querying.html) ." @@ -7377,6 +7396,24 @@ "ValidationDomain": "The domain name to which you want ACM to send validation emails. This domain name is the suffix of the email addresses that you want ACM to use. This must be the same as the `DomainName` value or a superdomain of the `DomainName` value. For example, if you request a certificate for `testing.example.com` , you can specify `example.com` as this value. In that case, ACM sends domain validation emails to the following five addresses:\n\n- admin@example.com\n- administrator@example.com\n- hostmaster@example.com\n- postmaster@example.com\n- webmaster@example.com" } }, + "AWS::Chatbot::MicrosoftTeamsChannelConfiguration": { + "attributes": { + "Arn": "", + "Ref": "When you pass the logical ID of this resource to the intrinsic Ref function, Ref returns the ARN of the configuration created." + }, + "description": "The `AWS::Chatbot::MicrosoftTeamsChannelConfiguration` resource configures a Microsoft Teams channel to allow users to use AWS Chatbot with AWS CloudFormation templates.\n\nThis resource requires some setup to be done in the AWS Chatbot console. To provide the required Microsoft Teams team and tenant IDs, you must perform the initial authorization flow with Microsoft Teams in the AWS Chatbot console, then copy and paste the IDs from the console. For more details, see steps 1-4 in [Setting Up AWS Chatbot with Microsoft Teams](https://docs.aws.amazon.com/chatbot/latest/adminguide/teams-setup.html#teams-client-setup) in the *AWS Chatbot Administrator Guide* .", + "properties": { + "ConfigurationName": "The name of the configuration.", + "GuardrailPolicies": "The list of IAM policy ARNs that are applied as channel guardrails. The AWS managed 'AdministratorAccess' policy is applied as a default if this is not set.", + "IamRoleArn": "The ARN of the IAM role that defines the permissions for AWS Chatbot .\n\nThis is a user-defined role that AWS Chatbot will assume. This is not the service-linked role. For more information, see [IAM Policies for AWS Chatbot](https://docs.aws.amazon.com/chatbot/latest/adminguide/chatbot-iam-policies.html) .", + "LoggingLevel": "Specifies the logging level for this configuration. This property affects the log entries pushed to Amazon CloudWatch Logs.\n\nLogging levels include `ERROR` , `INFO` , or `NONE` .", + "SnsTopicArns": "The ARNs of the SNS topics that deliver notifications to AWS Chatbot .", + "TeamId": "The ID of the Microsoft Team authorized with AWS Chatbot .\n\nTo get the team ID, you must perform the initial authorization flow with Microsoft Teams in the AWS Chatbot console. Then you can copy and paste the team ID from the console. For more details, see steps 1-4 in [Get started with Microsoft Teams](https://docs.aws.amazon.com/chatbot/latest/adminguide/teams-setup.html#teams-client-setup) in the *AWS Chatbot Administrator Guide* .", + "TeamsChannelId": "The ID of the Microsoft Teams channel.\n\nTo get the channel ID, open Microsoft Teams, right click on the channel name in the left pane, then choose Copy. An example of the channel ID syntax is: `19%3ab6ef35dc342d56ba5654e6fc6d25a071%40thread.tacv2` .", + "TeamsTenantId": "The ID of the Microsoft Teams tenant.\n\nTo get the tenant ID, you must perform the initial authorization flow with Microsoft Teams in the AWS Chatbot console. Then you can copy and paste the tenant ID from the console. For more details, see steps 1-4 in [Get started with Microsoft Teams](https://docs.aws.amazon.com/chatbot/latest/adminguide/teams-setup.html#teams-client-setup) in the *AWS Chatbot Administrator Guide* .", + "UserRoleRequired": "Enables use of a user role requirement in your chat configuration." + } + }, "AWS::Chatbot::SlackChannelConfiguration": { "attributes": { "Arn": "", @@ -10440,6 +10477,13 @@ "EntityTypes": "Up to 25 entity types that the model is trained to recognize." } }, + "AWS::Comprehend::Flywheel.EntityTypesListItem": { + "attributes": {}, + "description": "An entity type within a labeled training dataset that Amazon Comprehend uses to train a custom entity recognizer.", + "properties": { + "Type": "An entity type within a labeled training dataset that Amazon Comprehend uses to train a custom entity recognizer.\n\nEntity types must not contain the following invalid characters: \\n (line break), \\\\n (escaped line break, \\r (carriage return), \\\\r (escaped carriage return), \\t (tab), \\\\t (escaped tab), space, and , (comma)." + } + }, "AWS::Comprehend::Flywheel.TaskConfig": { "attributes": {}, "description": "Configuration about the custom classifier associated with the flywheel.", @@ -14610,14 +14654,14 @@ }, "AWS::EC2::IPAMResourceDiscoveryAssociation": { "attributes": { - "IpamArn": "", - "IpamRegion": "", + "IpamArn": "The IPAM ARN.", + "IpamRegion": "The IPAM home Region.", "IpamResourceDiscoveryAssociationArn": "The resource discovery association ARN.", "IpamResourceDiscoveryAssociationId": "The resource discovery association ID.", "IsDefault": "Defines if the resource discovery is the default. When you create an IPAM, a default resource discovery is created for your IPAM and it's associated with your IPAM.", "OwnerId": "The owner ID.", "Ref": "`Ref` returns the resource discovery ID. For example: `ipam-res-disco-111122223333` .", - "ResourceDiscoveryStatus": "", + "ResourceDiscoveryStatus": "The resource discovery status.\n\n- `active` - Connection or permissions required to read the results of the resource discovery are intact.\n- `not-found` - Connection or permissions required to read the results of the resource discovery are broken. This may happen if the owner of the resource discovery stopped sharing it or deleted the resource discovery. Verify the resource discovery still exists and the AWS RAM resource share is still intact.", "State": "The lifecycle state of the association when you associate or disassociate a resource discovery.\n\n- `associate-in-progress` - Resource discovery is being associated.\n- `associate-complete` - Resource discovery association is complete.\n- `associate-failed` - Resource discovery association has failed.\n- `disassociate-in-progress` - Resource discovery is being disassociated.\n- `disassociate-complete` - Resource discovery disassociation is complete.\n- `disassociate-failed` - Resource discovery disassociation has failed.\n- `isolate-in-progress` - AWS account that created the resource discovery association has been removed and the resource discovery associatation is being isolated.\n- `isolate-complete` - Resource discovery isolation is complete..\n- `restore-in-progress` - Resource discovery is being restored." }, "description": "An IPAM resource discovery association. An associated resource discovery is a resource discovery that has been associated with an IPAM. IPAM aggregates the resource CIDRs discovered by the associated resource discovery.", @@ -16675,7 +16719,6 @@ }, "AWS::EC2::VPCDHCPOptionsAssociation": { "attributes": { - "Id": "The ID of the DHCP options set.", "Ref": "`Ref` returns the ID of the DHCP options association." }, "description": "Associates a set of DHCP options with a VPC, or associates no DHCP options with the VPC.\n\nAfter you associate the options with the VPC, any existing instances and all new instances that you launch in that VPC use the options. You don't need to restart or relaunch the instances. They automatically pick up the changes within a few hours, depending on how frequently the instance renews its DHCP lease. You can explicitly renew the lease using the operating system on the instance.", @@ -16688,6 +16731,7 @@ "attributes": { "CreationTimestamp": "The date and time the VPC endpoint was created. For example: `Fri Sep 28 23:34:36 UTC 2018.`", "DnsEntries": "(Interface endpoints) The DNS entries for the endpoint. Each entry is a combination of the hosted zone ID and the DNS name. The entries are ordered as follows: regional public DNS, zonal public DNS, private DNS, and wildcard DNS. This order is not enforced for AWS Marketplace services.\n\nThe following is an example. In the first entry, the hosted zone ID is Z1HUB23UULQXV and the DNS name is vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com.\n\n[\"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3.ec2.us-east-1.vpce.amazonaws.com\", \"Z1HUB23UULQXV:vpce-01abc23456de78f9g-12abccd3-us-east-1a.ec2.us-east-1.vpce.amazonaws.com\", \"Z1C12344VYDITB0:ec2.us-east-1.amazonaws.com\"]\n\nIf you update the `PrivateDnsEnabled` or `SubnetIds` properties, the DNS entries in the list will change.", + "Id": "The ID of the VPC endpoint.", "NetworkInterfaceIds": "(Interface endpoints) The network interface IDs. If you update the `PrivateDnsEnabled` or `SubnetIds` properties, the items in this list might change.", "Ref": "`Ref` returns the ID of the VPC endpoint." }, @@ -35998,10 +36042,7 @@ "AWS::MediaPackage::PackagingConfiguration.EncryptionContractConfiguration": { "attributes": {}, "description": "Use `encryptionContractConfiguration` to configure one or more content encryption keys for your endpoints that use SPEKE Version 2.0. The encryption contract defines the content keys used to encrypt the audio and video tracks in your stream. To configure the encryption contract, specify which audio and video encryption presets to use. For more information about these presets, see [SPEKE Version 2.0 Presets](https://docs.aws.amazon.com/mediapackage/latest/ug/drm-content-speke-v2-presets.html) .\n\nNote the following considerations when using `encryptionContractConfiguration` :\n\n- You can use `encryptionContractConfiguration` for DASH endpoints that use SPEKE Version 2.0. SPEKE Version 2.0 relies on the CPIX Version 2.3 specification.\n- You cannot combine an `UNENCRYPTED` preset with `UNENCRYPTED` or `SHARED` presets across `presetSpeke20Audio` and `presetSpeke20Video` .\n- When you use a `SHARED` preset, you must use it for both `presetSpeke20Audio` and `presetSpeke20Video` .", - "properties": { - "PresetSpeke20Audio": "A collection of audio encryption presets.\n\nValue description:\n\n- `PRESET-AUDIO-1` - Use one content key to encrypt all of the audio tracks in your stream.\n- `PRESET-AUDIO-2` - Use one content key to encrypt all of the stereo audio tracks and one content key to encrypt all of the multichannel audio tracks.\n- `PRESET-AUDIO-3` - Use one content key to encrypt all of the stereo audio tracks, one content key to encrypt all of the multichannel audio tracks with 3 to 6 channels, and one content key to encrypt all of the multichannel audio tracks with more than 6 channels.\n- `SHARED` - Use the same content key for all of the audio and video tracks in your stream.\n- `UNENCRYPTED` - Don't encrypt any of the audio tracks in your stream.", - "PresetSpeke20Video": "A collection of video encryption presets.\n\nValue description:\n\n- `PRESET-VIDEO-1` - Use one content key to encrypt all of the video tracks in your stream.\n- `PRESET-VIDEO-2` - Use one content key to encrypt all of the SD video tracks and one content key for all HD and higher resolutions video tracks.\n- `PRESET-VIDEO-3` - Use one content key to encrypt all of the SD video tracks, one content key for HD video tracks and one content key for all UHD video tracks.\n- `PRESET-VIDEO-4` - Use one content key to encrypt all of the SD video tracks, one content key for HD video tracks, one content key for all UHD1 video tracks and one content key for all UHD2 video tracks.\n- `PRESET-VIDEO-5` - Use one content key to encrypt all of the SD video tracks, one content key for HD1 video tracks, one content key for HD2 video tracks, one content key for all UHD1 video tracks and one content key for all UHD2 video tracks.\n- `PRESET-VIDEO-6` - Use one content key to encrypt all of the SD video tracks, one content key for HD1 video tracks, one content key for HD2 video tracks and one content key for all UHD video tracks.\n- `PRESET-VIDEO-7` - Use one content key to encrypt all of the SD+HD1 video tracks, one content key for HD2 video tracks and one content key for all UHD video tracks.\n- `PRESET-VIDEO-8` - Use one content key to encrypt all of the SD+HD1 video tracks, one content key for HD2 video tracks, one content key for all UHD1 video tracks and one content key for all UHD2 video tracks.\n- `SHARED` - Use the same content key for all of the video and audio tracks in your stream.\n- `UNENCRYPTED` - Don't encrypt any of the video tracks in your stream." - } + "properties": {} }, "AWS::MediaPackage::PackagingConfiguration.HlsEncryption": { "attributes": {}, @@ -41562,6 +41603,7 @@ }, "AWS::RUM::AppMonitor": { "attributes": { + "Id": "The ID of the app monitor, such as `123456ab-1234-4ca9-9d2f-a1b2c3456789` .", "Ref": "`Ref` returns the name of the app monitor." }, "description": "Creates a CloudWatch RUM app monitor, which you can use to collect telemetry data from your application and send it to CloudWatch RUM. The data includes performance and reliability information such as page load time, client-side errors, and user behavior.\n\nAfter you create an app monitor, sign in to the CloudWatch RUM console to get the JavaScript code snippet to add to your web application. For more information, see [How do I find a code snippet that I've already generated?](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-RUM-find-code-snippet.html)", @@ -42550,14 +42592,14 @@ "AWS::RolesAnywhere::CRL": { "attributes": { "CrlId": "The unique primary identifier of the Crl", - "Ref": "`Ref` returns `CrlId` ." + "Ref": "The name of the CRL." }, - "description": "Imports the certificate revocation list (CRL). A CRL is a list of certificates that have been revoked by the issuing certificate Authority (CA). IAM Roles Anywhere validates against the CRL before issuing credentials.\n\n*Required permissions:* `rolesanywhere:ImportCrl` .", + "description": "Creates a Crl.", "properties": { - "CrlData": "The x509 v3 specified certificate revocation list (CRL).", - "Enabled": "Specifies whether the certificate revocation list (CRL) is enabled.", - "Name": "The name of the certificate revocation list (CRL).", - "Tags": "A list of tags to attach to the certificate revocation list (CRL).", + "CrlData": "x509 v3 Certificate Revocation List to revoke auth for corresponding certificates presented in CreateSession operations", + "Enabled": "The enabled status of the resource.", + "Name": "The customer specified name of the resource.", + "Tags": "A list of Tags.", "TrustAnchorArn": "The ARN of the TrustAnchor the certificate revocation list (CRL) will provide revocation for." } }, @@ -42565,18 +42607,18 @@ "attributes": { "ProfileArn": "The ARN of the profile.", "ProfileId": "The unique primary identifier of the Profile", - "Ref": "`Ref` returns `ProfileId` ." + "Ref": "The name of the Profile" }, - "description": "Creates a *profile* , a list of the roles that Roles Anywhere service is trusted to assume. You use profiles to intersect permissions with IAM managed policies.\n\n*Required permissions:* `rolesanywhere:CreateProfile` .", + "description": "Creates a Profile.", "properties": { - "DurationSeconds": "Sets the maximum number of seconds that vended temporary credentials through [CreateSession](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/authentication-create-session.html) will be valid for, between 900 and 3600.", - "Enabled": "Indicates whether the profile is enabled.", - "ManagedPolicyArns": "A list of managed policy ARNs that apply to the vended session credentials.", - "Name": "The name of the profile.", - "RequireInstanceProperties": "Specifies whether instance properties are required in temporary credential requests with this profile.", - "RoleArns": "A list of IAM role ARNs. During `CreateSession` , if a matching role ARN is provided, the properties in this profile will be applied to the intersection session policy.", - "SessionPolicy": "A session policy that applies to the trust boundary of the vended session credentials.", - "Tags": "The tags to attach to the profile." + "DurationSeconds": "The number of seconds vended session credentials will be valid for", + "Enabled": "The enabled status of the resource.", + "ManagedPolicyArns": "A list of managed policy ARNs. Managed policies identified by this list will be applied to the vended session credentials.", + "Name": "The customer specified name of the resource.", + "RequireInstanceProperties": "Specifies whether instance properties are required in CreateSession requests with this profile.", + "RoleArns": "A list of IAM role ARNs that can be assumed when this profile is specified in a CreateSession request.", + "SessionPolicy": "A session policy that will applied to the trust boundary of the vended session credentials.", + "Tags": "A list of Tags." } }, "AWS::RolesAnywhere::TrustAnchor": { @@ -42585,7 +42627,7 @@ "TrustAnchorArn": "The ARN of the trust anchor.", "TrustAnchorId": "The unique identifier of the trust anchor." }, - "description": "Creates a trust anchor to establish trust between IAM Roles Anywhere and your certificate authority (CA). You can define a trust anchor as a reference to an AWS Private Certificate Authority ( AWS Private CA ) or by uploading a CA certificate. Your AWS workloads can authenticate with the trust anchor using certificates issued by the CA in exchange for temporary AWS credentials.\n\n*Required permissions:* `rolesanywhere:CreateTrustAnchor` .", + "description": "Creates a TrustAnchor.", "properties": { "Enabled": "Indicates whether the trust anchor is enabled.", "Name": "The name of the trust anchor.", @@ -42595,15 +42637,15 @@ }, "AWS::RolesAnywhere::TrustAnchor.Source": { "attributes": {}, - "description": "The trust anchor type and its related certificate data.", + "description": "Object representing the TrustAnchor type and its related certificate data.", "properties": { - "SourceData": "The data field of the trust anchor depending on its type.", - "SourceType": "The type of the TrustAnchor.\n\n> `AWS_ACM_PCA` is not an allowed value in your region." + "SourceData": "A union object representing the data field of the TrustAnchor depending on its type", + "SourceType": "The type of the TrustAnchor." } }, "AWS::RolesAnywhere::TrustAnchor.SourceData": { "attributes": {}, - "description": "The data field of the trust anchor depending on its type.", + "description": "A union object representing the data field of the TrustAnchor depending on its type", "properties": { "AcmPcaArn": "The root certificate of the AWS Private Certificate Authority specified by this ARN is used in trust validation for temporary credential requests. Included for trust anchors of type `AWS_ACM_PCA` .\n\n> This field is not supported in your region.", "X509CertificateData": "The PEM-encoded data for the certificate anchor. Included for trust anchors of type `CERTIFICATE_BUNDLE` ." @@ -43148,6 +43190,8 @@ "HostVPCId": "The ID of the VPC that you want to create the resolver endpoint in.", "IpAddressCount": "The number of IP addresses that the resolver endpoint can use for DNS queries.", "Name": "The name that you assigned to the resolver endpoint when you created the endpoint.", + "OutpostArn": "", + "PreferredInstanceType": "", "Ref": "`Ref` returns the `ResolverEndpoint` object.", "ResolverEndpointId": "The ID of the resolver endpoint.", "ResolverEndpointType": "" @@ -43157,6 +43201,8 @@ "Direction": "Indicates whether the Resolver endpoint allows inbound or outbound DNS queries:\n\n- `INBOUND` : allows DNS queries to your VPC from your network\n- `OUTBOUND` : allows DNS queries from your VPC to your network", "IpAddresses": "The subnets and IP addresses in your VPC that DNS queries originate from (for outbound endpoints) or that you forward DNS queries to (for inbound endpoints). The subnet ID uniquely identifies a VPC.", "Name": "A friendly name that lets you easily find a configuration in the Resolver dashboard in the Route 53 console.", + "OutpostArn": "", + "PreferredInstanceType": "", "ResolverEndpointType": "The Resolver endpoint IP address type.", "SecurityGroupIds": "The ID of one or more security groups that control access to this VPC. The security group must include one or more inbound rules (for inbound endpoints) or outbound rules (for outbound endpoints). Inbound and outbound rules must allow TCP and UDP access. For inbound access, open port 53. For outbound access, open the port that you're using for DNS queries on your network.", "Tags": "Route 53 Resolver doesn't support updating tags through CloudFormation." @@ -44026,9 +44072,6 @@ }, "AWS::S3ObjectLambda::AccessPoint": { "attributes": { - "Alias": "", - "Alias.Status": "", - "Alias.Value": "", "Arn": "Specifies the ARN for the Object Lambda Access Point.", "CreationDate": "The date and time when the specified Object Lambda Access Point was created.", "PolicyStatus": "", @@ -44046,14 +44089,6 @@ "ObjectLambdaConfiguration": "A configuration used when creating an Object Lambda Access Point." } }, - "AWS::S3ObjectLambda::AccessPoint.Alias": { - "attributes": {}, - "description": "", - "properties": { - "Status": "", - "Value": "" - } - }, "AWS::S3ObjectLambda::AccessPoint.AwsLambda": { "attributes": {}, "description": "", @@ -46120,6 +46155,110 @@ "ImageName": "The name of the parent image.\n\n*Length Constraints* : Minimum length of 1. Maximum length of 63.\n\n*Pattern* : `^[a-zA-Z0-9]([-.]?[a-zA-Z0-9]){0,62}$`" } }, + "AWS::SageMaker::InferenceExperiment": { + "attributes": { + "Arn": "", + "CreationTime": "", + "EndpointMetadata": "", + "EndpointMetadata.EndpointConfigName": "", + "EndpointMetadata.EndpointName": "", + "EndpointMetadata.EndpointStatus": "", + "LastModifiedTime": "", + "Ref": "", + "Status": "" + }, + "description": "Creates an inference experiment using the configurations specified in the request.\n\nUse this API to setup and schedule an experiment to compare model variants on a Amazon SageMaker inference endpoint. For more information about inference experiments, see [Shadow tests](https://docs.aws.amazon.com/sagemaker/latest/dg/shadow-tests.html) .\n\nAmazon SageMaker begins your experiment at the scheduled time and routes traffic to your endpoint's model variants based on your specified configuration.\n\nWhile the experiment is in progress or after it has concluded, you can view metrics that compare your model variants. For more information, see [View, monitor, and edit shadow tests](https://docs.aws.amazon.com/sagemaker/latest/dg/shadow-tests-view-monitor-edit.html) .", + "properties": { + "DataStorageConfig": "", + "Description": "The description of the inference experiment.", + "DesiredState": "", + "EndpointName": "", + "KmsKey": "The AWS Key Management Service key that Amazon SageMaker uses to encrypt captured data at rest using Amazon S3 server-side encryption.", + "ModelVariants": "", + "Name": "The name of the inference experiment.", + "RoleArn": "The ARN of the IAM role that Amazon SageMaker can assume to access model artifacts and container images, and manage Amazon SageMaker Inference endpoints for model deployment.", + "Schedule": "The duration for which the inference experiment ran or will run.\n\nThe maximum duration that you can set for an inference experiment is 30 days.", + "ShadowModeConfig": "", + "StatusReason": "The error message for the inference experiment status result.", + "Tags": "", + "Type": "The type of the inference experiment." + } + }, + "AWS::SageMaker::InferenceExperiment.CaptureContentTypeHeader": { + "attributes": {}, + "description": "Configuration specifying how to treat different headers. If no headers are specified SageMaker will by default base64 encode when capturing the data.", + "properties": { + "CsvContentTypes": "The list of all content type headers that SageMaker will treat as CSV and capture accordingly.", + "JsonContentTypes": "The list of all content type headers that SageMaker will treat as JSON and capture accordingly." + } + }, + "AWS::SageMaker::InferenceExperiment.DataStorageConfig": { + "attributes": {}, + "description": "", + "properties": { + "ContentType": "", + "Destination": "", + "KmsKey": "" + } + }, + "AWS::SageMaker::InferenceExperiment.EndpointMetadata": { + "attributes": {}, + "description": "The metadata of the endpoint.", + "properties": { + "EndpointConfigName": "The name of the endpoint configuration.", + "EndpointName": "The name of the endpoint.", + "EndpointStatus": "The status of the endpoint. For possible values of the status of an endpoint, see `EndpointSummary$EndpointStatus` ." + } + }, + "AWS::SageMaker::InferenceExperiment.InferenceExperimentSchedule": { + "attributes": {}, + "description": "The start and end times of an inference experiment.\n\nThe maximum duration that you can set for an inference experiment is 30 days.", + "properties": { + "EndTime": "The timestamp at which the inference experiment ended or will end.", + "StartTime": "The timestamp at which the inference experiment started or will start." + } + }, + "AWS::SageMaker::InferenceExperiment.ModelInfrastructureConfig": { + "attributes": {}, + "description": "The configuration for the infrastructure that the model will be deployed to.", + "properties": { + "InfrastructureType": "The inference option to which to deploy your model. Possible values are the following:\n\n- `RealTime` : Deploy to real-time inference.", + "RealTimeInferenceConfig": "The infrastructure configuration for deploying the model to real-time inference." + } + }, + "AWS::SageMaker::InferenceExperiment.ModelVariantConfig": { + "attributes": {}, + "description": "Contains information about the deployment options of a model.", + "properties": { + "InfrastructureConfig": "The configuration for the infrastructure that the model will be deployed to.", + "ModelName": "The name of the Amazon SageMaker Model entity.", + "VariantName": "The name of the variant." + } + }, + "AWS::SageMaker::InferenceExperiment.RealTimeInferenceConfig": { + "attributes": {}, + "description": "The infrastructure configuration for deploying the model to a real-time inference endpoint.", + "properties": { + "InstanceCount": "The number of instances of the type specified by `InstanceType` .", + "InstanceType": "The instance type the model is deployed to." + } + }, + "AWS::SageMaker::InferenceExperiment.ShadowModeConfig": { + "attributes": {}, + "description": "The configuration of `ShadowMode` inference experiment type, which specifies a production variant to take all the inference requests, and a shadow variant to which Amazon SageMaker replicates a percentage of the inference requests. For the shadow variant it also specifies the percentage of requests that Amazon SageMaker replicates.", + "properties": { + "ShadowModelVariants": "List of shadow variant configurations.", + "SourceModelVariantName": "The name of the production variant, which takes all the inference requests." + } + }, + "AWS::SageMaker::InferenceExperiment.ShadowModelVariantConfig": { + "attributes": {}, + "description": "The name and sampling percentage of a shadow variant.", + "properties": { + "SamplingPercentage": "The percentage of inference requests that Amazon SageMaker replicates from the production variant to the shadow variant.", + "ShadowModelVariantName": "The name of the shadow variant." + } + }, "AWS::SageMaker::Model": { "attributes": { "ModelName": "The name of the model, such as `MyModel` .", @@ -47852,8 +47991,8 @@ "attributes": {}, "description": "Allows you to configure a time window during which EventBridge Scheduler invokes the schedule.", "properties": { - "MaximumWindowInMinutes": "The maximum time window during which a schedule can be invoked.", - "Mode": "Determines whether the schedule is invoked within a flexible time window." + "MaximumWindowInMinutes": "The maximum time window during which a schedule can be invoked.\n\n*Minimum* : `1`\n\n*Maximum* : `1440`", + "Mode": "Determines whether the schedule is invoked within a flexible time window.\n\n*Allowed Values* : `OFF` | `FLEXIBLE`" } }, "AWS::Scheduler::Schedule.KinesisParameters": { From cabff71139bf6a3b8ecd4cdf4a8dea093e67b8e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 11:35:39 +0000 Subject: [PATCH 3/9] chore(deps): bump hmarr/auto-approve-action from 3.2.0 to 3.2.1 (#24698) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [hmarr/auto-approve-action](https://github.com/hmarr/auto-approve-action) from 3.2.0 to 3.2.1.
Release notes

Sourced from hmarr/auto-approve-action's releases.

v3.2.1

What's Changed

Full Changelog: https://github.com/hmarr/auto-approve-action/compare/v3.2.0...v3.2.1

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hmarr/auto-approve-action&package-manager=github_actions&previous-version=3.2.0&new-version=3.2.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/auto-approve.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml index 1f596f1a62de4..1717e8fc6111f 100644 --- a/.github/workflows/auto-approve.yml +++ b/.github/workflows/auto-approve.yml @@ -12,6 +12,6 @@ jobs: permissions: pull-requests: write steps: - - uses: hmarr/auto-approve-action@v3.2.0 + - uses: hmarr/auto-approve-action@v3.2.1 with: github-token: "${{ secrets.GITHUB_TOKEN }}" From 9744a8295fab28f1e8c38a0b980935f7546990e6 Mon Sep 17 00:00:00 2001 From: Rico Hermans Date: Mon, 20 Mar 2023 14:41:30 +0100 Subject: [PATCH 4/9] feat(ec2): SSM sessions (#24673) It's not too hard to enable SSM Session Manager to Instances and AutoScalingGroups (it's a matter of picking the right AMI and adding the right managed policy to the instance role). This PR adds a single boolean to turn on the policy directly and advertises the feature in the README for people who might otherwise not know this feature exists. Also consistentize the use and explanation of `MachineImage.latestAmazonLinux` a bit. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-autoscaling/README.md | 54 ++++++++++++++--- .../aws-autoscaling/lib/auto-scaling-group.ts | 21 +++++++ .../test/auto-scaling-group.test.ts | 24 ++++++++ packages/@aws-cdk/aws-ec2/README.md | 59 +++++++++++++++---- packages/@aws-cdk/aws-ec2/lib/instance.ts | 21 +++++++ .../@aws-cdk/aws-ec2/lib/machine-image.ts | 14 +++++ .../@aws-cdk/aws-ec2/test/instance.test.ts | 23 ++++++++ 7 files changed, 198 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk/aws-autoscaling/README.md b/packages/@aws-cdk/aws-autoscaling/README.md index a9805d2a2c253..7efe26c2593e4 100644 --- a/packages/@aws-cdk/aws-autoscaling/README.md +++ b/packages/@aws-cdk/aws-autoscaling/README.md @@ -25,7 +25,11 @@ declare const vpc: ec2.Vpc; new autoscaling.AutoScalingGroup(this, 'ASG', { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO), - machineImage: new ec2.AmazonLinuxImage() // get the latest Amazon Linux image + + // The latest Amazon Linux image of a particular generation + machineImage: ec2.MachineImage.latestAmazonLinux({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + }), }); ``` @@ -41,7 +45,9 @@ const mySecurityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc }); new autoscaling.AutoScalingGroup(this, 'ASG', { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO), - machineImage: new ec2.AmazonLinuxImage(), + machineImage: ec2.MachineImage.latestAmazonLinux({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + }), securityGroup: mySecurityGroup, }); ``` @@ -538,6 +544,40 @@ new autoscaling.AutoScalingGroup(this, 'ASG', { }); ``` +## Connecting to your instances using SSM Session Manager + +SSM Session Manager makes it possible to connect to your instances from the +AWS Console, without preparing SSH keys. + +To do so, you need to: + +* Use an image with [SSM agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) installed + and configured. [Many images come with SSM Agent + preinstalled](https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html), otherwise you + may need to manually put instructions to [install SSM + Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-manual-agent-install.html) into your + instance's UserData or use EC2 Init). +* Create the AutoScalingGroup with `ssmSessionPermissions: true`. + +If these conditions are met, you can connect to the instance from the EC2 Console. Example: + +```ts +declare const vpc: ec2.Vpc; + +new autoscaling.AutoScalingGroup(this, 'ASG', { + vpc, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO), + + // Amazon Linux 2 comes with SSM Agent by default + machineImage: ec2.MachineImage.latestAmazonLinux({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + }), + + // Turn on SSM + ssmSessionPermissions: true, +}); +``` + ## Configuring Instance Metadata Service (IMDS) ### Toggling IMDSv1 @@ -596,13 +636,13 @@ autoScalingGroup.addWarmPool({ ### Default Instance Warming -You can use the default instance warmup feature to improve the Amazon CloudWatch metrics used for dynamic scaling. -When default instance warmup is not enabled, each instance starts contributing usage data to the aggregated metrics -as soon as the instance reaches the InService state. However, if you enable default instance warmup, this lets +You can use the default instance warmup feature to improve the Amazon CloudWatch metrics used for dynamic scaling. +When default instance warmup is not enabled, each instance starts contributing usage data to the aggregated metrics +as soon as the instance reaches the InService state. However, if you enable default instance warmup, this lets your instances finish warming up before they contribute the usage data. -To optimize the performance of scaling policies that scale continuously, such as target tracking and step scaling -policies, we strongly recommend that you enable the default instance warmup, even if its value is set to 0 seconds. +To optimize the performance of scaling policies that scale continuously, such as target tracking and step scaling +policies, we strongly recommend that you enable the default instance warmup, even if its value is set to 0 seconds. To set up Default Instance Warming for an autoscaling group, simply pass it in as a prop diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 9f229f5748f4e..36430ebda8cb9 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -365,6 +365,23 @@ export interface CommonAutoScalingGroupProps { * */ readonly capacityRebalance?: boolean; + + /** + * Add SSM session permissions to the instance role + * + * Setting this to `true` adds the necessary permissions to connect + * to the instance using SSM Session Manager. You can do this + * from the AWS Console. + * + * NOTE: Setting this flag to `true` may not be enough by itself. + * You must also use an AMI that comes with the SSM Agent, or install + * the SSM Agent yourself. See + * [Working with SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) + * in the SSM Developer Guide. + * + * @default false + */ + readonly ssmSessionPermissions?: boolean; } /** @@ -1278,6 +1295,10 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements this.grantPrincipal = this._role; + if (props.ssmSessionPermissions) { + this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')); + } + const iamProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', { roles: [this.role.roleName], }); diff --git a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts index 60e60e965b35d..0ea23a5bb5c29 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts @@ -2051,6 +2051,30 @@ test('add price-capacity-optimized', () => { }); }); +test('ssm permissions adds right managed policy', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new autoscaling.AutoScalingGroup(stack, 'mip-asg', { + vpc: mockVpc(stack), + machineImage: new AmazonLinuxImage(), + instanceType: InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.LARGE), + ssmSessionPermissions: true, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + ManagedPolicyArns: [ + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/AmazonSSMManagedInstanceCore', + ]], + }, + ], + }); +}); function mockSecurityGroup(stack: cdk.Stack) { return ec2.SecurityGroup.fromSecurityGroupId(stack, 'MySG', 'most-secure'); diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index 305d6bd7dbdaa..a1e2d5c85360d 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -788,7 +788,7 @@ AMIs control the OS that gets launched when you start your EC2 instance. The EC2 library contains constructs to select the AMI you want to use. Depending on the type of AMI, you select it a different way. Here are some -examples of things you might want to use: +examples of images you might want to use: [example of creating images](test/example.images.lit.ts) @@ -1039,27 +1039,27 @@ care of restarting your instance if it ever fails. declare const vpc: ec2.Vpc; declare const instanceType: ec2.InstanceType; -// AWS Linux +// Amazon Linux 1 new ec2.Instance(this, 'Instance1', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage(), + machineImage: ec2.MachineImage.latestAmazonLinux(), }); -// AWS Linux 2 +// Amazon Linux 2 new ec2.Instance(this, 'Instance2', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage({ + machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, }), }); -// AWS Linux 2 with kernel 5.x +// Amazon Linux 2 with kernel 5.x new ec2.Instance(this, 'Instance3', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage({ + machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, kernel: ec2.AmazonLinuxKernel.KERNEL5_X, }), @@ -1069,7 +1069,7 @@ new ec2.Instance(this, 'Instance3', { new ec2.Instance(this, 'Instance4', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage({ + machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2022, }), }); @@ -1078,7 +1078,7 @@ new ec2.Instance(this, 'Instance4', { new ec2.Instance(this, 'Instance5', { vpc, instanceType: ec2.InstanceType.of(ec2.InstanceClass.C7G, ec2.InstanceSize.LARGE), - machineImage: new ec2.AmazonLinuxImage({ + machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, cpuType: ec2.AmazonLinuxCpuType.ARM_64, }), @@ -1669,7 +1669,9 @@ The following demonstrates how to create a launch template with an Amazon Machin declare const vpc: ec2.Vpc; const template = new ec2.LaunchTemplate(this, 'LaunchTemplate', { - machineImage: ec2.MachineImage.latestAmazonLinux(), + machineImage: ec2.MachineImage.latestAmazonLinux({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + }), securityGroup: new ec2.SecurityGroup(this, 'LaunchTemplateSG', { vpc: vpc, }), @@ -1699,7 +1701,42 @@ declare const instanceType: ec2.InstanceType; new ec2.Instance(this, 'Instance1', { vpc, instanceType, - machineImage: new ec2.AmazonLinuxImage(), + machineImage: ec2.MachineImage.latestAmazonLinux(), detailedMonitoring: true, }); ``` + +## Connecting to your instances using SSM Session Manager + +SSM Session Manager makes it possible to connect to your instances from the +AWS Console, without preparing SSH keys. + +To do so, you need to: + +* Use an image with [SSM agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) installed + and configured. [Many images come with SSM Agent + preinstalled](https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html), otherwise you + may need to manually put instructions to [install SSM + Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-manual-agent-install.html) into your + instance's UserData or use EC2 Init). +* Create the instance with `ssmSessionPermissions: true`. + +If these conditions are met, you can connect to the instance from the EC2 Console. Example: + +```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; + +new ec2.Instance(this, 'Instance1', { + vpc, + instanceType, + + // Amazon Linux 2 comes with SSM Agent by default + machineImage: ec2.MachineImage.latestAmazonLinux({ + generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + }), + + // Turn on SSM + ssmSessionPermissions: true, +}); +``` diff --git a/packages/@aws-cdk/aws-ec2/lib/instance.ts b/packages/@aws-cdk/aws-ec2/lib/instance.ts index 4997f7dcbda3e..b02e62ecafdaa 100644 --- a/packages/@aws-cdk/aws-ec2/lib/instance.ts +++ b/packages/@aws-cdk/aws-ec2/lib/instance.ts @@ -254,6 +254,23 @@ export interface InstanceProps { * @default - false */ readonly detailedMonitoring?: boolean; + + /** + * Add SSM session permissions to the instance role + * + * Setting this to `true` adds the necessary permissions to connect + * to the instance using SSM Session Manager. You can do this + * from the AWS Console. + * + * NOTE: Setting this flag to `true` may not be enough by itself. + * You must also use an AMI that comes with the SSM Agent, or install + * the SSM Agent yourself. See + * [Working with SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) + * in the SSM Developer Guide. + * + * @default false + */ + readonly ssmSessionPermissions?: boolean; } /** @@ -342,6 +359,10 @@ export class Instance extends Resource implements IInstance { }); this.grantPrincipal = this.role; + if (props.ssmSessionPermissions) { + this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')); + } + const iamProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', { roles: [this.role.roleName], }); diff --git a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts index 4e1b87503004b..7d05353781b71 100644 --- a/packages/@aws-cdk/aws-ec2/lib/machine-image.ts +++ b/packages/@aws-cdk/aws-ec2/lib/machine-image.ts @@ -39,6 +39,20 @@ export abstract class MachineImage { * deployment. Be aware this will cause your instances to be replaced when a * new version of the image becomes available. Do not store stateful information * on the instance if you are using this image. + * + * N.B.: "latest" in the name of this function indicates that it always uses the most recent + * image of a particular generation of Amazon Linux, not that it uses the "latest generation". + * For backwards compatibility, this function uses Amazon Linux 1 if no generation + * is specified. + * + * Specify the desired generation using the `generation` property: + * + * ```ts + * ec2.MachineImage.latestAmazonLinux({ + * // Use Amazon Linux 2 + * generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, + * }) + * ``` */ public static latestAmazonLinux(props?: AmazonLinuxImageProps): IMachineImage { return new AmazonLinuxImage(props); diff --git a/packages/@aws-cdk/aws-ec2/test/instance.test.ts b/packages/@aws-cdk/aws-ec2/test/instance.test.ts index 9d91fc4fde8d2..ac64a7a6c78f5 100644 --- a/packages/@aws-cdk/aws-ec2/test/instance.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/instance.test.ts @@ -602,3 +602,26 @@ test('cause replacement from s3 asset in userdata', () => { }), })); }); + +test('ssm permissions adds right managed policy', () => { + // WHEN + new Instance(stack, 'InstanceOne', { + vpc, + machineImage: new AmazonLinuxImage(), + instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.LARGE), + ssmSessionPermissions: true, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + ManagedPolicyArns: [ + { + 'Fn::Join': ['', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':iam::aws:policy/AmazonSSMManagedInstanceCore', + ]], + }, + ], + }); +}); + From 3b7431b6ac27f8557c22a8959ae1ce431f6d2167 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Mon, 20 Mar 2023 18:21:09 +0100 Subject: [PATCH 5/9] fix(toolkit): RWLock.acquireRead is not re-entrant (#24702) If multiple threads of the same process attempt to acquire the same reader lock, the a race condition occurs, and the first thread to release the reader lock will release ALL the locks. Introduce a counter so that each acquire attempt uses a different file name, ensuring that the read lock is reentrant. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk/lib/api/util/rwlock.ts | 26 ++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/aws-cdk/lib/api/util/rwlock.ts b/packages/aws-cdk/lib/api/util/rwlock.ts index 6667bd17afe06..6fb0e4c945dfd 100644 --- a/packages/aws-cdk/lib/api/util/rwlock.ts +++ b/packages/aws-cdk/lib/api/util/rwlock.ts @@ -14,13 +14,12 @@ import * as path from 'path'; export class RWLock { private readonly pidString: string; private readonly writerFile: string; - private readonly readerFile: string; + private readCounter = 0; constructor(public readonly directory: string) { this.pidString = `${process.pid}`; this.writerFile = path.join(this.directory, 'synth.lock'); - this.readerFile = path.join(this.directory, `read.${this.pidString}.lock`); } /** @@ -62,14 +61,26 @@ export class RWLock { return this.doAcquireRead(); } + /** + * Obtains the name fo a (new) `readerFile` to use. This includes a counter so + * that if multiple threads of the same PID attempt to concurrently acquire + * the same lock, they're guaranteed to use a different reader file name (only + * one thread will ever execute JS code at once, guaranteeing the readCounter + * is incremented "atomically" from the point of view of this PID.). + */ + private readerFile(): string { + return path.join(this.directory, `read.${this.pidString}.${++this.readCounter}.lock`); + } + /** * Do the actual acquiring of a read lock. */ private async doAcquireRead(): Promise { - await writeFileAtomic(this.readerFile, this.pidString); + const readerFile = this.readerFile(); + await writeFileAtomic(readerFile, this.pidString); return { release: async () => { - await deleteFile(this.readerFile); + await deleteFile(readerFile); }, }; } @@ -102,7 +113,7 @@ export class RWLock { * Check the current readers (if any) */ private async currentReaders(): Promise { - const re = /^read\.([^.]+)\.lock$/; + const re = /^read\.([^.]+)\.[^.]+\.lock$/; const ret = new Array(); let children; @@ -156,9 +167,10 @@ async function readFileIfExists(filename: string): Promise { } } +let tmpCounter = 0; async function writeFileAtomic(filename: string, contents: string): Promise { await fs.mkdir(path.dirname(filename), { recursive: true }); - const tmpFile = `${filename}.${process.pid}`; + const tmpFile = `${filename}.${process.pid}_${++tmpCounter}`; await fs.writeFile(tmpFile, contents, { encoding: 'utf-8' }); await fs.rename(tmpFile, filename); } @@ -181,4 +193,4 @@ function processExists(pid: number) { } catch (e) { return false; } -} \ No newline at end of file +} From f3fe8e1c4348194f89b47a276e6c85328b1044fa Mon Sep 17 00:00:00 2001 From: Rico Hermans Date: Tue, 21 Mar 2023 10:53:05 +0100 Subject: [PATCH 6/9] feat(ec2): CFN-init support for systemd (#24683) CFN-init can be used to install software onto EC2 Instances that are created using CloudFormation. CFN init supports SystemD, but this was not yet available in CDK. This PR adds support for SystemD. It also adds a helper function to create a simple SystemD config files for your own services. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-ec2/README.md | 42 +++++ .../@aws-cdk/aws-ec2/lib/cfn-init-elements.ts | 138 +++++++++++++++- .../aws-ec2/test/cfn-init-element.test.ts | 45 ++++++ .../aws-elasticloadbalancing/package.json | 1 + ...efaultTestDeployAssertAF607556.assets.json | 2 +- ...-cdk-elb-instance-target-integ.assets.json | 6 +- ...dk-elb-instance-target-integ.template.json | 125 ++++++++++++++- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 30 ++-- .../tree.json | 147 ++++++++++++++---- .../test/integ.instanceTarget.elb.ts | 19 ++- 12 files changed, 494 insertions(+), 65 deletions(-) diff --git a/packages/@aws-cdk/aws-ec2/README.md b/packages/@aws-cdk/aws-ec2/README.md index a1e2d5c85360d..0640d3c63a2f4 100644 --- a/packages/@aws-cdk/aws-ec2/README.md +++ b/packages/@aws-cdk/aws-ec2/README.md @@ -1151,6 +1151,48 @@ new ec2.Instance(this, 'Instance', { }); ``` +`InitCommand` can not be used to start long-running processes. At deploy time, +`cfn-init` will always wait for the process to exit before continuing, causing +the CloudFormation deployment to fail because the signal hasn't been received +within the expected timeout. + +Instead, you should install a service configuration file onto your machine `InitFile`, +and then use `InitService` to start it. + +If your Linux OS is using SystemD (like Amazon Linux 2 or higher), the CDK has +helpers to create a long-running service using CFN Init. You can create a +SystemD-compatible config file using `InitService.systemdConfigFile()`, and +start it immediately. The following examples shows how to start a trivial Python +3 web server: + +```ts +declare const vpc: ec2.Vpc; +declare const instanceType: ec2.InstanceType; + +new ec2.Instance(this, 'Instance', { + vpc, + instanceType, + machineImage: ec2.MachineImage.latestAmazonLinux({ + // Amazon Linux 2 uses SystemD + generation: ec2.AmazonLinuxGeneration: AMAZON_LINUX_2, + }), + + init: ec2.CloudFormationInit.fromElements([ + // Create a simple config file that runs a Python web server + ec2.InitService.systemdConfigFile('simpleserver', { + command: '/usr/bin/python3 -m http.server 8080', + cwd: '/var/www/html', + }), + // Start the server using SystemD + ec2.InitService.enable('simpleserver', { + serviceManager: ec2.ServiceManager.SYSTEMD, + }), + // Drop an example file to show the web server working + ec2.InitFile.fromString('/var/www/html/index.html', 'Hello! It\'s working!'), + ]), +}); +``` + You can have services restarted after the init process has made changes to the system. To do that, instantiate an `InitServiceRestartHandle` and pass it to the config elements that need to trigger the restart and the service itself. For example, the following diff --git a/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts b/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts index 646d6b2dcbfa4..fb347ac20f5df 100644 --- a/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts +++ b/packages/@aws-cdk/aws-ec2/lib/cfn-init-elements.ts @@ -781,6 +781,16 @@ export interface InitServiceOptions { * @default - No files trigger restart */ readonly serviceRestartHandle?: InitServiceRestartHandle; + + /** + * What service manager to use + * + * This needs to match the actual service manager on your Operating System. + * For example, Amazon Linux 1 uses SysVinit, but Amazon Linux 2 uses Systemd. + * + * @default ServiceManager.SYSVINIT for Linux images, ServiceManager.WINDOWS for Windows images + */ + readonly serviceManager?: ServiceManager; } /** @@ -806,6 +816,39 @@ export class InitService extends InitElement { return new InitService(serviceName, { enabled: false, ensureRunning: false }); } + /** + * Install a systemd-compatible config file for the given service + * + * This is a helper function to create a simple systemd configuration + * file that will allow running a service on the machine using `InitService.enable()`. + * + * Systemd allows many configuration options; this function does not pretend + * to expose all of them. If you need advanced configuration options, you + * can use `InitFile` to create exactly the configuration file you need + * at `/etc/systemd/system/${serviceName}.service`. + */ + public static systemdConfigFile(serviceName: string, options: SystemdConfigFileOptions): InitFile { + if (!options.command.startsWith('/')) { + throw new Error(`SystemD executables must use an absolute path, got '${options.command}'`); + } + + const lines = [ + '[Unit]', + ...(options.description ? [`Description=${options.description}`] : []), + ...(options.afterNetwork ?? true ? ['After=network.target'] : []), + '[Service]', + `ExecStart=${options.command}`, + ...(options.cwd ? [`WorkingDirectory=${options.cwd}`] : []), + ...(options.user ? [`User=${options.user}`] : []), + ...(options.group ? [`Group=${options.user}`] : []), + ...(options.keepRunning ?? true ? ['Restart=always'] : []), + '[Install]', + 'WantedBy=multi-user.target', + ]; + + return InitFile.fromString(`/etc/systemd/system/${serviceName}.service`, lines.join('\n')); + } + public readonly elementType = InitElementType.SERVICE.toString(); private constructor(private readonly serviceName: string, private readonly serviceOptions: InitServiceOptions) { @@ -814,11 +857,12 @@ export class InitService extends InitElement { /** @internal */ public _bind(options: InitBindOptions): InitElementConfig { - const serviceManager = options.platform === InitPlatform.LINUX ? 'sysvinit' : 'windows'; + const serviceManager = this.serviceOptions.serviceManager + ?? (options.platform === InitPlatform.LINUX ? ServiceManager.SYSVINIT : ServiceManager.WINDOWS); return { config: { - [serviceManager]: { + [serviceManagerToString(serviceManager)]: { [this.serviceName]: { enabled: this.serviceOptions.enabled, ensureRunning: this.serviceOptions.ensureRunning, @@ -970,3 +1014,93 @@ function standardS3Auth(role: iam.IRole, bucketName: string) { }, }; } + +/** + * The service manager that will be used by InitServices + * + * The value needs to match the service manager used by your operating + * system. + */ +export enum ServiceManager { + /** + * Use SysVinit + * + * This is the default for Linux systems. + */ + SYSVINIT, + + /** + * Use Windows + * + * This is the default for Windows systems. + */ + WINDOWS, + + /** + * Use systemd + */ + SYSTEMD, +} + +function serviceManagerToString(x: ServiceManager): string { + switch (x) { + case ServiceManager.SYSTEMD: return 'systemd'; + case ServiceManager.SYSVINIT: return 'sysvinit'; + case ServiceManager.WINDOWS: return 'windows'; + } +} + +/** + * Options for creating a SystemD configuration file + */ +export interface SystemdConfigFileOptions { + /** + * The command to run to start this service + */ + readonly command: string; + + /** + * The working directory for the command + * + * @default Root directory or home directory of specified user + */ + readonly cwd?: string; + + /** + * A description of this service + * + * @default - No description + */ + readonly description?: string; + + /** + * The user to execute the process under + * + * @default root + */ + readonly user?: string; + + /** + * The group to execute the process under + * + * @default root + */ + readonly group?: string; + + /** + * Keep the process running all the time + * + * Restarts the process when it exits for any reason other + * than the machine shutting down. + * + * @default true + */ + readonly keepRunning?: boolean; + + /** + * Start the service after the networking part of the OS comes up + * + * @default true + */ + readonly afterNetwork?: boolean; +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts index 808783201ee3e..7b6c61e47c590 100644 --- a/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts +++ b/packages/@aws-cdk/aws-ec2/test/cfn-init-element.test.ts @@ -625,6 +625,51 @@ describe('InitService', () => { }); }); + test('can request systemd service', () => { + // WHEN + const service = ec2.InitService.enable('httpd', { + serviceManager: ec2.ServiceManager.SYSTEMD, + }); + + // THEN + const bindOptions = defaultOptions(InitPlatform.LINUX); + const rendered = service._bind(bindOptions).config; + + // THEN + expect(rendered.systemd).toEqual({ + httpd: { + enabled: true, + ensureRunning: true, + }, + }); + }); + + test('can create simple systemd config file', () => { + // WHEN + const file = ec2.InitService.systemdConfigFile('myserver', { + command: '/start/my/service', + cwd: '/my/dir', + user: 'ec2-user', + group: 'ec2-user', + description: 'my service', + }); + + // THEN + const bindOptions = defaultOptions(InitPlatform.LINUX); + const rendered = file._bind(bindOptions).config; + expect(rendered).toEqual({ + '/etc/systemd/system/myserver.service': expect.objectContaining({ + content: expect.any(String), + }), + }); + + const capture = rendered['/etc/systemd/system/myserver.service'].content; + expect(capture).toContain('ExecStart=/start/my/service'); + expect(capture).toContain('WorkingDirectory=/my/dir'); + expect(capture).toContain('User=ec2-user'); + expect(capture).toContain('Group=ec2-user'); + expect(capture).toContain('Description=my service'); + }); }); describe('InitSource', () => { diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package.json b/packages/@aws-cdk/aws-elasticloadbalancing/package.json index f3b4e13aacb23..7651b907d9554 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package.json @@ -84,6 +84,7 @@ "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/integ-runner": "0.0.0", "@aws-cdk/integ-tests": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.5.2" diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/InstanceTargetTestDefaultTestDeployAssertAF607556.assets.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/InstanceTargetTestDefaultTestDeployAssertAF607556.assets.json index 3493f6a48b43c..f9e2b4b4362b2 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/InstanceTargetTestDefaultTestDeployAssertAF607556.assets.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/InstanceTargetTestDefaultTestDeployAssertAF607556.assets.json @@ -1,5 +1,5 @@ { - "version": "29.0.0", + "version": "31.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.assets.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.assets.json index 1d178796401c7..d7bf74af2618a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.assets.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "29.0.0", + "version": "31.0.0", "files": { - "11ca0111a871a53be970c5db0c5a24d4146213fd59f6d172b6fc1bc3de206cf9": { + "c8ab3e4e4503281b1f7df3028abab9a0ca3738640d31201b5118a18aaa225eab": { "source": { "path": "aws-cdk-elb-instance-target-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "11ca0111a871a53be970c5db0c5a24d4146213fd59f6d172b6fc1bc3de206cf9.json", + "objectKey": "c8ab3e4e4503281b1f7df3028abab9a0ca3738640d31201b5118a18aaa225eab.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-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.template.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.template.json index 07931ccc284e9..7823c4ecbcfb1 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.template.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/aws-cdk-elb-instance-target-integ.template.json @@ -272,6 +272,20 @@ ], "Version": "2012-10-17" }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonSSMManagedInstanceCore" + ] + ] + } + ], "Tags": [ { "Key": "Name", @@ -280,6 +294,32 @@ ] } }, + "targetInstanceInstanceRoleDefaultPolicy1E71262F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "cloudformation:DescribeStackResource", + "cloudformation:SignalResource" + ], + "Effect": "Allow", + "Resource": { + "Ref": "AWS::StackId" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "targetInstanceInstanceRoleDefaultPolicy1E71262F", + "Roles": [ + { + "Ref": "targetInstanceInstanceRole3F8EC526" + } + ] + } + }, "targetInstanceInstanceProfile0A012423": { "Type": "AWS::IAM::InstanceProfile", "Properties": { @@ -290,7 +330,7 @@ ] } }, - "targetInstance603C5817": { + "targetInstance603C5817b329f03eca862331": { "Type": "AWS::EC2::Instance", "Properties": { "AvailabilityZone": { @@ -307,7 +347,7 @@ "ImageId": { "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" }, - "InstanceType": "t2.micro", + "InstanceType": "t3.micro", "SecurityGroupIds": [ { "Fn::GetAtt": [ @@ -326,12 +366,77 @@ } ], "UserData": { - "Fn::Base64": "#!/bin/bash" + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\n# fingerprint: e15d4219bb1dd06a\n(\n set +e\n /opt/aws/bin/cfn-init -v --region ", + { + "Ref": "AWS::Region" + }, + " --stack ", + { + "Ref": "AWS::StackName" + }, + " --resource targetInstance603C5817b329f03eca862331 -c default\n /opt/aws/bin/cfn-signal -e $? --region ", + { + "Ref": "AWS::Region" + }, + " --stack ", + { + "Ref": "AWS::StackName" + }, + " --resource targetInstance603C5817b329f03eca862331\n cat /var/log/cfn-init.log >&2\n)" + ] + ] + } } }, "DependsOn": [ + "targetInstanceInstanceRoleDefaultPolicy1E71262F", "targetInstanceInstanceRole3F8EC526" - ] + ], + "CreationPolicy": { + "ResourceSignal": { + "Count": 1, + "Timeout": "PT30M" + } + }, + "Metadata": { + "AWS::CloudFormation::Init": { + "configSets": { + "default": [ + "config" + ] + }, + "config": { + "files": { + "/etc/systemd/system/pythonweb.service": { + "content": "[Unit]\nAfter=network.target\n[Service]\nExecStart=/usr/bin/python3 -m http.server 8080\nWorkingDirectory=/var/www/html\nRestart=always\n[Install]\nWantedBy=multi-user.target", + "encoding": "plain", + "mode": "000644", + "owner": "root", + "group": "root" + }, + "/var/www/html/index.html": { + "content": "Hello! You can see me!", + "encoding": "plain", + "mode": "000644", + "owner": "root", + "group": "root" + } + }, + "services": { + "systemd": { + "pythonweb": { + "enabled": true, + "ensureRunning": true + } + } + } + } + } + } }, "LBSecurityGroup8A41EA2B": { "Type": "AWS::EC2::SecurityGroup", @@ -386,10 +491,10 @@ "CrossZone": true, "Instances": [ { - "Ref": "targetInstance603C5817" + "Ref": "targetInstance603C5817b329f03eca862331" } ], - "Scheme": "internal", + "Scheme": "internet-facing", "SecurityGroups": [ { "Fn::GetAtt": [ @@ -400,10 +505,14 @@ ], "Subnets": [ { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + "Ref": "VPCPublicSubnet1SubnetB4246D30" } ] - } + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet1RouteTableAssociation0B0896DC" + ] } }, "Parameters": { diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/cdk.out b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/cdk.out index d8b441d447f8a..7925065efbcc4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"29.0.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/integ.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/integ.json index 23c31182b8fce..d8a20aea57f70 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "29.0.0", + "version": "31.0.0", "testCases": { "InstanceTargetTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/manifest.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/manifest.json index f0e7e3434a175..8984d5a32c526 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "29.0.0", + "version": "31.0.0", "artifacts": { "aws-cdk-elb-instance-target-integ.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,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}/11ca0111a871a53be970c5db0c5a24d4146213fd59f6d172b6fc1bc3de206cf9.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c8ab3e4e4503281b1f7df3028abab9a0ca3738640d31201b5118a18aaa225eab.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -129,6 +129,12 @@ "data": "targetInstanceInstanceRole3F8EC526" } ], + "/aws-cdk-elb-instance-target-integ/targetInstance/InstanceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "targetInstanceInstanceRoleDefaultPolicy1E71262F" + } + ], "/aws-cdk-elb-instance-target-integ/targetInstance/InstanceProfile": [ { "type": "aws:cdk:logicalId", @@ -138,7 +144,7 @@ "/aws-cdk-elb-instance-target-integ/targetInstance/Resource": [ { "type": "aws:cdk:logicalId", - "data": "targetInstance603C5817" + "data": "targetInstance603C5817b329f03eca862331" } ], "/aws-cdk-elb-instance-target-integ/SsmParameterValue:--aws--service--ami-amazon-linux-latest--amzn2-ami-hvm-x86_64-gp2:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [ @@ -162,7 +168,10 @@ "/aws-cdk-elb-instance-target-integ/LB/Resource": [ { "type": "aws:cdk:logicalId", - "data": "LB8A12904C" + "data": "LB8A12904C", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" + ] } ], "/aws-cdk-elb-instance-target-integ/BootstrapVersion": [ @@ -177,19 +186,10 @@ "data": "CheckBootstrapVersion" } ], - "targetInstanceInstanceSecurityGroupfromawscdkelbinstancetargetintegLBSecurityGroup395870CC80E053AA6C": [ - { - "type": "aws:cdk:logicalId", - "data": "targetInstanceInstanceSecurityGroupfromawscdkelbinstancetargetintegLBSecurityGroup395870CC80E053AA6C", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } - ], - "LBSecurityGrouptoawscdkelbinstancetargetintegtargetInstanceInstanceSecurityGroup4B82664E80A95A3BE8": [ + "targetInstance603C5817": [ { "type": "aws:cdk:logicalId", - "data": "LBSecurityGrouptoawscdkelbinstancetargetintegtargetInstanceInstanceSecurityGroup4B82664E80A95A3BE8", + "data": "targetInstance603C5817", "trace": [ "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" ] diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/tree.json b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/tree.json index 6d4e4af19f1eb..ac9955bdfdf39 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.js.snapshot/tree.json @@ -31,7 +31,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -75,7 +75,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -105,7 +105,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -124,7 +124,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -144,7 +144,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -164,7 +164,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -192,13 +192,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -242,7 +242,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -272,7 +272,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -291,7 +291,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -311,13 +311,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -336,7 +336,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnInternetGateway", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -355,13 +355,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPCGatewayAttachment", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.Vpc", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -399,7 +399,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -428,13 +428,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroupIngress", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -468,6 +468,20 @@ ], "Version": "2012-10-17" }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/AmazonSSMManagedInstanceCore" + ] + ] + } + ], "tags": [ { "key": "Name", @@ -480,6 +494,50 @@ "fqn": "@aws-cdk/aws-iam.CfnRole", "version": "0.0.0" } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-elb-instance-target-integ/targetInstance/InstanceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-elb-instance-target-integ/targetInstance/InstanceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "cloudformation:DescribeStackResource", + "cloudformation:SignalResource" + ], + "Effect": "Allow", + "Resource": { + "Ref": "AWS::StackId" + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "targetInstanceInstanceRoleDefaultPolicy1E71262F", + "roles": [ + { + "Ref": "targetInstanceInstanceRole3F8EC526" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } } }, "constructInfo": { @@ -525,7 +583,7 @@ "imageId": { "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter" }, - "instanceType": "t2.micro", + "instanceType": "t3.micro", "securityGroupIds": [ { "Fn::GetAtt": [ @@ -544,18 +602,41 @@ } ], "userData": { - "Fn::Base64": "#!/bin/bash" + "Fn::Base64": { + "Fn::Join": [ + "", + [ + "#!/bin/bash\n# fingerprint: e15d4219bb1dd06a\n(\n set +e\n /opt/aws/bin/cfn-init -v --region ", + { + "Ref": "AWS::Region" + }, + " --stack ", + { + "Ref": "AWS::StackName" + }, + " --resource targetInstance603C5817b329f03eca862331 -c default\n /opt/aws/bin/cfn-signal -e $? --region ", + { + "Ref": "AWS::Region" + }, + " --stack ", + { + "Ref": "AWS::StackName" + }, + " --resource targetInstance603C5817b329f03eca862331\n cat /var/log/cfn-init.log >&2\n)" + ] + ] + } } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnInstance", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.Instance", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -605,7 +686,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } }, @@ -634,13 +715,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroupEgress", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -661,10 +742,10 @@ "crossZone": true, "instances": [ { - "Ref": "targetInstance603C5817" + "Ref": "targetInstance603C5817b329f03eca862331" } ], - "scheme": "internal", + "scheme": "internet-facing", "securityGroups": [ { "Fn::GetAtt": [ @@ -675,19 +756,19 @@ ], "subnets": [ { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + "Ref": "VPCPublicSubnet1SubnetB4246D30" } ] } }, "constructInfo": { - "fqn": "@aws-cdk/aws-elasticloadbalancing.CfnLoadBalancer", + "fqn": "@aws-cdk/core.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-elasticloadbalancing.LoadBalancer", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -726,7 +807,7 @@ "path": "InstanceTargetTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.237" + "version": "10.1.264" } }, "DeployAssert": { @@ -772,7 +853,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.237" + "version": "10.1.264" } } }, diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.ts b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.ts index 57ab3f1371ff0..a54154a229971 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/test/integ.instanceTarget.elb.ts @@ -1,5 +1,7 @@ #!/usr/bin/env node import * as ec2 from '@aws-cdk/aws-ec2'; +// eslint-disable-next-line import/no-extraneous-dependencies +import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; import * as elb from '../lib'; @@ -14,16 +16,31 @@ const vpc = new ec2.Vpc(stack, 'VPC', { const instance = new ec2.Instance(stack, 'targetInstance', { vpc: vpc, instanceType: ec2.InstanceType.of( // t2.micro has free tier usage in aws - ec2.InstanceClass.T2, + ec2.InstanceClass.T3, ec2.InstanceSize.MICRO, ), machineImage: ec2.MachineImage.latestAmazonLinux({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, }), + initOptions: { + timeout: cdk.Duration.minutes(30), + }, + init: ec2.CloudFormationInit.fromElements( + ec2.InitService.systemdConfigFile('pythonweb', { + command: '/usr/bin/python3 -m http.server 8080', + cwd: '/var/www/html', + }), + ec2.InitService.enable('pythonweb', { + serviceManager: ec2.ServiceManager.SYSTEMD, + }), + ec2.InitFile.fromString('/var/www/html/index.html', 'Hello! You can see me!'), + ), }); +instance.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')); const elbalancer = new elb.LoadBalancer(stack, 'LB', { vpc, + internetFacing: true, }); elbalancer.addTarget(new elb.InstanceTarget(instance)); From f6cda61e31ef0c73ad307aee96f686c1886c198d Mon Sep 17 00:00:00 2001 From: AWS CDK Automation <43080478+aws-cdk-automation@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:32:31 +0000 Subject: [PATCH 7/9] docs(cfnspec): update CloudFormation documentation (#24715) --- .../spec-source/cfn-docs/cfn-docs.json | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json index 6f25a36973931..368b4305da9e3 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json +++ b/packages/@aws-cdk/cfnspec/spec-source/cfn-docs/cfn-docs.json @@ -1932,7 +1932,7 @@ "properties": { "ApplicationId": "The application ID.", "Description": "A description of the configuration profile.", - "LocationUri": "A URI to locate the configuration. You can specify the following:\n\n- For the AWS AppConfig hosted configuration store and for feature flags, specify `hosted` .\n- For an AWS Systems Manager Parameter Store parameter, specify either the parameter name in the format `ssm-parameter://` or the ARN.\n- For an AWS Secrets Manager secret, specify the URI in the following format: `secrets-manager` ://.\n- For an Amazon S3 object, specify the URI in the following format: `s3:///` . Here is an example: `s3://my-bucket/my-app/us-east-1/my-config.json`\n- For an SSM document, specify either the document name in the format `ssm-document://` or the Amazon Resource Name (ARN).", + "LocationUri": "A URI to locate the configuration. You can specify the following:\n\n- For the AWS AppConfig hosted configuration store and for feature flags, specify `hosted` .\n- For an AWS Systems Manager Parameter Store parameter, specify either the parameter name in the format `ssm-parameter://` or the ARN.\n- For an AWS Secrets Manager secret, specify the URI in the following format: `secretsmanager` ://.\n- For an Amazon S3 object, specify the URI in the following format: `s3:///` . Here is an example: `s3://my-bucket/my-app/us-east-1/my-config.json`\n- For an SSM document, specify either the document name in the format `ssm-document://` or the Amazon Resource Name (ARN).", "Name": "A name for the configuration profile.", "RetrievalRoleArn": "The ARN of an IAM role with permission to access the configuration at the specified `LocationUri` .\n\n> A retrieval role ARN is not required for configurations stored in the AWS AppConfig hosted configuration store. It is required for all other sources that store your configuration.", "Tags": "Metadata to assign to the configuration profile. Tags help organize and categorize your AWS AppConfig resources. Each tag consists of a key and an optional value, both of which you define.", @@ -5221,7 +5221,7 @@ "description": "Contains customized metric specification information for a target tracking scaling policy for Application Auto Scaling.\n\nFor information about the available metrics for a service, see [AWS services that publish CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) in the *Amazon CloudWatch User Guide* .\n\nTo create your customized metric specification:\n\n- Add values for each required parameter from CloudWatch. You can use an existing metric, or a new metric that you create. To use your own metric, you must first publish the metric to CloudWatch. For more information, see [Publish custom metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html) in the *Amazon CloudWatch User Guide* .\n- Choose a metric that changes proportionally with capacity. The value of the metric should increase or decrease in inverse proportion to the number of capacity units. That is, the value of the metric should decrease when capacity increases, and increase when capacity decreases.\n\nFor an example of how creating new metrics can be useful, see [Scaling based on Amazon SQS](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-using-sqs-queue.html) in the *Amazon EC2 Auto Scaling User Guide* . This topic mentions Auto Scaling groups, but the same scenario for Amazon SQS can apply to the target tracking scaling policies that you create for a Spot Fleet by using Application Auto Scaling.\n\nFor more information about the CloudWatch terminology below, see [Amazon CloudWatch concepts](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html) .\n\n`CustomizedMetricSpecification` is a property of the [AWS::ApplicationAutoScaling::ScalingPolicy TargetTrackingScalingPolicyConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-applicationautoscaling-scalingpolicy-targettrackingscalingpolicyconfiguration.html) property type.", "properties": { "Dimensions": "The dimensions of the metric.\n\nConditional: If you published your metric with dimensions, you must specify the same dimensions in your scaling policy.", - "MetricName": "The name of the metric. To get the exact metric name, namespace, and dimensions, inspect the [Metric](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Metric.html) object that is returned by a call to [ListMetrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html) .", + "MetricName": "The name of the metric. To get the exact metric name, namespace, and dimensions, inspect the [Metric](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Metric.html) object that's returned by a call to [ListMetrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html) .", "Namespace": "The namespace of the metric.", "Statistic": "The statistic of the metric.", "Unit": "The unit of the metric. For a complete list of the units that CloudWatch supports, see the [MetricDatum](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html) data type in the *Amazon CloudWatch API Reference* ." @@ -16971,7 +16971,7 @@ }, "AWS::ECR::ReplicationConfiguration.RepositoryFilter": { "attributes": {}, - "description": "The filter settings used with image replication. Specifying a repository filter to a replication rule provides a method for controlling which repositories in a private registry are replicated. If no repository filter is specified, all images in the repository are replicated.", + "description": "The filter settings used with image replication. Specifying a repository filter to a replication rule provides a method for controlling which repositories in a private registry are replicated. If no filters are added, the contents of all repositories are replicated.", "properties": { "Filter": "The repository filter details. When the `PREFIX_MATCH` filter type is specified, this value is required and should be the repository name prefix to configure replication for.", "FilterType": "The repository filter type. The only supported value is `PREFIX_MATCH` , which is a repository name prefix specified with the `filter` parameter." @@ -42592,14 +42592,14 @@ "AWS::RolesAnywhere::CRL": { "attributes": { "CrlId": "The unique primary identifier of the Crl", - "Ref": "The name of the CRL." + "Ref": "`Ref` returns `CrlId` ." }, - "description": "Creates a Crl.", + "description": "Imports the certificate revocation list (CRL). A CRL is a list of certificates that have been revoked by the issuing certificate Authority (CA). IAM Roles Anywhere validates against the CRL before issuing credentials.\n\n*Required permissions:* `rolesanywhere:ImportCrl` .", "properties": { - "CrlData": "x509 v3 Certificate Revocation List to revoke auth for corresponding certificates presented in CreateSession operations", - "Enabled": "The enabled status of the resource.", - "Name": "The customer specified name of the resource.", - "Tags": "A list of Tags.", + "CrlData": "The x509 v3 specified certificate revocation list (CRL).", + "Enabled": "Specifies whether the certificate revocation list (CRL) is enabled.", + "Name": "The name of the certificate revocation list (CRL).", + "Tags": "A list of tags to attach to the certificate revocation list (CRL).", "TrustAnchorArn": "The ARN of the TrustAnchor the certificate revocation list (CRL) will provide revocation for." } }, @@ -42607,18 +42607,18 @@ "attributes": { "ProfileArn": "The ARN of the profile.", "ProfileId": "The unique primary identifier of the Profile", - "Ref": "The name of the Profile" + "Ref": "`Ref` returns `ProfileId` ." }, - "description": "Creates a Profile.", + "description": "Creates a *profile* , a list of the roles that Roles Anywhere service is trusted to assume. You use profiles to intersect permissions with IAM managed policies.\n\n*Required permissions:* `rolesanywhere:CreateProfile` .", "properties": { - "DurationSeconds": "The number of seconds vended session credentials will be valid for", - "Enabled": "The enabled status of the resource.", - "ManagedPolicyArns": "A list of managed policy ARNs. Managed policies identified by this list will be applied to the vended session credentials.", - "Name": "The customer specified name of the resource.", - "RequireInstanceProperties": "Specifies whether instance properties are required in CreateSession requests with this profile.", - "RoleArns": "A list of IAM role ARNs that can be assumed when this profile is specified in a CreateSession request.", - "SessionPolicy": "A session policy that will applied to the trust boundary of the vended session credentials.", - "Tags": "A list of Tags." + "DurationSeconds": "Sets the maximum number of seconds that vended temporary credentials through [CreateSession](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/authentication-create-session.html) will be valid for, between 900 and 3600.", + "Enabled": "Indicates whether the profile is enabled.", + "ManagedPolicyArns": "A list of managed policy ARNs that apply to the vended session credentials.", + "Name": "The name of the profile.", + "RequireInstanceProperties": "Specifies whether instance properties are required in temporary credential requests with this profile.", + "RoleArns": "A list of IAM role ARNs. During `CreateSession` , if a matching role ARN is provided, the properties in this profile will be applied to the intersection session policy.", + "SessionPolicy": "A session policy that applies to the trust boundary of the vended session credentials.", + "Tags": "The tags to attach to the profile." } }, "AWS::RolesAnywhere::TrustAnchor": { @@ -42627,7 +42627,7 @@ "TrustAnchorArn": "The ARN of the trust anchor.", "TrustAnchorId": "The unique identifier of the trust anchor." }, - "description": "Creates a TrustAnchor.", + "description": "Creates a trust anchor to establish trust between IAM Roles Anywhere and your certificate authority (CA). You can define a trust anchor as a reference to an AWS Private Certificate Authority ( AWS Private CA ) or by uploading a CA certificate. Your AWS workloads can authenticate with the trust anchor using certificates issued by the CA in exchange for temporary AWS credentials.\n\n*Required permissions:* `rolesanywhere:CreateTrustAnchor` .", "properties": { "Enabled": "Indicates whether the trust anchor is enabled.", "Name": "The name of the trust anchor.", @@ -42637,15 +42637,15 @@ }, "AWS::RolesAnywhere::TrustAnchor.Source": { "attributes": {}, - "description": "Object representing the TrustAnchor type and its related certificate data.", + "description": "The trust anchor type and its related certificate data.", "properties": { - "SourceData": "A union object representing the data field of the TrustAnchor depending on its type", - "SourceType": "The type of the TrustAnchor." + "SourceData": "The data field of the trust anchor depending on its type.", + "SourceType": "The type of the TrustAnchor.\n\n> `AWS_ACM_PCA` is not an allowed value in your region." } }, "AWS::RolesAnywhere::TrustAnchor.SourceData": { "attributes": {}, - "description": "A union object representing the data field of the TrustAnchor depending on its type", + "description": "The data field of the trust anchor depending on its type.", "properties": { "AcmPcaArn": "The root certificate of the AWS Private Certificate Authority specified by this ARN is used in trust validation for temporary credential requests. Included for trust anchors of type `AWS_ACM_PCA` .\n\n> This field is not supported in your region.", "X509CertificateData": "The PEM-encoded data for the certificate anchor. Included for trust anchors of type `CERTIFICATE_BUNDLE` ." @@ -43194,9 +43194,9 @@ "PreferredInstanceType": "", "Ref": "`Ref` returns the `ResolverEndpoint` object.", "ResolverEndpointId": "The ID of the resolver endpoint.", - "ResolverEndpointType": "" + "ResolverEndpointType": "For the endpoint type you can choose either IPv4, IPv6. or dual-stack. A dual-stack endpoint means that it will resolve via both IPv4 and IPv6. If you choose either IPv4 or IPv6, this endpoint type is applied to all IP addresses." }, - "description": "Creates a Resolver endpoint. There are two types of Resolver endpoints, inbound and outbound:\n\n- An *inbound Resolver endpoint* forwards DNS queries to the DNS service for a VPC from your network.\n- An *outbound Resolver endpoint* forwards DNS queries from the DNS service for a VPC to your network.", + "description": "Creates a Resolver endpoint. There are two types of Resolver endpoints, inbound and outbound:\n\n- An *inbound Resolver endpoint* forwards DNS queries to the DNS service for a VPC from your network.\n- An *outbound Resolver endpoint* forwards DNS queries from the DNS service for a VPC to your network.\n\n> - You cannot update `ResolverEndpointType` and `IpAddresses` in the same request.\n> - When you update a dual-stack IP address, you must update both IP addresses. You can\u2019t update only an IPv4 or IPv6 and keep an existing IP address.", "properties": { "Direction": "Indicates whether the Resolver endpoint allows inbound or outbound DNS queries:\n\n- `INBOUND` : allows DNS queries to your VPC from your network\n- `OUTBOUND` : allows DNS queries from your VPC to your network", "IpAddresses": "The subnets and IP addresses in your VPC that DNS queries originate from (for outbound endpoints) or that you forward DNS queries to (for inbound endpoints). The subnet ID uniquely identifies a VPC.", @@ -43266,7 +43266,7 @@ "Name": "The name for the Resolver rule, which you specified when you created the Resolver rule.", "ResolverEndpointId": "The ID of the endpoint that the rule is associated with.", "RuleType": "When you want to forward DNS queries for specified domain name to resolvers on your network, specify `FORWARD` .\n\nWhen you have a forwarding rule to forward DNS queries for a domain to your network and you want Resolver to process queries for a subdomain of that domain, specify `SYSTEM` .\n\nFor example, to forward DNS queries for example.com to resolvers on your network, you create a rule and specify `FORWARD` for `RuleType` . To then have Resolver process queries for apex.example.com, you create a rule and specify `SYSTEM` for `RuleType` .\n\nCurrently, only Resolver can create rules that have a value of `RECURSIVE` for `RuleType` .", - "Tags": "Route 53 Resolver doesn't support updating tags through CloudFormation.", + "Tags": "Tags help organize and categorize your Resolver rules. Each tag consists of a key and an optional value, both of which you define.", "TargetIps": "An array that contains the IP addresses and ports that an outbound endpoint forwards DNS queries to. Typically, these are the IP addresses of DNS resolvers on your network." } }, @@ -43578,7 +43578,7 @@ }, "AWS::S3::Bucket.NotificationFilter": { "attributes": {}, - "description": "Specifies object key name filtering rules. For information about key name filtering, see [Configuring Event Notifications](https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html) in the *Amazon S3 User Guide* .", + "description": "Specifies object key name filtering rules. For information about key name filtering, see [Configuring event notifications using object key name filtering](https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-filtering.html) in the *Amazon S3 User Guide* .", "properties": { "S3Key": "A container for object key name prefix and suffix filtering rules." } @@ -47919,7 +47919,7 @@ "Arn": "The Amazon Resource Name (ARN) for the Amazon EventBridge Scheduler schedule.", "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the `Name` attribute of theschedule." }, - "description": "Creates the specified schedule.", + "description": "A *schedule* is the main resource you create, configure, and manage using Amazon EventBridge Scheduler.\n\nEvery schedule has a *schedule expression* that determines when, and with what frequency, the schedule runs. EventBridge Scheduler supports three types of schedules: rate, cron, and one-time schedules. For more information about different schedule types, see [Schedule types](https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html) in the *EventBridge Scheduler User Guide* .\n\nWhen you create a schedule, you configure a target for the schedule to invoke. A target is an API operation that EventBridge Scheduler calls on your behalf every time your schedule runs. EventBridge Scheduler supports two types of targets: *templated* targets invoke common API operations across a core groups of services, and customizeable *universal* targets that you can use to call more than 6,000 operations across over 270 services. For more information about configuring targets, see [Managing targets](https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets.html) in the *EventBridge Scheduler User Guide* .\n\nFor more information about managing schedules, changing the schedule state, setting up flexible time windows, and configuring a dead-letter queue for a schedule, see [Managing a schedule](https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule.html) in the *EventBridge Scheduler User Guide* .", "properties": { "Description": "The description you specify for the schedule.", "EndDate": "The date, in UTC, before which the schedule can invoke its target. Depending on the schedule's recurrence expression, invocations might stop on, or before, the `EndDate` you specify.\nEventBridge Scheduler ignores `EndDate` for one-time schedules.", @@ -47930,7 +47930,7 @@ "ScheduleExpression": "The expression that defines when the schedule runs. The following formats are supported.\n\n- `at` expression - `at(yyyy-mm-ddThh:mm:ss)`\n- `rate` expression - `rate(unit value)`\n- `cron` expression - `cron(fields)`\n\nYou can use `at` expressions to create one-time schedules that invoke a target once, at the time and in the time zone, that you specify. You can use `rate` and `cron` expressions to create recurring schedules. Rate-based schedules are useful when you want to invoke a target at regular intervals, such as every 15 minutes or every five days. Cron-based schedules are useful when you want to invoke a target periodically at a specific time, such as at 8:00 am (UTC+0) every 1st day of the month.\n\nA `cron` expression consists of six fields separated by white spaces: `(minutes hours day_of_month month day_of_week year)` .\n\nA `rate` expression consists of a *value* as a positive integer, and a *unit* with the following options: `minute` | `minutes` | `hour` | `hours` | `day` | `days`\n\nFor more information and examples, see [Schedule types on EventBridge Scheduler](https://docs.aws.amazon.com/scheduler/latest/UserGuide/schedule-types.html) in the *EventBridge Scheduler User Guide* .", "ScheduleExpressionTimezone": "The timezone in which the scheduling expression is evaluated.", "StartDate": "The date, in UTC, after which the schedule can begin invoking its target. Depending on the schedule's recurrence expression, invocations might occur on, or after, the `StartDate` you specify.\nEventBridge Scheduler ignores `StartDate` for one-time schedules.", - "State": "Specifies whether the schedule is enabled or disabled.", + "State": "Specifies whether the schedule is enabled or disabled.\n\n*Allowed Values* : `ENABLED` | `DISABLED`", "Target": "The schedule's target details." } }, @@ -48077,9 +48077,9 @@ "CreationDate": "The date and time at which the schedule group was created.", "LastModificationDate": "The time at which the schedule group was last modified.", "Ref": "When you pass the logical ID of this resource to the intrinsic `Ref` function, `Ref` returns the `Name` attribute of the schedule group.", - "State": "Specifies the state of the schedule group.\n\nValid values are `ACTIVE` and `DELETING` ." + "State": "Specifies the state of the schedule group.\n\n*Allowed Values* : `ACTIVE` | `DELETING`" }, - "description": "Creates the specified schedule group.", + "description": "A *schedule group* is an Amazon EventBridge Scheduler resource you use to organize your schedules.\n\nYour AWS account comes with a `default` scheduler group. You associate a new schedule with the `default` group or with schedule groups that you create and manage. You can create up to [500 schedule groups](https://docs.aws.amazon.com/scheduler/latest/UserGuide/scheduler-quotas.html) in your AWS account. With EventBridge Scheduler, you apply [tags](https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html) to schedule groups, not to individual schedules to organize your resources.\n\nFor more information about managing schedule groups, see [Managing a schedule group](https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-group.html) in the *EventBridge Scheduler User Guide* .", "properties": { "Name": "The name of the schedule group.", "Tags": "An array of key-value pairs to apply to this resource.\n\nFor more information, see [Tag](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html) ." From f511000c149dff3dbdee5e70064767d79db0004e Mon Sep 17 00:00:00 2001 From: Rico Hermans Date: Tue, 21 Mar 2023 12:56:16 +0100 Subject: [PATCH 8/9] chore: detect property type renames to protect against breakage (#24718) Upstream service teams may rename property types in the resource specification. This is strictly speaking not breaking from the point of view of the spec, because the names of the property types don't appear anywhere in the code a user would normally type (i.e., in a CloudFormation template). However, CDK generates classes for these types, and so the name *does* matter and changing it is breaking. To detect these instances, we check that during an upgrade, all old property type names are still present. If not, the reason is probably that they renamed a type. Note that this is not a 100% guaranteed to catch all scenarios (I'm sure you can think of changes that would be breaking and still pass this check), but it's at least very likely to catch honest mistakes in commonly expected scenarios. For those interested in how it works: * During the spec upgrade, we have both the old and the new spec available. * We iterate over all objects keys in the property types of the old spec, looking like: `{ "PropertyTypes": { "AWS::ElastiCache::ReplicationGroup.LogDeliveryConfigurationRequest": { ... }, ... }` object, and make sure that the keys are also present in the property types of the new spec. Also change the `copy/paste` operation pair of a previous patch into a `move` operation, so that if the type definition changes in the future we won't accidentally keep it at an old definition. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/cfnspec/build-tools/spec-diff.ts | 52 +++++++++ .../@aws-cdk/cfnspec/build-tools/update.sh | 2 + ...Fv2_RuleGroup_Rename_Properties_patch.json | 100 +++--------------- 3 files changed, 69 insertions(+), 85 deletions(-) diff --git a/packages/@aws-cdk/cfnspec/build-tools/spec-diff.ts b/packages/@aws-cdk/cfnspec/build-tools/spec-diff.ts index b39f50aa17fdb..d575b1ed5939f 100644 --- a/packages/@aws-cdk/cfnspec/build-tools/spec-diff.ts +++ b/packages/@aws-cdk/cfnspec/build-tools/spec-diff.ts @@ -27,6 +27,8 @@ async function main() { oldSpec.ResourceTypes = {}; } + validatePropertyTypeNameConsistency(oldSpec, newSpec); + const out = jsonDiff(oldSpec, newSpec); // Here's the magic output format of this thing @@ -278,6 +280,56 @@ async function main() { } } +/** + * Safeguard check: make sure that all old property type names in the old spec exist in the new spec + * + * If not, it's probably because the service team renamed a type between spec + * version `v(N)` to `v(N+1)`.. In the CloudFormation spec itself, this is not a + * problem. However, CDK will have generated actual classes and interfaces with + * the type names at `v(N)`, which people will have written code against. If the + * classes and interfaces would have a new name at `v(N+1)`, all user code would + * break. + */ +function validatePropertyTypeNameConsistency(oldSpec: any, newSpec: any) { + const newPropsTypes = newSpec.PropertyTypes ?? {}; + const disappearedKeys = Object.keys(oldSpec.PropertyTypes ?? {}).filter(k => !(k in newPropsTypes)); + if (disappearedKeys.length === 0) { + return; + } + + const exampleJsonPatch = { + patch: { + description: 'Undoing upstream property type renames of because ', + operations: disappearedKeys.map((key) => ({ + op: 'move', + from: `/PropertyTypes/${key.split('.')[0]}.`, + path: `/PropertyTypes/${key}`, + })), + }, + }; + + process.stderr.write([ + '┌───────────────────────────────────────────────────────────────────────────────────────┐', + '│ ▐█', + '│ PROPERTY TYPES HAVE DISAPPEARED ▐█', + '│ ▐█', + '│ Some type names have disappeared from the old specification. ▐█', + '│ ▐█', + '│ This probably indicates that the service team renamed one of the types. We have ▐█', + '│ to keep the old type names though: renaming them would constitute a breaking change ▐█', + '│ to consumers of the L1 resources. ▐█', + '│ ▐█', + '└─▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟█', + '', + 'See what the renames were, check out this PR locally and add a JSON patch file for these types:', + '', + '(Example)', + '', + JSON.stringify(exampleJsonPatch, undefined, 2), + ].join('\n')); + process.exitCode = 1; +} + main().catch(e => { process.stderr.write(e.stack); process.stderr.write('\n'); diff --git a/packages/@aws-cdk/cfnspec/build-tools/update.sh b/packages/@aws-cdk/cfnspec/build-tools/update.sh index 7b3c73eac2d3d..78fd3fdc57a92 100755 --- a/packages/@aws-cdk/cfnspec/build-tools/update.sh +++ b/packages/@aws-cdk/cfnspec/build-tools/update.sh @@ -10,6 +10,8 @@ scriptdir=$(cd $(dirname $0) && pwd) rm -f CHANGELOG.md.new + +# update-spec <SOURCE> <TARGETDIR> <IS_GZIPPED> <SHOULD_SPLIT> [<SVC> [...]] function update-spec() { local title=$1 local url=$2 diff --git a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/500_WAFv2_RuleGroup_Rename_Properties_patch.json b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/500_WAFv2_RuleGroup_Rename_Properties_patch.json index c040a1da5b032..7ed7c8d51b4d4 100644 --- a/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/500_WAFv2_RuleGroup_Rename_Properties_patch.json +++ b/packages/@aws-cdk/cfnspec/spec-source/specification/000_cfn/500_WAFv2_RuleGroup_Rename_Properties_patch.json @@ -3,99 +3,29 @@ "description": "Reverting property type names from FooAction to Foo, which were introduced as part of this PR: https://github.com/aws/aws-cdk/pull/23984", "operations": [ { - "op": "remove", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.AllowAction" + "op": "move", + "from": "/PropertyTypes/AWS::WAFv2::RuleGroup.AllowAction", + "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Allow" }, { - "op": "add", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Allow", - "value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-allowaction.html", - "Properties": { - "CustomRequestHandling": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-allowaction.html#cfn-wafv2-rulegroup-allowaction-customrequesthandling", - "Required": false, - "Type": "CustomRequestHandling", - "UpdateType": "Mutable" - } - } - } + "op": "move", + "from": "/PropertyTypes/AWS::WAFv2::RuleGroup.BlockAction", + "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Block" }, { - "op": "remove", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.BlockAction" + "op": "move", + "from": "/PropertyTypes/AWS::WAFv2::RuleGroup.CaptchaAction", + "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Captcha" }, { - "op": "add", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Block", - "value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-blockaction.html", - "Properties": { - "CustomResponse": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-blockaction.html#cfn-wafv2-rulegroup-blockaction-customresponse", - "Required": false, - "Type": "CustomResponse", - "UpdateType": "Mutable" - } - } - } + "op": "move", + "from": "/PropertyTypes/AWS::WAFv2::RuleGroup.ChallengeAction", + "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Challenge" }, { - "op": "remove", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.CaptchaAction" - }, - { - "op": "add", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Captcha", - "value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-captchaaction.html", - "Properties": { - "CustomRequestHandling": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-captchaaction.html#cfn-wafv2-rulegroup-captchaaction-customrequesthandling", - "Required": false, - "Type": "CustomRequestHandling", - "UpdateType": "Mutable" - } - } - } - }, - { - "op": "remove", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.ChallengeAction" - }, - { - "op": "add", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Challenge", - "value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-challengeaction.html", - "Properties": { - "CustomRequestHandling": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-challengeaction.html#cfn-wafv2-rulegroup-challengeaction-customrequesthandling", - "Required": false, - "Type": "CustomRequestHandling", - "UpdateType": "Mutable" - } - } - } - }, - { - "op": "remove", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.CountAction" - }, - { - "op": "add", - "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Count", - "value": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-countaction.html", - "Properties": { - "CustomRequestHandling": { - "Documentation": "http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-wafv2-rulegroup-countaction.html#cfn-wafv2-rulegroup-countaction-customrequesthandling", - "Required": false, - "Type": "CustomRequestHandling", - "UpdateType": "Mutable" - } - } - } + "op": "move", + "from": "/PropertyTypes/AWS::WAFv2::RuleGroup.CountAction", + "path": "/PropertyTypes/AWS::WAFv2::RuleGroup.Count" } ] } From 413b64347f333573b2a07150e87244bd4c11d264 Mon Sep 17 00:00:00 2001 From: Romain Marcadier <rmuller@amazon.fr> Date: Tue, 21 Mar 2023 13:36:34 +0100 Subject: [PATCH 9/9] fix(sfn): stop replacing JsonPath.DISCARD with `null` (#24717) Follow-up to #24593. The `renderJsonPath` function is subsituting a literal `null` for `JsonPath.DISCARD`, which results in the key being dropped if the value is sent across a language boundary, which effectively changes semantics. The `JsonPath.DISCARD` value is a `Token` that ultimately resolves to `null`, and it must be preserved as such so that it is safe to exchange across languages. Thanks to @beck3905 for reporting & diagnosing this. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-stepfunctions/lib/states/state.ts | 3 +- .../aws-stepfunctions/test/state.test.ts | 29 ++++++++++++------- .../core/lib/private/cloudformation-lang.ts | 2 +- packages/@aws-cdk/core/lib/private/resolve.ts | 8 +++++ packages/@aws-cdk/core/lib/token.ts | 10 +++++-- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts index 66869e282b163..901743caec625 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/states/state.ts @@ -1,7 +1,7 @@ import { Token } from '@aws-cdk/core'; import { IConstruct, Construct, Node } from 'constructs'; import { Condition } from '../condition'; -import { FieldUtils, JsonPath } from '../fields'; +import { FieldUtils } from '../fields'; import { StateGraph } from '../state-graph'; import { CatchProps, Errors, IChainable, INextable, RetryProps } from '../types'; @@ -578,7 +578,6 @@ export function renderList<T>(xs: T[], mapFn: (x: T) => any, sortFn?: (a: T, b: */ export function renderJsonPath(jsonPath?: string): undefined | null | string { if (jsonPath === undefined) { return undefined; } - if (jsonPath === JsonPath.DISCARD) { return null; } if (!Token.isUnresolved(jsonPath) && !jsonPath.startsWith('$')) { throw new Error(`Expected JSON path to start with '$', got: ${jsonPath}`); diff --git a/packages/@aws-cdk/aws-stepfunctions/test/state.test.ts b/packages/@aws-cdk/aws-stepfunctions/test/state.test.ts index 0b2157f7526ec..d878935dd5056 100644 --- a/packages/@aws-cdk/aws-stepfunctions/test/state.test.ts +++ b/packages/@aws-cdk/aws-stepfunctions/test/state.test.ts @@ -1,26 +1,33 @@ +import * as assert from '@aws-cdk/assertions'; import * as cdk from '@aws-cdk/core'; import { FakeTask } from './fake-task'; -import { renderGraph } from './private/render-util'; -import { JsonPath } from '../lib'; +import { JsonPath, StateMachine } from '../lib'; test('JsonPath.DISCARD can be used to discard a state\'s output', () => { - const stack = new cdk.Stack(); - + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'TestStack'); const task = new FakeTask(stack, 'my-state', { inputPath: JsonPath.DISCARD, outputPath: JsonPath.DISCARD, resultPath: JsonPath.DISCARD, }); + new StateMachine(stack, 'state-machine', { + definition: task, + }); + + // WHEN + const definitionString = new assert.Capture(); + assert.Template.fromStack(stack).hasResourceProperties('AWS::StepFunctions::StateMachine', { + DefinitionString: definitionString, + }); + + // THEN + const definition = JSON.parse(definitionString.asString()); - expect(renderGraph(task)).toEqual({ - StartAt: 'my-state', + expect(definition).toMatchObject({ States: { 'my-state': { - End: true, - Type: 'Task', - Resource: expect.any(String), - Parameters: expect.any(Object), - // The important bits: InputPath: null, OutputPath: null, ResultPath: null, diff --git a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts index c31d097c4f9f9..9e278eebf8a00 100644 --- a/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts +++ b/packages/@aws-cdk/core/lib/private/cloudformation-lang.ts @@ -452,4 +452,4 @@ class ScopedCache<O extends object, K, V> { } } -const stringifyCache = new ScopedCache<Stack, string, string>(); \ No newline at end of file +const stringifyCache = new ScopedCache<Stack, string, string>(); diff --git a/packages/@aws-cdk/core/lib/private/resolve.ts b/packages/@aws-cdk/core/lib/private/resolve.ts index 9041ecfc4f15d..b16ab314182f0 100644 --- a/packages/@aws-cdk/core/lib/private/resolve.ts +++ b/packages/@aws-cdk/core/lib/private/resolve.ts @@ -192,6 +192,14 @@ export function resolve(obj: any, options: IResolveOptions): any { return arr; } + // + // literal null -- from JsonNull resolution, preserved as-is (semantically meaningful) + // + + if (obj === null) { + return obj; + } + // // tokens - invoke 'resolve' and continue to resolve recursively // diff --git a/packages/@aws-cdk/core/lib/token.ts b/packages/@aws-cdk/core/lib/token.ts index 0ff003b2c28c5..c6af813dd6da2 100644 --- a/packages/@aws-cdk/core/lib/token.ts +++ b/packages/@aws-cdk/core/lib/token.ts @@ -4,7 +4,7 @@ import { unresolved } from './private/encoding'; import { Intrinsic } from './private/intrinsic'; import { resolve } from './private/resolve'; import { TokenMap } from './private/token-map'; -import { IResolvable, ITokenResolver } from './resolvable'; +import { IResolvable, ITokenResolver, IResolveContext } from './resolvable'; import { TokenizedStringFragments } from './string-fragments'; /** @@ -236,12 +236,18 @@ export class Tokenization { * An object which serializes to the JSON `null` literal, and which can safely * be passed across languages where `undefined` and `null` are not different. */ -export class JsonNull { +export class JsonNull implements IResolvable { /** The canonical instance of `JsonNull`. */ public static readonly INSTANCE = new JsonNull(); + public readonly creationStack: string[] = []; + private constructor() { } + public resolve(_ctx: IResolveContext): any { + return null; + } + /** Obtains the JSON representation of this object (`null`) */ public toJSON(): any { return null;