diff --git a/CHANGELOG.md b/CHANGELOG.md index 12097effc..094a10e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Table of Contents - [Introduction](#introduction) +- [2022-05-15](#2022-05-15) - [2022-04-25](#2022-04-25) - [2022-04-14](#2022-04-14) - [2022-04-10](#2022-04-10) @@ -27,6 +28,28 @@ All notable changes to this project will be documented in this file. --- +## 2022-05-15 + +### Added + +- Added customizations-for-aws-control-tower.template to align with the latest [user guide](https://docs.aws.amazon.com/controltower/latest/userguide/cfct-template.html) instructions. + +### Changed + +- [Common CFCT Setup](aws_sra_examples/solutions/common/common_cfct_setup) solution updates: + - Replaced the S3 template link with the latest template from the GitHub repository. +- [EC2 Default EBS Encryption](aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption) solution updates: + - Added account and organization event support. + - Added SNS fanout for configuring accounts to replace multi-threading. + - Added Lambda environment variables to replace SSM parameter for configuration. +- [S3 Block Account Public Access](aws_sra_examples/solutions/s3_block_account_public_access) solution updates: + - Added account and organization event support. + - Added SNS fanout for configuring accounts to replace multi-threading. + - Added Lambda environment variables to replace SSM parameter for configuration. +- [Security Hub Organization](aws_sra_examples/solutions/securityhub/securityhub_org) updates: + - Added account and organization event support. +- Updated the staging script to include \*.template files. + ## 2022-04-25 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9cebe6c4..35624afd2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,6 @@ - [Introduction](#introduction) - [Reporting Bugs/Feature Requests](#reporting-bugsfeature-requests) - [Contributing via Pull Requests](#contributing-via-pull-requests) -- [Finding contributions to work on](#finding-contributions-to-work-on) - [Code of Conduct](#code-of-conduct) - [Security issue notifications](#security-issue-notifications) - [Licensing](#licensing) @@ -29,27 +28,11 @@ When filing an issue, please check existing open, or recently closed, issues to ## Contributing via Pull Requests -Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: +At this time, we are not accepting contributions via Pull Requests. -1. You are working against the latest source on the _master_ branch. -2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. -3. You open an issue to discuss any significant work - we would hate for your time to be wasted. +If you have code to contribute, please fork the repository and create an issue with a link to your forked repository. Our team will review your code and contact you with insructions for submitting your code. -To send us a pull request, please: - -1. Fork the repository. -2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. -3. Ensure local tests pass. -4. Commit to your fork using clear commit messages. -5. Send us a pull request, answering any default questions in the pull request interface. -6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. - -GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). - -## Finding contributions to work on - -Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues -is a great place to start. +GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/). ## Code of Conduct diff --git a/GENERAL-CONTRIBUTING-GUIDANCE.md b/GENERAL-CONTRIBUTING-GUIDANCE.md deleted file mode 100644 index 68f2215d1..000000000 --- a/GENERAL-CONTRIBUTING-GUIDANCE.md +++ /dev/null @@ -1,48 +0,0 @@ -# General Guidance for Contributing - -## Table of Contents - -- [CloudFormation](#cloudformation) -- [Encryption](#encryption) -- [IAM](#iam) -- [Lambda](#lambda) -- [Testing](#testing) - -## CloudFormation - -- [ ] GG-CLOUDFORMATION1 = Parameterize all resource values -- [ ] GG-CLOUDFORMATION2 = Include parameter groups and labels -- [ ] GG-CLOUDFORMATION3 = Validate all parameters -- [ ] GG-CLOUDFORMATION4 = Sort everything in alphabetical order (e.g. Labels, Parameters, Policy Actions, etc.) -- [ ] GG-CLOUDFORMATION5 = No inline Lambda code -- [ ] GG-CLOUDFORMATION6 = Use custom resource properties over Lambda resource environment variables -- [ ] GG-CLOUDFORMATION7 = Scan templates using CFN NAG and provide metadata with specific reason for any findings that cannot be remediated - -## Encryption - -- [ ] GG-ENCRYPTION1 = Enable encryption by default. Customer Managed KMS Key preferred. -- [ ] GG-ENCRYPTION2 = Least privilege used in key policies - -## IAM - -- [ ] GG-IAM1 = All IAM roles and users must be least privileged with full action names (no wildcards) listed in policies -- [ ] GG-IAM2 = IAM policy files and/or statements are grouped by service with read and write actions in separate statements -- [ ] GG-IAM3 = Avoid using AWS managed policies -- [ ] GG-IAM4 = Restrict actions to a resource or resource prefix when possible - -## Lambda - -- [ ] GG-LAMBDA1 = Add disclaimer stating input validation covered in CloudFormation -- [ ] GG-LAMBDA2 = Handle all exceptions -- [ ] GG-LAMBDA3 = Code broken up in to smaller specific methods or classes for readability -- [ ] GG-LAMBDA4 = No hardcoded values -- [ ] GG-LAMBDA5 = Unique IAM role used for each function -- [ ] GG-LAMBDA6 = Only include libraries that are not included by the Lambda runtime (e.g. boto3 containing new API) -- [ ] GG-LAMBDA7 = Include a packaging script or instructions instead of including packaged Lambda code (e.g. zip file) -- [ ] GG-LAMBDA8 = Run a SAST scan on the code and fix all findings, if possible but at a minimum fix critical and high findings (e.g. bandit for python) - -## Testing - -- [ ] GG-SOLUTION_TESTING1 = Test deploying the solution in a multi-account environment using Customizations for AWS Control Tower -- [ ] GG-SOLUTION_TESTING2 = Test removing the solution in a multi-account environment following the provided instructions -- [ ] GG-SOLUTION_TESTING3 = Have at least 1 peer review of the solution before submitting a merge/pull request diff --git a/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx b/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx index 491d0336b..65dabba30 100644 Binary files a/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx and b/aws_sra_examples/solutions/account/account_alternate_contacts/documentation/account-alternate-contacts.pptx differ diff --git a/aws_sra_examples/solutions/common/common_cfct_setup/README.md b/aws_sra_examples/solutions/common/common_cfct_setup/README.md index eb910d2c6..113cfce98 100644 --- a/aws_sra_examples/solutions/common/common_cfct_setup/README.md +++ b/aws_sra_examples/solutions/common/common_cfct_setup/README.md @@ -36,8 +36,7 @@ factory, the solution ensures that all resources attached to the account's OUs w - The [Customizations for AWS Control Tower](https://aws.amazon.com/solutions/implementations/customizations-for-aws-control-tower/) (CFCT) solution to support deploying customizations easily to your AWS Control Tower landing zone. - Defaults updated per SRA recommendations: - - - `Amazon S3 URL` = https://s3.amazonaws.com/solutions-reference/customizations-for-aws-control-tower/latest/custom-control-tower-initiation.template + - Latest template downloaded from [GitHub - customizations-for-aws-control-tower.template](https://github.com/aws-solutions/aws-control-tower-customizations/blob/main/customizations-for-aws-control-tower.template) - `AWS CodePipeline Source` = AWS CodeCommit - `Failure Tolerance Percentage` = 0 diff --git a/aws_sra_examples/solutions/common/common_cfct_setup/templates/customizations-for-aws-control-tower.template b/aws_sra_examples/solutions/common/common_cfct_setup/templates/customizations-for-aws-control-tower.template new file mode 100644 index 000000000..91a641444 --- /dev/null +++ b/aws_sra_examples/solutions/common/common_cfct_setup/templates/customizations-for-aws-control-tower.template @@ -0,0 +1,3113 @@ +# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. +AWSTemplateFormatVersion: '2010-09-09' +Description: '(SO0089) - customizations-for-aws-control-tower Solution. Version: v2.3.0' + +Parameters: + PipelineApprovalStage: + Description: Do you want to add a manual approval stage to the Custom Control Tower Configuration Pipeline? + AllowedValues: + - 'Yes' + - 'No' + Default: 'No' + Type: String + + PipelineApprovalEmail: + Description: (Not required if Pipeline Approval Stage = 'No') Email for notifying that the CustomControlTower pipeline is waiting for an Approval + Type: String + + CodePipelineSource: + Description: Which AWS CodePipeline source provider do you want to select? + AllowedValues: + - 'Amazon S3' + - 'AWS CodeCommit' + Default: 'Amazon S3' + Type: String + + CodeCommitRepositoryName: + Description: Name of the CodeCommit repository that contains custom Control Tower configuration. The suffix .git is prohibited. + Default: custom-control-tower-configuration + Type: String + AllowedPattern: ^[\w\.-]+ + + CodeCommitBranchName: + Description: Name of the branch in CodeCommit repository that contains custom Control Tower configuration. + Default: main + Type: String + + ExistingRepository: + Description: Are you using an existing CodeCommit repository that already contains custom Control Tower configuration? + Default: 'No' + Type: String + AllowedValues: + - 'Yes' + - 'No' + + RegionConcurrencyType: + Description: Select the the concurrency type of deploying StackSets operations in Regions. + Default: 'PARALLEL' + Type: String + AllowedValues: + - 'PARALLEL' + - 'SEQUENTIAL' + + MaxConcurrentPercentage: + Description: The maximum percentage of accounts in which to perform this operation at one time. + Default: 100 + Type: String + + FailureTolerancePercentage: + Description: + The percentage of accounts, per Region, for which this stack operation can fail before AWS CloudFormation stops the operation in that Region. + Default: 10 + Type: String + +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: Pipeline Configuration + Parameters: + - PipelineApprovalStage + - PipelineApprovalEmail + - CodePipelineSource + - Label: + default: AWS CodeCommit Setup (Applicable if 'AWS CodeCommit' was selected as the CodePipeline Source) + Parameters: + - ExistingRepository + - CodeCommitRepositoryName + - CodeCommitBranchName + - Label: + default: AWS CloudFormation StackSets Configuration + Parameters: + - RegionConcurrencyType + - MaxConcurrentPercentage + - FailureTolerancePercentage + + ParameterLabels: + PipelineApprovalStage: + default: Pipeline Approval Stage + PipelineApprovalEmail: + default: Pipeline Approval Email Address + CodePipelineSource: + default: AWS CodePipeline Source + ExistingRepository: + default: Existing CodeCommit Repository? + CodeCommitRepositoryName: + default: CodeCommit Repository Name + CodeCommitBranchName: + default: CodeCommit Branch Name + RegionConcurrencyType: + default: Region Concurrency Type + MaxConcurrentPercentage: + default: Max Concurrent Percentage + FailureTolerancePercentage: + default: Failure Tolerance Percentage + +Mappings: + BucketConfiguration: + SourceBucketName: + Name: control-tower-cfct-assets-prod + SourceKeyName: + Name: customizations-for-aws-control-tower/v2.3.0/custom-control-tower-configuration.zip + CustomControlTowerPipelineS3TriggerKey: + Name: custom-control-tower-configuration.zip + CustomControlTowerPipelineS3NonTriggerKey: + Name: _custom-control-tower-configuration.zip + CodePipelineSource: + CodeCommit: + RepoName: /Customizations-for-aws-control-tower/CodeCommitRepoName + BranchName: /Customizations-for-aws-control-tower/CodeCommitBranchName + KMS: + Alias: + Name: CustomControlTowerKMSKey + Solution: + Metrics: + SendAnonymousData: 'Yes' + SolutionID: 'SO0089' + MetricsURL: 'https://metrics.awssolutionsbuilder.com/generic' + Data: + AddonTemplate: 'https://s3.amazonaws.com/control-tower-cfct-assets-prod/customizations-for-aws-control-tower/v2.3.0/custom-control-tower-initiation.template' + AWSControlTower: + ExecutionRole: + Name: 'AWSControlTowerExecution' + LambdaFunction: + Logging: + Level: 'info' + FindReplace: + Values: + NoneType: 'null' + BoolType: 'yes,no,Yes,No,True,False,true,false' # no spaces are allowed in this string, comma is the only allowed delimiter + AutoBuild: + CustomControlTower: + Flag: 'No' + ControlTowerBaselineConfigStackset: + Info: + Name: 'AWSControlTowerBP-BASELINE-CONFIG' + +Conditions: + IsPipelineApprovalStageCondition: !Equals [!Ref PipelineApprovalStage, 'Yes'] + IsBuildCustomControlTowerCondition: !Equals [!FindInMap [AutoBuild, CustomControlTower, Flag], 'Yes'] + IsCodeCommitPipelineSource: !Equals [!Ref CodePipelineSource, 'AWS CodeCommit'] + IsExistingRepository: !Equals [!Ref ExistingRepository, 'Yes'] + IsNewCodeCommitRepository: !And [!Not [!Condition IsExistingRepository], !Condition IsCodeCommitPipelineSource] + +Resources: + PipelineApprovalTopic: + Type: AWS::SNS::Topic + Condition: IsPipelineApprovalStageCondition + Properties: + KmsMasterKeyId: alias/aws/sns + Subscription: + - Endpoint: !Ref PipelineApprovalEmail + Protocol: email + + CustomControlTowerPipelineS3Bucket: + Type: AWS::S3::Bucket + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + BucketName: !Sub custom-control-tower-configuration-${AWS::AccountId}-${AWS::Region} + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + VersioningConfiguration: + Status: Enabled + LoggingConfiguration: + DestinationBucketName: !Ref CustomControlTowerS3AccessLogsBucket + PublicAccessBlockConfiguration: + BlockPublicAcls: True + BlockPublicPolicy: True + IgnorePublicAcls: True + RestrictPublicBuckets: True + + CustomControlTowerPipelineS3BucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CustomControlTowerPipelineS3Bucket + PolicyDocument: + Statement: + - Sid: DenyDeleteBucket + Effect: Deny + Principal: '*' + Action: s3:DeleteBucket + Resource: !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineS3Bucket} + + CustomControlTowerPipelineArtifactS3Bucket: + Type: AWS::S3::Bucket + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + VersioningConfiguration: + Status: Enabled + LoggingConfiguration: + DestinationBucketName: !Ref CustomControlTowerS3AccessLogsBucket + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + PublicAccessBlockConfiguration: + BlockPublicAcls: True + BlockPublicPolicy: True + IgnorePublicAcls: True + RestrictPublicBuckets: True + + CustomControlTowerPipelineArtifactS3BucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CustomControlTowerPipelineArtifactS3Bucket + PolicyDocument: + Statement: + - Sid: DenyDeleteBucket + Effect: Deny + Principal: '*' + Action: s3:DeleteBucket + Resource: !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket} + + # Create buckets using S3-SSE keys for default encryption + CustomControlTowerS3AccessLogsBucket: + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Type: AWS::S3::Bucket + Metadata: + cfn_nag: + rules_to_suppress: + - id: W35 + reason: + "This S3 bucket is used as the destination for 'CustomControlTowerPipelineS3Bucket' and 'CustomControlTowerPipelineArtifactS3Bucket'" + checkov: + skip: + - id: CKV_AWS_18 + comment: S3 bucket logging is not enabled. + - id: CKV_AWS_116 + comment: DLQ not needed. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + AccessControl: LogDeliveryWrite + VersioningConfiguration: + Status: Enabled + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + PublicAccessBlockConfiguration: + BlockPublicAcls: True + BlockPublicPolicy: True + IgnorePublicAcls: True + RestrictPublicBuckets: True + + CustomControlTowerS3AccessLogsBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CustomControlTowerS3AccessLogsBucket + PolicyDocument: + Statement: + - Sid: DenyDeleteBucket + Effect: Deny + Principal: '*' + Action: s3:DeleteBucket + Resource: !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerS3AccessLogsBucket} + + CustomControlTowerCodeCommit: + Type: AWS::CodeCommit::Repository + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Condition: IsNewCodeCommitRepository + Properties: + RepositoryDescription: Configuration for Customizations for AWS Control Tower solution + RepositoryName: !Ref CodeCommitRepositoryName + Code: + S3: + Bucket: control-tower-cfct-assets-prod + Key: !Sub customizations-for-aws-control-tower/v2.3.0/custom-control-tower-configuration-${AWS::Region}.zip + + # SSM Parameter to store the git repository name + CustomControlTowerRepoNameParameter: + Type: AWS::SSM::Parameter + Properties: + Name: + Fn::FindInMap: + - CodePipelineSource + - CodeCommit + - RepoName + Description: Contains the name of the CodeCommit repository + Type: String + Value: !Ref CodeCommitRepositoryName + + # SSM Parameter to store the git repository branch name + CustomControlTowerBranchNameParameter: + Type: AWS::SSM::Parameter + Properties: + Name: + Fn::FindInMap: + - CodePipelineSource + - CodeCommit + - BranchName + Description: Contains the name of the CodeCommit repository branch + Type: String + Value: !Ref CodeCommitBranchName + + CustomControlTowerCodePipelineRole: + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: 'The role name is defined to identify Custom Control Tower resources.' + - id: W11 + reason: + 'Allow Resource * for KMS/SSM API. KMS Service only support all resources. Key ID is generated by the service. SSM parameters are + customer defined.' + Properties: + RoleName: CustomControlTowerCodePipelineRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'codepipeline.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + Policies: + - PolicyName: 'Custom-Control-Tower-CodePipeline-Policy' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - s3:GetBucketVersioning + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket} + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineS3Bucket} + - Effect: 'Allow' + Action: + - s3:PutObject + - s3:GetObject + - s3:GetObjectVersion + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket}/* + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineS3Bucket}/* + - Effect: Allow + Action: + - ssm:PutParameter + - ssm:GetParameter + - ssm:DeleteParameter + - ssm:GetParametersByPath + - ssm:DescribeParameters + Resource: '*' + - Effect: 'Allow' + Action: + - 'codebuild:BatchGetBuilds' + - 'codebuild:StartBuild' + Resource: + - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:project/${CustomControlTowerCodeBuild} + - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:project/${SCPCodeBuild} + - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:project/${StackSetCodeBuild} + - Effect: 'Allow' + Action: + - codecommit:GetBranch + - codecommit:GetCommit + - codecommit:UploadArchive + - codecommit:GetUploadArchiveStatus + - codecommit:CancelUploadArchive + Resource: '*' + - Effect: 'Allow' + Action: + - lambda:ListFunctions + - lambda:ListVersionsByFunction + Resource: '*' + - !If + - IsPipelineApprovalStageCondition + - Effect: 'Allow' + Action: + - 'sns:Publish' + Resource: !Ref PipelineApprovalTopic + - !Ref AWS::NoValue + + CustomControlTowerCodePipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + Name: Custom-Control-Tower-CodePipeline + RoleArn: !GetAtt CustomControlTowerCodePipelineRole.Arn + ArtifactStore: + Location: !Ref CustomControlTowerPipelineArtifactS3Bucket + Type: S3 + Stages: + - Name: Source + Actions: + - Name: Source + ActionTypeId: !If + - IsCodeCommitPipelineSource + - Category: Source + Owner: AWS + Version: '1' + Provider: CodeCommit + - Category: Source + Owner: AWS + Version: '1' + Provider: S3 + OutputArtifacts: + - Name: SourceApp + Configuration: !If + - IsCodeCommitPipelineSource + - RepositoryName: !Ref CodeCommitRepositoryName + BranchName: !Ref CodeCommitBranchName + - S3Bucket: !Ref CustomControlTowerPipelineS3Bucket + S3ObjectKey: !FindInMap [BucketConfiguration, CustomControlTowerPipelineS3TriggerKey, Name] + RunOrder: 1 + - Name: Build + Actions: + - Name: CodeBuild + InputArtifacts: + - Name: SourceApp + ActionTypeId: + Category: Build + Owner: AWS + Version: '1' + Provider: CodeBuild + OutputArtifacts: + - Name: BuiltApp + Configuration: + ProjectName: !Ref CustomControlTowerCodeBuild + - !If + - IsPipelineApprovalStageCondition + - Name: Approval + Actions: + - Name: Approval + ActionTypeId: + Category: Approval + Owner: AWS + Version: '1' + Provider: Manual + RunOrder: 1 + Configuration: + NotificationArn: !Ref PipelineApprovalTopic + - !Ref AWS::NoValue + - Name: ServiceControlPolicy + Actions: + - Name: CodeBuild + InputArtifacts: + - Name: BuiltApp + ActionTypeId: + Category: Build + Owner: AWS + Version: '1' + Provider: CodeBuild + Configuration: + ProjectName: !Ref SCPCodeBuild + - Name: CloudformationResource + Actions: + - Name: CodeBuild + InputArtifacts: + - Name: BuiltApp + ActionTypeId: + Category: Build + Owner: AWS + Version: '1' + Provider: CodeBuild + Configuration: + ProjectName: !Ref StackSetCodeBuild + + CustomControlTowerCodeBuildRole: + Type: 'AWS::IAM::Role' + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: 'Allow Resource * for Cloudformation/SSM API: needs to support user defined cfn templates and ssm parameter names.' + checkov: + skip: + - id: CKV_AWS_108 + comment: 'Allow Resource * for Cloudformation/SSM API: needs to support user defined cfn templates and ssm parameter names.' + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'codebuild.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + Policies: + - PolicyName: 'Custom-Control-Tower-CodeBuild-Policy' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/* + - Effect: 'Allow' + Action: + - s3:PutObject + - s3:GetObjectVersion + - s3:DeleteObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket}/* + - Effect: Allow + Action: + - s3:GetObject + - cloudformation:ValidateTemplate + Resource: '*' + - Effect: 'Allow' + Action: + - s3:GetObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::control-tower-cfct-assets-prod/* + - Effect: Allow + Action: + - ssm:GetParameter + - ssm:GetParametersByPath + Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* + - Effect: Allow + Action: + - ssm:DescribeParameters + Resource: '*' # The APIs above only support '*' resource. + + CustomControlTowerCodeBuild: + Type: AWS::CodeBuild::Project + DependsOn: CustomControlTowerDeploymentLambda + Properties: + Name: Custom-Control-Tower-CodeBuild + ServiceRole: !GetAtt CustomControlTowerCodeBuildRole.Arn + EncryptionKey: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + Source: + Type: CODEPIPELINE + BuildSpec: + "version: 0.2\nphases:\n install:\n runtime-versions:\n python: 3.8\n ruby: 2.6\n commands:\n - export + current=$(pwd)\n - if [ -f manifest.yaml ];then export current=$(pwd);else if [ -f custom-control-tower-configuration/manifest.yaml ]; + then export current=$(pwd)/custom-control-tower-configuration; else echo 'manifest.yaml does not exist at the root level of + custom-control-tower-configuration.zip or inside custom-control-tower-configuration folder, please check the ZIP file'; exit 1; fi; + fi;\n # https://github.com/aws-solutions/aws-control-tower-customizations/issues/102\n - apt-mark hold + java-1.8.0-amazon-corretto-jdk\n - apt-get -q update 1> /dev/null && apt-get -q upgrade -y 1> /dev/null\n - apt-get -q install zip + wget python-pip libyaml-dev -y 1>/dev/null\n - export LC_ALL='en_US.UTF-8'\n - locale-gen en_US en_US.UTF-8\n - + dpkg-reconfigure locales\n pre_build:\n commands:\n - cd $current\n - echo 'Download CustomControlTower Scripts'\n - aws + s3 cp --quiet s3://control-tower-cfct-assets-prod/customizations-for-aws-control-tower/v2.3.0/custom-control-tower-scripts.zip + $current\n - unzip -q -o $current/custom-control-tower-scripts.zip -d $current\n - cp codebuild_scripts/* .\n - bash + install_stage_dependencies.sh $STAGE_NAME\n build:\n commands:\n - echo 'Starting build $(date) in $(pwd)'\n - echo 'bash + execute_stage_scripts.sh $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME $BOOL_VALUES + $NONE_TYPE_VALUES'\n - bash execute_stage_scripts.sh $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME + $BOOL_VALUES $NONE_TYPE_VALUES \n - echo 'Running build scripts completed $(date)'\n post_build:\n commands:\n - echo + 'Starting post build $(date) in $(pwd)'\n - echo 'build completed on $(date)'\n\nartifacts:\n files:\n - '**/*'\n\n" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: 'aws/codebuild/standard:4.0' + Type: LINUX_CONTAINER + EnvironmentVariables: + - Name: ARTIFACT_BUCKET + Value: !Ref CustomControlTowerPipelineArtifactS3Bucket + - Name: NONE_TYPE_VALUES + Value: !FindInMap [FindReplace, Values, NoneType] + - Name: BOOL_VALUES + Value: !FindInMap [FindReplace, Values, BoolType] + - Name: STAGE_NAME + Value: 'build' + - Name: SM_ARN + Value: 'NA' + - Name: LOG_LEVEL + Value: !FindInMap [LambdaFunction, Logging, Level] + - Name: WAIT_TIME + Value: '30' + - Name: KMS_KEY_ALIAS_NAME + Value: !FindInMap [KMS, Alias, Name] + - Name: SOLUTION_ID + Value: !FindInMap [Solution, Metrics, SolutionID] + - Name: SOLUTION_VERSION + Value: v2.3.0 + Artifacts: + Name: !Sub ${CustomControlTowerPipelineArtifactS3Bucket}-Built + Type: CODEPIPELINE + + SCPCodeBuildRole: + Type: 'AWS::IAM::Role' + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: 'Allow * for Organizations APIs to list/describe/move user created child accounts in the AWS Organizations' + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'codebuild.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + Policies: + - PolicyName: 'Custom-Control-Tower-SCP-CodeBuild-Policy-Logs' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/* + - PolicyName: 'Custom-Control-Tower-SCP-CodeBuild-Policy-S3' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - s3:GetObject + - s3:PutObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket}/* + - Effect: 'Allow' + Action: + - s3:GetObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::*/* # needed to support validation of remotely sourced templates feature. The host S3 bucket can be created by the customers or partners. + - PolicyName: 'Custom-Control-Tower-SCP-CodeBuild-Policy-StepFunctions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - states:ListExecutions + - states:StartExecution + - states:StopExecution + - states:DescribeStateMachine + Resource: + - !Ref ServiceControlPolicyMachine + - Effect: Allow + Action: + - states:DescribeStateMachineForExecution + - states:DescribeExecution + Resource: + - !Sub arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:execution:${ServiceControlPolicyMachine.Name}:* + - PolicyName: 'Custom-Control-Tower-SCP-CodeBuild-Policy-Organizations' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - organizations:ListRoots + - organizations:ListOrganizationalUnitsForParent + - organizations:ListAccountsForParent + Resource: '*' # The APIs above only support '*' resource. + - PolicyName: 'Custom-Control-Tower-SCP-CodeBuild-Policy-SSM' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ssm:GetParameter + - ssm:GetParametersByPath + Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* + - Effect: Allow + Action: + - ssm:DescribeParameters + Resource: '*' # The APIs above only support '*' resource. + + SCPCodeBuild: + Type: AWS::CodeBuild::Project + DependsOn: CustomControlTowerDeploymentLambda + Properties: + Name: Custom-Control-Tower-SCP-CodeBuild + ServiceRole: !GetAtt SCPCodeBuildRole.Arn + EncryptionKey: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + Source: + Type: CODEPIPELINE + BuildSpec: + "version: 0.2\nphases:\n install:\n runtime-versions:\n python: 3.8\n ruby: 2.6\n commands:\n - export + current=$(pwd)\n - if [ -f manifest.yaml ];then export current=$(pwd);else if [ -f custom-control-tower-configuration/manifest.yaml ]; + then export current=$(pwd)/custom-control-tower-configuration; else echo 'manifest.yaml does not exist at the root level of + custom-control-tower-configuration.zip or inside custom-control-tower-configuration folder, please check the ZIP file'; exit 1; fi; + fi;\n # https://github.com/aws-solutions/aws-control-tower-customizations/issues/102\n - apt-mark hold + java-1.8.0-amazon-corretto-jdk\n - apt-get -q update 1> /dev/null && apt-get -q upgrade -y 1> /dev/null\n - apt-get -q install zip + wget python-pip libyaml-dev -y 1> /dev/null \n pre_build:\n commands:\n - cd $current\n - echo 'Download CustomControlTower + Scripts'\n - aws s3 cp --quiet + s3://control-tower-cfct-assets-prod/customizations-for-aws-control-tower/v2.3.0/custom-control-tower-scripts.zip $current\n - unzip -q + -o $current/custom-control-tower-scripts.zip -d $current\n - cp codebuild_scripts/* .\n - bash install_stage_dependencies.sh + $STAGE_NAME\n build:\n commands:\n - echo 'Starting build $(date) in $(pwd)'\n - echo 'bash execute_stage_scripts.sh + $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME $BOOL_VALUES $NONE_TYPE_VALUES'\n - bash + execute_stage_scripts.sh $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME $BOOL_VALUES + $NONE_TYPE_VALUES\n - echo 'Running build scripts completed $(date)'\n post_build:\n commands:\n - echo 'Starting post build + $(date) in $(pwd)'\n - echo 'build completed on $(date)'\n\nartifacts:\n files:\n - '**/*'\n" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: 'aws/codebuild/standard:4.0' + Type: LINUX_CONTAINER + EnvironmentVariables: + - Name: SM_ARN + Value: !Ref ServiceControlPolicyMachine + - Name: LOG_LEVEL + Value: !FindInMap [LambdaFunction, Logging, Level] + - Name: WAIT_TIME + Value: '30' + - Name: STAGE_NAME + Value: 'scp' + - Name: ARTIFACT_BUCKET + Value: !Ref CustomControlTowerPipelineArtifactS3Bucket + - Name: KMS_KEY_ALIAS_NAME + Value: !FindInMap [KMS, Alias, Name] + - Name: SOLUTION_ID + Value: !FindInMap [Solution, Metrics, SolutionID] + - Name: SOLUTION_VERSION + Value: v2.3.0 + Artifacts: + Name: !Sub ${CustomControlTowerPipelineArtifactS3Bucket}-Built + Type: CODEPIPELINE + TimeoutInMinutes: 60 + + StackSetCodeBuildRole: + Type: 'AWS::IAM::Role' + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: 'Allow * for Organizations APIs to list/describe/move user created child accounts in the AWS Organizations' + - id: W11 + reason: 'Allow * for ec2 APIs because information like account, region, etc. are dynamically determined by custom configuration' + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'codebuild.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + Policies: + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-Logs' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/* + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-S3' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - s3:GetObject + - s3:PutObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineArtifactS3Bucket}/* + - Effect: 'Allow' + Action: + - s3:GetObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::*/* # needed to support validation of remotely sourced templates feature. The host S3 bucket can be created by the customers or partners. + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-StepFunctions' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - states:ListExecutions + - states:StartExecution + - states:StopExecution + - states:DescribeStateMachine + Resource: + - !Ref StackSetStateMachine + - Effect: Allow + Action: + - states:DescribeStateMachineForExecution + - states:DescribeExecution + Resource: + - !Sub arn:${AWS::Partition}:states:${AWS::Region}:${AWS::AccountId}:execution:${StackSetStateMachine.Name}:* + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-Organizations' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - organizations:ListRoots + - organizations:ListOrganizationalUnitsForParent + - organizations:ListAccountsForParent + - organizations:ListAccounts + - organizations:DescribeOrganization + Resource: '*' # The APIs above only support '*' resource. + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-SSM' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ssm:GetParameter + - ssm:PutParameter + - ssm:GetParametersByPath + Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* + - Effect: Allow + Action: + - ssm:DescribeParameters + Resource: '*' # The APIs above only support '*' resource. + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-KMS' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - kms:Encrypt + - kms:Decrypt + - kms:ReEncryptFrom + - kms:ReEncryptTo + - kms:GenerateDataKey + - kms:GenerateDataKeyWithoutPlaintext + - kms:DescribeKey + Resource: + - !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/* + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-STS' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - sts:AssumeRole + Resource: !Sub + - arn:${AWS::Partition}:iam::*:role/${CustomControlTowerExecutionRole} + - { CustomControlTowerExecutionRole: !FindInMap [AWSControlTower, ExecutionRole, Name] } + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-EC2' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:DescribeAvailabilityZones + Resource: + - '*' # The APIs above only support '*' resource. + - PolicyName: 'Custom-Control-Tower-StackSet-CodeBuild-Policy-CloudFormation' + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - cloudformation:DescribeStackSet + - cloudformation:ListStackInstances + - cloudformation:ListStackSetOperations + Resource: + - !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/* + + StackSetCodeBuild: + Type: AWS::CodeBuild::Project + DependsOn: CustomControlTowerDeploymentLambda + Properties: + Name: Custom-Control-Tower-StackSet-CodeBuild + ServiceRole: !GetAtt StackSetCodeBuildRole.Arn + EncryptionKey: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + Source: + Type: CODEPIPELINE + BuildSpec: + "version: 0.2\nphases:\n install:\n runtime-versions:\n python: 3.8\n ruby: 2.6\n commands:\n - export + current=$(pwd)\n - if [ -f manifest.yaml ];then export current=$(pwd);else if [ -f custom-control-tower-configuration/manifest.yaml ]; + then export current=$(pwd)/custom-control-tower-configuration; else echo 'manifest.yaml does not exist at the root level of + custom-control-tower-configuration.zip or inside custom-control-tower-configuration folder, please check the ZIP file'; exit 1; fi; + fi;\n # https://github.com/aws-solutions/aws-control-tower-customizations/issues/102\n - apt-mark hold + java-1.8.0-amazon-corretto-jdk\n - apt-get -q update 1> /dev/null && apt-get -q upgrade -y 1> /dev/null\n - apt-get -q install zip + wget python-pip libyaml-dev -y 1> /dev/null\n pre_build:\n commands:\n - cd $current\n - echo 'Download CustomControlTower + Scripts'\n - aws s3 cp --quiet + s3://control-tower-cfct-assets-prod/customizations-for-aws-control-tower/v2.3.0/custom-control-tower-scripts.zip $current\n - unzip -q + -o $current/custom-control-tower-scripts.zip -d $current\n - cp codebuild_scripts/* .\n - bash install_stage_dependencies.sh + $STAGE_NAME\n build:\n commands:\n - echo 'Starting build $(date) in $(pwd)'\n - echo 'bash execute_stage_scripts.sh + $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME $BOOL_VALUES $NONE_TYPE_VALUES'\n - bash + execute_stage_scripts.sh $STAGE_NAME $LOG_LEVEL $WAIT_TIME $SM_ARN $ARTIFACT_BUCKET $KMS_KEY_ALIAS_NAME $BOOL_VALUES + $NONE_TYPE_VALUES\n - echo 'Running build scripts completed $(date)'\n post_build:\n commands:\n - echo 'Starting post build + $(date) in $(pwd)'\n - echo 'build completed on $(date)'\n\nartifacts:\n files:\n - '**/*'\n" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + Image: 'aws/codebuild/standard:4.0' + Type: LINUX_CONTAINER + EnvironmentVariables: + - Name: SM_ARN + Value: !Ref StackSetStateMachine + - Name: LOG_LEVEL + Value: !FindInMap [LambdaFunction, Logging, Level] + - Name: WAIT_TIME + Value: '30' + - Name: STAGE_NAME + Value: 'stackset' + - Name: ARTIFACT_BUCKET + Value: !Ref CustomControlTowerPipelineArtifactS3Bucket + - Name: KMS_KEY_ALIAS_NAME + Value: !FindInMap [KMS, Alias, Name] + - Name: EXECUTION_ROLE_NAME + Value: !FindInMap [AWSControlTower, ExecutionRole, Name] + - Name: SOLUTION_ID + Value: !FindInMap [Solution, Metrics, SolutionID] + - Name: SOLUTION_VERSION + Value: v2.3.0 + - Name: METRICS_URL + Value: !FindInMap [Solution, Metrics, MetricsURL] + - Name: CONTROL_TOWER_BASELINE_CONFIG_STACKSET + Value: !FindInMap [ControlTowerBaselineConfigStackset, Info, Name] + Artifacts: + Name: !Sub ${CustomControlTowerPipelineArtifactS3Bucket}-Built + Type: CODEPIPELINE + TimeoutInMinutes: 480 + + CustomControlTowerDeploymentLambdaRole: + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: 'Allow Resource * for KMS API. KMS Service only support all resources. Key ID is generated by the service.' + - id: W28 + reason: 'The role name is defined to identify Custom Control Tower resources.' + Properties: + RoleName: CustomControlTowerDeploymentLambdaRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Path: / + Policies: + - PolicyName: Custom-Control-Tower-DeploymentLambda-Logs + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/* + - Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + Resource: '*' + - PolicyName: Custom-Control-Tower-DeploymentLambda-KMS + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - kms:DescribeKey + - kms:TagResource + - kms:PutKeyPolicy + - kms:GetKeyRotationStatus + - kms:EnableKeyRotation + Resource: + - !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/* + - Effect: 'Allow' + Action: + - kms:CreateKey + - kms:ListAliases + Resource: '*' + - Effect: 'Allow' + Action: + - kms:CreateAlias + Resource: + - !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/* + - !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/* + - PolicyName: Custom-Control-Tower-DeploymentLambda-S3 + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - s3:GetEncryptionConfiguration + - s3:PutEncryptionConfiguration + Resource: + - !GetAtt CustomControlTowerPipelineS3Bucket.Arn + - Effect: 'Allow' + Action: + - s3:GetObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::control-tower-cfct-assets-prod/* + - Effect: 'Allow' + Action: + - s3:GetObject + - s3:PutObject + Resource: + - !Sub arn:${AWS::Partition}:s3:::${CustomControlTowerPipelineS3Bucket}/* + - PolicyName: Custom-Control-Tower-DeploymentLambda-SSM + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ssm:PutParameter + - ssm:GetParameter + - ssm:DeleteParameter + - ssm:GetParametersByPath + Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* + - Effect: Allow + Action: + - ssm:DescribeParameters + Resource: '*' # The APIs above only support '*' resource. + + CustomControlTowerDeploymentLambda: + Type: AWS::Lambda::Function + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: 'Permission for writing cloudwatch logs is defined in the lambda role' + - id: W89 + reason: 'This lambda function does not need access to VPC resources' + - id: W92 + reason: 'This use case does not need to set the ReservedConcurrentExecutions' + checkov: + skip: + - id: CKV_AWS_18 + comment: S3 bucket logging is not enabled. + - id: CKV_AWS_116 + comment: DLQ not needed. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + Environment: + Variables: + LOG_LEVEL: !FindInMap [LambdaFunction, Logging, Level] + SOLUTION_ID: !FindInMap [Solution, Metrics, SolutionID] + SOLUTION_VERSION: v2.3.0 + Code: + S3Bucket: !Sub 'control-tower-cfct-assets-prod-${AWS::Region}' + S3Key: customizations-for-aws-control-tower/v2.3.0/custom-control-tower-config-deployer.zip + FunctionName: CustomControlTowerDeploymentLambda + Description: Custom Control Tower Deployment Lambda + Handler: config_deployer.lambda_handler + MemorySize: 512 + Role: !GetAtt 'CustomControlTowerDeploymentLambdaRole.Arn' + Runtime: python3.8 + Timeout: 300 + TracingConfig: + Mode: Active + + CustomControlTowerConfigDeployer: + Type: Custom::ConfigDeployer + Properties: + MetricsFlag: !FindInMap [Solution, Metrics, SendAnonymousData] + BucketConfig: + DestinationBucketName: !Ref CustomControlTowerPipelineS3Bucket + DestinationS3Key: + !If [ + IsBuildCustomControlTowerCondition, + !FindInMap [BucketConfiguration, CustomControlTowerPipelineS3TriggerKey, Name], + !FindInMap [BucketConfiguration, CustomControlTowerPipelineS3NonTriggerKey, Name], + ] + SourceBucketName: !FindInMap [BucketConfiguration, SourceBucketName, Name] + SourceS3Key: !FindInMap [BucketConfiguration, SourceKeyName, Name] + KMSConfig: + KMSKeyAlias: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + KMSKeyPolicy: + Version: '2012-10-17' + Id: 'key-CustomControlTower-1' + Statement: + - Sid: 'Allow administration of the key' + Effect: 'Allow' + Principal: + AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root + Action: + - 'kms:Create*' + - 'kms:Describe*' + - 'kms:Enable*' + - 'kms:List*' + - 'kms:Put*' + - 'kms:Update*' + - 'kms:Revoke*' + - 'kms:Disable*' + - 'kms:Get*' + - 'kms:Delete*' + - 'kms:ScheduleKeyDeletion' + - 'kms:CancelKeyDeletion' + Resource: '*' + - Sid: 'Allow use of the key' + Effect: 'Allow' + Principal: + AWS: + - Fn::Sub: ${CustomControlTowerStateMachineLambdaRole.Arn} + - Fn::Sub: ${CustomControlTowerDeploymentLambdaRole.Arn} + - Fn::Sub: ${CustomControlTowerCodePipelineRole.Arn} + - Fn::Sub: ${CustomControlTowerCodeBuildRole.Arn} + - Fn::Sub: ${SCPCodeBuildRole.Arn} + - Fn::Sub: ${StackSetCodeBuildRole.Arn} + - Fn::Sub: ${CustomControlTowerLELambdaRole.Arn} + Service: + - 'events.amazonaws.com' + Action: + - 'kms:Encrypt' + - 'kms:Decrypt' + - 'kms:ReEncrypt*' + - 'kms:GenerateDataKey*' + - 'kms:DescribeKey' + Resource: '*' + FindReplace: + - FileName: manifest.yaml.j2 + Parameters: + region: !Sub ${AWS::Region} + ServiceToken: !GetAtt CustomControlTowerDeploymentLambda.Arn + + CustomControlTowerStateMachineLambdaRole: + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: F38 + reason: 'PassRole action is required to make changes to all (*) the Service Catalog Resources' + - id: W28 + reason: 'The role name is defined to identify Custom Control Tower resources.' + - id: W11 + reason: 'Allow Resource * for KMS/SSM/Org/SC/CFN API. Key ID is generated by the service. Other resources are customer defined.' + checkov: + skip: + - id: CKV_AWS_108 + comment: 'Allow Resource * for KMS/SSM/Org/SC/CFN API. Key ID is generated by the service. Other resources are customer defined.' + - id: CKV_AWS_109 + comment: Permission management required + - id: CKV_AWS_111 + comment: wild card required for service actions + Properties: + RoleName: CustomControlTowerStateMachineLambdaRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Path: / + Policies: + - PolicyName: State-Machine-Lambda-Policy-Logs + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/* + - Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + Resource: '*' + - PolicyName: State-Machine-Lambda-Policy-IAM + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - iam:GetRole + Resource: '*' + - Effect: Allow + Action: + - iam:PassRole + Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + - PolicyName: State-Machine-Lambda-Policy-Organizations + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - organizations:CreateOrganization + - organizations:CreateOrganizationalUnit + - organizations:ListPolicies + - organizations:ListPoliciesForTarget + - organizations:ListTargetsForPolicy + - organizations:ListParents + - organizations:ListRoots + - organizations:ListAccounts + - organizations:ListOrganizationalUnitsForParent + - organizations:ListAccountsForParent + - organizations:EnablePolicyType + - organizations:CreatePolicy + - organizations:UpdatePolicy + - organizations:DeletePolicy + - organizations:DetachPolicy + - organizations:AttachPolicy + - organizations:CreateAccount + - organizations:DescribeAccount + - organizations:DescribeCreateAccountStatus + - organizations:DescribeOrganization + - organizations:UpdateOrganizationalUnit + Resource: '*' # The APIs above only support '*' resource. + - PolicyName: State-Machine-Lambda-Policy-CloudFormation + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - cloudformation:CreateStackSet + - cloudformation:CreateStack + - cloudformation:DeleteStack + - cloudformation:DeleteStackSet + - cloudformation:CreateStackInstances + - cloudformation:DeleteStackInstances + - cloudformation:DescribeStackInstance + - cloudformation:DescribeStackSetOperation + - cloudformation:DescribeStackSet + - cloudformation:UpdateStackSet + - cloudformation:UpdateStackInstances + - cloudformation:TagResource + - cloudformation:ListStackInstances + - cloudformation:GetTemplateSummary + - cloudformation:DescribeStacks + Resource: + - !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/* + - !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/* + - Effect: Allow + Action: + - cloudformation:ValidateTemplate + Resource: '*' + - PolicyName: State-Machine-Lambda-Policy-SSM + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ssm:PutParameter + - ssm:GetParameter + - ssm:GetParameters + - ssm:DeleteParameter + - ssm:GetParametersByPath + Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/* + - Effect: Allow + Action: + - ssm:DescribeParameters + Resource: '*' + - PolicyName: State-Machine-Lambda-Policy-KMS + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - kms:Encrypt + - kms:Decrypt + - kms:ReEncryptFrom + - kms:ReEncryptTo + - kms:GenerateDataKey + - kms:GenerateDataKeyWithoutPlaintext + - kms:DescribeKey + Resource: + - !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/* + - PolicyName: State-Machine-Lambda-Policy-S3 + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - s3:PutObject + - s3:GetObject + - s3:ListBucketByTags + - s3:ListBucketMultipartUploads + - s3:ListAllMyBuckets + - s3:PutBucketLogging + - s3:ListBucketVersions + - s3:PutBucketPolicy + - s3:CreateBucket + - s3:ListBucket + - s3:GetBucketPolicy + Resource: '*' # supports remotely sourced templates feature. The host S3 bucket can be created by the customer. + - PolicyName: State-Machine-Lambda-Policy-EC2 + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - ec2:DescribeRegions + Resource: '*' + - PolicyName: State-Machine-Lambda-Policy-STS + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - sts:AssumeRole + Resource: !Sub + - arn:${AWS::Partition}:iam::*:role/${CustomControlTowerExecutionRole} + - { CustomControlTowerExecutionRole: !FindInMap [AWSControlTower, ExecutionRole, Name] } + + StateMachineLambda: + Type: AWS::Lambda::Function + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: 'Permission for writing cloudwatch logs is defined in the lambda role' + - id: W89 + reason: 'This lambda function does not need access to VPC resources' + - id: W92 + reason: 'This use case does not need to set the ReservedConcurrentExecutions' + checkov: + skip: + - id: CKV_AWS_18 + comment: S3 bucket logging is not enabled. + - id: CKV_AWS_116 + comment: DLQ not needed. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + Environment: + Variables: + LOG_LEVEL: !FindInMap [LambdaFunction, Logging, Level] + KMS_KEY_ALIAS_NAME: !FindInMap [KMS, Alias, Name] + ADMINISTRATION_ROLE_ARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + EXECUTION_ROLE_NAME: !FindInMap [AWSControlTower, ExecutionRole, Name] + SOLUTION_ID: !FindInMap [Solution, Metrics, SolutionID] + SOLUTION_VERSION: v2.3.0 + METRICS_URL: !FindInMap [Solution, Metrics, MetricsURL] + MAX_CONCURRENT_PERCENT: !Ref MaxConcurrentPercentage + FAILED_TOLERANCE_PERCENT: !Ref FailureTolerancePercentage + REGION_CONCURRENCY_TYPE: !Ref RegionConcurrencyType + Code: + S3Bucket: !Sub 'control-tower-cfct-assets-prod-${AWS::Region}' + S3Key: customizations-for-aws-control-tower/v2.3.0/custom-control-tower-state-machine.zip + FunctionName: CustomControlTowerStateMachineLambda + Description: Custom Control Tower State Machine Handler + Handler: state_machine_router.lambda_handler + MemorySize: 1024 + Role: !GetAtt 'CustomControlTowerStateMachineLambdaRole.Arn' + Runtime: python3.8 + Timeout: 300 + TracingConfig: + Mode: Active + + StateMachineRole: + Type: 'AWS::IAM::Role' + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - !Sub 'states.${AWS::Region}.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + Policies: + - PolicyName: State-Machine-Invoke-Lambda + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Action: + - 'lambda:InvokeFunction' + Resource: !GetAtt StateMachineLambda.Arn + + ServiceControlPolicyMachine: + Type: 'AWS::StepFunctions::StateMachine' + Properties: + StateMachineName: CustomControlTowerServiceControlPolicyMachine + RoleArn: !GetAtt 'StateMachineRole.Arn' + DefinitionString: + Fn::Sub: |- + { + "Comment": "A state machine that manages the Service Control Policies.", + "StartAt": "Metrics Pass", + "States": { + "Metrics Pass": { + "Type": "Pass", + "Result": { + "ClassName": "StackSetSMRequests", + "FunctionName": "send_execution_data" + }, + "ResultPath": "$.params", + "Next": "Metrics" + }, + "Metrics": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Create/Delete or Attach/Detach Policy?" + }, + "Create/Delete or Attach/Detach Policy?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.ResourceProperties.AccountId", + "StringEquals": "", + "Next": "Enable Policy Type params" + }, + { + "Variable": "$.ResourceProperties.AccountId", + "StringGreaterThan": "", + "Next": "Attach/Detach Policy params" + } + ] + }, + "Enable Policy Type params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "enable_policy_type" + }, + "ResultPath": "$.params", + "Next": "Enable Policy Type" + }, + "Enable Policy Type": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Wait" + }, + "Wait": { + "Type": "Wait", + "Seconds": 10, + "Next": "Create/Delete Policy params" + }, + "Create/Delete Policy params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "list_policies" + }, + "ResultPath": "$.params", + "Next": "Check If Policy Exist?" + }, + "Check If Policy Exist?": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Create or Delete Policy?" + }, + "Create or Delete Policy?": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Or": [ + { + "Variable": "$.RequestType", + "StringEquals": "Create" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Update" + } + ] + }, + { + "Variable": "$.PolicyExist", + "StringEquals": "no" + } + ], + "Next": "Create Policy Params" + }, + { + "And": [ + { + "Or": [ + { + "Variable": "$.RequestType", + "StringEquals": "Create" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Update" + } + ] + }, + { + "Variable": "$.PolicyExist", + "StringEquals": "yes" + } + ], + "Next": "Update Policy Params" + }, + { + "And": [ + { + "Variable": "$.RequestType", + "StringEquals": "Delete" + }, + { + "Variable": "$.PolicyExist", + "StringEquals": "yes" + } + ], + "Next": "Detach Policy from All Accounts Params" + }, + { + "And": [ + { + "Variable": "$.RequestType", + "StringEquals": "Delete" + }, + { + "Variable": "$.PolicyExist", + "StringEquals": "no" + } + ], + "Next": "Finish" + } + ] + }, + "Create Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "create_policy" + }, + "ResultPath": "$.params", + "Next": "Create Policy" + }, + "Create Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "ConfigureCount2 params" + }, + "Update Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "update_policy" + }, + "ResultPath": "$.params", + "Next": "Update Policy" + }, + "Update Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "ConfigureCount2 params" + }, + "ConfigureCount2 params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "configure_count_2" + }, + "ResultPath": "$.params", + "Next": "ConfigureCount2" + }, + "ConfigureCount2": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator2 params" + }, + "Iterator2 params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "iterator2" + }, + "ResultPath": "$.params", + "Next": "Iterator2" + }, + "Iterator2": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "Next": "IsCountReached2" + }, + "IsCountReached2": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.Continue", + "BooleanEquals": true, + "Next": "List Policies For OU Params" + } + ], + "Default": "Finish" + }, + "List Policies For OU Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "list_policies_for_ou" + }, + "ResultPath": "$.params", + "Next": "List Policies For OU" + }, + "List Policies For OU": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Attach or Detach Policy to OU Choice" + }, + "Attach or Detach Policy to OU Choice": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.Operation", + "StringEquals": "Attach", + "Next": "Check if Policy is attached to OU?" + }, + { + "Variable": "$.Operation", + "StringEquals": "Detach", + "Next": "Check if Policy is detached from OU?" + } + ], + "Default": "Invalid Operation2" + }, + "Invalid Operation2": { + "Type": "Fail", + "Cause": "Invalid Operation Type, valid choices are [Attach, Detach]", + "Error": "Returning NULL in the response." + }, + "Check if Policy is attached to OU?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.PolicyAttached", + "StringEquals": "yes", + "Next": "Iterator2 params" + }, + { + "Variable": "$.PolicyAttached", + "StringEquals": "no", + "Next": "Attach Policy to OU Params" + } + ], + "Default": "Invalid Operation2" + }, + "Attach Policy to OU Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "attach_policy" + }, + "ResultPath": "$.params", + "Next": "Attach Policy to OU" + }, + "Attach Policy to OU": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator2 params" + }, + "Check if Policy is detached from OU?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.PolicyAttached", + "StringEquals": "yes", + "Next": "Detach Policy from OU Params" + }, + { + "Variable": "$.PolicyAttached", + "StringEquals": "no", + "Next": "Iterator2 params" + } + ], + "Default": "Invalid Operation2" + }, + "Detach Policy from OU Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "detach_policy" + }, + "ResultPath": "$.params", + "Next": "Detach Policy from OU" + }, + "Detach Policy from OU": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator2 params" + }, + "Detach Policy from All Accounts Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "detach_policy_from_all_accounts" + }, + "ResultPath": "$.params", + "Next": "Detach Policy from All Accounts" + }, + "Detach Policy from All Accounts": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Delete Policy Params" + }, + "Delete Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "delete_policy" + }, + "ResultPath": "$.params", + "Next": "Delete Policy" + }, + "Delete Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Finish" + }, + "Attach/Detach Policy params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "configure_count" + }, + "ResultPath": "$.params", + "Next": "ConfigureCount" + }, + "ConfigureCount": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator params" + }, + "Iterator params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "iterator" + }, + "ResultPath": "$.params", + "Next": "Iterator" + }, + "Iterator": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "Next": "IsCountReached" + }, + "IsCountReached": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.Continue", + "BooleanEquals": true, + "Next": "List Policy Params" + } + ], + "Default": "Finish" + }, + "List Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "list_policies" + }, + "ResultPath": "$.params", + "Next": "List Policy" + }, + "List Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "List Policies For Account Params" + }, + "List Policies For Account Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "list_policies_for_account" + }, + "ResultPath": "$.params", + "Next": "List Policies For Account" + }, + "List Policies For Account": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Attach or Detach Policy Choice" + }, + "Attach or Detach Policy Choice": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Or": [ + { + "Variable": "$.RequestType", + "StringEquals": "Create" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Update" + } + ] + }, + { + "Variable": "$.ResourceProperties.Operation", + "StringEquals": "Attach" + } + ], + "Next": "Check if Policy is attached?" + }, + { + "And": [ + { + "Variable": "$.RequestType", + "StringEquals": "Delete" + }, + { + "Variable": "$.ResourceProperties.Operation", + "StringEquals": "Attach" + } + ], + "Next": "Check if Policy is detached?" + }, + { + "Variable": "$.ResourceProperties.Operation", + "StringEquals": "Detach", + "Next": "Check if Policy is detached?" + } + ], + "Default": "Invalid Operation" + }, + "Invalid Operation": { + "Type": "Fail", + "Cause": "Invalid Operation Type, valid choices are [Attach, Detach]", + "Error": "Returning NULL in the response." + }, + "Check if Policy is attached?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.PolicyAttached", + "StringEquals": "yes", + "Next": "Iterator params" + }, + { + "Variable": "$.PolicyAttached", + "StringEquals": "no", + "Next": "Attach Policy Params" + } + ], + "Default": "Invalid Operation" + }, + "Attach Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "attach_policy" + }, + "ResultPath": "$.params", + "Next": "Attach Policy" + }, + "Attach Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator params" + }, + "Check if Policy is detached?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.PolicyAttached", + "StringEquals": "yes", + "Next": "Detach Policy Params" + }, + { + "Variable": "$.PolicyAttached", + "StringEquals": "no", + "Next": "Iterator params" + } + ], + "Default": "Invalid Operation" + }, + "Detach Policy Params": { + "Type": "Pass", + "Result": { + "ClassName": "SCP", + "FunctionName": "detach_policy" + }, + "ResultPath": "$.params", + "Next": "Detach Policy" + }, + "Detach Policy": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Iterator params" + }, + "Finish": { + "Type": "Succeed" + } + } + } + + StackSetStateMachine: + Type: 'AWS::StepFunctions::StateMachine' + Properties: + StateMachineName: CustomControlTowerStackSetStateMachine + RoleArn: !GetAtt 'StateMachineRole.Arn' + DefinitionString: + Fn::Sub: |- + { + "Comment": "A state machine that manages the CloudFormation stacks in multiple accounts using StackSet APIs.", + "StartAt": "Metrics Pass", + "States": { + "Metrics Pass": { + "Type": "Pass", + "Result": { + "ClassName": "StackSetSMRequests", + "FunctionName": "send_execution_data" + }, + "ResultPath": "$.params", + "Next": "Metrics" + }, + "Metrics": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Describe StackSet Pass" + }, + "Describe StackSet Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set" + }, + "ResultPath": "$.params", + "Next": "Check StackSet Existence" + }, + "Check StackSet Existence": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "StackSets: Create or Delete?" + }, + "StackSets: Create or Delete?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.RequestType", + "StringEquals": "Create", + "Next": "Skip StackSets?" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Update", + "Next": "Skip StackSets?" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Delete", + "Next": "Describe StackSet" + } + ], + "Default": "Undefined Request Type" + }, + "Undefined Request Type": { + "Type": "Pass", + "Next": "Failed" + }, + "Skip StackSets?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.ResourceProperties.TemplateURL", + "StringEquals": "", + "Next": "Check Instance Pass" + } + ], + "Default": "Does StackSet Exist?" + }, + "Does StackSet Exist?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.StackSetExist", + "StringEquals": "no", + "Next": "Deploy StackSet Pass" + }, + { + "Variable": "$.StackSetExist", + "StringEquals": "yes", + "Next": "List StackInstances Accounts Pass" + } + ], + "Default": "Unable to describe StackSet" + }, + "Unable to describe StackSet": { + "Type": "Pass", + "Next": "Failed" + }, + "Deploy StackSet Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "create_stack_set" + }, + "ResultPath": "$.params", + "Next": "Deploy StackSet" + }, + "Deploy StackSet": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "StackSet Deployed?" + }, + "StackSet Deployed?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.StackSetStatus", + "StringEquals": "success", + "Next": "Deploy Stack Instance?" + }, + { + "Variable": "$.StackSetStatus", + "StringEquals": "failure", + "Next": "StackSet Deployment Failed" + } + ], + "Default": "StackSet Deployment Failed" + }, + "StackSet Deployment Failed": { + "Type": "Pass", + "Next": "Failed" + }, + "Deploy Stack Instance?": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Variable": "$.ResourceProperties.AccountList", + "StringLessThan": "1" + }, + { + "Variable": "$.ResourceProperties.RegionList", + "StringLessThan": "1" + } + ], + "Next": "StackSet Deployed" + } + ], + "Default": "Create or Delete Stack Instance?" + }, + "Create or Delete Stack Instance?": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "no" + }, + { + "Variable": "$.DeleteInstance", + "StringEquals": "yes" + } + ], + "Next": "Delete Stack Instances Pass" + }, + { + "Variable": "$.CreateInstance", + "StringEquals": "yes", + "Next": "Deploy Stack Instance Pass" + }, + { + "And": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "no" + }, + { + "Variable": "$.DeleteInstance", + "StringEquals": "no" + } + ], + "Next": "Export Stack Output Pass" + } + ], + "Default": "Deploy Stack Instance Pass" + }, + "StackSet Deployed": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Deploy Stack Instance Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "create_stack_instances" + }, + "ResultPath": "$.params", + "Next": "Deploy Stack Instance" + }, + "Deploy Stack Instance": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Create Operation ID?" + }, + "Create Operation ID?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationId", + "StringEquals": "OperationInProgressException", + "Next": "Waiting on create... OperationInProgress" + } + ], + "Default": "Create Task Running" + }, + "Waiting on create... OperationInProgress": { + "Type": "Wait", + "Seconds": 30, + "Next": "Deploy Stack Instance" + }, + "Create Task Running": { + "Type": "Wait", + "Seconds": 10, + "Next": "Create Task Pass" + }, + "Create Task Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set_operation" + }, + "ResultPath": "$.params", + "Next": "Create Task Status?" + }, + "Create Task Status?": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Create Task Completed?" + }, + "Create Task Completed?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationStatus", + "StringEquals": "SUCCEEDED", + "Next": "Create Task Completed" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "RUNNING", + "Next": "Create Task Running" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "FAILED", + "Next": "Create Task Failed" + } + ], + "Default": "Create Task Failed" + }, + "Create Task Completed": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Create Task Failed": { + "Type": "Pass", + "Next": "Failed" + }, + "List StackInstances Accounts Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "list_stack_instances_account_ids" + }, + "ResultPath": "$.params", + "Next": "List StackInstances Accounts" + }, + "List StackInstances Accounts": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Check List StackInstances Accounts Complete?" + }, + "Check List StackInstances Accounts Complete?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.NextToken", + "StringEquals": "Complete", + "Next": "Skip Update StackSet?" + } + ], + "Default": "Check List StackInstances Accounts Wait" + }, + "Check List StackInstances Accounts Wait": { + "Type": "Wait", + "Seconds": 5, + "Next": "List StackInstances Accounts" + }, + "Skip Update StackSet?": { + "Type": "Choice", + "Choices": [ + { + "Or": [ + { + "Variable": "$.LoopFlag", + "StringEquals": "yes" + }, + { + "Variable": "$.SkipUpdateStackSet", + "StringEquals": "yes" + } + ], + "Next": "Check Instance Pass" + } + ], + "Default": "Update StackSet Pass" + }, + "Update StackSet Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "update_stack_set" + }, + "ResultPath": "$.params", + "Next": "Update StackSet" + }, + "Update StackSet": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Update Operation ID?" + }, + "Update Operation ID?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationId", + "StringEquals": "OperationInProgressException", + "Next": "Waiting on update... OperationInProgress" + } + ], + "Default": "Update Task Running" + }, + "Waiting on update... OperationInProgress": { + "Type": "Wait", + "Seconds": 30, + "Next": "Update StackSet" + }, + "Update Task Running": { + "Type": "Wait", + "Seconds": 10, + "Next": "Update Task Pass" + }, + "Update Task Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set_operation" + }, + "ResultPath": "$.params", + "Next": "Update Task Status?" + }, + "Update Task Status?": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Update Task Completed?" + }, + "Update Task Completed?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationStatus", + "StringEquals": "SUCCEEDED", + "Next": "Check Instance Pass" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "RUNNING", + "Next": "Update Task Running" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "STOPPED", + "Next": "Update Task Completed" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "STOPPING", + "Next": "Update Task Running" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "FAILED", + "Next": "Update Task Failed" + } + ], + "Default": "Update Task Failed" + }, + "Update Task Completed": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Update Task Failed": { + "Type": "Pass", + "Next": "Failed" + }, + "Check Instance Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "list_stack_instances" + }, + "ResultPath": "$.params", + "Next": "Check Instance" + }, + "Check Instance": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "Next": "Check Complete?" + }, + "Check Complete?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.NextToken", + "StringEquals": "Complete", + "Next": "Create or Update Instance?" + } + ], + "Default": "Check Instance Wait" + }, + "Check Instance Wait": { + "Type": "Wait", + "Seconds": 5, + "Next": "Check Instance" + }, + "Create or Update Instance?": { + "Type": "Choice", + "Choices": [ + { + "Or": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "yes" + }, + { + "Variable": "$.DeleteInstance", + "StringEquals": "yes" + } + ], + "Next": "Deploy Stack Instance?" + }, + { + "And": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "no" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Create" + } + ], + "Next": "Export Stack Output Pass" + }, + { + "And": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "no" + }, + { + "Variable": "$.RequestType", + "StringEquals": "Update" + } + ], + "Next": "Update Stack Instance?" + } + ], + "Default": "Export Stack Output Pass" + }, + "Update Stack Instance?": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Variable": "$.ResourceProperties.AccountList", + "StringLessThan": "1" + }, + { + "Variable": "$.ResourceProperties.RegionList", + "StringLessThan": "1" + } + ], + "Next": "StackSet Updated" + }, + { + "Variable": "$.OverrideParametersExist", + "StringEquals": "no", + "Next": "Override parameters do not exist in the event" + } + ], + "Default": "Update Stack Instance Pass" + }, + "StackSet Updated": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Override parameters do not exist in the event": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Update Stack Instance Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "update_stack_instances" + }, + "ResultPath": "$.params", + "Next": "Update Stack Instance" + }, + "Update Stack Instance": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Update Instance Operation ID?" + }, + "Update Instance Operation ID?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationId", + "StringEquals": "OperationInProgressException", + "Next": "Waiting on Update... OperationInProgress" + } + ], + "Default": "Update Instance Task Running" + }, + "Waiting on Update... OperationInProgress": { + "Type": "Wait", + "Seconds": 30, + "Next": "Update Stack Instance" + }, + "Update Instance Task Running": { + "Type": "Wait", + "Seconds": 10, + "Next": "Update Instance Task Pass" + }, + "Update Instance Task Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set_operation" + }, + "ResultPath": "$.params", + "Next": "Update Instance Task Status?" + }, + "Update Instance Task Status?": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Update Instance Task Completed?" + }, + "Update Instance Task Completed?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationStatus", + "StringEquals": "SUCCEEDED", + "Next": "Update Instance Task Completed" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "RUNNING", + "Next": "Update Instance Task Running" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "FAILED", + "Next": "Update Instance Task Failed" + } + ], + "Default": "Update Task Failed" + }, + "Update Instance Task Completed": { + "Type": "Pass", + "Next": "Export Stack Output Pass" + }, + "Update Instance Task Failed": { + "Type": "Pass", + "Next": "Failed" + }, + "Describe StackSet": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set" + }, + "ResultPath": "$.params", + "Next": "Describe StackSet Function" + }, + "Describe StackSet Function": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Check StackSet Existence?" + }, + "Check StackSet Existence?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.StackSetExist", + "StringEquals": "no", + "Next": "StackSet Not Found" + }, + { + "Variable": "$.StackSetExist", + "StringEquals": "yes", + "Next": "List Stack Instances Pass" + } + ], + "Default": "Unable to find StackSet" + }, + "Unable to find StackSet": { + "Type": "Pass", + "Next": "Failed" + }, + "StackSet Not Found": { + "Type": "Pass", + "Next": "Success" + }, + "List Stack Instances Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "list_stack_instances" + }, + "ResultPath": "$.params", + "Next": "List Stack Instances" + }, + "List Stack Instances": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Does Stack Instance Exist?" + }, + "Does Stack Instance Exist?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.InstanceExist", + "StringEquals": "yes", + "Next": "Delete Stack Instances Pass" + }, + { + "Variable": "$.InstanceExist", + "StringEquals": "no", + "Next": "Event from CloudFormation?" + } + ], + "Default": "Unable to list stack instances" + }, + "Event from CloudFormation?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.ResourceProperties.TemplateURL", + "StringEquals": "", + "Next": "Success" + } + ], + "Default": "Delete StackSet Pass" + }, + "Unable to list stack instances": { + "Type": "Pass", + "Next": "Failed" + }, + "Delete Stack Instances Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "delete_stack_instances" + }, + "ResultPath": "$.params", + "Next": "Delete Stack Instance Function" + }, + "Delete Stack Instance Function": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Delete Operation ID?" + }, + "Delete Operation ID?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationId", + "StringEquals": "OperationInProgressException", + "Next": "Waiting on delete... OperationInProgress" + } + ], + "Default": "Delete Task Running" + }, + "Waiting on delete... OperationInProgress": { + "Type": "Wait", + "Seconds": 30, + "Next": "Delete Stack Instance Function" + }, + "Delete Task Running": { + "Type": "Wait", + "Seconds": 10, + "Next": "Delete Task Pass" + }, + "Delete Task Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "describe_stack_set_operation" + }, + "ResultPath": "$.params", + "Next": "Delete Task Status?" + }, + "Delete Task Status?": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Delete Task Completed?" + }, + "Delete Task Completed?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.OperationStatus", + "StringEquals": "SUCCEEDED", + "Next": "List Stack Remaining Instances Pass" + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "RUNNING", + "Next": "Delete Task Running" + }, + { + "And": [ + { + "Variable": "$.RetryDeleteFlag", + "BooleanEquals": false + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "FAILED" + } + ], + "Next": "Delete Task Failed" + }, + { + "And": [ + { + "Variable": "$.RetryDeleteFlag", + "BooleanEquals": true + }, + { + "Variable": "$.OperationStatus", + "StringEquals": "FAILED" + } + ], + "Next": "Delete Stack Instances Pass" + } + ], + "Default": "Delete Task Failed" + }, + "List Stack Remaining Instances Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "list_stack_instances" + }, + "ResultPath": "$.params", + "Next": "List Stack Instances Again" + }, + "List Stack Instances Again": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Check Remaining Stack Instance?" + }, + "Check Remaining Stack Instance?": { + "Type": "Choice", + "Choices": [ + { + "Or": [ + { + "Variable": "$.InstanceExist", + "StringEquals": "yes" + }, + { + "Variable": "$.ResourceProperties.TemplateURL", + "StringEquals": "" + } + ], + "Next": "Stack Instance Deleted" + }, + { + "Variable": "$.InstanceExist", + "StringEquals": "no", + "Next": "Delete StackSet Pass" + } + ], + "Default": "Failed" + }, + "Stack Instance Deleted": { + "Type": "Pass", + "Next": "Both Account and Region Lists Changes?" + }, + "Delete Task Failed": { + "Type": "Pass", + "Next": "Failed" + }, + "Delete StackSet Pass": { + "Type": "Pass", + "Result": { + "ClassName": "CloudFormation", + "FunctionName": "delete_stack_set" + }, + "ResultPath": "$.params", + "Next": "Delete StackSet Function" + }, + "Delete StackSet Function": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "InputPath": "$", + "Next": "Deleted StackSet" + }, + "Deleted StackSet": { + "Type": "Pass", + "Next": "Success" + }, + "Export Stack Output Pass": { + "Type": "Pass", + "Result": { + "ClassName": "StackSetSMRequests", + "FunctionName": "export_cfn_output" + }, + "ResultPath": "$.params", + "Next": "Export Stack Output" + }, + "Export Stack Output": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "SSM Parameter Store Pass" + }, + "SSM Parameter Store Pass": { + "Type": "Pass", + "Result": { + "ClassName": "StackSetSMRequests", + "FunctionName": "ssm_put_parameters" + }, + "ResultPath": "$.params", + "Next": "Put Parameters" + }, + "Put Parameters": { + "Type": "Task", + "Resource": "${StateMachineLambda.Arn}", + "TimeoutSeconds": 300, + "HeartbeatSeconds": 60, + "Next": "Delete Stack Instance or Finish?" + }, + "Delete Stack Instance or Finish?": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Variable": "$.CreateInstance", + "StringEquals": "yes" + }, + { + "Variable": "$.DeleteInstance", + "StringEquals": "yes" + } + ], + "Next": "Delete Stack Instances Pass" + } + ], + "Default": "Both Account and Region Lists Changes?" + }, + + "Both Account and Region Lists Changes?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.LoopFlag", + "StringEquals": "yes", + "Next": "List StackInstances Accounts Pass" + } + ], + "Default": "Success" + }, + "Success": { + "Type": "Succeed" + }, + "Failed": { + "Type": "Fail" + } + } + } + + # + # Lifecycle Event (LE) Resources + # + CustomControlTowerLELambdaRole: + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: 'Allow Resource * for XRay APIs' + - id: W28 + reason: 'The role name is defined to identify Custom Control Tower resources.' + Properties: + RoleName: CustomControlTowerLELambdaRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Path: / + Policies: + - PolicyName: Custom-Control-Tower-LELambdaPolicy-Logs + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/* + - Effect: Allow + Action: + - xray:PutTraceSegments + - xray:PutTelemetryRecords + Resource: '*' + - PolicyName: Custom-Control-Tower-LELambdaPolicy-SQS + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - sqs:ReceiveMessage + - sqs:DeleteMessage + - sqs:ListQueues + - sqs:GetQueueAttributes + Resource: !GetAtt CustomControlTowerLEFIFOQueue.Arn + - PolicyName: Custom-Control-Tower-LELambdaPolicy-CodePipeline + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - codepipeline:StartPipelineExecution + Resource: !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${CustomControlTowerCodePipeline} + + # Lambda function to process messages (lifecycle events) from SQS + CustomControlTowerLELambda: + Type: AWS::Lambda::Function + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: 'Permission for writing cloudwatch logs is defined in the lambda role' + - id: W89 + reason: 'This lambda function does not need access to VPC resources' + - id: W92 + reason: 'This use case does not need to set the ReservedConcurrentExecutions' + checkov: + skip: + - id: CKV_AWS_18 + comment: S3 bucket logging is not enabled. + - id: CKV_AWS_116 + comment: DLQ not needed. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + Environment: + Variables: + LOG_LEVEL: !FindInMap [LambdaFunction, Logging, Level] + CODE_PIPELINE_NAME: !Ref CustomControlTowerCodePipeline + SOLUTION_ID: !FindInMap [Solution, Metrics, SolutionID] + SOLUTION_VERSION: v2.3.0 + Code: + S3Bucket: !Sub 'control-tower-cfct-assets-prod-${AWS::Region}' + S3Key: customizations-for-aws-control-tower/v2.3.0/custom-control-tower-lifecycle-event-handler.zip + Description: Custom Control Tower Lifecyle event Lambda to handle lifecycle events + Handler: lifecycle_event_handler.lambda_handler + MemorySize: 512 + Role: !GetAtt 'CustomControlTowerLELambdaRole.Arn' + Runtime: python3.8 + Timeout: 30 + TracingConfig: + Mode: Active + + # FIFO SQS Dead Letter Queue for storing Lifecycle Events (LE) that can't be processed (consumed) successfully + CustomControlTowerLEFIFODLQueue: + Type: 'AWS::SQS::Queue' + DependsOn: CustomControlTowerDeploymentLambda + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: 'The queue name is defined in order not to exceed the limit on the length of SQS queue name.' + Properties: + QueueName: CustomControlTowerLEFIFODLQueue.fifo + ContentBasedDeduplication: True + FifoQueue: True + MessageRetentionPeriod: 1209600 #1209600 seconds (14 days) + KmsDataKeyReusePeriodSeconds: 300 + KmsMasterKeyId: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + ReceiveMessageWaitTimeSeconds: 10 + + # FIFO SQS Queue for storing Lifecycle Events (LE) + CustomControlTowerLEFIFOQueue: + Type: 'AWS::SQS::Queue' + DependsOn: CustomControlTowerDeploymentLambda + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: 'The queue name is defined in order not to exceed the limit on the length of SQS queue name.' + Properties: + QueueName: CustomControlTowerLEFIFOQueue.fifo + ContentBasedDeduplication: True + FifoQueue: True + KmsDataKeyReusePeriodSeconds: 300 + KmsMasterKeyId: !Sub + - alias/${KMSKeyName} + - { KMSKeyName: !FindInMap [KMS, Alias, Name] } + MessageRetentionPeriod: 345600 #345600 seconds (4 days) + ReceiveMessageWaitTimeSeconds: 20 + VisibilityTimeout: 30 #30 seconds + RedrivePolicy: + deadLetterTargetArn: !GetAtt CustomControlTowerLEFIFODLQueue.Arn + maxReceiveCount: 5 + + # Create event source mapping between the lifecycle event FIFO queue and lambda function to make the queue as the lambda trigger + CustomControlTowerLEQueueLambdaEventMapping: + Type: AWS::Lambda::EventSourceMapping + Properties: + BatchSize: 10 + Enabled: true + EventSourceArn: !GetAtt CustomControlTowerLEFIFOQueue.Arn + FunctionName: !Ref CustomControlTowerLELambda + + CustomControlTowerPipelineTriggerRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: 'Allow' + Principal: + Service: + - 'events.amazonaws.com' + Action: + - 'sts:AssumeRole' + + CustomControlTowerCodeCommitPipelineTriggerCWEventRule: + Type: AWS::Events::Rule + Condition: IsCodeCommitPipelineSource + Properties: + Description: Custom Control Tower - Rule for triggering CodePipeline from CodeCommit + EventPattern: + { + 'source': ['aws.codecommit'], + 'detail-type': ['CodeCommit Repository State Change'], + 'resources': [!Sub 'arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName}'], + 'detail': { 'event': ['referenceCreated', 'referenceUpdated'], 'referenceType': ['branch'], 'referenceName': [!Ref CodeCommitBranchName] }, + } + State: ENABLED + Targets: + - Arn: !Sub arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${CustomControlTowerCodePipeline} + Id: 'CustomControlTower_Pipeline_Trigger' + RoleArn: !GetAtt CustomControlTowerPipelineTriggerRole.Arn + + # Cloudwatch Event Rule for Lifecycle Event (LE): triggered by LE events and send events to SQS + CustomControlTowerLECWEventRule: + Type: AWS::Events::Rule + Properties: + Description: Custom Control Tower - Rule for lifecycle events from Control Tower Service + EventPattern: + { + 'detail-type': ['AWS Service Event via CloudTrail'], + 'source': ['aws.controltower'], + 'detail': { 'eventName': ['CreateManagedAccount'], 'serviceEventDetails': { 'createManagedAccountStatus': { 'state': ['SUCCEEDED'] } } }, + } + State: ENABLED + Targets: + - Arn: !GetAtt CustomControlTowerLEFIFOQueue.Arn + Id: 'CustomControlTower_Lifecycle_Event_FIFO_Queue' + SqsParameters: + MessageGroupId: CustomControlTower_Lifecycle_Event + + # Lifecycle event SQS Policy + CustomControlTowerLEQueuePolicy: + Type: AWS::SQS::QueuePolicy + Properties: + Queues: + - !Ref CustomControlTowerLEFIFOQueue + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: sqs:SendMessage + Resource: !GetAtt CustomControlTowerLEFIFOQueue.Arn + Condition: + ArnEquals: + aws:SourceArn: !GetAtt CustomControlTowerLECWEventRule.Arn + +Outputs: + CustomControlTowerCodePipeline: + Description: Custom Control Tower CodePipieline + Value: !Ref CustomControlTowerCodePipeline + CustomControlTowerPipelineS3Bucket: + Description: Custom Control Tower Configuration Bucket + Value: !Ref CustomControlTowerPipelineS3Bucket + CustomControlTowerSolutionVersion: + Description: Version Number + Value: 'v2.3.0' + Export: + Name: Custom-Control-Tower-Version diff --git a/aws_sra_examples/solutions/common/common_cfct_setup/templates/sra-common-cfct-setup-main.yaml b/aws_sra_examples/solutions/common/common_cfct_setup/templates/sra-common-cfct-setup-main.yaml index cc53ceb15..5063ba16c 100644 --- a/aws_sra_examples/solutions/common/common_cfct_setup/templates/sra-common-cfct-setup-main.yaml +++ b/aws_sra_examples/solutions/common/common_cfct_setup/templates/sra-common-cfct-setup-main.yaml @@ -8,7 +8,7 @@ Description: https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse2a) Metadata: SRA: - Version: 1.0 + Version: 1.1 Entry: Parameters for deploying CFCT solution without resolving SSM parameters Order: 1 cfn-lint: @@ -21,10 +21,10 @@ Metadata: default: General Properties Parameters: - pSRASolutionName + - pSRAStagingS3BucketName - Label: default: CFCT - Pipeline Configuration Parameters: - - pDeployCustomizationsForAWSControlTower - pPipelineApprovalStage - pPipelineApprovalEmail - pCodePipelineSource @@ -48,8 +48,6 @@ Metadata: default: CodeCommit Repository Name pCodePipelineSource: default: AWS CodePipeline Source - pDeployCustomizationsForAWSControlTower: - default: Deploy Customizations for AWS Control Tower pExistingRepository: default: Existing CodeCommit Repository? pFailureTolerancePercentage: @@ -64,6 +62,8 @@ Metadata: default: Region Concurrency Type pSRASolutionName: default: SRA Solution Name + pSRAStagingS3BucketName: + default: SRA Staging S3 Bucket Name Parameters: pCodeCommitBranchName: @@ -83,11 +83,6 @@ Parameters: Default: AWS CodeCommit Description: Which AWS CodePipeline source provider do you want to select? Type: String - pDeployCustomizationsForAWSControlTower: - AllowedValues: ['true', 'false'] - Default: 'true' - Description: Indicates whether Customizations for AWS Control Tower (CFCT) should be deployed. - Type: String pExistingRepository: AllowedValues: ['Yes', 'No'] Default: 'No' @@ -127,6 +122,15 @@ Parameters: Default: sra-common-cfct-setup Description: The SRA solution name. The Description value is the folder name of the solution Type: String + pSRAStagingS3BucketName: + AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$' + ConstraintDescription: + Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Default: /sra/staging-s3-bucket-name + Description: + SSM Parameter for SRA Staging S3 bucket name for the artifacts relevant to solution. (e.g., lambda zips, CloudFormation templates) S3 bucket + name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). + Type: AWS::SSM::Parameter::Value Rules: PipelineApprovalEmailValidation: @@ -135,15 +139,12 @@ Rules: - AssertDescription: "'Pipeline Approval Email Address' parameter is required if the 'Pipeline Approval Stage' parameter is set to 'Yes'." Assert: !Equals [!Ref pPipelineApprovalStage, 'No'] -Conditions: - cDeployCustomizationsForAWSControlTower: !Equals [!Ref pDeployCustomizationsForAWSControlTower, 'true'] - Resources: rCFCTStack: - Condition: cDeployCustomizationsForAWSControlTower Type: AWS::CloudFormation::Stack Properties: - TemplateURL: https://s3.amazonaws.com/solutions-reference/customizations-for-aws-control-tower/latest/custom-control-tower-initiation.template + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/customizations-for-aws-control-tower.template + # TemplateURL: https://s3.amazonaws.com/solutions-reference/customizations-for-aws-control-tower/latest/custom-control-tower-initiation.template Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -157,3 +158,8 @@ Resources: PipelineApprovalEmail: !Ref pPipelineApprovalEmail PipelineApprovalStage: !Ref pPipelineApprovalStage RegionConcurrencyType: !Ref pRegionConcurrencyType + +Outputs: + CustomControlTowerSolutionVersion: + Description: Version Number + Value: 'v2.3.0' diff --git a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml index 3e63c24ca..690b8a47b 100644 --- a/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml +++ b/aws_sra_examples/solutions/common/common_prerequisites/templates/sra-common-prerequisites-staging-s3-bucket.yaml @@ -33,6 +33,8 @@ Metadata: - pLambdaLogGroupKmsKey - pLambdaLogLevel ParameterLabels: + pAWSControlTowerExecutionRoleName: + default: Control Tower Execution Role Name pCreateLambdaLogGroup: default: Create Lambda Log Group pLambdaLogGroupKmsKey: diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/README.md b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/README.md index ccd902c36..eb0154cfb 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/README.md +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/README.md @@ -18,6 +18,12 @@ unencrypted snapshot. For examples of transitioning from unencrypted to encrypte Encryption by default has no effect on existing EBS volumes or snapshots. +**Key solution features:** + +- Sets EC2 Default EBS Encryption settings for all existing accounts and provided regions including the `management account` and future accounts. +- Ability to exclude accounts via provided account tags. +- Triggered when new accounts are added to the AWS Organization, account tag updates, and on account status changes. + ### **Considerations** - Encryption by default is a Region-specific setting. If you enable it for a Region, you cannot disable it for individual volumes or snapshots in that Region. @@ -41,35 +47,50 @@ Encryption by default has no effect on existing EBS volumes or snapshots. - The [Customizations for AWS Control Tower](https://aws.amazon.com/solutions/implementations/customizations-for-aws-control-tower/) solution deploys all templates as a CloudFormation `StackSet`. - For parameter details, review the [AWS CloudFormation templates](templates/). -#### 1.2 AWS Lambda Function +#### 1.2 IAM Roles -- The AWS Lambda Function contains the logic for configuring the EC2 default EBS encryption settings within each account and region. -- The function is triggered by CloudFormation Create, Update, and Delete events and also by the `Control Tower Lifecycle Event Rule` when new accounts are provisioned. +- The `Lambda IAM Role` is used by the Lambda function to identify existing and future accounts that need EC2 Default EBS Encryption configured. +- The EC2 default EBS encryption IAM role is deployed into each account within the AWS Organization and it is assumed by the central `AWS Lambda Function` to configure the default encryption setting for the account and region. +- The `Event Rule IAM Role` is assumed by EventBridge to forward Global events to the `Home Region` default Event Bus. -#### 1.3 AWS SSM Parameter Store +#### 1.3 Regional Event Rules -- The Lambda Function creates/updates configuration parameters within the `SSM Parameter Store` on CloudFormation events and the parameters are used when triggered by the `Control Tower Lifecycle Event Rule`. +- The `AWS Control Tower Lifecycle Event Rule` triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +- The `Organization Compliance Scheduled Event Rule` triggers the `AWS Lambda Function` to capture AWS Account status updates (e.g. suspended to active). + - A parameter is provided to set the schedule frequency. + - See the [Instructions to Manually Run the Lambda Function](#instructions-to-manually-run-the-lambda-function) for triggering the `AWS Lambda Function` before the next scheduled run time. +- The `AWS Organizations Event Rule` triggers the `AWS Lambda Function` when updates are made to accounts within the organization. + - When AWS Accounts are added to the AWS Organization outside of the AWS Control Tower Account Factory. (e.g. account created via AWS Organizations console, account invited from another AWS Organization). + - When tags are added or updated on AWS Accounts. -#### 1.4 AWS Control Tower Lifecycle Event Rule +#### 1.4 Global Event Rules -- The AWS Control Tower Lifecycle Event Rule triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +- If the `Home Region` is different from the `Global Region (e.g. us-east-1)`, then global event rules are created within the `Global Region` to forward events to the `Home Region` default Event Bus. +- The `AWS Organizations Event Rule` forwards AWS Organization account update events. -#### 1.5 AWS Lambda CloudWatch Log Group +#### 1.5 Dead Letter Queue (DLQ) + +- SQS dead letter queue used for retaining any failed Lambda events. + +#### 1.6 AWS Lambda Function + +- The AWS Lambda Function contains the logic for configuring the EC2 default EBS encryption settings within each account and region. + +#### 1.7 Lambda CloudWatch Log Group - All the `AWS Lambda Function` logs are sent to a CloudWatch Log Group `` to help with debugging and traceability of the actions performed. -- By default the `AWS Lambda Function` will create the CloudWatch Log Group with a `Retention` (Never expire) and are encrypted with a CloudWatch Logs service managed encryption key. -- Optional parameters are included to allow creating the CloudWatch Log Group, which allows setting `KMS Encryption` using a customer managed KMS key and setting the `Retention` to a specific value (e.g. 14 days). +- By default the `AWS Lambda Function` will create the CloudWatch Log Group and logs are encrypted with a CloudWatch Logs service managed encryption key. +- Parameters are provided for changing the default log group retention and encryption KMS key. -#### 1.6 AWS Lambda Function Role +#### 1.8 Alarm SNS Topic -- The AWS Lambda Function Role allows the AWS Lambda service to assume the role and perform actions defined in the attached IAM policies. -- The role is also trusted by the EC2 Default EBS Encryption IAM Role within each account so that it can configure the default EBS encryption account settings. +- SNS Topic used to notify subscribers when messages hit the Dead Letter Queue (DLQ). -#### 1.7 EC2 Default EBS Encryption IAM Role +#### 1.9 SNS Topic -- The EC2 default EBS encryption IAM role is deployed into each account within the AWS Organization and it is assumed by the central `AWS Lambda Function` to configure the default encryption setting for the account and region. +- SNS Topic used to fanout the Lambda function for setting the EC2 default EBS encryption configuration. -#### 1.8 EC2 Default EBS Encryption +#### 1.10 EC2 Default EBS Encryption - The `AWS Lambda Function` configures the default EBS encryption for the account and region with the `AWS managed EBS encryption key` (alias/aws/ebs). @@ -83,11 +104,11 @@ Encryption by default has no effect on existing EBS volumes or snapshots. #### 2.2 EC2 Default EBS Encryption IAM Role -- See [1.7 EC2 Default EBS Encryption IAM Role](#17-ec2-default-ebs-encryption-iam-role) +- The EC2 default EBS encryption IAM role is deployed into each account within the AWS Organization and it is assumed by the central `AWS Lambda Function` to configure the default encryption setting for the account and region. #### 2.3 EC2 Default EBS Encryption -- See [1.8 EC2 Default EBS Encryption](#18-ec2-default-ebs-encryption) +- See [1.10 EC2 Default EBS Encryption](#110-ec2-default-ebs-encryption) --- @@ -137,6 +158,11 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* 2. Select a region where the EBS default encryption was enabled 3. Select the `EBS Encryption` from the `Account attributes` section and verify the settings match the parameters provided in the configuration +#### Solution Update Instructions + +1. [Download and Stage the SRA Solutions](../../../docs/DOWNLOAD-AND-STAGE-SOLUTIONS.md). **Note:** Get the latest code and run the staging script. +2. Update the existing CloudFormation Stack or CFCT configuration. **Note:** Make sure to update the `SRA Solution Version` parameter and any new added parameters. + #### Solution Delete Instructions 1. In the `management account (home region)`, delete the AWS CloudFormation **Stack** created in step 3 of the solution deployment. **Note:** The solution will not modify the default EBS encryption setting on a `Delete` event. Only the SSM @@ -145,6 +171,15 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* 3. In the `management account (home region)`, delete the AWS CloudFormation **StackSet** created in step 1 of the solution deployment. **Note:** there should not be any `stack instances` associated with this StackSet. 4. In the `management account (home region)`, delete the AWS CloudWatch **Log Group** (e.g. /aws/lambda/) for the Lambda function deployed in step 2 of the solution deployment. +#### Instructions to Manually Run the Lambda Function + +1. In the `management account (home region)`. +2. Navigate to the AWS Lambda Functions page. +3. Select the `checkbox` next to the Lambda Function and select `Test` from the `Actions` menu. +4. Scroll down to view the `Test event`. +5. Click the `Test` button to trigger the Lambda Function with the default values. +6. Verify that the updates were successful within the expected account(s). + --- ## References diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/manifest_v2.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/manifest_v2.yaml index bd432f3d5..2df9f82d4 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/manifest_v2.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/manifest_v2.yaml @@ -11,26 +11,26 @@ resources: - name: sra-ec2-default-ebs-encryption-main-ssm resource_file: templates/sra-ec2-default-ebs-encryption-main-ssm.yaml parameters: - - parameter_key: pControlTowerLifeCycleRuleName - parameter_value: sra-ec2-default-ebs-encryption-trigger + - parameter_key: pComplianceFrequency + parameter_value: 7 - parameter_key: pControlTowerRegionsOnly parameter_value: 'true' - - parameter_key: pCreateEC2DefaultEBSEncryptionLambdaLogGroup + - parameter_key: pCreateLambdaLogGroup parameter_value: 'false' - - parameter_key: pEC2DefaultEBSEncryptionLambdaFunctionName - parameter_value: sra-ec2-default-ebs-encryption - - parameter_key: pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey + - parameter_key: pEnabledRegions parameter_value: '' - - parameter_key: pEC2DefaultEBSEncryptionLambdaLogLevel - parameter_value: INFO - - parameter_key: pEC2DefaultEBSEncryptionLambdaLogGroupRetention + - parameter_key: pExcludeEC2DefaultEBSEncryptionTags + parameter_value: '' + - parameter_key: pLambdaLogGroupKmsKey + parameter_value: '' + - parameter_key: pLambdaLogGroupRetention parameter_value: '14' - - parameter_key: pEC2DefaultEBSEncryptionLambdaRoleName - parameter_value: sra-ec2-default-ebs-encryption-lambda - - parameter_key: pEC2DefaultEBSEncryptionRoleName - parameter_value: sra-ec2-default-ebs-encryption - - parameter_key: pEnabledRegions + - parameter_key: pLambdaLogLevel + parameter_value: INFO + - parameter_key: pSRAAlarmEmail parameter_value: '' + - parameter_key: pSRASolutionVersion + parameter_value: v1.2 deploy_method: stack_set deployment_targets: accounts: @@ -39,31 +39,31 @@ resources: # - name: sra-ec2-default-ebs-encryption-main # resource_file: templates/sra-ec2-default-ebs-encryption-main.yaml # parameters: - # - parameter_key: pControlTowerLifeCycleRuleName - # parameter_value: sra-ec2-default-ebs-encryption-trigger + # - parameter_key: pComplianceFrequency + # parameter_value: 7 # - parameter_key: pControlTowerRegionsOnly # parameter_value: 'true' - # - parameter_key: pCreateEC2DefaultEBSEncryptionLambdaLogGroup + # - parameter_key: pCreateLambdaLogGroup # parameter_value: 'false' - # - parameter_key: pEC2DefaultEBSEncryptionLambdaFunctionName - # parameter_value: sra-ec2-default-ebs-encryption - # - parameter_key: pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - # parameter_value: '' - # - parameter_key: pEC2DefaultEBSEncryptionLambdaLogLevel - # parameter_value: INFO - # - parameter_key: pEC2DefaultEBSEncryptionLambdaLogGroupRetention - # parameter_value: '14' - # - parameter_key: pEC2DefaultEBSEncryptionLambdaRoleName - # parameter_value: sra-ec2-default-ebs-encryption-lambda - # - parameter_key: pEC2DefaultEBSEncryptionRoleName - # parameter_value: sra-ec2-default-ebs-encryption # - parameter_key: pEnabledRegions # parameter_value: '' + # - parameter_key: pExcludeEC2DefaultEBSEncryptionTags + # parameter_value: '' + # - parameter_key: pLambdaLogGroupKmsKey + # parameter_value: '' + # - parameter_key: pLambdaLogGroupRetention + # parameter_value: '14' + # - parameter_key: pLambdaLogLevel + # parameter_value: INFO # - parameter_key: pOrganizationId # parameter_value: '' # - parameter_key: pRootOrganizationalUnitId # parameter_value: '' - # - parameter_key: pSRAStagingS3BucketName + # - parameter_key: pSRAAlarmEmail + # parameter_value: '' + # - parameter_key: pSRASolutionVersion + # parameter_value: v1.2 + # - parameter_key: pSRAStagingS3BucketName # parameter_value: '' # deploy_method: stack_set # deployment_targets: diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main-ssm.json b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main-ssm.json index dcc2ce878..92b5a2ca1 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main-ssm.json +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main-ssm.json @@ -1,42 +1,42 @@ [ { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-ec2-default-ebs-encryption-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pControlTowerRegionsOnly", "ParameterValue": "true" }, { - "ParameterKey": "pCreateEC2DefaultEBSEncryptionLambdaLogGroup", + "ParameterKey": "pCreateLambdaLogGroup", "ParameterValue": "false" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaFunctionName", - "ParameterValue": "sra-ec2-default-ebs-encryption" + "ParameterKey": "pEnabledRegions", + "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey", + "ParameterKey": "pExcludeEC2DefaultEBSEncryptionTags", "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogLevel", - "ParameterValue": "INFO" + "ParameterKey": "pLambdaLogGroupKmsKey", + "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogGroupRetention", + "ParameterKey": "pLambdaLogGroupRetention", "ParameterValue": "14" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaRoleName", - "ParameterValue": "sra-ec2-default-ebs-encryption-lambda" + "ParameterKey": "pLambdaLogLevel", + "ParameterValue": "INFO" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionRoleName", - "ParameterValue": "sra-ec2-default-ebs-encryption" + "ParameterKey": "pSRAAlarmEmail", + "ParameterValue": "" }, { - "ParameterKey": "pEnabledRegions", - "ParameterValue": "" + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.2" } ] \ No newline at end of file diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main.json b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main.json index 2dc47922b..631f55e70 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main.json +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/customizations_for_aws_control_tower/parameters/sra-ec2-default-ebs-encryption-main.json @@ -1,51 +1,51 @@ [ { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-ec2-default-ebs-encryption-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pControlTowerRegionsOnly", "ParameterValue": "true" }, { - "ParameterKey": "pCreateEC2DefaultEBSEncryptionLambdaLogGroup", + "ParameterKey": "pCreateLambdaLogGroup", "ParameterValue": "false" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaFunctionName", - "ParameterValue": "sra-ec2-default-ebs-encryption" + "ParameterKey": "pEnabledRegions", + "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey", + "ParameterKey": "pExcludeEC2DefaultEBSEncryptionTags", "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogLevel", - "ParameterValue": "INFO" + "ParameterKey": "pLambdaLogGroupKmsKey", + "ParameterValue": "" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaLogGroupRetention", + "ParameterKey": "pLambdaLogGroupRetention", "ParameterValue": "14" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionLambdaRoleName", - "ParameterValue": "sra-ec2-default-ebs-encryption-lambda" + "ParameterKey": "pLambdaLogLevel", + "ParameterValue": "INFO" }, { - "ParameterKey": "pEC2DefaultEBSEncryptionRoleName", - "ParameterValue": "sra-ec2-default-ebs-encryption" + "ParameterKey": "pOrganizationId", + "ParameterValue": "" }, { - "ParameterKey": "pEnabledRegions", + "ParameterKey": "pRootOrganizationalUnitId", "ParameterValue": "" }, { - "ParameterKey": "pOrganizationId", + "ParameterKey": "pSRAAlarmEmail", "ParameterValue": "" }, { - "ParameterKey": "pRootOrganizationalUnitId", - "ParameterValue": "" + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.2" }, { "ParameterKey": "pSRAStagingS3BucketName", diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png index 11de0aa5e..d2ff464d1 100644 Binary files a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png and b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.png differ diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx index 647d1b557..e1cec17f6 100644 Binary files a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx and b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/documentation/ec2-default-ebs-encryption.pptx differ diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py index fa0a2ba9d..118e69ac7 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py @@ -1,5 +1,9 @@ """The purpose of this script is to configure the EC2 EBS default encryption within each account and region. +Version: 1.1 + +'ec2_default_ebs_encryption' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ @@ -9,66 +13,51 @@ import logging import os import re -from concurrent.futures import ThreadPoolExecutor, as_completed from time import sleep -from typing import TYPE_CHECKING, Any, Dict +from typing import TYPE_CHECKING, Any, List, Optional, Union import boto3 from botocore.exceptions import ClientError from crhelper import CfnResource if TYPE_CHECKING: + from aws_lambda_typing.context import Context + from aws_lambda_typing.events import CloudFormationCustomResourceEvent from mypy_boto3_cloudformation import CloudFormationClient - from mypy_boto3_ec2 import EC2Client + from mypy_boto3_ec2.client import EC2Client + from mypy_boto3_ec2.type_defs import GetEbsEncryptionByDefaultResultTypeDef from mypy_boto3_organizations import OrganizationsClient - from mypy_boto3_ssm.client import SSMClient - from mypy_boto3_sts.client import STSClient + from mypy_boto3_organizations.type_defs import AccountTypeDef, DescribeAccountResponseTypeDef, TagTypeDef + from mypy_boto3_sns import SNSClient + from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef, PublishResponseTypeDef + from mypy_boto3_sts import STSClient # Setup Default Logger -LOGGER = logging.getLogger(__name__) +LOGGER = logging.getLogger("sra") log_level = os.environ.get("LOG_LEVEL", logging.ERROR) LOGGER.setLevel(log_level) # Global Variables CLOUDFORMATION_PAGE_SIZE = 20 CLOUDFORMATION_THROTTLE_PERIOD = 0.2 -MAX_THREADS = 20 -ORG_PAGE_SIZE = 20 # Max page size for list_accounts -ORG_THROTTLE_PERIOD = 0.2 +ORGANIZATIONS_PAGE_SIZE = 20 +ORGANIZATIONS_THROTTLE_PERIOD = 0.2 +SNS_PUBLISH_BATCH_MAX = 10 UNEXPECTED = "Unexpected!" -SSM_PARAMETER_PREFIX = os.environ.get("SSM_PARAMETER_PREFIX", "/sra/ec2-default-ebs-encryption") -# Initialise the helper -helper = CfnResource(json_logging=True, log_level="DEBUG", boto_level="CRITICAL") +# Initialize the helper. `sleep_on_delete` allows time for the CloudWatch Logs to get captured. +helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120) try: MANAGEMENT_ACCOUNT_SESSION = boto3.Session() - ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations") - SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm") CFN_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation") + ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations") + SNS_CLIENT: SNSClient = MANAGEMENT_ACCOUNT_SESSION.client("sns") except Exception as error: LOGGER.error({"Unexpected_Error": error}) raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None -def get_all_organization_accounts() -> list: - """Get all the active AWS Organization accounts. - - Returns: - List of active account IDs - """ - account_ids = [] - paginator = ORG_CLIENT.get_paginator("list_accounts") - - for page in paginator.paginate(PaginationConfig={"PageSize": ORG_PAGE_SIZE}): - for acct in page["Accounts"]: - if acct["Status"] == "ACTIVE": # Store active accounts in a dict - account_ids.append(acct["Id"]) - sleep(ORG_THROTTLE_PERIOD) - - return account_ids - - def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: """Assumes the provided role in the given account and returns a session. @@ -128,7 +117,7 @@ def get_control_tower_regions() -> list: # noqa: CCR001 return list(customer_regions) -def get_enabled_regions(customer_regions: str, control_tower_regions_only: bool = False) -> list: # noqa: CCR001 +def get_enabled_regions(customer_regions: str = None, control_tower_regions_only: bool = False) -> list: # noqa: CCR001 """Query STS to identify enabled regions. Args: @@ -138,7 +127,7 @@ def get_enabled_regions(customer_regions: str, control_tower_regions_only: bool Returns: Enabled regions """ - if customer_regions.strip(): + if customer_regions and customer_regions.strip(): LOGGER.debug(f"CUSTOMER PROVIDED REGIONS: {str(customer_regions)}") region_list = [value.strip() for value in customer_regions.split(",") if value != ""] elif control_tower_regions_only: @@ -189,24 +178,66 @@ def get_enabled_regions(customer_regions: str, control_tower_regions_only: bool return enabled_regions -def process_enable_ebs_encryption_by_default( - management_account_session: boto3.Session, role_to_assume: str, role_session_name: str, account_id: str, available_regions: list -) -> None: +def get_active_organization_accounts() -> list[AccountTypeDef]: + """Get all the active AWS Organization accounts. + + Returns: + List of active account IDs + """ + paginator = ORG_CLIENT.get_paginator("list_accounts") + accounts: list[AccountTypeDef] = [] + for page in paginator.paginate(PaginationConfig={"PageSize": ORGANIZATIONS_PAGE_SIZE}): + for account in page["Accounts"]: + if account["Status"] == "ACTIVE": + accounts.append(account) + sleep(ORGANIZATIONS_THROTTLE_PERIOD) + return accounts + + +def get_account_info(account_id: str) -> AccountTypeDef: + """Get AWS Account info. + + Args: + account_id: ID of the AWS account + + Returns: + Account info + """ + response: DescribeAccountResponseTypeDef = ORG_CLIENT.describe_account(AccountId=account_id) + api_call_details = {"API_Call": "organizations:DescribeAccounts", "API_Response": response} + LOGGER.info(api_call_details) + return response["Account"] + + +def get_organization_resource_tags(resource_id: str) -> List[TagTypeDef]: + """Get Org Resource Tags. + + Args: + resource_id: ID of the AWS account + + Returns: + Account Tags + """ + paginator = ORG_CLIENT.get_paginator("list_tags_for_resource") + tags = [] + for page in paginator.paginate(ResourceId=resource_id): + tags += page["Tags"] + sleep(ORGANIZATIONS_THROTTLE_PERIOD) + return tags + + +def process_enable_ebs_encryption_by_default(account_session: boto3.Session, account_id: str, regions: list) -> None: """Process enable ec2 default EBS encryption. Args: - management_account_session: boto3 session - role_to_assume: IAM role to assume - role_session_name: role session name + account_session: boto3 session account_id: account to assume role in - available_regions: regions to process + regions: regions to process """ - account_session = assume_role(role_to_assume, role_session_name, account_id, management_account_session) - - for region in available_regions: + for region in regions: ec2_client: EC2Client = account_session.client("ec2", region) - response = ec2_client.get_ebs_encryption_by_default() + response: GetEbsEncryptionByDefaultResultTypeDef = ec2_client.get_ebs_encryption_by_default() if not response["EbsEncryptionByDefault"]: ec2_client.enable_ebs_encryption_by_default() LOGGER.info(f"Default EBS encryption enabled in {account_id} | {region}") @@ -214,200 +245,356 @@ def process_enable_ebs_encryption_by_default( LOGGER.info(f"Default EBS encryption is already enabled in {account_id} | {region}") -def get_ssm_parameter_value(ssm_client: SSMClient, name: str) -> str: - """Get SSM Parameter Value. +def publish_sns_message(message: dict, subject: str, sns_topic_arn: str) -> None: + """Publish SNS Message. + + Args: + message: SNS Message + subject: SNS Topic Subject + sns_topic_arn: SNS Topic ARN + """ + LOGGER.info(f"Publishing SNS message for {message['AccountId']}.") + LOGGER.info({"SNSMessage": message}) + response: PublishResponseTypeDef = SNS_CLIENT.publish(Message=json.dumps(message), Subject=subject, TopicArn=sns_topic_arn) + api_call_details = {"API_Call": "sns:Publish", "API_Response": response} + LOGGER.info(api_call_details) + + +def publish_sns_message_batch(message_batch: list, sns_topic_arn: str) -> None: + """Publish SNS Message Batches. + + Args: + message_batch: Batch of SNS messages + sns_topic_arn: SNS Topic ARN + """ + LOGGER.info("Publishing SNS Message Batch") + LOGGER.info({"SNSMessageBatch": message_batch}) + response: PublishBatchResponseTypeDef = SNS_CLIENT.publish_batch(TopicArn=sns_topic_arn, PublishBatchRequestEntries=message_batch) + api_call_details = {"API_Call": "sns:PublishBatch", "API_Response": response} + LOGGER.info(api_call_details) + + +def process_sns_message_batches(sns_messages: list, sns_topic_arn: str) -> None: + """Process SNS Message Batches for Publishing. + + Args: + sns_messages: SNS messages to be batched. + sns_topic_arn: SNS Topic ARN + """ + message_batches = [] + for i in range(SNS_PUBLISH_BATCH_MAX, len(sns_messages) + SNS_PUBLISH_BATCH_MAX, SNS_PUBLISH_BATCH_MAX): + message_batches.append(sns_messages[i - SNS_PUBLISH_BATCH_MAX : i]) + + for batch in message_batches: + publish_sns_message_batch(batch, sns_topic_arn) + + +def is_account_with_exclude_tags(aws_account: AccountTypeDef, params: dict) -> bool: + """Validate if account has tags to be excluded. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name + aws_account: AWS account to update + params: solution parameters Returns: - Value string + If account has exclude tags """ - return ssm_client.get_parameter(Name=name, WithDecryption=True)["Parameter"]["Value"] + if params["EXCLUDE_ACCOUNT_TAGS"]: + account_tags = get_organization_resource_tags(aws_account["Id"]) + for tag in params["EXCLUDE_ACCOUNT_TAGS"]: + if tag in account_tags: + LOGGER.info(f"Excluding account: {aws_account['Id']} ({aws_account['Name']}) matching tags: {tag}.") + return True + return False -def put_ssm_parameter(ssm_client: SSMClient, name: str, description: str, value: str) -> None: - """Put SSM Parameter. +def local_testing(aws_account: AccountTypeDef, params: dict) -> None: + """Local Testing. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name - description: Parameter description - value: Parameter value + aws_account: AWS account to update + params: solution parameters """ - ssm_client.put_parameter( - Name=name, - Description=description, - Value=value, - Type="SecureString", - Overwrite=True, - Tier="Standard", - DataType="text", - ) + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + regions = get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"]) + process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) -def delete_ssm_parameter(ssm_client: SSMClient, name: str) -> None: - """Delete SSM Parameter. +def process_accounts(event: Union[CloudFormationCustomResourceEvent, dict], params: dict) -> None: + """Process Accounts and Create SNS Messages for each account for solution deployment. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name + event: event data + params: solution parameters """ - ssm_client.delete_parameter(Name=name) + sns_messages = [] + accounts = get_active_organization_accounts() + for account in accounts: + if is_account_with_exclude_tags(account, params): + continue -def set_configuration_ssm_parameters(params: dict) -> None: - """Set Configuration SSM Parameters. + if event.get("local_testing") == "true" or event.get("ResourceProperties", {}).get("local_testing") == "true": # type: ignore + local_testing(account, params) + else: + sns_message = {"Action": params["action"], "AccountId": account["Id"]} + sns_messages.append({"Id": account["Id"], "Message": json.dumps(sns_message), "Subject": "EC2 Default EBS Encryption"}) + + process_sns_message_batches(sns_messages, params["SNS_TOPIC_ARN"]) + + +def process_account(event: dict, aws_account_id: str, params: dict) -> None: + """Process Account and Create SNS Message for solution deployment. Args: - params: Parameters + event: event data + aws_account_id: AWS Account ID + params: solution parameters """ - ssm_parameter_value = { - "CONTROL_TOWER_REGIONS_ONLY": params["CONTROL_TOWER_REGIONS_ONLY"], - "ENABLED_REGIONS": params["ENABLED_REGIONS"], - "ROLE_SESSION_NAME": params["ROLE_SESSION_NAME"], - "ROLE_TO_ASSUME": params["ROLE_TO_ASSUME"], - } + aws_account = get_account_info(account_id=aws_account_id) - put_ssm_parameter(SSM_CLIENT, f"{SSM_PARAMETER_PREFIX}", "", json.dumps(ssm_parameter_value)) + if is_account_with_exclude_tags(aws_account, params): + return + if event.get("local_testing") == "true": + local_testing(aws_account, params) + else: + sns_message = {"Action": "Add", "AccountId": aws_account["Id"]} + publish_sns_message(sns_message, "EC2 Default EBS Encryption", params["SNS_TOPIC_ARN"]) -def get_configuration_ssm_parameters() -> dict: - """Get Configuration SSM Parameters. - Returns: - Parameter dictionary +def process_event(event: dict) -> None: + """Process Event. + + Args: + event: event data """ - ssm_parameter = json.loads(get_ssm_parameter_value(SSM_CLIENT, f"{SSM_PARAMETER_PREFIX}")) - return { - "CONTROL_TOWER_REGIONS_ONLY": ssm_parameter["CONTROL_TOWER_REGIONS_ONLY"], - "ENABLED_REGIONS": ssm_parameter["ENABLED_REGIONS"], - "ROLE_SESSION_NAME": ssm_parameter["ROLE_SESSION_NAME"], - "ROLE_TO_ASSUME": ssm_parameter["ROLE_TO_ASSUME"], - } + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) + + process_accounts(event, params) -def parameter_pattern_validator(parameter_name: str, parameter_value: str, pattern: str) -> None: - """Validate CloudFormation Custom Resource Parameters. +def process_event_sns(event: dict) -> None: + """Process SNS event. Args: - parameter_name: CloudFormation custom resource parameter name - parameter_value: CloudFormation custom resource parameter value - pattern: REGEX pattern to validate against. + event: event data + """ + params = get_validated_parameters({}) - Raises: - ValueError: Parameter does not follow the allowed pattern + regions = get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"]) + + for record in event["Records"]: + record["Sns"]["Message"] = json.loads(record["Sns"]["Message"]) + LOGGER.info({"SNS Record": record}) + message = record["Sns"]["Message"] + params["action"] = message["Action"] + + aws_account = get_account_info(account_id=message["AccountId"]) + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) + + +def process_event_organizations(event: dict) -> None: + """Process Event from AWS Organizations. + + Args: + event: event data """ - if not re.match(pattern, parameter_value): - raise ValueError(f"'{parameter_name}' parameter with value of '{parameter_value}' does not follow the allowed pattern: {pattern}.") + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) + + if event["detail"]["eventName"] == "TagResource" and params["EXCLUDE_ACCOUNT_TAGS"]: + aws_account_id = event["detail"]["requestParameters"]["resourceId"] + process_account(event, aws_account_id, params) + elif event["detail"]["eventName"] == "AcceptHandShake" and event["responseElements"]["handshake"]["state"] == "ACCEPTED": + for party in event["responseElements"]["handshake"]["parties"]: + if party["type"] == "ACCOUNT": + aws_account_id = party["id"] + process_account(event, aws_account_id, params) + break + elif event["detail"]["eventName"] == "CreateAccountResult": + aws_account_id = event["detail"]["serviceEventDetails"]["createAccountStatus"]["accountId"] + process_account(event, aws_account_id, params) + else: + LOGGER.info("Organization event does not match expected values.") -def get_validated_parameters(event: Dict[str, Any]) -> dict: # noqa: CCR001 (cognitive complexity) - """Validate AWS CloudFormation parameters. +def process_event_lifecycle(event: dict) -> None: + """Process Lifecycle Event from AWS Control Tower. Args: event: event data - Returns: - Validated parameters + Raises: + ValueError: Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus' """ - params = event["ResourceProperties"].copy() - actions = {"Create": "Add", "Update": "Add", "Delete": "Remove"} - params["action"] = actions[event["RequestType"]] + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) - parameter_pattern_validator("CONTROL_TOWER_REGIONS_ONLY", params.get("CONTROL_TOWER_REGIONS_ONLY"), pattern=r"(?i)^true|false$") - parameter_pattern_validator("ENABLED_REGIONS", params.get("ENABLED_REGIONS"), pattern=r"^$|[a-z0-9-, ]+$") - parameter_pattern_validator("ROLE_SESSION_NAME", params.get("ROLE_SESSION_NAME"), pattern=r"^[\w=,@.-]+$") - parameter_pattern_validator("ROLE_TO_ASSUME", params.get("ROLE_TO_ASSUME"), pattern=r"^[\w+=,.@-]{1,64}$") + aws_account_id = "" + if event["detail"]["serviceEventDetails"].get("createManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + elif event["detail"]["serviceEventDetails"].get("updateManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["updateManagedAccountStatus"]["account"]["accountId"] + else: + raise ValueError("Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus'") - return params + process_account(event, aws_account_id, params) @helper.create @helper.update @helper.delete -def process_cloudformation_event(event: Dict[str, Any], context: Any) -> str: # noqa U100 +def process_event_cloudformation(event: CloudFormationCustomResourceEvent, context: Context) -> str: # noqa: U100 """Process Event from AWS CloudFormation. Args: event: event data context: runtime information - Raises: - ValueError: "There was an error updating the EC2 default EBS encryption setting" - Returns: AWS CloudFormation physical resource id """ - request_type = event["RequestType"] - LOGGER.info(f"{request_type} Event") - - params = get_validated_parameters(event) - set_configuration_ssm_parameters(params) - control_tower_regions_only = (params.get("CONTROL_TOWER_REGIONS_ONLY", "true")).lower() in "true" - - if params["action"] in ("Add"): - account_ids = get_all_organization_accounts() - available_regions = get_enabled_regions( - customer_regions=params.get("ENABLED_REGIONS", ""), control_tower_regions_only=control_tower_regions_only - ) - if len(available_regions) > 0: - thread_cnt = MAX_THREADS - if MAX_THREADS > len(account_ids): - thread_cnt = max(len(account_ids) - 2, 1) - - processes = [] - with ThreadPoolExecutor(max_workers=thread_cnt) as executor: - for account_id in account_ids: - processes.append( - executor.submit( - process_enable_ebs_encryption_by_default, - MANAGEMENT_ACCOUNT_SESSION, - params["ROLE_TO_ASSUME"], - params["ROLE_SESSION_NAME"], - account_id, - available_regions, - ) - ) - for future in as_completed(processes, timeout=60): - try: - future.result() - except Exception as error: - LOGGER.error(f"{error}") - raise ValueError("There was an error updating the EC2 default EBS encryption setting") from None - else: - LOGGER.info("No valid enabled regions provided.") + event_info = {"Event": event} + LOGGER.info(event_info) + + if event["RequestType"] in ["Create", "Update"]: + params = get_validated_parameters({"RequestType": event["RequestType"]}) + process_accounts(event, params) else: - delete_ssm_parameter(SSM_CLIENT, SSM_PARAMETER_PREFIX) + LOGGER.info("No changes were made to EC2 Default EBS Encryption Configuration.") - return f"EC2DefaultEBSEncryption-{params['ROLE_TO_ASSUME']}-{params['ROLE_SESSION_NAME']}-{len(params.get('ENABLED_REGIONS','').strip())}" + return "EC2-DEFAULT-EBS-ENCRYPTION" -def process_lifecycle_event(event: Dict[str, Any]) -> str: - """Process Lifecycle Event. +def parameter_tags_validator(parameter_name: str, parameter_value: Optional[str]) -> dict: # noqa: CCR001 + """Validate Resource Tags in CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables. + + Args: + parameter_name: CloudFormation custom resource parameter name and/or Lambda function environment variable name + parameter_value: CloudFormation custom resource parameter value and/or Lambda function environment variable value + + Raises: + ValueError: Parameter not in JSON format + ValueError: Parameter invalid Tag Keys and/or Tag Values + + Returns: + Validated Tags Parameter in JSON format + """ + tag_key_pattern = r"^(?![aA][wW][sS]:).{1,128}$" + tag_value_pattern = r"^.{0,256}$" + + invalid_tag_keys = [] + invalid_tag_values = [] + format_message = f'"{parameter_name}" not in JSON format: [{{"Key": "string", "Value": "string"}}]' + try: + tags_json = json.loads(str(parameter_value)) + except Exception: + raise ValueError(format_message) from None + + for tag in tags_json: + if not tag.get("Key") or "Value" not in tag: + raise ValueError(format_message) + if not re.match(tag_key_pattern, tag["Key"]): + invalid_tag_keys.append(tag["Key"]) + if not re.match(tag_value_pattern, tag["Value"]): + invalid_tag_values.append(tag["Value"]) + + if invalid_tag_keys or invalid_tag_values: + message = f"In '{parameter_name}' parameter, Invalid Tag Keys: {invalid_tag_keys}, Invalid Tag Values: {invalid_tag_values} entered." + raise ValueError(message) + + return {parameter_name: tags_json} + + +def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str, is_optional: bool = False) -> dict: + """Validate CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables. + + Args: + parameter_name: CloudFormation custom resource parameter name and/or Lambda function environment variable name + parameter_value: CloudFormation custom resource parameter value and/or Lambda function environment variable value + pattern: REGEX pattern to validate against. + is_optional: Allow empty or missing value when True + + Raises: + ValueError: Parameter has a value of empty string. + ValueError: Parameter is missing + ValueError: Parameter does not follow the allowed pattern + + Returns: + Validated Parameter + """ + if parameter_value == "" and not is_optional: + raise ValueError(f"'{parameter_name}' parameter has a value of empty string.") + elif not parameter_value and not is_optional: + raise ValueError(f"'{parameter_name}' parameter is missing.") + elif pattern == "tags_json" and parameter_value: + return parameter_tags_validator(parameter_name, parameter_value) + elif pattern == "tags_json": + return {parameter_name: parameter_value} + elif not re.match(pattern, str(parameter_value)): + raise ValueError(f"'{parameter_name}' parameter with value of '{parameter_value}'" + f" does not follow the allowed pattern: {pattern}.") + return {parameter_name: parameter_value} + + +def get_validated_parameters(event: dict) -> dict: + """Validate AWS CloudFormation parameters and/or Lambda Function Environment Variables. Args: event: event data Returns: - string with account ID + Validated parameters """ - params = get_configuration_ssm_parameters() - LOGGER.info(f"Parameters: {params}") + params: dict = {} + cfn_params = event.get("ResourceProperties", {}).copy() # noqa: F841 # NOSONAR + actions = {"Create": "Add", "Update": "Update", "Delete": "Remove"} + params["action"] = actions[event.get("RequestType", "Create")] - control_tower_regions_only = (params.get("CONTROL_TOWER_REGIONS_ONLY", "true")).lower() in "true" - available_regions = get_enabled_regions(customer_regions=params.get("ENABLED_REGIONS", ""), control_tower_regions_only=control_tower_regions_only) - account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + sns_topic_pattern = r"^arn:(aws[a-zA-Z-]*){1}:sns:[a-z0-9-]+:\d{12}:[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" + true_false_pattern = r"^true|false$" + + # Required Parameters + params.update(parameter_pattern_validator("CONFIGURATION_ROLE_NAME", os.environ.get("CONFIGURATION_ROLE_NAME"), pattern=r"^[\w+=,.@-]{1,64}$")) + params.update(parameter_pattern_validator("CONTROL_TOWER_REGIONS_ONLY", os.environ.get("CONTROL_TOWER_REGIONS_ONLY"), pattern=true_false_pattern)) + params.update(parameter_pattern_validator("ROLE_SESSION_NAME", os.environ.get("ROLE_SESSION_NAME"), pattern=r"^[\w=,@.-]+$")) + params.update(parameter_pattern_validator("SNS_TOPIC_ARN", os.environ.get("SNS_TOPIC_ARN"), pattern=sns_topic_pattern)) + + # Optional Parameters + params.update(parameter_pattern_validator("ENABLED_REGIONS", os.environ.get("ENABLED_REGIONS"), pattern=r"^$|[a-z0-9-, ]+$", is_optional=True)) + params.update(parameter_pattern_validator("EXCLUDE_ACCOUNT_TAGS", os.environ.get("EXCLUDE_ACCOUNT_TAGS"), pattern="tags_json", is_optional=True)) + + # Convert true/false string parameters to boolean + params.update({"CONTROL_TOWER_REGIONS_ONLY": (params["CONTROL_TOWER_REGIONS_ONLY"] == "true")}) + + return params - process_enable_ebs_encryption_by_default( - MANAGEMENT_ACCOUNT_SESSION, params["ROLE_TO_ASSUME"], params["ROLE_SESSION_NAME"], account_id, available_regions - ) - return f"lifecycle-event-processed-for-{account_id}" +def orchestrator(event: dict, context: Any) -> None: + """Orchestration of Events. + + Args: + event: event data + context: runtime information + """ + if event.get("RequestType"): + helper(event, context) + elif event.get("source") == "aws.controltower": + process_event_lifecycle(event) + elif event.get("source") == "aws.organizations": + process_event_organizations(event) + elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": + process_event_sns(event) + else: + process_event(event) -def lambda_handler(event: Dict[str, Any], context: Any) -> None: # noqa U100 +def lambda_handler(event: dict, context: Any) -> None: """Lambda Handler. Args: @@ -418,17 +605,10 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> None: # noqa U100 ValueError: Unexpected error executing Lambda function """ LOGGER.info("....Lambda Handler Started....") - event_info = {"Event": event} - LOGGER.info(event_info) try: - if "source" not in event and "RequestType" not in event: - raise ValueError( - f"The event did not include source = aws.controltower or RequestType. Review CloudWatch logs '{context.log_group_name}' for details." - ) from None - elif "source" in event and event["source"] == "aws.controltower": - process_lifecycle_event(event) - elif "RequestType" in event: - helper(event, context) + event_info = {"Event": event} + LOGGER.info(event_info) + orchestrator(event, context) except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml new file mode 100644 index 000000000..aeadb87d0 --- /dev/null +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-global-events.yaml @@ -0,0 +1,68 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: 2010-09-09 +Description: + This template creates an event rule to send organization events to the home region. - 'ec2_default_ebs_encryption' solution in the repo, + https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse40) +Metadata: + SRA: + Version: 1.0 + Order: 4 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pHomeRegion + - Label: + default: Event Rule Properties + Parameters: + - pEventRuleRoleName + ParameterLabels: + pSRASolutionName: + default: SRA Solution Name + +Parameters: + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-ec2-default-ebs-encryption-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String + pHomeRegion: + AllowedPattern: '^[a-z0-9-]{1,64}$' + ConstraintDescription: AWS Region Example - 'us-east-1' + Description: Name of the Control Tower home region + Type: String + pSRASolutionName: + AllowedValues: [sra-ec2-default-ebs-encryption] + Default: sra-ec2-default-ebs-encryption + Description: The SRA solution name. The default value is the folder name of the solution + Type: String + +Resources: + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pSRASolutionName}-forward-org-events + Description: SRA EC2 Default EBS Encryption Forward Organizations events to home region. + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + - TagResource + State: ENABLED + Targets: + - Arn: !Sub arn:${AWS::Partition}:events:${pHomeRegion}:${AWS::AccountId}:event-bus/default + Id: !Sub ${pSRASolutionName}-org-events-to-home-region + RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pEventRuleRoleName} diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml index 437a99594..7319d8543 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main-ssm.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Entry: Parameters for deploying solution resolving SSM parameters Order: 1 AWS::CloudFormation::Interface: @@ -17,63 +17,56 @@ Metadata: - Label: default: General Properties Parameters: - - pOrganizationId - - pRootOrganizationalUnitId - pSRASolutionName - pSRASolutionVersion - pSRAStagingS3BucketName - - - Label: - default: EC2 Default EBS Encryption - Lambda Function Properties - Parameters: - - pEC2DefaultEBSEncryptionLambdaFunctionName - - pEC2DefaultEBSEncryptionLambdaRoleName - - - Label: - default: EC2 Default EBS Encryption - CloudWatch Log Group Properties - Parameters: - - pCreateEC2DefaultEBSEncryptionLambdaLogGroup - - pEC2DefaultEBSEncryptionLambdaLogGroupRetention - - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - - pEC2DefaultEBSEncryptionLambdaLogLevel + - pRootOrganizationalUnitId + - pSRAAlarmEmail - Label: default: Custom Resource Properties Parameters: + - pOrganizationId + - pExcludeEC2DefaultEBSEncryptionTags - pControlTowerRegionsOnly - pEnabledRegions - - pEC2DefaultEBSEncryptionRoleName - Label: - default: EC2 Default EBS Encryption - EventBridge Rule Properties + default: General Lambda Function Properties Parameters: - - pControlTowerLifeCycleRuleName + - pCreateLambdaLogGroup + - pLambdaLogGroupRetention + - pLambdaLogGroupKmsKey + - pLambdaLogLevel + + - Label: + default: EventBridge Rule Properties + Parameters: + - pComplianceFrequency ParameterLabels: - pControlTowerLifeCycleRuleName: - default: Control Tower Lifecycle Rule Name + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerRegionsOnly: default: Control Tower Regions Only - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: + pCreateLambdaLogGroup: default: Create Lambda Log Group - pEC2DefaultEBSEncryptionLambdaFunctionName: - default: Lambda Function Name - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: + pEnabledRegions: + default: Enabled Regions + pExcludeEC2DefaultEBSEncryptionTags: + default: (Optional) Exclude EC2 Default EBS Encryption Tags + pLambdaLogGroupKmsKey: default: (Optional) Lambda Log Group KMS Key - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: + pLambdaLogGroupRetention: default: Lambda Log Group Retention - pEC2DefaultEBSEncryptionLambdaLogLevel: + pLambdaLogLevel: default: Lambda Logging Level - pEC2DefaultEBSEncryptionLambdaRoleName: - default: Lambda Role Name - pEC2DefaultEBSEncryptionRoleName: - default: EC2 Enable Default Encryption Role Name - pEnabledRegions: - default: Enabled Regions pOrganizationId: default: Organization ID pRootOrganizationalUnitId: default: Root Organizational Unit ID + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name pSRASolutionVersion: @@ -82,30 +75,42 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: - pControlTowerLifeCycleRuleName: - AllowedPattern: '^[\w.-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] - Default: sra-ec2-default-ebs-encryption-trigger - Description: The name of the AWS Control Tower Life Cycle Rule. - Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerRegionsOnly: Type: String Description: Only enable in the Control Tower governed regions - Default: true - AllowedValues: [true, false] - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: + Default: 'true' AllowedValues: ['true', 'false'] - Default: 'false' + pCreateLambdaLogGroup: + AllowedValues: [true, false] + Default: false Description: Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. Type: String - pEC2DefaultEBSEncryptionLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-ec2-default-ebs-encryption + pEnabledRegions: + AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$' + ConstraintDescription: + Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g. + us-east-1,ap-southeast-2) + Default: '' + Description: + (Optional) List the regions to enable (AWS regions, separated by commas) the solution in. Leave blank to enable all regions. Regions must be + enabled in all accounts within the AWS Organization. Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: + pExcludeEC2DefaultEBSEncryptionTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-ec2-default-ebs-encryption", "Value": "true"}].' + Type: String + pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' Default: '' @@ -113,32 +118,16 @@ Parameters: (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: + pLambdaLogGroupRetention: AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] Default: 14 Description: Specifies the number of days you want to retain log events Type: String - pEC2DefaultEBSEncryptionLambdaLogLevel: + pLambdaLogLevel: AllowedValues: [DEBUG, INFO, ERROR] Default: INFO Description: Lambda Function Logging Level Type: String - pEC2DefaultEBSEncryptionLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption-lambda - Description: EC2 Default EBS Encryption Lambda Role Name - Type: String - pEC2DefaultEBSEncryptionRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption - Description: EC2 Default EBS Encryption Role Name - Type: String - pEnabledRegions: - Default: '' - Description: (Optional) Comma delimited list of regions to enable. Leave blank to enable all regions. - Type: String pOrganizationId: AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$' ConstraintDescription: @@ -153,14 +142,21 @@ Parameters: Default: /sra/control-tower/root-organizational-unit-id Description: SSM Parameter for Root Organizational Unit ID Type: AWS::SSM::Parameter::Value + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. + Type: String pSRASolutionName: AllowedValues: [sra-ec2-default-ebs-encryption] Default: sra-ec2-default-ebs-encryption Description: The SRA solution name. The default value is the folder name of the solution Type: String pSRASolutionVersion: - AllowedValues: [v1.1] - Default: v1.1 + AllowedValues: [v1.2] + Default: v1.2 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String pSRAStagingS3BucketName: @@ -173,6 +169,16 @@ Parameters: name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: AWS::SSM::Parameter::Value +Rules: + EnabledRegionValidation: + RuleCondition: !Equals [!Ref pControlTowerRegionsOnly, 'true'] + Assertions: + - Assert: !Equals [!Ref pEnabledRegions, ''] + AssertDescription: "'Control Tower Regions Only' parameter needs to be false, if 'Enabled Regions' are provided." + +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rEC2DefaultEBSEncryptionRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -186,7 +192,7 @@ Resources: - CAPABILITY_NAMED_IAM Description: !Sub ${pSRASolutionVersion} - Deploys an IAM role via ${pSRASolutionName} OperationPreferences: - FailureTolerancePercentage: 0 + FailureTolerancePercentage: 100 MaxConcurrentPercentage: 100 RegionConcurrencyType: PARALLEL PermissionModel: SERVICE_MANAGED @@ -198,10 +204,6 @@ Resources: - !Ref AWS::Region TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-ec2-default-ebs-encryption-role.yaml Parameters: - - ParameterKey: pEC2DefaultEBSEncryptionRoleName - ParameterValue: !Ref pEC2DefaultEBSEncryptionRoleName - - ParameterKey: pEC2DefaultEBSEncryptionLambdaRoleName - ParameterValue: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId Tags: @@ -217,8 +219,6 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Parameters: - pEC2DefaultEBSEncryptionLambdaRoleName: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - pEC2DefaultEBSEncryptionRoleName: !Ref pEC2DefaultEBSEncryptionRoleName pManagementAccountId: !Ref AWS::AccountId rEC2DefaultEBSEncryptionStack: @@ -230,15 +230,47 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Parameters: - pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName + pComplianceFrequency: !Ref pComplianceFrequency pControlTowerRegionsOnly: !Ref pControlTowerRegionsOnly - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: !Ref pCreateEC2DefaultEBSEncryptionLambdaLogGroup - pEC2DefaultEBSEncryptionLambdaFunctionName: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: !Ref pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: !Ref pEC2DefaultEBSEncryptionLambdaLogGroupRetention - pEC2DefaultEBSEncryptionLambdaLogLevel: !Ref pEC2DefaultEBSEncryptionLambdaLogLevel - pEC2DefaultEBSEncryptionLambdaRoleName: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - pEC2DefaultEBSEncryptionRoleName: !Ref pEC2DefaultEBSEncryptionRoleName + pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup pEnabledRegions: !Ref pEnabledRegions + pExcludeEC2DefaultEBSEncryptionTags: !Ref pExcludeEC2DefaultEBSEncryptionTags + pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention + pLambdaLogLevel: !Ref pLambdaLogLevel + pManagementAccountId: !Ref AWS::AccountId pOrganizationId: !Ref pOrganizationId + pSRAAlarmEmail: !Ref pSRAAlarmEmail pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName + + rEC2DefaultEBSEncryptionGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rEC2DefaultEBSEncryptionStack + Properties: + StackSetName: sra-ec2-default-ebs-encryption-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-ec2-default-ebs-encryption-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml index f621bacd3..546db79d2 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-main.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Entry: Parameters for deploying solution Order: 1 AWS::CloudFormation::Interface: @@ -17,63 +17,56 @@ Metadata: - Label: default: General Properties Parameters: - - pOrganizationId - - pRootOrganizationalUnitId - pSRASolutionName - pSRASolutionVersion - pSRAStagingS3BucketName - - - Label: - default: EC2 Default EBS Encryption - Lambda Function Properties - Parameters: - - pEC2DefaultEBSEncryptionLambdaFunctionName - - pEC2DefaultEBSEncryptionLambdaRoleName - - - Label: - default: EC2 Default EBS Encryption - CloudWatch Log Group Properties - Parameters: - - pCreateEC2DefaultEBSEncryptionLambdaLogGroup - - pEC2DefaultEBSEncryptionLambdaLogGroupRetention - - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - - pEC2DefaultEBSEncryptionLambdaLogLevel + - pRootOrganizationalUnitId + - pSRAAlarmEmail - Label: default: Custom Resource Properties Parameters: + - pOrganizationId + - pExcludeEC2DefaultEBSEncryptionTags - pControlTowerRegionsOnly - pEnabledRegions - - pEC2DefaultEBSEncryptionRoleName - Label: - default: EC2 Default EBS Encryption - EventBridge Rule Properties + default: General Lambda Function Properties Parameters: - - pControlTowerLifeCycleRuleName + - pCreateLambdaLogGroup + - pLambdaLogGroupRetention + - pLambdaLogGroupKmsKey + - pLambdaLogLevel + + - Label: + default: EventBridge Rule Properties + Parameters: + - pComplianceFrequency ParameterLabels: - pControlTowerLifeCycleRuleName: - default: Control Tower Lifecycle Rule Name + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerRegionsOnly: default: Control Tower Regions Only - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: + pCreateLambdaLogGroup: default: Create Lambda Log Group - pEC2DefaultEBSEncryptionLambdaFunctionName: - default: Lambda Function Name - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: + pEnabledRegions: + default: Enabled Regions + pExcludeEC2DefaultEBSEncryptionTags: + default: (Optional) Exclude EC2 Default EBS Encryption Tags + pLambdaLogGroupKmsKey: default: (Optional) Lambda Log Group KMS Key - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: + pLambdaLogGroupRetention: default: Lambda Log Group Retention - pEC2DefaultEBSEncryptionLambdaLogLevel: + pLambdaLogLevel: default: Lambda Logging Level - pEC2DefaultEBSEncryptionLambdaRoleName: - default: Lambda Role Name - pEC2DefaultEBSEncryptionRoleName: - default: EC2 Enable Default Encryption Role Name - pEnabledRegions: - default: Enabled Regions pOrganizationId: default: Organization ID pRootOrganizationalUnitId: default: Root Organizational Unit ID + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name pSRASolutionVersion: @@ -82,30 +75,42 @@ Metadata: default: SRA Staging S3 Bucket Name Parameters: - pControlTowerLifeCycleRuleName: - AllowedPattern: '^[\w.-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] - Default: sra-ec2-default-ebs-encryption-trigger - Description: The name of the AWS Control Tower Life Cycle Rule. - Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerRegionsOnly: Type: String Description: Only enable in the Control Tower governed regions Default: true AllowedValues: [true, false] - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: + pCreateLambdaLogGroup: AllowedValues: ['true', 'false'] Default: 'false' Description: Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. Type: String - pEC2DefaultEBSEncryptionLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-ec2-default-ebs-encryption + pEnabledRegions: + AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$' + ConstraintDescription: + Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g. + us-east-1,ap-southeast-2) + Default: '' + Description: + (Optional) If Control Tower Regions Only = false, list the regions to enable (AWS regions, separated by commas). Leave blank to enable all + regions. Regions must be enabled in all accounts within the AWS Organization. + Type: String + pExcludeEC2DefaultEBSEncryptionTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-ec2-default-ebs-encryption", "Value": "true"}].' Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: + pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' Default: '' @@ -113,32 +118,16 @@ Parameters: (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: + pLambdaLogGroupRetention: AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] Default: 14 Description: Specifies the number of days you want to retain log events Type: String - pEC2DefaultEBSEncryptionLambdaLogLevel: + pLambdaLogLevel: AllowedValues: [DEBUG, INFO, ERROR] Default: INFO Description: Lambda Function Logging Level Type: String - pEC2DefaultEBSEncryptionLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption-lambda - Description: EC2 Default EBS Encryption Lambda Role Name - Type: String - pEC2DefaultEBSEncryptionRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption - Description: EC2 Default EBS Encryption Role Name - Type: String - pEnabledRegions: - Default: '' - Description: (Optional) Comma delimited list of regions to enable. Leave blank to enable all regions. - Type: String pOrganizationId: AllowedPattern: '^o-[a-z0-9]{10,32}$' ConstraintDescription: Must start with 'o-' followed by from 10 to 32 lowercase letters or digits. (e.g. o-abc1234567) @@ -149,14 +138,21 @@ Parameters: ConstraintDescription: Must start with 'r-' followed by from 4 to 32 lowercase letters or digits. (e.g. r-abc123) Description: Root Organizational Unit ID Type: String + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. + Type: String pSRASolutionName: AllowedValues: [sra-ec2-default-ebs-encryption] Default: sra-ec2-default-ebs-encryption Description: The SRA solution name. The default value is the folder name of the solution Type: String pSRASolutionVersion: - AllowedValues: [v1.1] - Default: v1.1 + AllowedValues: [v1.2] + Default: v1.2 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String pSRAStagingS3BucketName: @@ -168,6 +164,16 @@ Parameters: numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String +Rules: + EnabledRegionValidation: + RuleCondition: !Equals [!Ref pControlTowerRegionsOnly, 'true'] + Assertions: + - Assert: !Equals [!Ref pEnabledRegions, ''] + AssertDescription: "'Control Tower Regions Only' parameter needs to be false, if 'Enabled Regions' are provided." + +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rEC2DefaultEBSEncryptionRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -181,7 +187,7 @@ Resources: - CAPABILITY_NAMED_IAM Description: !Sub ${pSRASolutionVersion} - Deploys an IAM role via ${pSRASolutionName} OperationPreferences: - FailureTolerancePercentage: 0 + FailureTolerancePercentage: 100 MaxConcurrentPercentage: 100 RegionConcurrencyType: PARALLEL PermissionModel: SERVICE_MANAGED @@ -193,10 +199,6 @@ Resources: - !Ref AWS::Region TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-ec2-default-ebs-encryption-role.yaml Parameters: - - ParameterKey: pEC2DefaultEBSEncryptionRoleName - ParameterValue: !Ref pEC2DefaultEBSEncryptionRoleName - - ParameterKey: pEC2DefaultEBSEncryptionLambdaRoleName - ParameterValue: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId Tags: @@ -212,8 +214,6 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Parameters: - pEC2DefaultEBSEncryptionLambdaRoleName: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - pEC2DefaultEBSEncryptionRoleName: !Ref pEC2DefaultEBSEncryptionRoleName pManagementAccountId: !Ref AWS::AccountId rEC2DefaultEBSEncryptionStack: @@ -225,15 +225,47 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Parameters: - pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName + pComplianceFrequency: !Ref pComplianceFrequency pControlTowerRegionsOnly: !Ref pControlTowerRegionsOnly - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: !Ref pCreateEC2DefaultEBSEncryptionLambdaLogGroup - pEC2DefaultEBSEncryptionLambdaFunctionName: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: !Ref pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: !Ref pEC2DefaultEBSEncryptionLambdaLogGroupRetention - pEC2DefaultEBSEncryptionLambdaLogLevel: !Ref pEC2DefaultEBSEncryptionLambdaLogLevel - pEC2DefaultEBSEncryptionLambdaRoleName: !Ref pEC2DefaultEBSEncryptionLambdaRoleName - pEC2DefaultEBSEncryptionRoleName: !Ref pEC2DefaultEBSEncryptionRoleName + pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup pEnabledRegions: !Ref pEnabledRegions + pExcludeEC2DefaultEBSEncryptionTags: !Ref pExcludeEC2DefaultEBSEncryptionTags + pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey + pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention + pLambdaLogLevel: !Ref pLambdaLogLevel + pManagementAccountId: !Ref AWS::AccountId pOrganizationId: !Ref pOrganizationId + pSRAAlarmEmail: !Ref pSRAAlarmEmail pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName + + rEC2DefaultEBSEncryptionGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rEC2DefaultEBSEncryptionStack + Properties: + StackSetName: sra-ec2-default-ebs-encryption-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-ec2-default-ebs-encryption-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-role.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-role.yaml index 996cfc2d5..8f44c43c7 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-role.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption-role.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 2 AWS::CloudFormation::Interface: ParameterGroups: @@ -20,7 +20,6 @@ Metadata: - pEC2DefaultEBSEncryptionLambdaRoleName - pManagementAccountId - pSRASolutionName - - pSRASolutionTagKey ParameterLabels: pEC2DefaultEBSEncryptionRoleName: @@ -31,8 +30,6 @@ Metadata: default: Management Account ID pSRASolutionName: default: SRA Solution Name - pSRASolutionTagKey: - default: SRA Solution Tag Key Parameters: pEC2DefaultEBSEncryptionLambdaRoleName: @@ -57,11 +54,6 @@ Parameters: Default: sra-ec2-default-ebs-encryption Description: The SRA solution name. The default value is the folder name of the solution Type: String - pSRASolutionTagKey: - AllowedValues: [sra-solution] - Default: sra-solution - Description: The SRA solution tag key applied to all resources created by the solution that support tagging. The value is the pSRASolutionName. - Type: String Resources: rEC2DefaultEBSEncryptionRole: @@ -100,5 +92,5 @@ Resources: - ec2:EnableEbsEncryptionByDefault Resource: '*' Tags: - - Key: !Ref pSRASolutionTagKey + - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml index e069938b5..6a850adff 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/templates/sra-ec2-default-ebs-encryption.yaml @@ -9,32 +9,23 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 3 AWS::CloudFormation::Interface: ParameterGroups: - Label: default: General Properties Parameters: - - pOrganizationId - pSRASolutionName - - pSRASolutionTagKey - pSRAStagingS3BucketName + - pSRAAlarmEmail - Label: - default: EC2 Default EBS Encryption - Lambda Function Properties + default: Lambda Function Properties Parameters: - pEC2DefaultEBSEncryptionLambdaFunctionName - pEC2DefaultEBSEncryptionLambdaRoleName - - pSRASSMParameterPrefix - - - Label: - default: EC2 Default EBS Encryption - CloudWatch Log Group Properties - Parameters: - - pCreateEC2DefaultEBSEncryptionLambdaLogGroup - - pEC2DefaultEBSEncryptionLambdaLogGroupRetention - - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey - - pEC2DefaultEBSEncryptionLambdaLogLevel + - pOrganizationId - Label: default: Custom Resource Properties @@ -42,45 +33,67 @@ Metadata: - pControlTowerRegionsOnly - pEnabledRegions - pEC2DefaultEBSEncryptionRoleName + - pExcludeEC2DefaultEBSEncryptionTags - Label: - default: EC2 Default EBS Encryption - EventBridge Rule Properties + default: General Lambda Function Properties Parameters: + - pCreateLambdaLogGroup + - pLambdaLogGroupRetention + - pLambdaLogGroupKmsKey + - pLambdaLogLevel + + - Label: + default: EventBridge Rule Properties + Parameters: + - pComplianceFrequency - pControlTowerLifeCycleRuleName + - pEventRuleRoleName ParameterLabels: + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name - pControlTowerRegionsOnly: - default: Control Tower Regions Only - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: + pCreateLambdaLogGroup: default: Create Lambda Log Group pEC2DefaultEBSEncryptionLambdaFunctionName: default: Lambda Function Name - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: - default: (Optional) Lambda Log Group KMS Key - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: - default: Lambda Log Group Retention - pEC2DefaultEBSEncryptionLambdaLogLevel: - default: Lambda Logging Level pEC2DefaultEBSEncryptionLambdaRoleName: default: Lambda Role Name pEC2DefaultEBSEncryptionRoleName: default: EC2 Enable Default Encryption Role Name pEnabledRegions: default: Enabled Regions + pEventRuleRoleName: + default: Event Rule Role Name + pExcludeEC2DefaultEBSEncryptionTags: + default: (Optional) Exclude EC2 Default EBS Encryption Tags + pLambdaLogGroupKmsKey: + default: (Optional) Lambda Logs KMS Key + pLambdaLogGroupRetention: + default: Lambda Log Group Retention + pLambdaLogLevel: + default: Lambda Log Level + pManagementAccountId: + default: Management Account ID pOrganizationId: default: Organization ID - pSRASSMParameterPrefix: - default: SRA SSM Parameter Prefix + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name - pSRASolutionTagKey: - default: SRA Solution Tag Key pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] @@ -92,9 +105,9 @@ Parameters: Description: Only enable in the Control Tower governed regions Default: true AllowedValues: [true, false] - pCreateEC2DefaultEBSEncryptionLambdaLogGroup: - AllowedValues: ['true', 'false'] - Default: 'false' + pCreateLambdaLogGroup: + AllowedValues: [true, false] + Default: false Description: Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. @@ -104,7 +117,41 @@ Parameters: ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] Default: sra-ec2-default-ebs-encryption Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey: + pEC2DefaultEBSEncryptionLambdaRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] + Default: sra-ec2-default-ebs-encryption-lambda + Description: EC2 Default EBS Encryption Lambda Role Name + Type: String + pEC2DefaultEBSEncryptionRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] + Default: sra-ec2-default-ebs-encryption + Description: EC2 Default EBS Encryption Role Name + Type: String + pEnabledRegions: + AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$' + ConstraintDescription: + Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g. + us-east-1,ap-southeast-2) + Default: '' + Description: + (Optional) If Control Tower Regions Only = false, list the regions to enable (AWS regions, separated by commas). Leave blank to enable all + regions. Regions must be enabled in all accounts within the AWS Organization. + Type: String + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-ec2-default-ebs-encryption-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String + pExcludeEC2DefaultEBSEncryptionTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-ec2-default-ebs-encryption", "Value": "true"}].' + Type: String + pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' Default: '' @@ -112,51 +159,39 @@ Parameters: (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. Type: String - pEC2DefaultEBSEncryptionLambdaLogGroupRetention: + pLambdaLogGroupRetention: AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] Default: 14 Description: Specifies the number of days you want to retain log events Type: String - pEC2DefaultEBSEncryptionLambdaLogLevel: + pLambdaLogLevel: AllowedValues: [DEBUG, INFO, ERROR] Default: INFO Description: Lambda Function Logging Level Type: String - pEC2DefaultEBSEncryptionLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption-lambda - Description: EC2 Default EBS Encryption Lambda Role Name - Type: String - pEC2DefaultEBSEncryptionRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-ec2-default-ebs-encryption - Description: EC2 Default EBS Encryption Role Name - Type: String - pEnabledRegions: - Description: (Optional) Comma delimited list of regions to enable. Leave blank to enable all regions. + pManagementAccountId: + AllowedPattern: '^\d{12}$' + ConstraintDescription: + Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Description: AWS Account ID of the Control Tower Management account. Type: String pOrganizationId: AllowedPattern: '^o-[a-z0-9]{10,32}$' ConstraintDescription: Must start with 'o-' followed by from 10 to 32 lowercase letters or digits. (e.g. o-abc1234567) Description: AWS Organizations ID Type: String - pSRASSMParameterPrefix: - AllowedValues: ['/sra/ec2-default-ebs-encryption'] - Default: '/sra/ec2-default-ebs-encryption' - Description: SRA SSM parameter prefix to use for storing the configuration properties needed when a new account is created. + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. Type: String pSRASolutionName: AllowedValues: [sra-ec2-default-ebs-encryption] Default: sra-ec2-default-ebs-encryption Description: The SRA solution name. The default value is the folder name of the solution Type: String - pSRASolutionTagKey: - AllowedValues: [sra-solution] - Default: sra-solution - Description: The SRA solution tag key applied to all resources created by the solution that support tagging. The value is the pSRASolutionName. - Type: String pSRAStagingS3BucketName: AllowedPattern: '^(?=^.{3,63}$)(?!.*[.-]{2})(?!.*[--]{2})(?!^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$)(^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$)' ConstraintDescription: @@ -167,8 +202,10 @@ Parameters: Type: String Conditions: - cIsUsingKmsKey: !Not [!Equals [!Ref pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey, '']] - cIsCreateEC2DefaultEBSEncryptionLambdaLogGroup: !Equals [!Ref pCreateEC2DefaultEBSEncryptionLambdaLogGroup, 'true'] + cComplianceFrequencySingleDay: !Equals [!Ref pComplianceFrequency, 1] + cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']] + cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] cUseGraviton: !Or - !Equals [!Ref 'AWS::Region', ap-northeast-1] - !Equals [!Ref 'AWS::Region', ap-south-1] @@ -180,47 +217,82 @@ Conditions: - !Equals [!Ref 'AWS::Region', us-east-1] - !Equals [!Ref 'AWS::Region', us-east-2] - !Equals [!Ref 'AWS::Region', us-west-2] + cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] Resources: - # Trigger Lambda after account is vended by AWS Control Tower - rControlTowerLifeCycleRule: - Type: AWS::Events::Rule + rEC2DefaultEBSEncryptionDLQ: + Type: AWS::SQS::Queue Properties: - Name: !Ref pControlTowerLifeCycleRuleName - Description: SRA EC2 Default EBS Encryption Life Cycle Trigger - EventPattern: - source: - - aws.controltower - detail-type: - - AWS Service Event via CloudTrail - detail: - eventName: - - CreateManagedAccount - State: ENABLED - Targets: - - Arn: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn - Id: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName + KmsMasterKeyId: alias/aws/sqs + QueueName: !Sub ${pSRASolutionName}-dlq + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName - rPermissionForControlTowerRuleToInvokeLambda: - Type: AWS::Lambda::Permission + rEC2DefaultEBSEncryptionDLQAlarm: + Type: AWS::CloudWatch::Alarm + Condition: cCreateDLQAlarm Properties: - FunctionName: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn - Action: lambda:InvokeFunction - Principal: events.amazonaws.com - SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn + AlarmDescription: SRA DLQ alarm if the queue depth is 1 + Namespace: AWS/SQS + MetricName: ApproximateNumberOfMessagesVisible + Dimensions: + - Name: QueueName + Value: !GetAtt rEC2DefaultEBSEncryptionDLQ.QueueName + Statistic: Sum + Period: 300 + EvaluationPeriods: 1 + Threshold: 1 + ComparisonOperator: GreaterThanThreshold + AlarmActions: + - !Ref rEC2DefaultEBSEncryptionDLQAlarmTopic + InsufficientDataActions: + - !Ref rEC2DefaultEBSEncryptionDLQAlarmTopic + + rEC2DefaultEBSEncryptionDLQAlarmTopic: + Type: AWS::SNS::Topic + Condition: cCreateDLQAlarm + Properties: + DisplayName: !Sub ${pSRASolutionName}-dlq-alarm + KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns + TopicName: !Sub ${pSRASolutionName}-dlq-alarm + Subscription: + - Endpoint: !Ref pSRAAlarmEmail + Protocol: email + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rEC2DefaultEBSEncryptionDLQPolicy: + Type: AWS::SQS::QueuePolicy + Properties: + Queues: + - !Ref rEC2DefaultEBSEncryptionDLQ + PolicyDocument: + Statement: + - Effect: Allow + Action: SQS:SendMessage + Condition: + ArnEquals: + aws:SourceArn: + - !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Resource: + - !GetAtt rEC2DefaultEBSEncryptionDLQ.Arn + Principal: + Service: events.amazonaws.com rEC2DefaultEBSEncryptionLambdaLogGroup: Type: AWS::Logs::LogGroup - Condition: cIsCreateEC2DefaultEBSEncryptionLambdaLogGroup + Condition: cCreateLambdaLogGroup DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: KmsKeyId: !If - - cIsUsingKmsKey - - !Ref pEC2DefaultEBSEncryptionLambdaLogGroupKmsKey + - cUseKmsKey + - !Ref pLambdaLogGroupKmsKey - !Ref AWS::NoValue LogGroupName: !Sub '/aws/lambda/${pEC2DefaultEBSEncryptionLambdaFunctionName}' - RetentionInDays: !Ref pEC2DefaultEBSEncryptionLambdaLogGroupRetention + RetentionInDays: !Ref pLambdaLogGroupRetention rEC2DefaultEBSEncryptionLambdaRole: Type: AWS::IAM::Role @@ -245,46 +317,77 @@ Resources: - sts:AssumeRole Path: '/' Policies: - - PolicyName: sra-ec2-default-ebs-encryption-policy + - PolicyName: sra-ec2-default-ebs-encryption-policy-cloudformation PolicyDocument: Version: 2012-10-17 Statement: - - Sid: CreateLogStreamAndEvents + - Sid: CloudFormation Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pEC2DefaultEBSEncryptionLambdaFunctionName}:log-stream:* + Action: cloudformation:ListStackInstances + Resource: !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/AWSControlTowerBP-* + - PolicyName: sra-ec2-default-ebs-encryption-policy-iam + PolicyDocument: + Version: 2012-10-17 + Statement: - Sid: AssumeRole Effect: Allow Action: sts:AssumeRole + Resource: !Sub arn:${AWS::Partition}:iam::*:role/${pEC2DefaultEBSEncryptionRoleName} Condition: StringEquals: aws:PrincipalOrgId: !Ref pOrganizationId - Resource: !Sub arn:${AWS::Partition}:iam::*:role/${pEC2DefaultEBSEncryptionRoleName} - - Sid: Organizations + - PolicyName: sra-ec2-default-ebs-encryption-policy-logs + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: CreateLogStreamAndEvents + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pEC2DefaultEBSEncryptionLambdaFunctionName}:log-stream:* + + - PolicyName: sra-ec2-default-ebs-encryption-policy-organizations + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: OrganizationsReadAccess Effect: Allow - Action: organizations:ListAccounts + Action: + - organizations:DescribeAccount + - organizations:ListAccounts Resource: '*' - - Sid: CloudFormation + - Sid: ListTagsForAccounts Effect: Allow - Action: cloudformation:ListStackInstances - Resource: !Sub arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stackset/AWSControlTowerBP-* + Action: organizations:ListTagsForResource + Resource: !Sub arn:${AWS::Partition}:organizations::${pManagementAccountId}:account/${pOrganizationId}/* - - Sid: SSM + - PolicyName: sra-ec2-default-ebs-encryption-policy-sns + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: SNSPublish Effect: Allow Action: - - ssm:DeleteParameter - - ssm:GetParameter - - ssm:PutParameter - Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter${pSRASSMParameterPrefix}* + - sns:Publish + - sns:PublishBatch + Resource: !Ref rEC2DefaultEBSEncryptionTopic + + - PolicyName: sra-ec2-default-ebs-encryption-policy-sqs + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: SQSSendMessage + Effect: Allow + Action: sqs:SendMessage + Resource: !GetAtt rEC2DefaultEBSEncryptionDLQ.Arn Tags: - - Key: !Ref pSRASolutionTagKey + - Key: sra-solution Value: !Ref pSRASolutionName rEC2DefaultEBSEncryptionLambdaFunction: @@ -313,7 +416,6 @@ Resources: - !Ref AWS::NoValue Handler: app.lambda_handler Role: !GetAtt rEC2DefaultEBSEncryptionLambdaRole.Arn - MemorySize: 2048 Runtime: python3.9 Timeout: 900 Code: @@ -321,10 +423,15 @@ Resources: S3Key: !Sub ${pSRASolutionName}/lambda_code/${pSRASolutionName}.zip Environment: Variables: - LOG_LEVEL: !Ref pEC2DefaultEBSEncryptionLambdaLogLevel - SSM_PARAMETER_PREFIX: !Ref pSRASSMParameterPrefix + LOG_LEVEL: !Ref pLambdaLogLevel + CONFIGURATION_ROLE_NAME: !Ref pEC2DefaultEBSEncryptionRoleName + CONTROL_TOWER_REGIONS_ONLY: !Ref pControlTowerRegionsOnly + ENABLED_REGIONS: !Ref pEnabledRegions + EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeEC2DefaultEBSEncryptionTags + ROLE_SESSION_NAME: sra-ec2-default-ebs-encryption + SNS_TOPIC_ARN: !Ref rEC2DefaultEBSEncryptionTopic Tags: - - Key: !Ref pSRASolutionTagKey + - Key: sra-solution Value: !Ref pSRASolutionName rEC2DefaultEBSEncryptionLambdaCustomResource: @@ -332,10 +439,142 @@ Resources: Version: '1.0' Properties: ServiceToken: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + CONFIGURATION_ROLE_NAME: !Ref pEC2DefaultEBSEncryptionRoleName CONTROL_TOWER_REGIONS_ONLY: !Ref pControlTowerRegionsOnly ENABLED_REGIONS: !Ref pEnabledRegions + EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeEC2DefaultEBSEncryptionTags ROLE_SESSION_NAME: sra-ec2-default-ebs-encryption - ROLE_TO_ASSUME: !Ref pEC2DefaultEBSEncryptionRoleName + SNS_TOPIC_ARN: !Ref rEC2DefaultEBSEncryptionTopic + + rEC2DefaultEBSEncryptionTopic: + Type: AWS::SNS::Topic + Properties: + DisplayName: !Sub ${pSRASolutionName}-configuration + KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rEC2DefaultEBSEncryptionTopicLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + Action: lambda:InvokeFunction + FunctionName: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Principal: sns.amazonaws.com + SourceArn: !Ref rEC2DefaultEBSEncryptionTopic + + rEC2DefaultEBSEncryptionTopicSubscription: + Type: AWS::SNS::Subscription + Properties: + Endpoint: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Protocol: lambda + TopicArn: !Ref rEC2DefaultEBSEncryptionTopic + + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-org-update + Description: SRA EC2 Default EBS Encryption Trigger on Organizations update + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + - TagResource + State: ENABLED + Targets: + - Arn: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Id: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName + + rControlTowerLifeCycleRule: + Type: AWS::Events::Rule + Properties: + Name: !Ref pControlTowerLifeCycleRuleName + Description: SRA EC2 Default EBS Encryption Control Tower Life Cycle Trigger (triggers on new Control Tower vended accounts) + EventPattern: + source: + - aws.controltower + detail-type: + - AWS Service Event via CloudTrail + detail: + eventName: + - CreateManagedAccount + - UpdateManagedAccount + State: ENABLED + Targets: + - Arn: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Id: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName + + rPermissionForControlTowerRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn + + rPermissionForOrganizationsRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rOrganizationsRule.Arn + + rPermissionForScheduledComplianceRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rScheduledComplianceRule.Arn + + rScheduledComplianceRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-org-compliance + Description: SRA EC2 Default EBS Encryption Trigger for scheduled organization compliance + ScheduleExpression: !If + - cComplianceFrequencySingleDay + - !Sub rate(${pComplianceFrequency} day) + - !Sub rate(${pComplianceFrequency} days) + State: ENABLED + Targets: + - Arn: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn + Id: !Ref pEC2DefaultEBSEncryptionLambdaFunctionName + + rCrossRegionEventRuleRole: + Type: AWS::IAM::Role + Condition: cNotGlobalRegionUsEast1 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: Specific role name provided + Properties: + RoleName: !Ref pEventRuleRoleName + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - events.amazonaws.com + Policies: + - PolicyName: sra-ec2-default-ebs-encryption-policy-events + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: events:PutEvents + Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default Outputs: oControlTowerLifeCycleRule: @@ -345,7 +584,7 @@ Outputs: Description: SRA EC2 Default EBS Encryption Lambda Function ARN Value: !GetAtt rEC2DefaultEBSEncryptionLambdaFunction.Arn oEC2DefaultEBSEncryptionLambdaLogGroupArn: - Condition: cIsCreateEC2DefaultEBSEncryptionLambdaLogGroup + Condition: cCreateLambdaLogGroup Description: SRA EC2 Default EBS Encryption Lambda Log Group ARN Value: !GetAtt rEC2DefaultEBSEncryptionLambdaLogGroup.Arn oEC2DefaultEBSEncryptionLambdaRoleArn: diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/README.md b/aws_sra_examples/solutions/s3/s3_block_account_public_access/README.md index ae9aa1cca..1248408f6 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/README.md +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/README.md @@ -18,6 +18,12 @@ users can modify bucket policies, access point policies, or object permissions t With S3 Block Public Access, account administrators and bucket owners can easily set up centralized controls to limit public access to their Amazon S3 resources that are enforced regardless of how the resources are created. +**Key solution features:** + +- Sets S3 block account public access settings for all existing accounts including the `management account` and future accounts. +- Ability to exclude accounts via provided account tags. +- Triggered when new accounts are added to the AWS Organization, account tag updates, and on account status changes. + ### Block public access settings > **S3 Block Public Access provides four settings. This solution applies the settings to the account, which applies to all buckets and access points that are owned by that account.** @@ -50,36 +56,50 @@ With S3 Block Public Access, account administrators and bucket owners can easily - The [Customizations for AWS Control Tower](https://aws.amazon.com/solutions/implementations/customizations-for-aws-control-tower/) solution deploys all templates as a CloudFormation `StackSet`. - For parameter details, review the [AWS CloudFormation templates](templates/). -#### 1.2 AWS Lambda Function +#### 1.2 IAM Roles -- The AWS Lambda Function contains the logic for configuring the S3 block public access settings within each account. -- The function is triggered by CloudFormation Create, Update, and Delete events and also by the `Control Tower Lifecycle Event Rule` when new accounts are provisioned. +- The `Lambda IAM Role` is used by the Lambda function to identify existing and future accounts that need S3 Block Account Public Access configured. +- The `S3 Block Account Public Access IAM Role` is assumed by the Lambda function to set S3 Block Account Public Access for the management account and the member accounts. +- The `Event Rule IAM Role` is assumed by EventBridge to forward Global events to the `Home Region` default Event Bus. + +#### 1.3 Regional Event Rules + +- The `AWS Control Tower Lifecycle Event Rule` triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +- The `Organization Compliance Scheduled Event Rule` triggers the `AWS Lambda Function` to capture AWS Account status updates (e.g. suspended to active). + - A parameter is provided to set the schedule frequency. + - See the [Instructions to Manually Run the Lambda Function](#instructions-to-manually-run-the-lambda-function) for triggering the `AWS Lambda Function` before the next scheduled run time. +- The `AWS Organizations Event Rule` triggers the `AWS Lambda Function` when updates are made to accounts within the organization. + - When AWS Accounts are added to the AWS Organization outside of the AWS Control Tower Account Factory. (e.g. account created via AWS Organizations console, account invited from another AWS Organization). + - When tags are added or updated on AWS Accounts. + +#### 1.4 Global Event Rules -#### 1.3 AWS SSM Parameter Store +- If the `Home Region` is different from the `Global Region (e.g. us-east-1)`, then global event rules are created within the `Global Region` to forward events to the `Home Region` default Event Bus. +- The `AWS Organizations Event Rule` forwards AWS Organization account update events. -- The Lambda Function creates/updates configuration parameters within the `SSM Parameter Store` on CloudFormation events and the parameters are used when triggered by the `Control Tower Lifecycle Event Rule`, which does not send the properties on the - event like CloudFormation does. +#### 1.5 Dead Letter Queue (DLQ) -#### 1.4 AWS Control Tower Lifecycle Event Rule +- SQS dead letter queue used for retaining any failed Lambda events. -- The AWS Control Tower Lifecycle Event Rule triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +#### 1.6 AWS Lambda Function -#### 1.5 AWS Lambda CloudWatch Log Group +- The AWS Lambda Function contains the logic for configuring the S3 block public access settings within each account. + +#### 1.7 Lambda CloudWatch Log Group - All the `AWS Lambda Function` logs are sent to a CloudWatch Log Group `` to help with debugging and traceability of the actions performed. -- By default the `AWS Lambda Function` will create the CloudWatch Log Group with a `Retention` (Never expire) and are encrypted with a CloudWatch Logs service managed encryption key. -- Optional parameters are included to allow creating the CloudWatch Log Group, which allows setting `KMS Encryption` using a customer managed KMS key and setting the `Retention` to a specific value (e.g. 14 days). +- By default the `AWS Lambda Function` will create the CloudWatch Log Group and logs are encrypted with a CloudWatch Logs service managed encryption key. +- Parameters are provided for changing the default log group retention and encryption KMS key. -#### 1.6 AWS Lambda Function Role +#### 1.8 Alarm SNS Topic -- The AWS Lambda Function Role allows the AWS Lambda service to assume the role and perform actions defined in the attached IAM policies. -- The role is also trusted by the S3 Block Account Public Access IAM Role within each account so that it can configure the S3 account settings. +- SNS Topic used to notify subscribers when messages hit the Dead Letter Queue (DLQ). -#### 1.7 S3 Block Account Public Access IAM Role +#### 1.9 SNS Topic -- The S3 block account public access IAM role is deployed into each account within the AWS Organization and it is assumed by the central `AWS Lambda Function` to configure the block public access settings for the account. +- SNS Topic used to fanout the Lambda function for setting the S3 block account public access configuration. -#### 1.8 S3 Account Settings +#### 1.10 S3 Account Settings - The `AWS Lambda Function` configures the block public access settings for the account. @@ -93,11 +113,11 @@ With S3 Block Public Access, account administrators and bucket owners can easily #### 2.2 S3 Block Account Public Access IAM Role -- See [1.7 S3 Block Account Public Access IAM Role](#17-s3-block-account-public-access-iam-role) +- The `S3 Block Account Public Access IAM Role` is assumed by the Lambda function within the management account to set S3 Block Account Public Access for the account. #### 2.3 S3 Account Settings -- See [1.8 S3 Account Settings](#18-s3-account-settings) +- See [1.10 S3 Account Settings](#110-s3-account-settings) --- @@ -140,11 +160,25 @@ How to verify after the pipeline completes? 1. Log into an account and navigate to the S3 console page 2. Select the `Block Public Access settings for this account` in the side menu and verify the settings match the parameters provided in the configuration +#### Solution Update Instructions + +1. [Download and Stage the SRA Solutions](../../../docs/DOWNLOAD-AND-STAGE-SOLUTIONS.md). **Note:** Get the latest code and run the staging script. +2. Update the existing CloudFormation Stack or CFCT configuration. **Note:** Make sure to update the `SRA Solution Version` parameter and any new added parameters. + #### Solution Delete Instructions 1. In the `management account (home region)`, delete the AWS CloudFormation **Stack** (`sra-s3-block-account-public-access-main-ssm` or `sra-s3-block-account-public-access-main`) created above. 2. In the `management account (home region)`, delete the AWS CloudWatch **Log Group** (e.g. /aws/lambda/) for the Lambda function deployed. +#### Instructions to Manually Run the Lambda Function + +1. In the `management account (home region)`. +2. Navigate to the AWS Lambda Functions page. +3. Select the `checkbox` next to the Lambda Function and select `Test` from the `Actions` menu. +4. Scroll down to view the `Test event`. +5. Click the `Test` button to trigger the Lambda Function with the default values. +6. Verify that the updates were successful within the expected account(s). + --- ## References diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/manifest_v2.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/manifest_v2.yaml index 429405847..ee93ed014 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/manifest_v2.yaml +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/manifest_v2.yaml @@ -11,8 +11,8 @@ resources: - name: sra-s3-block-account-public-access-main-ssm resource_file: templates/sra-s3-block-account-public-access-main-ssm.yaml parameters: - - parameter_key: pControlTowerLifeCycleRuleName - parameter_value: sra-s3-block-account-public-access-trigger + - parameter_key: pComplianceFrequency + parameter_value: 7 - parameter_key: pCreateLambdaLogGroup parameter_value: 'false' - parameter_key: pEnableBlockPublicAcls @@ -23,18 +23,18 @@ resources: parameter_value: 'true' - parameter_key: pEnableRestrictPublicBuckets parameter_value: 'true' + - parameter_key: pExcludeS3BlockAccountPublicAccessTags + parameter_value: '' - parameter_key: pLambdaLogGroupKmsKey parameter_value: '' - parameter_key: pLambdaLogLevel parameter_value: 'INFO' - parameter_key: pLambdaLogGroupRetention parameter_value: '14' - - parameter_key: pS3BlockAccountPublicAccessLambdaFunctionName - parameter_value: sra-s3-block-account-public-access - - parameter_key: pS3BlockAccountPublicAccessLambdaRoleName - parameter_value: sra-s3-block-account-public-access-lambda - - parameter_key: pS3BlockAccountPublicAccessRoleName - parameter_value: sra-s3-block-account-public-access + - parameter_key: pSRAAlarmEmail + parameter_value: '' + - parameter_key: pSRASolutionVersion + parameter_value: 'v1.2' deploy_method: stack_set deployment_targets: accounts: @@ -43,8 +43,8 @@ resources: # - name: sra-s3-block-account-public-access-main # resource_file: templates/sra-s3-block-account-public-access-main.yaml # parameters: - # - parameter_key: pControlTowerLifeCycleRuleName - # parameter_value: sra-s3-block-account-public-access-trigger + # - parameter_key: pComplianceFrequency + # parameter_value: 7 # - parameter_key: pCreateLambdaLogGroup # parameter_value: 'false' # - parameter_key: pEnableBlockPublicAcls @@ -55,6 +55,8 @@ resources: # parameter_value: 'true' # - parameter_key: pEnableRestrictPublicBuckets # parameter_value: 'true' + # - parameter_key: pExcludeS3BlockAccountPublicAccessTags + # parameter_value: '' # - parameter_key: pLambdaLogGroupKmsKey # parameter_value: '' # - parameter_key: pLambdaLogLevel @@ -65,14 +67,12 @@ resources: # parameter_value: '' # - parameter_key: pRootOrganizationalUnitId # parameter_value: '' - # - parameter_key: pS3BlockAccountPublicAccessLambdaFunctionName - # parameter_value: sra-s3-block-account-public-access - # - parameter_key: pS3BlockAccountPublicAccessLambdaRoleName - # parameter_value: sra-s3-block-account-public-access-lambda - # - parameter_key: pS3BlockAccountPublicAccessRoleName - # parameter_value: sra-s3-block-account-public-access + # - parameter_key: pSRAAlarmEmail + # parameter_value: '' # - parameter_key: pSRAStagingS3BucketName # parameter_value: '' + # - parameter_key: pSRASolutionVersion + # parameter_value: 'v1.2' # deploy_method: stack_set # deployment_targets: # accounts: diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main-ssm.json b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main-ssm.json index 7001a476f..120803f05 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main-ssm.json +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main-ssm.json @@ -1,7 +1,7 @@ [ { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-s3-block-account-public-access-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pCreateLambdaLogGroup", @@ -23,6 +23,10 @@ "ParameterKey": "pEnableRestrictPublicBuckets", "ParameterValue": "true" }, + { + "ParameterKey": "pExcludeS3BlockAccountPublicAccessTags", + "ParameterValue": "" + }, { "ParameterKey": "pLambdaLogGroupKmsKey", "ParameterValue": "" @@ -36,15 +40,11 @@ "ParameterValue": "14" }, { - "ParameterKey": "pS3BlockAccountPublicAccessLambdaFunctionName", - "ParameterValue": "sra-s3-block-account-public-access" - }, - { - "ParameterKey": "pS3BlockAccountPublicAccessLambdaRoleName", - "ParameterValue": "sra-s3-block-account-public-access-lambda" + "ParameterKey": "pSRAAlarmEmail", + "ParameterValue": "" }, { - "ParameterKey": "pS3BlockAccountPublicAccessRoleName", - "ParameterValue": "sra-s3-block-account-public-access" + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.2" } ] \ No newline at end of file diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main.json b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main.json index e52f67bdb..cbeea5831 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main.json +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/customizations_for_aws_control_tower/parameters/sra-s3-block-account-public-access-main.json @@ -1,7 +1,7 @@ [ { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-s3-block-account-public-access-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pCreateLambdaLogGroup", @@ -23,6 +23,10 @@ "ParameterKey": "pEnableRestrictPublicBuckets", "ParameterValue": "true" }, + { + "ParameterKey": "pExcludeS3BlockAccountPublicAccessTags", + "ParameterValue": "" + }, { "ParameterKey": "pLambdaLogGroupKmsKey", "ParameterValue": "" @@ -44,19 +48,15 @@ "ParameterValue": "" }, { - "ParameterKey": "pS3BlockAccountPublicAccessLambdaFunctionName", - "ParameterValue": "sra-s3-block-account-public-access" - }, - { - "ParameterKey": "pS3BlockAccountPublicAccessLambdaRoleName", - "ParameterValue": "sra-s3-block-account-public-access-lambda" - }, - { - "ParameterKey": "pS3BlockAccountPublicAccessRoleName", - "ParameterValue": "sra-s3-block-account-public-access" + "ParameterKey": "pSRAAlarmEmail", + "ParameterValue": "" }, { "ParameterKey": "pSRAStagingS3BucketName", "ParameterValue": "" + }, + { + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.2" } ] \ No newline at end of file diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.png b/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.png index 7cd69b817..5150a66d5 100644 Binary files a/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.png and b/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.png differ diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.pptx b/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.pptx index 58a3708ed..bbdf61a54 100644 Binary files a/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.pptx and b/aws_sra_examples/solutions/s3/s3_block_account_public_access/documentation/s3-block-account-public-access.pptx differ diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/app.py b/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/app.py index 15e1fd55d..d5ce4b1f5 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/app.py +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/app.py @@ -1,5 +1,9 @@ """The purpose of this script is to configure the S3 account public access block settings. +Version: 1.1 + +'s3_block_account_public_access' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ @@ -9,54 +13,132 @@ import logging import os import re -from concurrent.futures import ThreadPoolExecutor, as_completed -from typing import TYPE_CHECKING, Any, Dict, Optional # noqa: TYP001 (guard import) +from time import sleep +from typing import TYPE_CHECKING, Any, List, Optional, Union import boto3 -import common from crhelper import CfnResource if TYPE_CHECKING: + from aws_lambda_typing.context import Context + from aws_lambda_typing.events import CloudFormationCustomResourceEvent + from mypy_boto3_organizations import OrganizationsClient + from mypy_boto3_organizations.type_defs import AccountTypeDef, DescribeAccountResponseTypeDef, TagTypeDef from mypy_boto3_s3control.client import S3ControlClient - from mypy_boto3_ssm.client import SSMClient + from mypy_boto3_s3control.type_defs import GetPublicAccessBlockOutputTypeDef + from mypy_boto3_sns import SNSClient + from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef, PublishResponseTypeDef + from mypy_boto3_sts import STSClient # Setup Default Logger LOGGER = logging.getLogger("sra") log_level = os.environ.get("LOG_LEVEL", logging.ERROR) LOGGER.setLevel(log_level) -# Initialize the helper. `sleep_on_delete` allows time for the CloudWatch Logs to get captured. -helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120) - # Global Variables -MAX_THREADS = 10 -SSM_PARAMETER_PREFIX = os.environ.get("SSM_PARAMETER_PREFIX", "/sra/s3-block-account-public-access") UNEXPECTED = "Unexpected!" +ORGANIZATIONS_PAGE_SIZE = 20 +ORGANIZATIONS_THROTTLE_PERIOD = 0.2 +SNS_PUBLISH_BATCH_MAX = 10 + +# Initialize the helper. `sleep_on_delete` allows time for the CloudWatch Logs to get captured. +helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120) try: MANAGEMENT_ACCOUNT_SESSION = boto3.Session() -except Exception: - LOGGER.exception(UNEXPECTED) + ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations") + SNS_CLIENT: SNSClient = MANAGEMENT_ACCOUNT_SESSION.client("sns") +except Exception as error: + LOGGER.error({"Unexpected_Error": error}) raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None -def put_account_public_access_block( - s3_client: S3ControlClient, - account_id: str, - enable_block_public_acls: bool, - enable_ignore_public_acls: bool, - enable_block_public_policy: bool, - enable_restrict_public_buckets: bool, -) -> None: +def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: + """Assumes the provided role in the given account and returns a session. + + Args: + role: Role to assume in target account. + role_session_name: Identifier for the assumed role session. + account: AWS account number. Defaults to None. + session: Boto3 session. Defaults to None. + + Returns: + Session object for the specified AWS account + """ + if not session: + session = boto3.Session() + sts_client: STSClient = session.client("sts") + sts_arn = sts_client.get_caller_identity()["Arn"] + LOGGER.info(f"USER: {sts_arn}") + if not account: + account = sts_arn.split(":")[4] + partition = sts_arn.split(":")[1] + role_arn = f"arn:{partition}:iam::{account}:role/{role}" + + response = sts_client.assume_role(RoleArn=role_arn, RoleSessionName=role_session_name) + LOGGER.info(f"ASSUMED ROLE: {response['AssumedRoleUser']['Arn']}") + return boto3.Session( + aws_access_key_id=response["Credentials"]["AccessKeyId"], + aws_secret_access_key=response["Credentials"]["SecretAccessKey"], + aws_session_token=response["Credentials"]["SessionToken"], + ) + + +def get_active_organization_accounts() -> list[AccountTypeDef]: + """Get all the active AWS Organization accounts. + + Returns: + List of active account IDs + """ + paginator = ORG_CLIENT.get_paginator("list_accounts") + accounts: list[AccountTypeDef] = [] + for page in paginator.paginate(PaginationConfig={"PageSize": ORGANIZATIONS_PAGE_SIZE}): + for account in page["Accounts"]: + if account["Status"] == "ACTIVE": + accounts.append(account) + sleep(ORGANIZATIONS_THROTTLE_PERIOD) + return accounts + + +def get_account_info(account_id: str) -> AccountTypeDef: + """Get AWS Account info. + + Args: + account_id: ID of the AWS account + + Returns: + Account info + """ + response: DescribeAccountResponseTypeDef = ORG_CLIENT.describe_account(AccountId=account_id) + api_call_details = {"API_Call": "organizations:DescribeAccounts", "API_Response": response} + LOGGER.info(api_call_details) + return response["Account"] + + +def get_organization_resource_tags(resource_id: str) -> List[TagTypeDef]: + """Get Org Resource Tags. + + Args: + resource_id: ID of the AWS account + + Returns: + Account Tags + """ + paginator = ORG_CLIENT.get_paginator("list_tags_for_resource") + tags = [] + for page in paginator.paginate(ResourceId=resource_id): + tags += page["Tags"] + sleep(ORGANIZATIONS_THROTTLE_PERIOD) + return tags + + +def put_account_public_access_block(s3_client: S3ControlClient, account_id: str, params: dict) -> None: """Put account public access block. Args: s3_client: S3ControlClient account_id: The account to set the public access block - enable_block_public_acls: True or False - enable_ignore_public_acls: True or False - enable_block_public_policy: True or False - enable_restrict_public_buckets: True or False + params: solution parameters Raises: ValueError: Error setting account public access block @@ -64,10 +146,10 @@ def put_account_public_access_block( try: s3_client.put_public_access_block( PublicAccessBlockConfiguration={ - "BlockPublicAcls": enable_block_public_acls, - "IgnorePublicAcls": enable_ignore_public_acls, - "BlockPublicPolicy": enable_block_public_policy, - "RestrictPublicBuckets": enable_restrict_public_buckets, + "BlockPublicAcls": params["ENABLE_BLOCK_PUBLIC_ACLS"], + "IgnorePublicAcls": params["ENABLE_IGNORE_PUBLIC_ACLS"], + "BlockPublicPolicy": params["ENABLE_BLOCK_PUBLIC_POLICY"], + "RestrictPublicBuckets": params["ENABLE_RESTRICT_PUBLIC_BUCKETS"], }, AccountId=account_id, ) @@ -78,254 +160,258 @@ def put_account_public_access_block( def settings_changed( s3_client: S3ControlClient, - account_id: str, - enable_block_public_acls: bool, - enable_ignore_public_acls: bool, - enable_block_public_policy: bool, - enable_restrict_public_buckets: bool, + aws_account: AccountTypeDef, + params: dict, ) -> bool: """Account public access block settings changed. Args: s3_client: S3ControlClient - account_id: The account to set the public access block - enable_block_public_acls: True or False - enable_ignore_public_acls: True or False - enable_block_public_policy: True or False - enable_restrict_public_buckets: True or False + aws_account: The account to set the public access block + params: solution parameters Returns: True or False """ try: - response = s3_client.get_public_access_block(AccountId=account_id) + response: GetPublicAccessBlockOutputTypeDef = s3_client.get_public_access_block(AccountId=aws_account["Id"]) if ( - response["PublicAccessBlockConfiguration"]["BlockPublicAcls"] is enable_block_public_acls - and response["PublicAccessBlockConfiguration"]["IgnorePublicAcls"] is enable_ignore_public_acls - and response["PublicAccessBlockConfiguration"]["BlockPublicPolicy"] is enable_block_public_policy - and response["PublicAccessBlockConfiguration"]["RestrictPublicBuckets"] is enable_restrict_public_buckets + response["PublicAccessBlockConfiguration"]["BlockPublicAcls"] is params["ENABLE_BLOCK_PUBLIC_ACLS"] + and response["PublicAccessBlockConfiguration"]["IgnorePublicAcls"] is params["ENABLE_IGNORE_PUBLIC_ACLS"] + and response["PublicAccessBlockConfiguration"]["BlockPublicPolicy"] is params["ENABLE_BLOCK_PUBLIC_POLICY"] + and response["PublicAccessBlockConfiguration"]["RestrictPublicBuckets"] is params["ENABLE_RESTRICT_PUBLIC_BUCKETS"] ): return False except s3_client.exceptions.NoSuchPublicAccessBlockConfiguration: - LOGGER.warning(f"Unable to get the public access block configuration from {account_id}") + LOGGER.warning(f"Unable to get the public access block configuration from {aws_account['Id']}") return True -def get_ssm_parameter_value(ssm_client: SSMClient, name: str) -> str: - """Get SSM Parameter Value. +def process_put_account_public_access_block( + s3_client: S3ControlClient, aws_account: AccountTypeDef, params: dict +) -> None: # noqa: CFQ002 (max arguments) + """Process put account public access block. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name - - Returns: - Value string + s3_client: S3ControlClient + aws_account: account to assume role in + params: solution parameters """ - return ssm_client.get_parameter(Name=name, WithDecryption=True)["Parameter"]["Value"] + if settings_changed(s3_client, aws_account, params): + put_account_public_access_block( + s3_client, + aws_account["Id"], + params, + ) + LOGGER.info(f"Enabled account S3 Block Public Access in {aws_account['Id']}") -def put_ssm_parameter(ssm_client: SSMClient, name: str, description: str, value: str) -> None: - """Put SSM Parameter. +def publish_sns_message(message: dict, subject: str, sns_topic_arn: str) -> None: + """Publish SNS Message. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name - description: Parameter description - value: Parameter value + message: SNS Message + subject: SNS Topic Subject + sns_topic_arn: SNS Topic ARN """ - ssm_client.put_parameter( - Name=name, - Description=description, - Value=value, - Type="SecureString", - Overwrite=True, - Tier="Standard", - DataType="text", - ) + LOGGER.info(f"Publishing SNS message for {message['AccountId']}.") + LOGGER.info({"SNSMessage": message}) + response: PublishResponseTypeDef = SNS_CLIENT.publish(Message=json.dumps(message), Subject=subject, TopicArn=sns_topic_arn) + api_call_details = {"API_Call": "sns:Publish", "API_Response": response} + LOGGER.info(api_call_details) -def delete_ssm_parameter(ssm_client: SSMClient, name: str) -> None: - """Delete SSM Parameter. +def publish_sns_message_batch(message_batch: list, sns_topic_arn: str) -> None: + """Publish SNS Message Batches. Args: - ssm_client: SSM Boto3 Client - name: Parameter Name + message_batch: Batch of SNS messages + sns_topic_arn: SNS Topic ARN """ - ssm_client.delete_parameter(Name=name) + LOGGER.info("Publishing SNS Message Batch") + LOGGER.info({"SNSMessageBatch": message_batch}) + response: PublishBatchResponseTypeDef = SNS_CLIENT.publish_batch(TopicArn=sns_topic_arn, PublishBatchRequestEntries=message_batch) + api_call_details = {"API_Call": "sns:PublishBatch", "API_Response": response} + LOGGER.info(api_call_details) -def set_configuration_ssm_parameters(management_session: boto3.Session, params: dict) -> None: - """Set Configuration SSM Parameters. +def process_sns_message_batches(sns_messages: list, sns_topic_arn: str) -> None: + """Process SNS Message Batches for Publishing. Args: - management_session: Management account session - params: Parameters + sns_messages: SNS messages to be batched. + sns_topic_arn: SNS Topic ARN """ - ssm_client: SSMClient = management_session.client("ssm") - ssm_parameter_value = { - "ENABLE_BLOCK_PUBLIC_ACLS": params["ENABLE_BLOCK_PUBLIC_ACLS"], - "ENABLE_IGNORE_PUBLIC_ACLS": params["ENABLE_IGNORE_PUBLIC_ACLS"], - "ENABLE_BLOCK_PUBLIC_POLICY": params["ENABLE_BLOCK_PUBLIC_POLICY"], - "ENABLE_RESTRICT_PUBLIC_BUCKETS": params["ENABLE_RESTRICT_PUBLIC_BUCKETS"], - "ROLE_SESSION_NAME": params["ROLE_SESSION_NAME"], - "ROLE_TO_ASSUME": params["ROLE_TO_ASSUME"], - } + message_batches = [] + for i in range(SNS_PUBLISH_BATCH_MAX, len(sns_messages) + SNS_PUBLISH_BATCH_MAX, SNS_PUBLISH_BATCH_MAX): + message_batches.append(sns_messages[i - SNS_PUBLISH_BATCH_MAX : i]) - put_ssm_parameter(ssm_client, f"{SSM_PARAMETER_PREFIX}", "", json.dumps(ssm_parameter_value)) + for batch in message_batches: + publish_sns_message_batch(batch, sns_topic_arn) -def get_configuration_ssm_parameters() -> dict: - """Get Configuration SSM Parameters. +def is_account_with_exclude_tags(aws_account: AccountTypeDef, params: dict) -> bool: + """Validate if account has tags to be excluded. + + Args: + aws_account: AWS account to update + params: solution parameters Returns: - Parameter dictionary + If account has exclude tags """ - ssm_client: SSMClient = boto3.session.Session().client("ssm") + if params["EXCLUDE_ACCOUNT_TAGS"]: + account_tags = get_organization_resource_tags(aws_account["Id"]) + for tag in params["EXCLUDE_ACCOUNT_TAGS"]: + if tag in account_tags: + LOGGER.info(f"Excluding account: {aws_account['Id']} ({aws_account['Name']}) matching tags: {tag}.") + return True + return False - ssm_parameter = json.loads(get_ssm_parameter_value(ssm_client, f"{SSM_PARAMETER_PREFIX}")) - return { - "ENABLE_BLOCK_PUBLIC_ACLS": ssm_parameter["ENABLE_BLOCK_PUBLIC_ACLS"], - "ENABLE_IGNORE_PUBLIC_ACLS": ssm_parameter["ENABLE_IGNORE_PUBLIC_ACLS"], - "ENABLE_BLOCK_PUBLIC_POLICY": ssm_parameter["ENABLE_BLOCK_PUBLIC_POLICY"], - "ENABLE_RESTRICT_PUBLIC_BUCKETS": ssm_parameter["ENABLE_RESTRICT_PUBLIC_BUCKETS"], - "ROLE_SESSION_NAME": ssm_parameter["ROLE_SESSION_NAME"], - "ROLE_TO_ASSUME": ssm_parameter["ROLE_TO_ASSUME"], - } +def local_testing(aws_account: AccountTypeDef, params: dict) -> None: + """Local Testing. -def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str) -> None: - """Validate CloudFormation Custom Resource Parameters. + Args: + aws_account: AWS account to update + params: solution parameters + """ + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + s3_client: S3ControlClient = account_session.client("s3control") + process_put_account_public_access_block(s3_client, aws_account, params) + + +def process_accounts(event: Union[CloudFormationCustomResourceEvent, dict], params: dict) -> None: + """Process Accounts and Create SNS Messages for each account for solution deployment. Args: - parameter_name: CloudFormation custom resource parameter name - parameter_value: CloudFormation custom resource parameter value - pattern: REGEX pattern to validate against. + event: event data + params: solution parameters + """ + sns_messages = [] + accounts = get_active_organization_accounts() + for account in accounts: - Raises: - ValueError: Parameter is missing - ValueError: Parameter does not follow the allowed pattern + if is_account_with_exclude_tags(account, params): + continue + + if event.get("local_testing") == "true" or event.get("ResourceProperties", {}).get("local_testing") == "true": # type: ignore + local_testing(account, params) + else: + sns_message = {"Action": params["action"], "AccountId": account["Id"]} + sns_messages.append({"Id": account["Id"], "Message": json.dumps(sns_message), "Subject": "S3 Block Account Public Access"}) + + process_sns_message_batches(sns_messages, params["SNS_TOPIC_ARN"]) + + +def process_account(event: dict, aws_account_id: str, params: dict) -> None: + """Process Account and Create SNS Message for solution deployment. + + Args: + event: event data + aws_account_id: AWS Account ID + params: solution parameters """ - if not parameter_value: - raise ValueError(f"'{parameter_name}' parameter is missing.") - elif not re.match(pattern, parameter_value): - raise ValueError(f"'{parameter_name}' parameter with value of '{parameter_value}' does not follow the allowed pattern: {pattern}.") + aws_account = get_account_info(account_id=aws_account_id) + if is_account_with_exclude_tags(aws_account, params): + return + + if event.get("local_testing") == "true": + local_testing(aws_account, params) + else: + sns_message = {"Action": "Add", "AccountId": aws_account["Id"]} + publish_sns_message(sns_message, "S3 Block Account Public Access", params["SNS_TOPIC_ARN"]) -def get_validated_parameters(event: Dict[str, Any]) -> dict: # noqa: CCR001 (cognitive complexity) - """Validate AWS CloudFormation parameters. + +def process_event(event: dict) -> None: + """Process Event. Args: event: event data + """ + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) - Returns: - Validated parameters + process_accounts(event, params) + + +def process_event_sns(event: dict) -> None: + """Process SNS event. + + Args: + event: event data """ - params = event["ResourceProperties"].copy() - actions = {"Create": "Add", "Update": "Add", "Delete": "Remove"} - params["action"] = actions[event["RequestType"]] + params = get_validated_parameters({}) - parameter_pattern_validator("ENABLE_BLOCK_PUBLIC_ACLS", params.get("ENABLE_BLOCK_PUBLIC_ACLS"), pattern=r"(?i)^true|false$") - parameter_pattern_validator("ENABLE_IGNORE_PUBLIC_ACLS", params.get("ENABLE_IGNORE_PUBLIC_ACLS"), pattern=r"(?i)^true|false$") - parameter_pattern_validator("ENABLE_BLOCK_PUBLIC_POLICY", params.get("ENABLE_BLOCK_PUBLIC_POLICY"), pattern=r"(?i)^true|false$") - parameter_pattern_validator("ENABLE_RESTRICT_PUBLIC_BUCKETS", params.get("ENABLE_RESTRICT_PUBLIC_BUCKETS"), pattern=r"(?i)^true|false$") - parameter_pattern_validator("ROLE_SESSION_NAME", params.get("ROLE_SESSION_NAME"), pattern=r"^[\w=,@.-]+$") - parameter_pattern_validator("ROLE_TO_ASSUME", params.get("ROLE_TO_ASSUME"), pattern=r"^[\w+=,.@-]{1,64}$") + for record in event["Records"]: + record["Sns"]["Message"] = json.loads(record["Sns"]["Message"]) + LOGGER.info({"SNS Record": record}) + message = record["Sns"]["Message"] + params["action"] = message["Action"] - return params + aws_account = get_account_info(account_id=message["AccountId"]) + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + s3_client: S3ControlClient = account_session.client("s3control") + process_put_account_public_access_block(s3_client, aws_account, params) -def process_put_account_public_access_block( # noqa: CFQ002 (max arguments) - role_to_assume: str, - role_session_name: str, - account_id: str, - enable_block_public_acls: bool, - enable_ignore_public_acls: bool, - enable_block_public_policy: bool, - enable_restrict_public_buckets: bool, -) -> None: - """Process put account public access block. +def process_event_organizations(event: dict) -> None: + """Process Event from AWS Organizations. Args: - role_to_assume: Role to assume - role_session_name: Role session name - account_id: account to assume role in - enable_block_public_acls: true or false - enable_ignore_public_acls: true or false - enable_block_public_policy: true or false - enable_restrict_public_buckets: true or false + event: event data """ - account_session = common.assume_role(role_to_assume, role_session_name, account_id, MANAGEMENT_ACCOUNT_SESSION) - s3_client: S3ControlClient = account_session.client("s3control") - - if settings_changed( - s3_client, account_id, enable_block_public_acls, enable_ignore_public_acls, enable_block_public_policy, enable_restrict_public_buckets - ): - put_account_public_access_block( - s3_client, - account_id, - enable_block_public_acls, - enable_ignore_public_acls, - enable_block_public_policy, - enable_restrict_public_buckets, - ) - LOGGER.info(f"Enabled account S3 Block Public Access in {account_id}") + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) + + if event["detail"]["eventName"] == "TagResource" and params["EXCLUDE_ACCOUNT_TAGS"]: + aws_account_id = event["detail"]["requestParameters"]["resourceId"] + process_account(event, aws_account_id, params) + elif event["detail"]["eventName"] == "AcceptHandShake" and event["responseElements"]["handshake"]["state"] == "ACCEPTED": + for party in event["responseElements"]["handshake"]["parties"]: + if party["type"] == "ACCOUNT": + aws_account_id = party["id"] + process_account(event, aws_account_id, params) + break + elif event["detail"]["eventName"] == "CreateAccountResult": + aws_account_id = event["detail"]["serviceEventDetails"]["createAccountStatus"]["accountId"] + process_account(event, aws_account_id, params) + else: + LOGGER.info("Organization event does not match expected values.") -def process_add_update( - role_to_assume: str, - role_session_name: str, - enable_block_public_acls: bool, - enable_ignore_public_acls: bool, - enable_block_public_policy: bool, - enable_restrict_public_buckets: bool, -) -> None: - """Process add/update events. +def process_event_lifecycle(event: dict) -> None: + """Process Lifecycle Event from AWS Control Tower. Args: - role_to_assume: Role to assume - role_session_name: Role session name - enable_block_public_acls: Enable block public ACLs - enable_ignore_public_acls: Enable ignore public ACLs - enable_block_public_policy: Enable block public policy - enable_restrict_public_buckets: Enable restrict public buckets + event: event data Raises: - Exception: General exception + ValueError: Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus' """ - account_ids = common.get_account_ids() - - thread_cnt = MAX_THREADS - if MAX_THREADS > len(account_ids): - thread_cnt = max(len(account_ids) - 2, 1) - - processes = [] - with ThreadPoolExecutor(max_workers=thread_cnt) as executor: - for account_id in account_ids: - processes.append( - executor.submit( - process_put_account_public_access_block, - role_to_assume, - role_session_name, - account_id, - enable_block_public_acls, - enable_ignore_public_acls, - enable_block_public_policy, - enable_restrict_public_buckets, - ) - ) - for future in as_completed(processes, timeout=60): - try: - future.result() - except Exception as error: - LOGGER.exception(f"Unexpected Error: {error}") - raise + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) + + aws_account_id = "" + if event["detail"]["serviceEventDetails"].get("createManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + elif event["detail"]["serviceEventDetails"].get("updateManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["updateManagedAccountStatus"]["account"]["accountId"] + else: + raise ValueError("Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus'") + + process_account(event, aws_account_id, params) @helper.create @helper.update @helper.delete -def process_cloudformation_event(event: Dict[str, Any], context: Any) -> str: +def process_event_cloudformation(event: CloudFormationCustomResourceEvent, context: Context) -> str: # noqa: U100 """Process Event from AWS CloudFormation. Args: @@ -335,70 +421,148 @@ def process_cloudformation_event(event: Dict[str, Any], context: Any) -> str: Returns: AWS CloudFormation physical resource id """ - LOGGER.debug(f"{context}") - params = get_validated_parameters(event) - set_configuration_ssm_parameters(MANAGEMENT_ACCOUNT_SESSION, params) - - enable_block_public_acls = (params.get("ENABLE_BLOCK_PUBLIC_ACLS", "true")).lower() in "true" - enable_ignore_public_acls = (params.get("ENABLE_IGNORE_PUBLIC_ACLS", "true")).lower() in "true" - enable_block_public_policy = (params.get("ENABLE_BLOCK_PUBLIC_POLICY", "true")).lower() in "true" - enable_restrict_public_buckets = (params.get("ENABLE_RESTRICT_PUBLIC_BUCKETS", "true")).lower() in "true" - - if params["action"] in ("Add"): - process_add_update( - params["ROLE_TO_ASSUME"], - params["ROLE_SESSION_NAME"], - enable_block_public_acls, - enable_ignore_public_acls, - enable_block_public_policy, - enable_restrict_public_buckets, - ) + event_info = {"Event": event} + LOGGER.info(event_info) + + if event["RequestType"] in ["Create", "Update"]: + params = get_validated_parameters({"RequestType": event["RequestType"]}) + process_accounts(event, params) else: - ssm_client: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm") - delete_ssm_parameter(ssm_client, SSM_PARAMETER_PREFIX) - - return ( - f"S3PublicAccessBlock-{params['ENABLE_BLOCK_PUBLIC_ACLS']}" - + f"-{params['ENABLE_IGNORE_PUBLIC_ACLS']}" - + f"-{params['ENABLE_BLOCK_PUBLIC_POLICY']}" - + f"-{params['ENABLE_RESTRICT_PUBLIC_BUCKETS']}" - ) + LOGGER.info("No changes were made to S3 Block Account Public Access Configuration.") + + return "S3-BLOCK-ACCOUNT-PUBLIC-ACCESS" -def process_lifecycle_event(event: Dict[str, Any]) -> str: - """Process Lifecycle Event. +def parameter_tags_validator(parameter_name: str, parameter_value: Optional[str]) -> dict: # noqa: CCR001 + """Validate Resource Tags in CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables. Args: - event: event data + parameter_name: CloudFormation custom resource parameter name and/or Lambda function environment variable name + parameter_value: CloudFormation custom resource parameter value and/or Lambda function environment variable value + + Raises: + ValueError: Parameter not in JSON format + ValueError: Parameter invalid Tag Keys and/or Tag Values Returns: - string with account ID + Validated Tags Parameter in JSON format """ - params = get_configuration_ssm_parameters() - LOGGER.info(f"Parameters: {params}") + tag_key_pattern = r"^(?![aA][wW][sS]:).{1,128}$" + tag_value_pattern = r"^.{0,256}$" + + invalid_tag_keys = [] + invalid_tag_values = [] + format_message = f'"{parameter_name}" not in JSON format: [{{"Key": "string", "Value": "string"}}]' + try: + tags_json = json.loads(str(parameter_value)) + except Exception: + raise ValueError(format_message) from None - enable_block_public_acls = (params.get("ENABLE_BLOCK_PUBLIC_ACLS", "true")).lower() in "true" - enable_ignore_public_acls = (params.get("ENABLE_IGNORE_PUBLIC_ACLS", "true")).lower() in "true" - enable_block_public_policy = (params.get("ENABLE_BLOCK_PUBLIC_POLICY", "true")).lower() in "true" - enable_restrict_public_buckets = (params.get("ENABLE_RESTRICT_PUBLIC_BUCKETS", "true")).lower() in "true" + for tag in tags_json: + if not tag.get("Key") or "Value" not in tag: + raise ValueError(format_message) + if not re.match(tag_key_pattern, tag["Key"]): + invalid_tag_keys.append(tag["Key"]) + if not re.match(tag_value_pattern, tag["Value"]): + invalid_tag_values.append(tag["Value"]) - account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + if invalid_tag_keys or invalid_tag_values: + message = f"In '{parameter_name}' parameter, Invalid Tag Keys: {invalid_tag_keys}, Invalid Tag Values: {invalid_tag_values} entered." + raise ValueError(message) - account_session = common.assume_role(params["ROLE_TO_ASSUME"], params["ROLE_SESSION_NAME"], account_id) - s3_client: S3ControlClient = account_session.client("s3control") - put_account_public_access_block( - s3_client, - account_id, - enable_block_public_acls, - enable_ignore_public_acls, - enable_block_public_policy, - enable_restrict_public_buckets, + return {parameter_name: tags_json} + + +def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str, is_optional: bool = False) -> dict: + """Validate CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables. + + Args: + parameter_name: CloudFormation custom resource parameter name and/or Lambda function environment variable name + parameter_value: CloudFormation custom resource parameter value and/or Lambda function environment variable value + pattern: REGEX pattern to validate against. + is_optional: Allow empty or missing value when True + + Raises: + ValueError: Parameter has a value of empty string. + ValueError: Parameter is missing + ValueError: Parameter does not follow the allowed pattern + + Returns: + Validated Parameter + """ + if parameter_value == "" and not is_optional: + raise ValueError(f"'{parameter_name}' parameter has a value of empty string.") + elif not parameter_value and not is_optional: + raise ValueError(f"'{parameter_name}' parameter is missing.") + elif pattern == "tags_json" and parameter_value: + return parameter_tags_validator(parameter_name, parameter_value) + elif pattern == "tags_json": + return {parameter_name: parameter_value} + elif not re.match(pattern, str(parameter_value)): + raise ValueError(f"'{parameter_name}' parameter with value of '{parameter_value}'" + f" does not follow the allowed pattern: {pattern}.") + return {parameter_name: parameter_value} + + +def get_validated_parameters(event: dict) -> dict: + """Validate AWS CloudFormation parameters and/or Lambda Function Environment Variables. + + Args: + event: event data + + Returns: + Validated parameters + """ + params: dict = {} + cfn_params = event.get("ResourceProperties", {}).copy() # noqa: F841 # NOSONAR + actions = {"Create": "Add", "Update": "Update", "Delete": "Remove"} + params["action"] = actions[event.get("RequestType", "Create")] + + sns_topic_pattern = r"^arn:(aws[a-zA-Z-]*){1}:sns:[a-z0-9-]+:\d{12}:[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" + true_false_pattern = r"^true|false$" + + # Required Parameters + params.update(parameter_pattern_validator("CONFIGURATION_ROLE_NAME", os.environ.get("CONFIGURATION_ROLE_NAME"), pattern=r"^[\w+=,.@-]{1,64}$")) + params.update(parameter_pattern_validator("ENABLE_BLOCK_PUBLIC_ACLS", os.environ.get("ENABLE_BLOCK_PUBLIC_ACLS"), pattern=true_false_pattern)) + params.update(parameter_pattern_validator("ENABLE_IGNORE_PUBLIC_ACLS", os.environ.get("ENABLE_IGNORE_PUBLIC_ACLS"), pattern=true_false_pattern)) + params.update(parameter_pattern_validator("ENABLE_BLOCK_PUBLIC_POLICY", os.environ.get("ENABLE_BLOCK_PUBLIC_POLICY"), pattern=true_false_pattern)) + params.update( + parameter_pattern_validator("ENABLE_RESTRICT_PUBLIC_BUCKETS", os.environ.get("ENABLE_RESTRICT_PUBLIC_BUCKETS"), pattern=true_false_pattern) ) + params.update(parameter_pattern_validator("ROLE_SESSION_NAME", os.environ.get("ROLE_SESSION_NAME"), pattern=r"^[\w=,@.-]+$")) + params.update(parameter_pattern_validator("SNS_TOPIC_ARN", os.environ.get("SNS_TOPIC_ARN"), pattern=sns_topic_pattern)) + + # Optional Parameters + params.update(parameter_pattern_validator("EXCLUDE_ACCOUNT_TAGS", os.environ.get("EXCLUDE_ACCOUNT_TAGS"), pattern="tags_json", is_optional=True)) + + # Convert true/false string parameters to boolean + params.update({"ENABLE_BLOCK_PUBLIC_ACLS": (params["ENABLE_BLOCK_PUBLIC_ACLS"] == "true")}) + params.update({"ENABLE_IGNORE_PUBLIC_ACLS": (params["ENABLE_IGNORE_PUBLIC_ACLS"] == "true")}) + params.update({"ENABLE_BLOCK_PUBLIC_POLICY": (params["ENABLE_BLOCK_PUBLIC_POLICY"] == "true")}) + params.update({"ENABLE_RESTRICT_PUBLIC_BUCKETS": (params["ENABLE_RESTRICT_PUBLIC_BUCKETS"] == "true")}) + + return params + - return f"lifecycle-event-processed-for-{account_id}" +def orchestrator(event: dict, context: Any) -> None: + """Orchestration of Events. + Args: + event: event data + context: runtime information + """ + if event.get("RequestType"): + helper(event, context) + elif event.get("source") == "aws.controltower": + process_event_lifecycle(event) + elif event.get("source") == "aws.organizations": + process_event_organizations(event) + elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": + process_event_sns(event) + else: + process_event(event) -def lambda_handler(event: Dict[str, Any], context: Any) -> None: + +def lambda_handler(event: dict, context: Any) -> None: """Lambda Handler. Args: @@ -409,17 +573,10 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> None: ValueError: Unexpected error executing Lambda function """ LOGGER.info("....Lambda Handler Started....") - event_info = {"Event": event} - LOGGER.info(event_info) try: - if "RequestType" not in event and ("source" not in event and event["source"] != "aws.controltower"): - raise ValueError( - f"The event did not include source = aws.controltower or RequestType. Review CloudWatch logs '{context.log_group_name}' for details." - ) from None - elif "RequestType" in event: - helper(event, context) - elif "source" in event and event["source"] == "aws.controltower": - process_lifecycle_event(event) - except Exception as error: - LOGGER.exception(f"Unexpected Error: {error}") + event_info = {"Event": event} + LOGGER.info(event_info) + orchestrator(event, context) + except Exception: + LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/common.py b/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/common.py deleted file mode 100644 index 6526ffb6f..000000000 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/lambda/src/common.py +++ /dev/null @@ -1,199 +0,0 @@ -"""This script includes common functions. - -Version: 1.1 - -Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -SPDX-License-Identifier: MIT-0 -""" -from __future__ import annotations - -import logging -import os -from time import sleep -from typing import TYPE_CHECKING - -import boto3 -from botocore.exceptions import ClientError - -if TYPE_CHECKING: - from mypy_boto3_cloudformation import CloudFormationClient - from mypy_boto3_organizations import OrganizationsClient - from mypy_boto3_sts.client import STSClient - -# Setup Default Logger -LOGGER = logging.getLogger("sra") -log_level = os.environ.get("LOG_LEVEL", logging.INFO) -LOGGER.setLevel(log_level) - -# Global variables -CLOUDFORMATION_PAGE_SIZE = 20 -CLOUDFORMATION_THROTTLE_PERIOD = 0.2 -ORG_PAGE_SIZE = 20 # Max page size for list_accounts -ORG_THROTTLE_PERIOD = 0.2 - - -def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: - """Assumes the provided role in the given account and returns a session. - - Args: - role: Role to assume in target account. - role_session_name: Identifier for the assumed role session. - account: AWS account number. Defaults to None. - session: Boto3 session. Defaults to None. - - Returns: - Session object for the specified AWS account - """ - if not session: - session = boto3.Session() - sts_client: STSClient = session.client("sts") - sts_arn = sts_client.get_caller_identity()["Arn"] - LOGGER.info(f"USER: {sts_arn}") - if not account: - account = sts_arn.split(":")[4] - partition = sts_arn.split(":")[1] - role_arn = f"arn:{partition}:iam::{account}:role/{role}" - - response = sts_client.assume_role(RoleArn=role_arn, RoleSessionName=role_session_name) - LOGGER.info(f"ASSUMED ROLE: {response['AssumedRoleUser']['Arn']}") - return boto3.Session( - aws_access_key_id=response["Credentials"]["AccessKeyId"], - aws_secret_access_key=response["Credentials"]["SecretAccessKey"], - aws_session_token=response["Credentials"]["SessionToken"], - ) - - -def get_all_organization_accounts(exclude_accounts: list = None) -> list: - """Get all the active AWS Organization accounts. - - Args: - exclude_accounts: list of account IDs to exclude - - Returns: - List of active account IDs - """ - if exclude_accounts is None: - exclude_accounts = ["00000000000"] - accounts = [] - management_account_session = boto3.Session() - org_client: OrganizationsClient = management_account_session.client("organizations") - paginator = org_client.get_paginator("list_accounts") - - for page in paginator.paginate(PaginationConfig={"PageSize": ORG_PAGE_SIZE}): - for acct in page["Accounts"]: - if acct["Status"] == "ACTIVE" and acct["Id"] not in exclude_accounts: # Store active accounts in a dict - account_record = {"AccountId": acct["Id"], "Email": acct["Email"]} - accounts.append(account_record) - sleep(ORG_THROTTLE_PERIOD) - - return accounts - - -def get_account_ids(accounts: list = None, exclude_accounts: list = None) -> list: - """Get Account IDs from account list dictionary. - - Args: - accounts: List of accounts. {'AccountId': '', 'Email': ''} - exclude_accounts: List of account IDs to exclude. - - Returns: - Account ID list of strings - """ - account_ids: list[str] = [] - if not accounts: - accounts = get_all_organization_accounts(exclude_accounts) - - for account in accounts: - account_ids.append(account["AccountId"]) - return account_ids - - -def get_control_tower_regions() -> list: # noqa: CCR001 - """Query 'AWSControlTowerBP-BASELINE-CLOUDWATCH' CloudFormation stack to identify customer regions. - - Returns: - Customer regions chosen in Control Tower - """ - management_account_session = boto3.Session() - cfn_client: CloudFormationClient = management_account_session.client("cloudformation") - paginator = cfn_client.get_paginator("list_stack_instances") - customer_regions = set() - aws_account = "" - all_regions_identified = False - for page in paginator.paginate(StackSetName="AWSControlTowerBP-BASELINE-CLOUDWATCH", PaginationConfig={"PageSize": CLOUDFORMATION_PAGE_SIZE}): - for instance in page["Summaries"]: - if not aws_account: - aws_account = instance["Account"] - customer_regions.add(instance["Region"]) - continue - if aws_account == instance["Account"]: - customer_regions.add(instance["Region"]) - continue - all_regions_identified = True - break - if all_regions_identified: - break - sleep(CLOUDFORMATION_THROTTLE_PERIOD) - - return list(customer_regions) - - -def get_enabled_regions(customer_regions: str, control_tower_regions_only: bool = False) -> list: # noqa: CCR001 - """Query STS to identify enabled regions. - - Args: - customer_regions: customer provided comma delimited string of regions - control_tower_regions_only: Use the Control Tower governed regions. Defaults to False. - - Returns: - Enabled regions - """ - if customer_regions.strip(): - LOGGER.debug(f"CUSTOMER PROVIDED REGIONS: {str(customer_regions)}") - region_list = [value.strip() for value in customer_regions.split(",") if value != ""] - elif control_tower_regions_only: - region_list = get_control_tower_regions() - else: - default_available_regions = [ - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "eu-central-1", - "eu-north-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - ] - LOGGER.info({"Default_Available_Regions": default_available_regions}) - region_list = default_available_regions - - enabled_regions = [] - disabled_regions = [] - invalid_regions = [] - region_session = boto3.Session() - for region in region_list: - try: - sts_client = region_session.client("sts", endpoint_url=f"https://sts.{region}.amazonaws.com", region_name=region) - sts_client.get_caller_identity() - enabled_regions.append(region) - except ClientError as error: - if error.response["Error"]["Code"] == "InvalidClientTokenId": - disabled_regions.append(region) - LOGGER.error(f"Error {error.response['Error']} occurred testing region {region}") - except Exception as error: - if "Could not connect to the endpoint URL" in str(error): - invalid_regions.append(region) - LOGGER.error(f"Region: '{region}' is not valid") - LOGGER.error(f"{error}") - LOGGER.info({"Disabled_Regions": disabled_regions}) - LOGGER.info({"Invalid_Regions": invalid_regions}) - return enabled_regions diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-global-events.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-global-events.yaml new file mode 100644 index 000000000..ea418426d --- /dev/null +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-global-events.yaml @@ -0,0 +1,68 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: 2010-09-09 +Description: + This template creates an event rule to send organization events to the home region. - 's3_block_account_public_access' solution in the repo, + https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse5t) +Metadata: + SRA: + Version: 1.0 + Order: 4 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pHomeRegion + - Label: + default: Event Rule Properties + Parameters: + - pEventRuleRoleName + ParameterLabels: + pSRASolutionName: + default: SRA Solution Name + +Parameters: + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-s3-block-account-public-access-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String + pHomeRegion: + AllowedPattern: '^[a-z0-9-]{1,64}$' + ConstraintDescription: AWS Region Example - 'us-east-1' + Description: Name of the Control Tower home region + Type: String + pSRASolutionName: + AllowedValues: [s3-block-account-public-access] + Default: s3-block-account-public-access + Description: The SRA solution name. The default value is the folder name of the solution + Type: String + +Resources: + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pSRASolutionName}-forward-org-events + Description: SRA S3 Block Account Public Access Forward Organizations events to home region. + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + - TagResource + State: ENABLED + Targets: + - Arn: !Sub arn:${AWS::Partition}:events:${pHomeRegion}:${AWS::AccountId}:event-bus/default + Id: !Sub ${pSRASolutionName}-org-events-to-home-region + RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pEventRuleRoleName} diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main-ssm.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main-ssm.yaml index 0fad752e5..d480fb690 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main-ssm.yaml +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main-ssm.yaml @@ -20,13 +20,12 @@ Metadata: - pSRASolutionVersion - pSRAStagingS3BucketName - pRootOrganizationalUnitId - - pOrganizationId + - pSRAAlarmEmail - Label: default: Lambda Function Properties Parameters: - - pS3BlockAccountPublicAccessLambdaFunctionName - - pS3BlockAccountPublicAccessLambdaRoleName + - pOrganizationId - Label: default: Custom Resource Properties @@ -35,7 +34,7 @@ Metadata: - pEnableBlockPublicPolicy - pEnableIgnorePublicAcls - pEnableRestrictPublicBuckets - - pS3BlockAccountPublicAccessRoleName + - pExcludeS3BlockAccountPublicAccessTags - Label: default: General Lambda Function Properties @@ -48,11 +47,11 @@ Metadata: - Label: default: EventBridge Rule Properties Parameters: - - pControlTowerLifeCycleRuleName + - pComplianceFrequency ParameterLabels: - pControlTowerLifeCycleRuleName: - default: Control Tower Lifecycle Rule Name + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pCreateLambdaLogGroup: default: Create Lambda Log Group pEnableBlockPublicAcls: @@ -63,6 +62,8 @@ Metadata: default: S3 Enable Ignore Public ACLs pEnableRestrictPublicBuckets: default: S3 Enable Restrict Public Buckets + pExcludeS3BlockAccountPublicAccessTags: + default: (Optional) Exclude S3 Block Account Public Access Tags pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: @@ -71,24 +72,25 @@ Metadata: default: Lambda Log Level pOrganizationId: default: Organization ID - pS3BlockAccountPublicAccessLambdaFunctionName: - default: Lambda Function Name - pS3BlockAccountPublicAccessLambdaRoleName: - default: Lambda Role Name - pS3BlockAccountPublicAccessRoleName: - default: S3 Enable Block Public Access Role Name + pRootOrganizationalUnitId: + default: Root Organizational Unit ID + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name + pSRASolutionVersion: + default: SRA Solution Version pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: - pControlTowerLifeCycleRuleName: - AllowedPattern: '^[\w.-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] - Default: sra-s3-block-account-public-access-trigger - Description: The name of the AWS Control Tower Life Cycle Rule. - Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pCreateLambdaLogGroup: AllowedValues: ['true', 'false'] Default: 'false' @@ -116,6 +118,12 @@ Parameters: Default: 'true' Description: S3 Enable Restrict Public Buckets Type: String + pExcludeS3BlockAccountPublicAccessTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-s3-block-account-public-access", "Value": "true"}].' + Type: String pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' @@ -148,23 +156,12 @@ Parameters: Default: /sra/control-tower/root-organizational-unit-id Description: SSM Parameter for Root Organizational Unit ID Type: AWS::SSM::Parameter::Value - pS3BlockAccountPublicAccessLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-s3-block-account-public-access - Description: Lambda function name - Type: String - pS3BlockAccountPublicAccessLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-s3-block-account-public-access-lambda - Description: Lambda execution role - Type: String - pS3BlockAccountPublicAccessRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-s3-block-account-public-access - Description: S3 Enable Block Public Access Role Name + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. Type: String pSRASolutionName: AllowedValues: [sra-s3-block-account-public-access] @@ -181,11 +178,14 @@ Parameters: name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: AWS::SSM::Parameter::Value pSRASolutionVersion: - AllowedValues: [v1.1] - Default: v1.1 + AllowedValues: [v1.2] + Default: v1.2 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rS3BlockAccountPublicAccessRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -213,10 +213,6 @@ Resources: Parameters: - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId - - ParameterKey: pS3BlockAccountPublicAccessRoleName - ParameterValue: !Ref pS3BlockAccountPublicAccessRoleName - - ParameterKey: pS3BlockAccountPublicAccessLambdaRoleName - ParameterValue: !Ref pS3BlockAccountPublicAccessLambdaRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -227,8 +223,6 @@ Resources: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access-role.yaml Parameters: pManagementAccountId: !Ref AWS::AccountId - pS3BlockAccountPublicAccessRoleName: !Ref pS3BlockAccountPublicAccessRoleName - pS3BlockAccountPublicAccessLambdaRoleName: !Ref pS3BlockAccountPublicAccessLambdaRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -241,20 +235,52 @@ Resources: Properties: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access.yaml Parameters: - pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName + pComplianceFrequency: !Ref pComplianceFrequency pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup pEnableBlockPublicAcls: !Ref pEnableBlockPublicAcls pEnableBlockPublicPolicy: !Ref pEnableBlockPublicPolicy pEnableIgnorePublicAcls: !Ref pEnableIgnorePublicAcls pEnableRestrictPublicBuckets: !Ref pEnableRestrictPublicBuckets + pExcludeS3BlockAccountPublicAccessTags: !Ref pExcludeS3BlockAccountPublicAccessTags pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention pLambdaLogLevel: !Ref pLambdaLogLevel + pManagementAccountId: !Ref AWS::AccountId pOrganizationId: !Ref pOrganizationId pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName - pS3BlockAccountPublicAccessLambdaFunctionName: !Ref pS3BlockAccountPublicAccessLambdaFunctionName - pS3BlockAccountPublicAccessLambdaRoleName: !Ref pS3BlockAccountPublicAccessLambdaRoleName - pS3BlockAccountPublicAccessRoleName: !Ref pS3BlockAccountPublicAccessRoleName + pSRAAlarmEmail: !Ref pSRAAlarmEmail + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rS3BlockAccountPublicAccessGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rS3BlockAccountPublicAccessStack + Properties: + StackSetName: sra-s3-block-account-public-access-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main.yaml index d4142044a..1ee08ae70 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main.yaml +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-main.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 1 AWS::CloudFormation::Interface: ParameterGroups: @@ -20,13 +20,12 @@ Metadata: - pSRASolutionVersion - pSRAStagingS3BucketName - pRootOrganizationalUnitId - - pOrganizationId + - pSRAAlarmEmail - Label: default: Lambda Function Properties Parameters: - - pS3BlockAccountPublicAccessLambdaFunctionName - - pS3BlockAccountPublicAccessLambdaRoleName + - pOrganizationId - Label: default: Custom Resource Properties @@ -35,7 +34,7 @@ Metadata: - pEnableBlockPublicPolicy - pEnableIgnorePublicAcls - pEnableRestrictPublicBuckets - - pS3BlockAccountPublicAccessRoleName + - pExcludeS3BlockAccountPublicAccessTags - Label: default: General Lambda Function Properties @@ -48,11 +47,11 @@ Metadata: - Label: default: EventBridge Rule Properties Parameters: - - pControlTowerLifeCycleRuleName + - pComplianceFrequency ParameterLabels: - pControlTowerLifeCycleRuleName: - default: Control Tower Lifecycle Rule Name + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pCreateLambdaLogGroup: default: Create Lambda Log Group pEnableBlockPublicAcls: @@ -63,6 +62,8 @@ Metadata: default: S3 Enable Ignore Public ACLs pEnableRestrictPublicBuckets: default: S3 Enable Restrict Public Buckets + pExcludeS3BlockAccountPublicAccessTags: + default: (Optional) Exclude S3 Block Account Public Access Tags pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: @@ -71,24 +72,25 @@ Metadata: default: Lambda Log Level pOrganizationId: default: Organization ID - pS3BlockAccountPublicAccessLambdaFunctionName: - default: Lambda Function Name - pS3BlockAccountPublicAccessLambdaRoleName: - default: Lambda Role Name - pS3BlockAccountPublicAccessRoleName: - default: S3 Enable Block Public Access Role Name + pRootOrganizationalUnitId: + default: Root Organizational Unit ID + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name + pSRASolutionVersion: + default: SRA Solution Version pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: - pControlTowerLifeCycleRuleName: - AllowedPattern: '^[\w.-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] - Default: sra-s3-block-account-public-access-trigger - Description: The name of the AWS Control Tower Life Cycle Rule. - Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pCreateLambdaLogGroup: AllowedValues: ['true', 'false'] Default: 'false' @@ -116,6 +118,12 @@ Parameters: Default: 'true' Description: S3 Enable Restrict Public Buckets Type: String + pExcludeS3BlockAccountPublicAccessTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-s3-block-account-public-access", "Value": "true"}].' + Type: String pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' @@ -145,23 +153,12 @@ Parameters: ConstraintDescription: Must start with 'r-' followed by from 4 to 32 lowercase letters or digits. (e.g. r-abc123) Description: Root Organizational Unit ID Type: String - pS3BlockAccountPublicAccessLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-s3-block-account-public-access - Description: Lambda function name - Type: String - pS3BlockAccountPublicAccessLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-s3-block-account-public-access-lambda - Description: Lambda execution role - Type: String - pS3BlockAccountPublicAccessRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-s3-block-account-public-access - Description: S3 Enable Block Public Access Role Name + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. Type: String pSRASolutionName: AllowedValues: [sra-s3-block-account-public-access] @@ -177,11 +174,14 @@ Parameters: numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String pSRASolutionVersion: - AllowedValues: [v1.1] - Default: v1.1 + AllowedValues: [v1.2] + Default: v1.2 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rS3BlockAccountPublicAccessRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -209,10 +209,6 @@ Resources: Parameters: - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId - - ParameterKey: pS3BlockAccountPublicAccessRoleName - ParameterValue: !Ref pS3BlockAccountPublicAccessRoleName - - ParameterKey: pS3BlockAccountPublicAccessLambdaRoleName - ParameterValue: !Ref pS3BlockAccountPublicAccessLambdaRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -223,8 +219,6 @@ Resources: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access-role.yaml Parameters: pManagementAccountId: !Ref AWS::AccountId - pS3BlockAccountPublicAccessRoleName: !Ref pS3BlockAccountPublicAccessRoleName - pS3BlockAccountPublicAccessLambdaRoleName: !Ref pS3BlockAccountPublicAccessLambdaRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -237,20 +231,52 @@ Resources: Properties: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access.yaml Parameters: - pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName + pComplianceFrequency: !Ref pComplianceFrequency pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup pEnableBlockPublicAcls: !Ref pEnableBlockPublicAcls pEnableBlockPublicPolicy: !Ref pEnableBlockPublicPolicy pEnableIgnorePublicAcls: !Ref pEnableIgnorePublicAcls pEnableRestrictPublicBuckets: !Ref pEnableRestrictPublicBuckets + pExcludeS3BlockAccountPublicAccessTags: !Ref pExcludeS3BlockAccountPublicAccessTags pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention pLambdaLogLevel: !Ref pLambdaLogLevel + pManagementAccountId: !Ref AWS::AccountId pOrganizationId: !Ref pOrganizationId pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName - pS3BlockAccountPublicAccessLambdaFunctionName: !Ref pS3BlockAccountPublicAccessLambdaFunctionName - pS3BlockAccountPublicAccessLambdaRoleName: !Ref pS3BlockAccountPublicAccessLambdaRoleName - pS3BlockAccountPublicAccessRoleName: !Ref pS3BlockAccountPublicAccessRoleName + pSRAAlarmEmail: !Ref pSRAAlarmEmail + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rS3BlockAccountPublicAccessGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rS3BlockAccountPublicAccessStack + Properties: + StackSetName: sra-s3-block-account-public-access-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-s3-block-account-public-access-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-role.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-role.yaml index 7987cfdf5..a7f440493 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-role.yaml +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access-role.yaml @@ -9,15 +9,14 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 2 AWS::CloudFormation::Interface: ParameterGroups: - Label: - default: General + default: General Properties Parameters: - pSRASolutionName - - Label: default: Role Properties Parameters: @@ -89,7 +88,7 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Policies: - - PolicyName: s3_block_account_public_access_acct + - PolicyName: sra-s3-block-account-public-access-policy PolicyDocument: Version: 2012-10-17 Statement: diff --git a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access.yaml b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access.yaml index 90b42249b..d576d383b 100644 --- a/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access.yaml +++ b/aws_sra_examples/solutions/s3/s3_block_account_public_access/templates/sra-s3-block-account-public-access.yaml @@ -9,23 +9,24 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 3 AWS::CloudFormation::Interface: ParameterGroups: - Label: default: General Properties Parameters: - - pOrganizationId - pSRASolutionName - - pSRASSMParameterPrefix - pSRAStagingS3BucketName + - pSRAAlarmEmail - Label: - default: S3 Block Account Public Access - Lambda Function Properties + default: Lambda Function Properties Parameters: - pS3BlockAccountPublicAccessLambdaFunctionName - pS3BlockAccountPublicAccessLambdaRoleName + - pManagementAccountId + - pOrganizationId - Label: default: Custom Resource Properties @@ -35,6 +36,7 @@ Metadata: - pEnableIgnorePublicAcls - pEnableRestrictPublicBuckets - pS3BlockAccountPublicAccessRoleName + - pExcludeS3BlockAccountPublicAccessTags - Label: default: General Lambda Function Properties @@ -45,11 +47,15 @@ Metadata: - pLambdaLogLevel - Label: - default: S3 Block Account Public Access - EventBridge Rule Properties + default: EventBridge Rule Properties Parameters: + - pComplianceFrequency - pControlTowerLifeCycleRuleName + - pEventRuleRoleName ParameterLabels: + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name pCreateLambdaLogGroup: @@ -62,12 +68,18 @@ Metadata: default: S3 Enable Ignore Public ACLs pEnableRestrictPublicBuckets: default: S3 Enable Restrict Public Buckets + pEventRuleRoleName: + default: Event Rule Role Name + pExcludeS3BlockAccountPublicAccessTags: + default: (Optional) Exclude S3 Block Account Public Access Tags pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: default: Lambda Log Group Retention pLambdaLogLevel: default: Lambda Log Level + pManagementAccountId: + default: Management Account ID pOrganizationId: default: Organization ID pS3BlockAccountPublicAccessLambdaFunctionName: @@ -76,14 +88,21 @@ Metadata: default: Lambda Role Name pS3BlockAccountPublicAccessRoleName: default: S3 Enable Block Public Access Role Name + pSRAAlarmEmail: + default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name - pSRASSMParameterPrefix: - default: SRA SSM Parameter Prefix pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] @@ -117,6 +136,18 @@ Parameters: Default: 'true' Description: S3 Enable Restrict Public Buckets Type: String + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-s3-block-account-public-access-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String + pExcludeS3BlockAccountPublicAccessTags: + AllowedPattern: '^$|.*' + Description: + '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, + ... ]. For example, [{"Key": "exclude-s3-block-account-public-access", "Value": "true"}].' + Type: String pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' @@ -135,6 +166,12 @@ Parameters: Default: 14 Description: Specifies the number of days you want to retain log events Type: String + pManagementAccountId: + AllowedPattern: '^\d{12}$' + ConstraintDescription: + Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Description: AWS Account ID of the Control Tower Management account. + Type: String pOrganizationId: AllowedPattern: '^o-[a-z0-9]{10,32}$' ConstraintDescription: The Org Id must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters @@ -158,16 +195,18 @@ Parameters: Default: sra-s3-block-account-public-access Description: S3 Enable Block Public Access Role Name Type: String + pSRAAlarmEmail: + AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' + ConstraintDescription: Email Validation as per RFC2822 standards. + Default: '' + Description: + (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. + Type: String pSRASolutionName: AllowedValues: [sra-s3-block-account-public-access] Default: sra-s3-block-account-public-access Description: The SRA solution name. The default value is the folder name of the solution Type: String - pSRASSMParameterPrefix: - AllowedValues: ['/sra/s3-block-account-public-access'] - Default: '/sra/s3-block-account-public-access' - Description: SRA SSM parameter prefix to use for storing the configuration properties needed when a new account is created. - Type: String pSRAStagingS3BucketName: AllowedPattern: '^(?=^.{3,63}$)(?!.*[.-]{2})(?!.*[--]{2})(?!^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$)(^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$)' ConstraintDescription: @@ -178,8 +217,10 @@ Parameters: Type: String Conditions: - cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] + cComplianceFrequencySingleDay: !Equals [!Ref pComplianceFrequency, 1] + cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']] cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] cUseGraviton: !Or - !Equals [!Ref 'AWS::Region', ap-northeast-1] - !Equals [!Ref 'AWS::Region', ap-south-1] @@ -191,45 +232,83 @@ Conditions: - !Equals [!Ref 'AWS::Region', us-east-1] - !Equals [!Ref 'AWS::Region', us-east-2] - !Equals [!Ref 'AWS::Region', us-west-2] + cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] Resources: - rControlTowerLifeCycleRule: - Type: AWS::Events::Rule + rS3BlockAccountPublicAccessDLQ: + Type: AWS::SQS::Queue Properties: - Name: !Ref pControlTowerLifeCycleRuleName - Description: SRA S3 Block Account Public Access Life Cycle Trigger - EventPattern: - source: - - aws.controltower - detail-type: - - AWS Service Event via CloudTrail - detail: - eventName: - - CreateManagedAccount - State: ENABLED - Targets: - - Arn: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn - Id: !Ref pS3BlockAccountPublicAccessLambdaFunctionName + KmsMasterKeyId: alias/aws/sqs + QueueName: !Sub ${pSRASolutionName}-dlq + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName - rPermissionForControlTowerRuleToInvokeLambda: - Type: AWS::Lambda::Permission + rS3BlockAccountPublicAccessDLQAlarm: + Type: AWS::CloudWatch::Alarm + Condition: cCreateDLQAlarm Properties: - FunctionName: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn - Action: lambda:InvokeFunction - Principal: events.amazonaws.com - SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn + AlarmDescription: SRA DLQ alarm if the queue depth is 1 + Namespace: AWS/SQS + MetricName: ApproximateNumberOfMessagesVisible + Dimensions: + - Name: QueueName + Value: !GetAtt rS3BlockAccountPublicAccessDLQ.QueueName + Statistic: Sum + Period: 300 + EvaluationPeriods: 1 + Threshold: 1 + ComparisonOperator: GreaterThanThreshold + AlarmActions: + - !Ref rS3BlockAccountPublicAccessDLQAlarmTopic + InsufficientDataActions: + - !Ref rS3BlockAccountPublicAccessDLQAlarmTopic + + rS3BlockAccountPublicAccessDLQAlarmTopic: + Type: AWS::SNS::Topic + Condition: cCreateDLQAlarm + Properties: + DisplayName: !Sub ${pSRASolutionName}-dlq-alarm + KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns + TopicName: !Sub ${pSRASolutionName}-dlq-alarm + Subscription: + - Endpoint: !Ref pSRAAlarmEmail + Protocol: email + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rS3BlockAccountPublicAccessDLQPolicy: + Type: AWS::SQS::QueuePolicy + Properties: + Queues: + - !Ref rS3BlockAccountPublicAccessDLQ + PolicyDocument: + Statement: + - Effect: Allow + Action: SQS:SendMessage + Condition: + ArnEquals: + aws:SourceArn: + - !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Resource: + - !GetAtt rS3BlockAccountPublicAccessDLQ.Arn + Principal: + Service: events.amazonaws.com rS3BlockAccountPublicAccessLambdaCustomResource: Type: Custom::LambdaCustomResource Version: '1.0' Properties: ServiceToken: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + CONFIGURATION_ROLE_NAME: !Ref pS3BlockAccountPublicAccessRoleName ENABLE_BLOCK_PUBLIC_ACLS: !Ref pEnableBlockPublicAcls - ENABLE_IGNORE_PUBLIC_ACLS: !Ref pEnableIgnorePublicAcls ENABLE_BLOCK_PUBLIC_POLICY: !Ref pEnableBlockPublicPolicy + ENABLE_IGNORE_PUBLIC_ACLS: !Ref pEnableIgnorePublicAcls ENABLE_RESTRICT_PUBLIC_BUCKETS: !Ref pEnableRestrictPublicBuckets + EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeS3BlockAccountPublicAccessTags ROLE_SESSION_NAME: sra-s3-block-account-public-access - ROLE_TO_ASSUME: !Ref pS3BlockAccountPublicAccessRoleName + SNS_TOPIC_ARN: !Ref rS3BlockAccountPublicAccessTopic rS3BlockAccountPublicAccessLambdaFunction: Type: AWS::Lambda::Function @@ -258,20 +337,28 @@ Resources: Handler: app.lambda_handler Role: !GetAtt rS3BlockAccountPublicAccessLambdaRole.Arn Runtime: python3.9 - MemorySize: 1024 Timeout: 900 Code: S3Bucket: !Ref pSRAStagingS3BucketName S3Key: !Sub ${pSRASolutionName}/lambda_code/${pSRASolutionName}.zip + DeadLetterConfig: + TargetArn: !GetAtt rS3BlockAccountPublicAccessDLQ.Arn Environment: Variables: LOG_LEVEL: !Ref pLambdaLogLevel - SSM_PARAMETER_PREFIX: !Ref pSRASSMParameterPrefix + CONFIGURATION_ROLE_NAME: !Ref pS3BlockAccountPublicAccessRoleName + ENABLE_BLOCK_PUBLIC_ACLS: !Ref pEnableBlockPublicAcls + ENABLE_BLOCK_PUBLIC_POLICY: !Ref pEnableBlockPublicPolicy + ENABLE_IGNORE_PUBLIC_ACLS: !Ref pEnableIgnorePublicAcls + ENABLE_RESTRICT_PUBLIC_BUCKETS: !Ref pEnableRestrictPublicBuckets + EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeS3BlockAccountPublicAccessTags + ROLE_SESSION_NAME: sra-s3-block-account-public-access + SNS_TOPIC_ARN: !Ref rS3BlockAccountPublicAccessTopic Tags: - Key: sra-solution Value: !Ref pSRASolutionName - rLambdaLogGroup: + rS3BlockAccountPublicAccessLambdaLogGroup: Condition: cCreateLambdaLogGroup Type: AWS::Logs::LogGroup DeletionPolicy: Retain @@ -292,7 +379,7 @@ Resources: - id: W11 reason: The Organizations actions require wildcard in the resource. - id: W28 - reason: Explicit name provided + reason: The role name is defined Properties: RoleName: !Ref pS3BlockAccountPublicAccessLambdaRoleName Description: !Sub SRA IAM role for '${pS3BlockAccountPublicAccessLambdaFunctionName}' Lambda function @@ -307,7 +394,19 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName Policies: - - PolicyName: s3-block-account-public-access-policy + - PolicyName: sra-s3-block-account-public-access-policy-iam + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: AssumeRole + Effect: Allow + Action: sts:AssumeRole + Resource: !Sub arn:${AWS::Partition}:iam::*:role/${pS3BlockAccountPublicAccessRoleName} + Condition: + StringEquals: + aws:PrincipalOrgId: !Ref pOrganizationId + + - PolicyName: sra-s3-block-account-public-access-policy-logs PolicyDocument: Version: 2012-10-17 Statement: @@ -319,41 +418,187 @@ Resources: - logs:PutLogEvents Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pS3BlockAccountPublicAccessLambdaFunctionName}:log-stream:* - - Sid: AssumeRole + - PolicyName: sra-s3-block-account-public-access-policy-organizations + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: OrganizationsReadAccess Effect: Allow - Action: sts:AssumeRole - Resource: !Sub arn:${AWS::Partition}:iam::*:role/${pS3BlockAccountPublicAccessRoleName} - Condition: - StringEquals: - aws:PrincipalOrgId: !Ref pOrganizationId + Action: + - organizations:DescribeAccount + - organizations:ListAccounts + Resource: '*' - - Sid: Organizations + - Sid: ListTagsForAccounts Effect: Allow - Action: organizations:ListAccounts - Resource: '*' + Action: organizations:ListTagsForResource + Resource: !Sub arn:${AWS::Partition}:organizations::${pManagementAccountId}:account/${pOrganizationId}/* - - Sid: SSM + - PolicyName: sra-s3-block-account-public-access-policy-sns + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: SNSPublish Effect: Allow Action: - - ssm:DeleteParameter - - ssm:GetParameter - - ssm:PutParameter - Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter${pSRASSMParameterPrefix}* + - sns:Publish + - sns:PublishBatch + Resource: !Ref rS3BlockAccountPublicAccessTopic + + - PolicyName: sra-s3-block-account-public-access-policy-sqs + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: SQSSendMessage + Effect: Allow + Action: sqs:SendMessage + Resource: !GetAtt rS3BlockAccountPublicAccessDLQ.Arn + + rS3BlockAccountPublicAccessTopic: + Type: AWS::SNS::Topic + Properties: + DisplayName: !Sub ${pSRASolutionName}-configuration + KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rS3BlockAccountPublicAccessTopicLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + Action: lambda:InvokeFunction + FunctionName: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Principal: sns.amazonaws.com + SourceArn: !Ref rS3BlockAccountPublicAccessTopic + + rS3BlockAccountPublicAccessTopicSubscription: + Type: AWS::SNS::Subscription + Properties: + Endpoint: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Protocol: lambda + TopicArn: !Ref rS3BlockAccountPublicAccessTopic + + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-org-update + Description: SRA S3 Block Account Public Access Trigger on Organizations update + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + - TagResource + State: ENABLED + Targets: + - Arn: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Id: !Ref pS3BlockAccountPublicAccessLambdaFunctionName + + rControlTowerLifeCycleRule: + Type: AWS::Events::Rule + Properties: + Name: !Ref pControlTowerLifeCycleRuleName + Description: SRA S3 Block Account Public Access Control Tower Life Cycle Trigger (triggers on new Control Tower vended accounts) + EventPattern: + source: + - aws.controltower + detail-type: + - AWS Service Event via CloudTrail + detail: + eventName: + - CreateManagedAccount + - UpdateManagedAccount + State: ENABLED + Targets: + - Arn: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Id: !Ref pS3BlockAccountPublicAccessLambdaFunctionName + + rPermissionForControlTowerRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn + + rPermissionForOrganizationsRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rOrganizationsRule.Arn + + rPermissionForScheduledComplianceRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rScheduledComplianceRule.Arn + + rScheduledComplianceRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-org-compliance + Description: SRA S3 Block Account Public Access Trigger for scheduled organization compliance + ScheduleExpression: !If + - cComplianceFrequencySingleDay + - !Sub rate(${pComplianceFrequency} day) + - !Sub rate(${pComplianceFrequency} days) + State: ENABLED + Targets: + - Arn: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn + Id: !Ref pS3BlockAccountPublicAccessLambdaFunctionName + + rCrossRegionEventRuleRole: + Type: AWS::IAM::Role + Condition: cNotGlobalRegionUsEast1 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: Specific role name provided + Properties: + RoleName: !Ref pEventRuleRoleName + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - events.amazonaws.com + Policies: + - PolicyName: sra-s3-block-account-public-access-policy-events + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: events:PutEvents + Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default Outputs: oControlTowerLifeCycleRule: Description: SRA Control Tower Life Cycle Rule ARN Value: !GetAtt rControlTowerLifeCycleRule.Arn - + oCrossRegionEventRuleRoleArn: + Condition: cNotGlobalRegionUsEast1 + Description: Cross Region Event Rule Role ARN + Value: !GetAtt rCrossRegionEventRuleRole.Arn oS3BlockAccountPublicAccessLambdaFunctionArn: Description: SRA S3 Block Account Public Access Lambda Function ARN Value: !GetAtt rS3BlockAccountPublicAccessLambdaFunction.Arn - oS3BlockAccountPublicAccessLambdaLogGroupArn: Condition: cCreateLambdaLogGroup Description: SRA S3 Block Account Public Access Lambda Log Group ARN - Value: !GetAtt rLambdaLogGroup.Arn - + Value: !GetAtt rS3BlockAccountPublicAccessLambdaLogGroup.Arn oS3BlockAccountPublicAccessLambdaRoleArn: Description: SRA S3 Block Account Public Access Lambda Role ARN Value: !GetAtt rS3BlockAccountPublicAccessLambdaRole.Arn diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/README.md b/aws_sra_examples/solutions/securityhub/securityhub_org/README.md index 31145731a..8348db6ba 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/README.md +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/README.md @@ -39,45 +39,50 @@ The Security Hub Organization solution will automate enabling AWS Security Hub b - The [Customizations for AWS Control Tower](https://aws.amazon.com/solutions/implementations/customizations-for-aws-control-tower/) solution deploys all templates as a CloudFormation `StackSet`. - For parameter details, review the [AWS CloudFormation templates](templates/). -#### 1.2 Lambda IAM Role +#### 1.2 IAM Roles -- IAM role used by the Lambda function to enable the Security Hub Delegated Administrator Account within each region provided. +- The `Lambda IAM Role` is used by the Lambda function to enable the Security Hub Delegated Administrator Account within each region provided. +- The `Configuration IAM Role` is assumed by the Lambda function to configure Security Hub within the delegated administrator account and all member accounts. +- The `Event Rule IAM Role` is assumed by EventBridge to forward Global events to the `Home Region` default Event Bus. -#### 1.3 Configuration IAM Role +#### 1.3 Regional Event Rules -- IAM role is assumed by the Lambda function to configure Security Hub within the delegated administrator account and all member accounts. +- The `AWS Control Tower Lifecycle Event Rule` triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +- The `Organization Compliance Scheduled Event Rule` triggers the `AWS Lambda Function` to capture AWS Account status updates (e.g. suspended to active). + - A parameter is provided to set the schedule frequency. + - See the [Instructions to Manually Run the Lambda Function](#instructions-to-manually-run-the-lambda-function) for triggering the `AWS Lambda Function` before the next scheduled run time. +- The `AWS Organizations Event Rule` triggers the `AWS Lambda Function` when updates are made to accounts within the organization. + - When AWS Accounts are added to the AWS Organization outside of the AWS Control Tower Account Factory. (e.g. account created via AWS Organizations console, account invited from another AWS Organization). + - When tags are added or updated on AWS Accounts. -#### 1.4 AWS Lambda Function +#### 1.4 Global Event Rules -- The Lambda function includes logic to enable and configure Security Hub. - -#### 1.5 Lambda CloudWatch Log Group - -- All the `AWS Lambda Function` logs are sent to a CloudWatch Log Group `` to help with debugging and traceability of the actions performed. -- By default the `AWS Lambda Function` will create the CloudWatch Log Group and logs are encrypted with a CloudWatch Logs service managed encryption key. -- Parameters are provided for changing the default log group retention and encryption KMS key. +- If the `Home Region` is different from the `Global Region (e.g. us-east-1)`, then global event rules are created within the `Global Region` to forward events to the `Home Region` default Event Bus. +- The `AWS Organizations Event Rule` forwards AWS Organization account update events. -#### 1.6 AWS SSM Parameter Store +#### 1.5 SNS Topic -- The Lambda Function creates/updates configuration parameters within the `SSM Parameter Store` on CloudFormation events and the parameters are used when triggered by the `Control Tower Lifecycle Event Rule` or `SNS Topic`. +- SNS Topic used to fanout the Lambda function for configuring and disabling the service within each account and region. -#### 1.7 Dead Letter Queue (DLQ) +#### 1.6 Dead Letter Queue (DLQ) - SQS dead letter queue used for retaining any failed Lambda events. -#### 1.8 Alarm SNS Topic +#### 1.7 AWS Lambda Function -- SNS Topic used to notify subscribers when messages hit the DLQ. +- The Lambda function includes logic to enable and configure Security Hub. -#### 1.9 SNS Topic +#### 1.8 Lambda CloudWatch Log Group -- SNS Topic used to fanout the Lambda function for deleting the service within each account and region. +- All the `AWS Lambda Function` logs are sent to a CloudWatch Log Group `` to help with debugging and traceability of the actions performed. +- By default the `AWS Lambda Function` will create the CloudWatch Log Group and logs are encrypted with a CloudWatch Logs service managed encryption key. +- Parameters are provided for changing the default log group retention and encryption KMS key. -#### 1.10 AWS Control Tower Lifecycle Event Rule +#### 1.9 Alarm SNS Topic -- The AWS Control Tower Lifecycle Event Rule triggers the `AWS Lambda Function` when a new AWS Account is provisioned through AWS Control Tower. +- SNS Topic used to notify subscribers when messages hit the DLQ. -#### 1.11 Security Hub +#### 1.10 Security Hub - The Security Hub delegated administrator is registered within the `management account` using the Security Hub APIs within each provided region. @@ -170,6 +175,11 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* 4. Verify the Auto-enable new controls is ON 3. Log into a member account and verify the standards are configured correctly +#### Solution Update Instructions + +1. [Download and Stage the SRA Solutions](../../../docs/DOWNLOAD-AND-STAGE-SOLUTIONS.md). **Note:** Get the latest code and run the staging script. +2. Update the existing CloudFormation Stack or CFCT configuration. **Note:** Make sure to update the `SRA Solution Version` parameter and any new added parameters. + #### Solution Delete Instructions 1. In the `management account (home region)`, change the `Disable Security Hub` parameter to `true` and update the AWS CloudFormation **Stack** (`sra-securityhub-org-main-ssm` or `sra-securityhub-org-main`). @@ -177,6 +187,15 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack* 3. In the `management account (home region)`, delete the AWS CloudFormation **Stack** (`sra-securityhub-org-main-ssm` or `sra-securityhub-org-main`). 4. In the `management account (home region)`, delete the AWS CloudWatch **Log Group** (e.g. /aws/lambda/) for the Lambda function deployed. +#### Instructions to Manually Run the Lambda Function + +1. In the `management account (home region)`. +2. Navigate to the AWS Lambda Functions page. +3. Select the `checkbox` next to the Lambda Function and select `Test` from the `Actions` menu. +4. Scroll down to view the `Test event`. +5. Click the `Test` button to trigger the Lambda Function with the default values. +6. Verify that the updates were successful within the expected account(s). + --- ## References diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/manifest-v2.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/manifest-v2.yaml index 66054f6fa..33e93306f 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/manifest-v2.yaml +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/manifest-v2.yaml @@ -11,8 +11,8 @@ resources: - name: sra-securityhub-org-main-ssm resource_file: templates/sra-securityhub-org-main-ssm.yaml parameters: - - parameter_key: pControlTowerLifeCycleRuleName - parameter_value: sra-securityhub-org-trigger + - parameter_key: pComplianceFrequency + parameter_value: 7 - parameter_key: pControlTowerRegionsOnly parameter_value: 'true' - parameter_key: pCreateLambdaLogGroup @@ -35,14 +35,10 @@ resources: parameter_value: INFO - parameter_key: pRegionLinkingMode parameter_value: SPECIFIED_REGIONS - - parameter_key: pSecurityHubConfigurationRoleName - parameter_value: sra-securityhub-configuration - - parameter_key: pSecurityHubOrgLambdaFunctionName - parameter_value: sra-securityhub-org - - parameter_key: pSecurityHubOrgLambdaRoleName - parameter_value: sra-securityhub-org-lambda - parameter_key: pSRAAlarmEmail parameter_value: '' + - parameter_key: pSRASolutionVersion + parameter_value: 'v1.3' deploy_method: stack_set deployment_targets: accounts: @@ -53,8 +49,8 @@ resources: # parameters: # - parameter_key: pAuditAccountId # parameter_value: '' - # - parameter_key: pControlTowerLifeCycleRuleName - # parameter_value: sra-securityhub-org-trigger + # - parameter_key: pComplianceFrequency + # parameter_value: 7 # - parameter_key: pControlTowerRegionsOnly # parameter_value: 'true' # - parameter_key: pCreateLambdaLogGroup @@ -81,14 +77,10 @@ resources: # parameter_value: SPECIFIED_REGIONS # - parameter_key: pRootOrganizationalUnitId # parameter_value: '' - # - parameter_key: pSecurityHubConfigurationRoleName - # parameter_value: sra-securityhub-configuration - # - parameter_key: pSecurityHubOrgLambdaFunctionName - # parameter_value: sra-securityhub-org - # - parameter_key: pSecurityHubOrgLambdaRoleName - # parameter_value: sra-securityhub-org-lambda # - parameter_key: pSRAAlarmEmail # parameter_value: '' + # - parameter_key: pSRASolutionVersion + # parameter_value: 'v1.3' # - parameter_key: pSRAStagingS3BucketName # parameter_value: '' # deploy_method: stack_set diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main-ssm.json b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main-ssm.json index de230130d..01d0d583c 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main-ssm.json +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main-ssm.json @@ -1,7 +1,7 @@ [ { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-securityhub-org-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pControlTowerRegionsOnly", @@ -47,20 +47,12 @@ "ParameterKey": "pRegionLinkingMode", "ParameterValue": "SPECIFIED_REGIONS" }, - { - "ParameterKey": "pSecurityHubConfigurationRoleName", - "ParameterValue": "sra-securityhub-configuration" - }, - { - "ParameterKey": "pSecurityHubOrgLambdaFunctionName", - "ParameterValue": "sra-securityhub-org" - }, - { - "ParameterKey": "pSecurityHubOrgLambdaRoleName", - "ParameterValue": "sra-securityhub-org-lambda" - }, { "ParameterKey": "pSRAAlarmEmail", "ParameterValue": "" + }, + { + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.3" } ] \ No newline at end of file diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main.json b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main.json index 728eda966..6ce755e0f 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main.json +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/customizations_for_aws_control_tower/parameters/sra-securityhub-org-main.json @@ -4,8 +4,8 @@ "ParameterValue": "" }, { - "ParameterKey": "pControlTowerLifeCycleRuleName", - "ParameterValue": "sra-securityhub-org-trigger" + "ParameterKey": "pComplianceFrequency", + "ParameterValue": "7" }, { "ParameterKey": "pControlTowerRegionsOnly", @@ -59,18 +59,6 @@ "ParameterKey": "pRootOrganizationalUnitId", "ParameterValue": "" }, - { - "ParameterKey": "pSecurityHubConfigurationRoleName", - "ParameterValue": "sra-securityhub-configuration" - }, - { - "ParameterKey": "pSecurityHubOrgLambdaFunctionName", - "ParameterValue": "sra-securityhub-org" - }, - { - "ParameterKey": "pSecurityHubOrgLambdaRoleName", - "ParameterValue": "sra-securityhub-org-lambda" - }, { "ParameterKey": "pSRAAlarmEmail", "ParameterValue": "" @@ -78,5 +66,9 @@ { "ParameterKey": "pSRAStagingS3BucketName", "ParameterValue": "" + }, + { + "ParameterKey": "pSRASolutionVersion", + "ParameterValue": "v1.3" } ] \ No newline at end of file diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.png b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.png index 5ae94da2e..34d56afc3 100644 Binary files a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.png and b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.png differ diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx index 21cf49f21..41b7a0a2f 100644 Binary files a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx and b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx differ diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py index 0c70ad617..8567e3a9f 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py @@ -1,6 +1,6 @@ """This script performs operations to enable, configure, and disable SecurityHub. -Version: 1.2 +Version: 1.3 'securityhub_org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples @@ -26,7 +26,7 @@ from aws_lambda_typing.events import CloudFormationCustomResourceEvent from mypy_boto3_organizations import OrganizationsClient from mypy_boto3_sns import SNSClient - from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef, PublishResponseTypeDef + from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef # Setup Default Logger LOGGER = logging.getLogger("sra") @@ -90,21 +90,6 @@ def create_sns_messages(accounts: list, regions: list, sns_topic_arn: str, actio process_sns_message_batches(sns_messages, sns_topic_arn) -def publish_sns_message(message: dict, subject: str, sns_topic_arn: str) -> None: - """Publish SNS Message. - - Args: - message: SNS Message - subject: SNS Topic Subject - sns_topic_arn: SNS Topic ARN - """ - LOGGER.info(f"Publishing SNS message for {message['AccountId']}.") - LOGGER.info({"SNSMessage": message}) - response: PublishResponseTypeDef = SNS_CLIENT.publish(Message=json.dumps(message), Subject=subject, TopicArn=sns_topic_arn) - api_call_details = {"API_Call": "sns:Publish", "API_Response": response} - LOGGER.info(api_call_details) - - def publish_sns_message_batch(message_batch: list, sns_topic_arn: str) -> None: """Publish SNS Message Batches. @@ -134,15 +119,15 @@ def process_sns_message_batches(sns_messages: list, sns_topic_arn: str) -> None: publish_sns_message_batch(batch, sns_topic_arn) -def process_sns_records(records: list) -> None: - """Process SNS records. +def process_event_sns(event: dict) -> None: + """Process SNS event. Args: - records: list of SNS event records + event: event data """ params = get_validated_parameters({}) - for record in records: + for record in event["Records"]: record["Sns"]["Message"] = json.loads(record["Sns"]["Message"]) LOGGER.info({"SNS Record": record}) message = record["Sns"]["Message"] @@ -156,12 +141,15 @@ def process_sns_records(records: list) -> None: securityhub.disable_securityhub(message["AccountId"], params["CONFIGURATION_ROLE_NAME"], message["Regions"]) -def process_lifecycle_event(event: Dict[str, Any]) -> str: +def process_event_lifecycle(event: Dict[str, Any]) -> str: """Process Lifecycle Event. Args: event: event data + Raises: + ValueError: Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus' + Returns: string with account ID """ @@ -169,14 +157,20 @@ def process_lifecycle_event(event: Dict[str, Any]) -> str: LOGGER.info({"Parameters": params}) regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true") - account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + aws_account_id = "" + if event["detail"]["serviceEventDetails"].get("createManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["createManagedAccountStatus"]["account"]["accountId"] + elif event["detail"]["serviceEventDetails"].get("updateManagedAccountStatus"): + aws_account_id = event["detail"]["serviceEventDetails"]["updateManagedAccountStatus"]["account"]["accountId"] + else: + raise ValueError("Control Tower Lifecycle Event not 'createManagedAccountStatus' or 'updateManagedAccountStatus'") - LOGGER.info(f"Configuring SecurityHub in {account_id}") + LOGGER.info(f"Configuring SecurityHub in {aws_account_id}") securityhub.configure_member_account( - account_id, params["CONFIGURATION_ROLE_NAME"], regions, get_standards_dictionary(params), params["AWS_PARTITION"] + aws_account_id, params["CONFIGURATION_ROLE_NAME"], regions, get_standards_dictionary(params), params["AWS_PARTITION"] ) - return f"lifecycle-event-processed-for-{account_id}" + return f"lifecycle-event-processed-for-{aws_account_id}" def process_add_update_event(params: dict) -> str: @@ -236,6 +230,18 @@ def process_add_update_event(params: dict) -> str: return "ADD_UPDATE_COMPLETE" +def process_event(event: dict) -> None: + """Process Event. + + Args: + event: event data + """ + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({"RequestType": "Update"}) + process_add_update_event(params) + + def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str, is_optional: bool = False) -> dict: """Validate CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables. @@ -253,12 +259,11 @@ def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[s Returns: Validated Parameter """ - if not parameter_value: - parameter_value = "" - if parameter_value == "" and not is_optional: raise ValueError(f"'{parameter_name}' parameter has a value of empty string.") - elif not re.match(pattern, parameter_value): + elif not parameter_value and not is_optional: + raise ValueError(f"'{parameter_name}' parameter is missing.") + elif not re.match(pattern, str(parameter_value)): raise ValueError(f"'{parameter_name}' parameter with value of '{parameter_value}'" + f" does not follow the allowed pattern: {pattern}.") return {parameter_name: parameter_value} @@ -308,7 +313,7 @@ def get_validated_parameters(event: Dict[str, Any]) -> dict: ) # Optional Parameters - params.update(parameter_pattern_validator("ENABLED_REGIONS", os.environ.get("ENABLED_REGIONS", ""), r"^$|[a-z0-9-, ]+$", True)) + params.update(parameter_pattern_validator("ENABLED_REGIONS", os.environ.get("ENABLED_REGIONS"), pattern=r"^$|[a-z0-9-, ]+$", is_optional=True)) return params @@ -328,10 +333,38 @@ def deregister_delegated_administrator(delegated_admin_account_id: str, service_ LOGGER.info(f"Account ({delegated_admin_account_id}) is not a registered delegated administrator: {error}") +def process_event_organizations(event: dict) -> None: + """Process Event from AWS Organizations. + + Args: + event: event data + """ + event_info = {"Event": event} + LOGGER.info(event_info) + params = get_validated_parameters({}) + regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true") + + if event["detail"]["eventName"] == "AcceptHandShake" and event["responseElements"]["handshake"]["state"] == "ACCEPTED": + for party in event["responseElements"]["handshake"]["parties"]: + if party["type"] == "ACCOUNT": + aws_account_id = party["id"] + securityhub.enable_account_securityhub( + aws_account_id, regions, params["CONFIGURATION_ROLE_NAME"], params["AWS_PARTITION"], get_standards_dictionary(params) + ) + break + elif event["detail"]["eventName"] == "CreateAccountResult": + aws_account_id = event["detail"]["serviceEventDetails"]["createAccountStatus"]["accountId"] + securityhub.enable_account_securityhub( + aws_account_id, regions, params["CONFIGURATION_ROLE_NAME"], params["AWS_PARTITION"], get_standards_dictionary(params) + ) + else: + LOGGER.info("Organization event does not match expected values.") + + @helper.create @helper.update @helper.delete -def process_cloudformation_event(event: CloudFormationCustomResourceEvent, context: Context) -> str: # noqa U100 +def process_event_cloudformation(event: CloudFormationCustomResourceEvent, context: Context) -> str: # noqa U100 """Process Event from AWS CloudFormation. Args: @@ -364,20 +397,17 @@ def orchestrator(event: Dict[str, Any], context: Any) -> None: Args: event: event data context: runtime information - - Raises: - ValueError: Unexpected error executing Lambda function """ - if event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": - process_sns_records(event["Records"]) - elif event.get("source") == "aws.controltower": - process_lifecycle_event(event) - elif event.get("RequestType"): + if event.get("RequestType"): helper(event, context) + elif event.get("source") == "aws.controltower": + process_event_lifecycle(event) + elif event.get("source") == "aws.organizations": + process_event_organizations(event) + elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": + process_event_sns(event) else: - raise ValueError( - f"The event did not include Records, RequestType, or source. Review CloudWatch logs '{context.log_group_name}' for details." - ) from None + process_event(event) def lambda_handler(event: Dict[str, Any], context: Any) -> None: diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/common.py b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/common.py index 36acd74c5..2a1e38cbc 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/common.py +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/common.py @@ -32,6 +32,14 @@ ORGANIZATIONS_PAGE_SIZE = 20 ORGANIZATIONS_THROTTLE_PERIOD = 0.2 +try: + MANAGEMENT_ACCOUNT_SESSION = boto3.Session() + CLOUDFORMATION_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation") + ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations") +except Exception as error: + LOGGER.error({"Unexpected_Error": error}) + raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None + def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: """Assumes the provided role in the given account and returns a session. @@ -75,10 +83,8 @@ def get_active_organization_accounts(exclude_accounts: list = None) -> list: """ if exclude_accounts is None: exclude_accounts = ["00000000000"] - accounts = [] - management_account_session = boto3.Session() - org_client: OrganizationsClient = management_account_session.client("organizations") - paginator = org_client.get_paginator("list_accounts") + accounts: list[dict] = [] + paginator = ORG_CLIENT.get_paginator("list_accounts") for page in paginator.paginate(PaginationConfig={"PageSize": ORGANIZATIONS_PAGE_SIZE}): for account in page["Accounts"]: @@ -95,9 +101,7 @@ def get_control_tower_regions() -> list: # noqa: CCR001 Returns: Customer regions chosen in Control Tower """ - management_account_session = boto3.Session() - cfn_client: CloudFormationClient = management_account_session.client("cloudformation") - paginator = cfn_client.get_paginator("list_stack_instances") + paginator = CLOUDFORMATION_CLIENT.get_paginator("list_stack_instances") customer_regions = [] aws_account = "" all_regions_identified = False diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/securityhub.py b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/securityhub.py index 32fe9501e..f08153a8c 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/securityhub.py +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/securityhub.py @@ -19,6 +19,7 @@ from botocore.exceptions import ClientError if TYPE_CHECKING: + from mypy_boto3_config import ConfigServiceClient from mypy_boto3_iam import IAMClient from mypy_boto3_securityhub import GetEnabledStandardsPaginator, ListMembersPaginator, ListOrganizationAdminAccountsPaginator, SecurityHubClient from mypy_boto3_securityhub.type_defs import CreateMembersResponseTypeDef, DeleteMembersResponseTypeDef @@ -59,7 +60,7 @@ def is_admin_account_enabled(securityhub_client: SecurityHubClient, admin_accoun return False -def process_organization_admin_account(admin_account_id: str, regions: list) -> None: # noqa: CCR001 +def process_organization_admin_account(admin_account_id: str, regions: list) -> None: # noqa: CCR001 # NOSONAR """Process the delegated admin account for each region. Args: @@ -174,7 +175,7 @@ def get_associated_members(securityhub_client: SecurityHubClient) -> list: def get_unprocessed_account_details(create_members_response: CreateMembersResponseTypeDef, accounts: list) -> list: - """Get unprocessed account details. + """Get unprocessed account list. Args: create_members_response: CreateMembersResponseTypeDef @@ -266,7 +267,9 @@ def enable_account_securityhub(account_id: str, regions: list, configuration_rol except securityhub_client.exceptions.ResourceConflictException: LOGGER.info(f"SecurityHub already enabled in {account_id} {region}") - process_standards(securityhub_client, standard_dict, standards_user_input["StandardsToEnable"]) + config_client: ConfigServiceClient = account_session.client("config", region) + if is_config_enabled(config_client): + process_standards(securityhub_client, standard_dict, standards_user_input["StandardsToEnable"]) def configure_delegated_admin_securityhub( @@ -329,7 +332,9 @@ def configure_member_account(account_id: str, configuration_role_name: str, regi standards_user_input["CISVersion"], standards_user_input["PCIVersion"], ) - process_standards(securityhub_client, standard_dict, standards_user_input["StandardsToEnable"]) + config_client: ConfigServiceClient = account_session.client("config", region) + if is_config_enabled(config_client): + process_standards(securityhub_client, standard_dict, standards_user_input["StandardsToEnable"]) def get_standard_dictionary(account_id: str, region: str, aws_partition: str, sbp_version: str, cis_version: str, pci_version: str) -> dict: @@ -503,7 +508,7 @@ def process_standard(securityhub_client: SecurityHubClient, standards_to_enable: return True -def create_finding_aggregator(securityhub_client: SecurityHubClient, region_linking_mode: str, regions: list, home_region: str) -> bool: +def create_finding_aggregator(securityhub_client: SecurityHubClient, region_linking_mode: str, regions: list, home_region: str) -> str: """Create Finding Aggregator. Args: @@ -513,13 +518,13 @@ def create_finding_aggregator(securityhub_client: SecurityHubClient, region_link home_region: Home Region Returns: - True + status string """ regions_minus_home_region = regions.copy() regions_minus_home_region.remove(home_region) if not regions_minus_home_region: LOGGER.info("Region aggregator not created due to only one governed region.") - return True + return "Not Created" finding_aggregator_arns: list = [] paginator = securityhub_client.get_paginator("list_finding_aggregators") @@ -539,7 +544,7 @@ def create_finding_aggregator(securityhub_client: SecurityHubClient, region_link response = securityhub_client.create_finding_aggregator(RegionLinkingMode=region_linking_mode, Regions=regions_minus_home_region) api_call_details = {"API_Call": "securityhub:CreateFindingAggregator", "API_Response": response} LOGGER.info(api_call_details) - return True + return "Aggregator Created or Updated" def update_finding_aggregator(securityhub_client: SecurityHubClient, region_linking_mode: str, regions: list, finding_aggregator_arns: list) -> None: @@ -571,7 +576,7 @@ def update_finding_aggregator(securityhub_client: SecurityHubClient, region_link def compare_lists(list1: list, list2: list) -> bool: - """Compare lists. + """Compare 2 lists. Args: list1: List 1 @@ -587,3 +592,20 @@ def compare_lists(list1: list, list2: list) -> bool: return True return False + + +def is_config_enabled(config_client: ConfigServiceClient) -> bool: + """Check if Config is enabled. + + Args: + config_client: ConfigServiceClient + + Returns: + True or False + """ + if ( + len(config_client.describe_configuration_recorders()["ConfigurationRecorders"]) > 0 + and config_client.describe_configuration_recorder_status()["ConfigurationRecordersStatus"][0]["recording"] + ): + return True + return False diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration-role.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration-role.yaml index 6daf59424..505d34133 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration-role.yaml +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration-role.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.1 + Version: 1.2 Order: 2 AWS::CloudFormation::Interface: ParameterGroups: @@ -105,6 +105,17 @@ Resources: Action: organizations:ListAccounts Resource: '*' + - PolicyName: sra-securityhub-org-policy-config + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: AllowConfigDescribeActions + Effect: Allow + Action: + - config:DescribeConfigurationRecorderStatus + - config:DescribeConfigurationRecorders + Resource: '*' + - PolicyName: sra-securityhub-org-policy-securityhub PolicyDocument: Version: 2012-10-17 diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration.yaml index 9ef40deeb..472847847 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration.yaml +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-configuration.yaml @@ -54,11 +54,15 @@ Metadata: - Label: default: EventBridge Rule Properties Parameters: + - pComplianceFrequency - pControlTowerLifeCycleRuleName + - pEventRuleRoleName ParameterLabels: pCISStandardVersion: default: CIS Standard Version + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name pControlTowerRegionsOnly: @@ -77,6 +81,8 @@ Metadata: default: Enable AWS Foundational Security Best Practices Standard pEnabledRegions: default: (Optional) Enabled Regions + pEventRuleRoleName: + default: Event Rule Role Name pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: @@ -110,6 +116,13 @@ Parameters: Default: 1.2.0 Description: CIS Standard Version Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] @@ -160,6 +173,12 @@ Parameters: Default: 'true' Description: Indicates whether to enable the AWS Foundational Security Best Practices Standard. Type: String + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-security-hub-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String pPCIStandardVersion: AllowedValues: [3.2.1] Default: 3.2.1 @@ -237,9 +256,9 @@ Parameters: Type: String Conditions: - cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] - cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] + cComplianceFrequencySingleDay: !Equals [!Ref pComplianceFrequency, 1] cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']] + cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] cUseGraviton: !Or - !Equals [!Ref 'AWS::Region', ap-northeast-1] - !Equals [!Ref 'AWS::Region', ap-south-1] @@ -251,6 +270,8 @@ Conditions: - !Equals [!Ref 'AWS::Region', us-east-1] - !Equals [!Ref 'AWS::Region', us-east-2] - !Equals [!Ref 'AWS::Region', us-west-2] + cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] Resources: rSecurityHubOrgLambdaLogGroup: @@ -578,12 +599,33 @@ Resources: InsufficientDataActions: - !Ref rSecurityHubOrgDLQAlarmTopic + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-org-update + Description: SRA Security Hub Trigger on Organizations update + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + State: ENABLED + Targets: + - Arn: !GetAtt rSecurityHubOrgLambdaFunction.Arn + Id: !Ref pSecurityHubOrgLambdaFunctionName + # Trigger Lambda after account is vended by AWS Control Tower rControlTowerLifeCycleRule: Type: AWS::Events::Rule Properties: Name: !Ref pControlTowerLifeCycleRuleName - Description: SRA Security Hub Control Tower Life Cycle Trigger + Description: SRA Security Hub Control Tower Life Cycle Trigger (triggers on new Control Tower vended accounts) EventPattern: source: - aws.controltower @@ -592,11 +634,20 @@ Resources: detail: eventName: - CreateManagedAccount + - UpdateManagedAccount State: ENABLED Targets: - Arn: !GetAtt rSecurityHubOrgLambdaFunction.Arn Id: !Ref pSecurityHubOrgLambdaFunctionName + PermissionForOrganizationsRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rSecurityHubOrgLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rOrganizationsRule.Arn + rPermissionForControlTowerRuleToInvokeLambda: Type: AWS::Lambda::Permission Properties: @@ -605,6 +656,55 @@ Resources: Principal: events.amazonaws.com SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn + rPermissionForScheduledComplianceRuleToInvokeLambda: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt rSecurityHubOrgLambdaFunction.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !GetAtt rScheduledComplianceRule.Arn + + rScheduledComplianceRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pControlTowerLifeCycleRuleName}-organization-compliance + Description: SRA Security Hub Trigger for scheduled organization compliance + ScheduleExpression: !If + - cComplianceFrequencySingleDay + - !Sub rate(${pComplianceFrequency} day) + - !Sub rate(${pComplianceFrequency} days) + State: ENABLED + Targets: + - Arn: !GetAtt rSecurityHubOrgLambdaFunction.Arn + Id: !Ref pSecurityHubOrgLambdaFunctionName + + rCrossRegionEventRuleRole: + Type: AWS::IAM::Role + Condition: cNotGlobalRegionUsEast1 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: Specific role name provided + Properties: + RoleName: !Ref pEventRuleRoleName + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - events.amazonaws.com + Policies: + - PolicyName: sra-account-alternate-contacts-policy-events + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: events:PutEvents + Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default + Outputs: oControlTowerLifeCycleRule: Description: SRA Control Tower Life Cycle Rule ARN diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-global-events.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-global-events.yaml new file mode 100644 index 000000000..35fe21cf8 --- /dev/null +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-global-events.yaml @@ -0,0 +1,67 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: 2010-09-09 +Description: + This template creates an event rule to send organization events to the home region. - 'securityhub_org' solution in the repo, + https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse6b) +Metadata: + SRA: + Version: 1.0 + Order: 4 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pHomeRegion + - Label: + default: Event Rule Properties + Parameters: + - pEventRuleRoleName + ParameterLabels: + pSRASolutionName: + default: SRA Solution Name + +Parameters: + pEventRuleRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-securityhub-global-events + Description: Event rule role name for putting events on the home region event bus + Type: String + pHomeRegion: + AllowedPattern: '^[a-z0-9-]{1,64}$' + ConstraintDescription: AWS Region Example - 'us-east-1' + Description: Name of the Control Tower home region + Type: String + pSRASolutionName: + AllowedValues: [sra-securityhub-org] + Default: sra-securityhub-org + Description: The SRA solution name. The default value is the folder name of the solution. + Type: String + +Resources: + rOrganizationsRule: + Type: AWS::Events::Rule + Properties: + Name: !Sub ${pSRASolutionName}-forward-org-events + Description: SRA Security Hub Forward Organizations events to home region. + EventPattern: + source: + - aws.organizations + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - organizations.amazonaws.com + eventName: + - AcceptHandshake + - CreateAccountResult + State: ENABLED + Targets: + - Arn: !Sub arn:${AWS::Partition}:events:${pHomeRegion}:${AWS::AccountId}:event-bus/default + Id: !Sub ${pSRASolutionName}-org-events-to-home-region + RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pEventRuleRoleName} diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main-ssm.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main-ssm.yaml index 6fa304652..3b6f79e67 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main-ssm.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.2 + Version: 1.3 Entry: Parameters for deploying the solution resolving SSM parameters Order: 1 AWS::CloudFormation::Interface: @@ -35,9 +35,6 @@ Metadata: - pRegionLinkingMode - pControlTowerRegionsOnly - pEnabledRegions - - pSecurityHubConfigurationRoleName - - pSecurityHubOrgLambdaRoleName - - pSecurityHubOrgLambdaFunctionName - Label: default: General Lambda Function Properties @@ -50,11 +47,14 @@ Metadata: - Label: default: EventBridge Rule Properties Parameters: + - pComplianceFrequency - pControlTowerLifeCycleRuleName ParameterLabels: pAuditAccountId: default: Audit Account ID + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name pControlTowerRegionsOnly: @@ -91,12 +91,6 @@ Metadata: default: SRA Solution Version pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name - pSecurityHubConfigurationRoleName: - default: SecurityHub Configuration Role Name - pSecurityHubOrgLambdaFunctionName: - default: Lambda Function Name - pSecurityHubOrgLambdaRoleName: - default: Lambda Role Name Parameters: pAuditAccountId: @@ -106,6 +100,13 @@ Parameters: Default: /sra/control-tower/audit-account-id Description: SSM Parameter for AWS Account ID of the Control Tower account to delegate administration. Type: AWS::SSM::Parameter::Value + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance by invoking the Lambda Function. + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] @@ -191,24 +192,6 @@ Parameters: Default: /sra/control-tower/root-organizational-unit-id Description: SSM Parameter for Root Organizational Unit ID Type: AWS::SSM::Parameter::Value - pSecurityHubConfigurationRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-securityhub-configuration - Description: SecurityHub Configuration role to assume in the delegated administrator account - Type: String - pSecurityHubOrgLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-securityhub-org - Description: Lambda function name - Type: String - pSecurityHubOrgLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-securityhub-org-lambda - Description: SecurityHub configuration Lambda role name - Type: String pSRAAlarmEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Must be a valid email address. @@ -230,11 +213,14 @@ Parameters: name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: AWS::SSM::Parameter::Value pSRASolutionVersion: - AllowedValues: [v1.2] - Default: v1.2 + AllowedValues: [v1.3] + Default: v1.3 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rSecurityHubConfigurationIAMRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -264,10 +250,6 @@ Resources: ParameterValue: !Ref pAuditAccountId - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId - - ParameterKey: pSecurityHubOrgLambdaRoleName - ParameterValue: !Ref pSecurityHubOrgLambdaRoleName - - ParameterKey: pSecurityHubConfigurationRoleName - ParameterValue: !Ref pSecurityHubConfigurationRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -279,8 +261,6 @@ Resources: Parameters: pDelegatedAdminAccountId: !Ref pAuditAccountId pManagementAccountId: !Ref AWS::AccountId - pSecurityHubOrgLambdaRoleName: !Ref pSecurityHubOrgLambdaRoleName - pSecurityHubConfigurationRoleName: !Ref pSecurityHubConfigurationRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -293,6 +273,7 @@ Resources: Properties: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-securityhub-org-configuration.yaml Parameters: + pComplianceFrequency: !Ref pComplianceFrequency pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName pControlTowerRegionsOnly: !Ref pControlTowerRegionsOnly pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup @@ -309,9 +290,38 @@ Resources: pRegionLinkingMode: !Ref pRegionLinkingMode pSRAAlarmEmail: !Ref pSRAAlarmEmail pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName - pSecurityHubConfigurationRoleName: !Ref pSecurityHubConfigurationRoleName - pSecurityHubOrgLambdaFunctionName: !Ref pSecurityHubOrgLambdaFunctionName - pSecurityHubOrgLambdaRoleName: !Ref pSecurityHubOrgLambdaRoleName + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rSecurityHubGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rSecurityHubConfigurationStack + Properties: + StackSetName: sra-securityhub-org-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-securityhub-org-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main.yaml b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main.yaml index 99a41f0ef..8ead07584 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main.yaml +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/templates/sra-securityhub-org-main.yaml @@ -9,7 +9,7 @@ Description: Metadata: SRA: - Version: 1.2 + Version: 1.3 Entry: Parameters for deploying the solution Order: 1 AWS::CloudFormation::Interface: @@ -35,9 +35,6 @@ Metadata: - pRegionLinkingMode - pControlTowerRegionsOnly - pEnabledRegions - - pSecurityHubConfigurationRoleName - - pSecurityHubOrgLambdaRoleName - - pSecurityHubOrgLambdaFunctionName - Label: default: General Lambda Function Properties @@ -50,11 +47,14 @@ Metadata: - Label: default: EventBridge Rule Properties Parameters: + - pComplianceFrequency - pControlTowerLifeCycleRuleName ParameterLabels: pAuditAccountId: default: Audit Account ID + pComplianceFrequency: + default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name pControlTowerRegionsOnly: @@ -71,12 +71,6 @@ Metadata: default: Enable AWS Foundational Security Best Practices Standard pEnabledRegions: default: (Optional) Enabled Regions - pSecurityHubOrgLambdaFunctionName: - default: Lambda Function Name - pSecurityHubOrgLambdaRoleName: - default: Lambda Role Name - pSecurityHubConfigurationRoleName: - default: SecurityHub Configuration Role Name pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: @@ -105,6 +99,13 @@ Parameters: Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. Description: AWS Account ID of the Control Tower Audit account. Type: String + pComplianceFrequency: + ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. + Default: 7 + Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance by invoking the Lambda Function. + MinValue: 1 + MaxValue: 30 + Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] @@ -187,24 +188,6 @@ Parameters: ConstraintDescription: Must start with 'r-' followed by from 4 to 32 lowercase letters or digits. (e.g. r-abc123) Description: Root Organizational Unit ID Type: String - pSecurityHubConfigurationRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-securityhub-configuration - Description: SecurityHub Configuration role to assume in the delegated administrator account - Type: String - pSecurityHubOrgLambdaFunctionName: - AllowedPattern: '^[\w-]{0,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] - Default: sra-securityhub-org - Description: Lambda function name - Type: String - pSecurityHubOrgLambdaRoleName: - AllowedPattern: '^[\w+=,.@-]{1,64}$' - ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] - Default: sra-securityhub-org-lambda - Description: SecurityHub configuration Lambda role name - Type: String pSRAAlarmEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Must be a valid email address. @@ -225,11 +208,14 @@ Parameters: numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String pSRASolutionVersion: - AllowedValues: [v1.2] - Default: v1.2 + AllowedValues: [v1.3] + Default: v1.3 Description: The SRA solution version. Used to trigger updates on the nested StackSets. Type: String +Conditions: + cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] + Resources: rSecurityHubConfigurationIAMRoleStackSet: Type: AWS::CloudFormation::StackSet @@ -259,10 +245,6 @@ Resources: ParameterValue: !Ref pAuditAccountId - ParameterKey: pManagementAccountId ParameterValue: !Ref AWS::AccountId - - ParameterKey: pSecurityHubOrgLambdaRoleName - ParameterValue: !Ref pSecurityHubOrgLambdaRoleName - - ParameterKey: pSecurityHubConfigurationRoleName - ParameterValue: !Ref pSecurityHubConfigurationRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -274,8 +256,6 @@ Resources: Parameters: pDelegatedAdminAccountId: !Ref pAuditAccountId pManagementAccountId: !Ref AWS::AccountId - pSecurityHubOrgLambdaRoleName: !Ref pSecurityHubOrgLambdaRoleName - pSecurityHubConfigurationRoleName: !Ref pSecurityHubConfigurationRoleName Tags: - Key: sra-solution Value: !Ref pSRASolutionName @@ -288,6 +268,7 @@ Resources: Properties: TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-securityhub-org-configuration.yaml Parameters: + pComplianceFrequency: !Ref pComplianceFrequency pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName pControlTowerRegionsOnly: !Ref pControlTowerRegionsOnly pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup @@ -304,9 +285,38 @@ Resources: pRegionLinkingMode: !Ref pRegionLinkingMode pSRAAlarmEmail: !Ref pSRAAlarmEmail pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName - pSecurityHubConfigurationRoleName: !Ref pSecurityHubConfigurationRoleName - pSecurityHubOrgLambdaFunctionName: !Ref pSecurityHubOrgLambdaFunctionName - pSecurityHubOrgLambdaRoleName: !Ref pSecurityHubOrgLambdaRoleName + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + + rSecurityHubGlobalEventsStackSet: + Type: AWS::CloudFormation::StackSet + Condition: cNotGlobalRegionUsEast1 + DependsOn: rSecurityHubConfigurationStack + Properties: + StackSetName: sra-securityhub-org-global-events + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: + !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region. + ExecutionRoleName: AWSControlTowerExecution + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref AWS::AccountId + Regions: + - us-east-1 + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-securityhub-org-global-events.yaml + Parameters: + - ParameterKey: pHomeRegion + ParameterValue: !Ref AWS::Region Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/utils/packaging_scripts/stage_solution.sh b/aws_sra_examples/utils/packaging_scripts/stage_solution.sh index 7bb3cef63..5e71631c4 100755 --- a/aws_sra_examples/utils/packaging_scripts/stage_solution.sh +++ b/aws_sra_examples/utils/packaging_scripts/stage_solution.sh @@ -164,7 +164,7 @@ upload_cloudformation_templates() { if [ "$(ls -A $1)" ]; then { # try { # shellcheck disable=SC2034 - templates_copy_result=$(aws s3 cp "$1/" s3://"$STAGING_BUCKET_NAME/$2/" --recursive --exclude "*" --include "*.yaml" 2>&1) + templates_copy_result=$(aws s3 cp "$1/" s3://"$STAGING_BUCKET_NAME/$2/" --recursive --exclude "*" --include "*.yaml" --include "*.template" 2>&1) } && { echo "...CloudFormation templates uploaded to $STAGING_BUCKET_NAME/$2/" } diff --git a/poetry.lock b/poetry.lock index 559ad3ed4..a40500677 100644 --- a/poetry.lock +++ b/poetry.lock @@ -41,7 +41,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (> [[package]] name = "aws-lambda-typing" -version = "2.10.1" +version = "2.11.1" description = "A package that provides type hints for AWS Lambda event, context and response objects" category = "dev" optional = false @@ -735,8 +735,8 @@ crt = ["awscrt (==0.12.5)"] [[package]] name = "botocore-stubs" -version = "1.24.46" -description = "Type annotations for botocore 1.24.46 generated with mypy-boto3-builder 7.5.9" +version = "1.26.0.post1" +description = "Type annotations for botocore 1.26.0 generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -765,7 +765,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.1.2" +version = "8.1.3" description = "Composable command line interface toolkit" category = "dev" optional = false @@ -792,7 +792,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.3.2" +version = "6.3.3" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -979,7 +979,7 @@ cognitive_complexity = "*" [[package]] name = "flake8-comprehensions" -version = "3.8.0" +version = "3.9.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." category = "dev" optional = false @@ -1010,7 +1010,7 @@ pydocstyle = ">=2.1" [[package]] name = "flake8-eradicate" -version = "1.2.0" +version = "1.2.1" description = "Flake8 plugin to find commented out code" category = "dev" optional = false @@ -1140,7 +1140,7 @@ flake8 = "*" [[package]] name = "flake8-print" -version = "4.0.0" +version = "4.0.1" description = "print statement checker plugin for flake8" category = "dev" optional = false @@ -1412,7 +1412,7 @@ python-versions = "*" [[package]] name = "more-itertools" -version = "8.12.0" +version = "8.13.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -1450,8 +1450,8 @@ reports = ["lxml"] [[package]] name = "mypy-boto3-accessanalyzer" -version = "1.21.34" -description = "Type annotations for boto3.AccessAnalyzer 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AccessAnalyzer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1461,8 +1461,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-account" -version = "1.21.34" -description = "Type annotations for boto3.Account 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Account 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1472,8 +1472,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-acm" -version = "1.21.34" -description = "Type annotations for boto3.ACM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ACM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1483,8 +1483,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-acm-pca" -version = "1.21.34" -description = "Type annotations for boto3.ACMPCA 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ACMPCA 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1494,8 +1494,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-alexaforbusiness" -version = "1.21.34" -description = "Type annotations for boto3.AlexaForBusiness 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AlexaForBusiness 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1505,8 +1505,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-amp" -version = "1.21.34" -description = "Type annotations for boto3.PrometheusService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PrometheusService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1516,8 +1516,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-amplify" -version = "1.21.34" -description = "Type annotations for boto3.Amplify 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Amplify 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1527,8 +1527,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-amplifybackend" -version = "1.21.34" -description = "Type annotations for boto3.AmplifyBackend 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AmplifyBackend 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1538,8 +1538,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-amplifyuibuilder" -version = "1.21.38" -description = "Type annotations for boto3.AmplifyUIBuilder 1.21.38 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AmplifyUIBuilder 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1549,8 +1549,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-apigateway" -version = "1.21.36" -description = "Type annotations for boto3.APIGateway 1.21.36 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.APIGateway 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1560,8 +1560,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-apigatewaymanagementapi" -version = "1.21.34" -description = "Type annotations for boto3.ApiGatewayManagementApi 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApiGatewayManagementApi 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1571,8 +1571,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-apigatewayv2" -version = "1.21.34" -description = "Type annotations for boto3.ApiGatewayV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApiGatewayV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1582,8 +1582,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appconfig" -version = "1.21.34" -description = "Type annotations for boto3.AppConfig 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppConfig 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1593,8 +1593,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appconfigdata" -version = "1.21.34" -description = "Type annotations for boto3.AppConfigData 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppConfigData 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1604,8 +1604,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appflow" -version = "1.21.41" -description = "Type annotations for boto3.Appflow 1.21.41 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Appflow 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1615,8 +1615,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appintegrations" -version = "1.21.34" -description = "Type annotations for boto3.AppIntegrationsService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppIntegrationsService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1626,8 +1626,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-application-autoscaling" -version = "1.21.34" -description = "Type annotations for boto3.ApplicationAutoScaling 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApplicationAutoScaling 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1637,8 +1637,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-application-insights" -version = "1.21.34" -description = "Type annotations for boto3.ApplicationInsights 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApplicationInsights 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1648,8 +1648,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-applicationcostprofiler" -version = "1.21.34" -description = "Type annotations for boto3.ApplicationCostProfiler 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApplicationCostProfiler 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1659,8 +1659,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appmesh" -version = "1.21.34" -description = "Type annotations for boto3.AppMesh 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppMesh 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1670,8 +1670,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-apprunner" -version = "1.21.38" -description = "Type annotations for boto3.AppRunner 1.21.38 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppRunner 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1681,8 +1681,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appstream" -version = "1.21.41" -description = "Type annotations for boto3.AppStream 1.21.41 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppStream 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1692,8 +1692,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-appsync" -version = "1.21.34" -description = "Type annotations for boto3.AppSync 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppSync 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1703,8 +1703,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-athena" -version = "1.21.42" -description = "Type annotations for boto3.Athena 1.21.42 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Athena 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1714,8 +1714,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-auditmanager" -version = "1.21.34" -description = "Type annotations for boto3.AuditManager 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AuditManager 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1725,8 +1725,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-autoscaling" -version = "1.21.43" -description = "Type annotations for boto3.AutoScaling 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AutoScaling 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1736,8 +1736,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-autoscaling-plans" -version = "1.21.34" -description = "Type annotations for boto3.AutoScalingPlans 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AutoScalingPlans 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1747,8 +1747,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-backup" -version = "1.21.34" -description = "Type annotations for boto3.Backup 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Backup 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1758,8 +1758,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-backup-gateway" -version = "1.21.34" -description = "Type annotations for boto3.BackupGateway 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.BackupGateway 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1769,8 +1769,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-batch" -version = "1.21.41" -description = "Type annotations for boto3.Batch 1.21.41 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Batch 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1780,8 +1780,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-braket" -version = "1.21.34" -description = "Type annotations for boto3.Braket 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Braket 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1791,8 +1791,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-budgets" -version = "1.21.34" -description = "Type annotations for boto3.Budgets 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Budgets 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1802,8 +1802,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ce" -version = "1.21.34" -description = "Type annotations for boto3.CostExplorer 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CostExplorer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1813,8 +1813,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-chime" -version = "1.21.34" -description = "Type annotations for boto3.Chime 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Chime 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1824,8 +1824,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-chime-sdk-identity" -version = "1.21.34" -description = "Type annotations for boto3.ChimeSDKIdentity 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ChimeSDKIdentity 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1835,8 +1835,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-chime-sdk-meetings" -version = "1.21.46" -description = "Type annotations for boto3.ChimeSDKMeetings 1.21.46 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.ChimeSDKMeetings 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1846,8 +1846,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-chime-sdk-messaging" -version = "1.21.34" -description = "Type annotations for boto3.ChimeSDKMessaging 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ChimeSDKMessaging 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1857,8 +1857,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloud9" -version = "1.21.34" -description = "Type annotations for boto3.Cloud9 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Cloud9 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1868,8 +1868,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudcontrol" -version = "1.21.34" -description = "Type annotations for boto3.CloudControlApi 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudControlApi 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1879,8 +1879,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-clouddirectory" -version = "1.21.34" -description = "Type annotations for boto3.CloudDirectory 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudDirectory 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1890,8 +1890,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudformation" -version = "1.21.34" -description = "Type annotations for boto3.CloudFormation 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudFormation 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1901,8 +1901,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudfront" -version = "1.21.34" -description = "Type annotations for boto3.CloudFront 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudFront 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1912,8 +1912,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudhsm" -version = "1.21.34" -description = "Type annotations for boto3.CloudHSM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudHSM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1923,8 +1923,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudhsmv2" -version = "1.21.34" -description = "Type annotations for boto3.CloudHSMV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudHSMV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1934,8 +1934,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudsearch" -version = "1.21.34" -description = "Type annotations for boto3.CloudSearch 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudSearch 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1945,8 +1945,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudsearchdomain" -version = "1.21.34" -description = "Type annotations for boto3.CloudSearchDomain 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudSearchDomain 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1956,8 +1956,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudtrail" -version = "1.21.34" -description = "Type annotations for boto3.CloudTrail 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudTrail 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1967,8 +1967,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudwatch" -version = "1.21.41" -description = "Type annotations for boto3.CloudWatch 1.21.41 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudWatch 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1978,8 +1978,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codeartifact" -version = "1.21.34" -description = "Type annotations for boto3.CodeArtifact 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeArtifact 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -1989,8 +1989,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codebuild" -version = "1.21.34" -description = "Type annotations for boto3.CodeBuild 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeBuild 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2000,8 +2000,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codecommit" -version = "1.21.34" -description = "Type annotations for boto3.CodeCommit 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeCommit 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2011,8 +2011,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codedeploy" -version = "1.21.34" -description = "Type annotations for boto3.CodeDeploy 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeDeploy 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2022,8 +2022,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codeguru-reviewer" -version = "1.21.34" -description = "Type annotations for boto3.CodeGuruReviewer 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeGuruReviewer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2033,8 +2033,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codeguruprofiler" -version = "1.21.34" -description = "Type annotations for boto3.CodeGuruProfiler 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeGuruProfiler 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2044,8 +2044,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codepipeline" -version = "1.21.34" -description = "Type annotations for boto3.CodePipeline 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodePipeline 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2055,8 +2055,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codestar" -version = "1.21.34" -description = "Type annotations for boto3.CodeStar 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeStar 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2066,8 +2066,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codestar-connections" -version = "1.21.34" -description = "Type annotations for boto3.CodeStarconnections 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeStarconnections 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2077,8 +2077,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-codestar-notifications" -version = "1.21.34" -description = "Type annotations for boto3.CodeStarNotifications 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CodeStarNotifications 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2088,8 +2088,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cognito-identity" -version = "1.21.34" -description = "Type annotations for boto3.CognitoIdentity 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CognitoIdentity 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2099,8 +2099,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cognito-idp" -version = "1.21.34" -description = "Type annotations for boto3.CognitoIdentityProvider 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CognitoIdentityProvider 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2110,8 +2110,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cognito-sync" -version = "1.21.34" -description = "Type annotations for boto3.CognitoSync 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CognitoSync 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2121,8 +2121,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-comprehend" -version = "1.21.34" -description = "Type annotations for boto3.Comprehend 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Comprehend 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2132,8 +2132,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-comprehendmedical" -version = "1.21.34" -description = "Type annotations for boto3.ComprehendMedical 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ComprehendMedical 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2143,8 +2143,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-compute-optimizer" -version = "1.21.34" -description = "Type annotations for boto3.ComputeOptimizer 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ComputeOptimizer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2154,8 +2154,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-config" -version = "1.21.35" -description = "Type annotations for boto3.ConfigService 1.21.35 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ConfigService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2165,8 +2165,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-connect" -version = "1.21.44" -description = "Type annotations for boto3.Connect 1.21.44 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.Connect 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2176,8 +2176,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-connect-contact-lens" -version = "1.21.34" -description = "Type annotations for boto3.ConnectContactLens 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ConnectContactLens 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2187,8 +2187,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-connectparticipant" -version = "1.21.34" -description = "Type annotations for boto3.ConnectParticipant 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ConnectParticipant 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2198,8 +2198,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cur" -version = "1.21.34" -description = "Type annotations for boto3.CostandUsageReportService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CostandUsageReportService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2209,8 +2209,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-customer-profiles" -version = "1.21.34" -description = "Type annotations for boto3.CustomerProfiles 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CustomerProfiles 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2220,8 +2220,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-databrew" -version = "1.21.34" -description = "Type annotations for boto3.GlueDataBrew 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GlueDataBrew 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2231,8 +2231,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dataexchange" -version = "1.21.34" -description = "Type annotations for boto3.DataExchange 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DataExchange 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2242,8 +2242,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-datapipeline" -version = "1.21.34" -description = "Type annotations for boto3.DataPipeline 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DataPipeline 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2253,8 +2253,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-datasync" -version = "1.21.34.post1" -description = "Type annotations for boto3.DataSync 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DataSync 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2264,8 +2264,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dax" -version = "1.21.34" -description = "Type annotations for boto3.DAX 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DAX 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2275,8 +2275,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-detective" -version = "1.21.34" -description = "Type annotations for boto3.Detective 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Detective 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2286,8 +2286,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-devicefarm" -version = "1.21.34" -description = "Type annotations for boto3.DeviceFarm 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DeviceFarm 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2297,8 +2297,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-devops-guru" -version = "1.21.39" -description = "Type annotations for boto3.DevOpsGuru 1.21.39 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DevOpsGuru 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2308,8 +2308,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-directconnect" -version = "1.21.34" -description = "Type annotations for boto3.DirectConnect 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DirectConnect 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2319,8 +2319,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-discovery" -version = "1.21.34" -description = "Type annotations for boto3.ApplicationDiscoveryService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ApplicationDiscoveryService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2330,8 +2330,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dlm" -version = "1.21.34" -description = "Type annotations for boto3.DLM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DLM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2341,8 +2341,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dms" -version = "1.21.34" -description = "Type annotations for boto3.DatabaseMigrationService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DatabaseMigrationService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2352,8 +2352,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-docdb" -version = "1.21.36" -description = "Type annotations for boto3.DocDB 1.21.36 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DocDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2363,8 +2363,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-drs" -version = "1.21.34" -description = "Type annotations for boto3.drs 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.drs 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2374,8 +2374,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ds" -version = "1.21.34" -description = "Type annotations for boto3.DirectoryService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DirectoryService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2385,8 +2385,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dynamodb" -version = "1.21.34" -description = "Type annotations for boto3.DynamoDB 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DynamoDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2396,8 +2396,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dynamodbstreams" -version = "1.21.34" -description = "Type annotations for boto3.DynamoDBStreams 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.DynamoDBStreams 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2407,8 +2407,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ebs" -version = "1.21.34" -description = "Type annotations for boto3.EBS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EBS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2418,8 +2418,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ec2" -version = "1.21.46" -description = "Type annotations for boto3.EC2 1.21.46 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.EC2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2429,8 +2429,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ec2-instance-connect" -version = "1.21.34" -description = "Type annotations for boto3.EC2InstanceConnect 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EC2InstanceConnect 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2440,8 +2440,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ecr" -version = "1.21.34" -description = "Type annotations for boto3.ECR 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ECR 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2451,8 +2451,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ecr-public" -version = "1.21.34" -description = "Type annotations for boto3.ECRPublic 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ECRPublic 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2462,8 +2462,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ecs" -version = "1.21.34" -description = "Type annotations for boto3.ECS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ECS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2473,8 +2473,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-efs" -version = "1.21.39" -description = "Type annotations for boto3.EFS 1.21.39 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EFS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2484,8 +2484,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-eks" -version = "1.21.34" -description = "Type annotations for boto3.EKS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EKS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2495,8 +2495,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elastic-inference" -version = "1.21.34" -description = "Type annotations for boto3.ElasticInference 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticInference 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2506,8 +2506,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elasticache" -version = "1.21.45" -description = "Type annotations for boto3.ElastiCache 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElastiCache 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2517,8 +2517,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elasticbeanstalk" -version = "1.21.34" -description = "Type annotations for boto3.ElasticBeanstalk 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticBeanstalk 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2528,8 +2528,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elastictranscoder" -version = "1.21.34" -description = "Type annotations for boto3.ElasticTranscoder 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticTranscoder 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2539,8 +2539,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elb" -version = "1.21.34" -description = "Type annotations for boto3.ElasticLoadBalancing 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticLoadBalancing 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2550,8 +2550,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-elbv2" -version = "1.21.34" -description = "Type annotations for boto3.ElasticLoadBalancingv2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticLoadBalancingv2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2561,8 +2561,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-emr" -version = "1.21.34" -description = "Type annotations for boto3.EMR 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EMR 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2572,8 +2572,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-emr-containers" -version = "1.21.34" -description = "Type annotations for boto3.EMRContainers 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EMRContainers 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2583,8 +2583,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-es" -version = "1.21.34" -description = "Type annotations for boto3.ElasticsearchService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ElasticsearchService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2594,8 +2594,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-events" -version = "1.21.36" -description = "Type annotations for boto3.EventBridge 1.21.36 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.EventBridge 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2605,8 +2605,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-evidently" -version = "1.21.34" -description = "Type annotations for boto3.CloudWatchEvidently 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudWatchEvidently 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2616,8 +2616,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-finspace" -version = "1.21.34" -description = "Type annotations for boto3.finspace 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.finspace 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2627,8 +2627,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-finspace-data" -version = "1.21.34" -description = "Type annotations for boto3.FinSpaceData 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.FinSpaceData 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2638,8 +2638,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-firehose" -version = "1.21.34" -description = "Type annotations for boto3.Firehose 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Firehose 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2649,8 +2649,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-fis" -version = "1.21.34" -description = "Type annotations for boto3.FIS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.FIS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2660,8 +2660,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-fms" -version = "1.21.34" -description = "Type annotations for boto3.FMS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.FMS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2671,8 +2671,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-forecast" -version = "1.21.34" -description = "Type annotations for boto3.ForecastService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ForecastService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2682,8 +2682,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-forecastquery" -version = "1.21.34" -description = "Type annotations for boto3.ForecastQueryService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ForecastQueryService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2693,8 +2693,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-frauddetector" -version = "1.21.34" -description = "Type annotations for boto3.FraudDetector 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.FraudDetector 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2704,8 +2704,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-fsx" -version = "1.21.40" -description = "Type annotations for boto3.FSx 1.21.40 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.FSx 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2715,8 +2715,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-gamelift" -version = "1.21.34" -description = "Type annotations for boto3.GameLift 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GameLift 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2726,8 +2726,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-glacier" -version = "1.21.34" -description = "Type annotations for boto3.Glacier 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Glacier 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2737,8 +2737,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-globalaccelerator" -version = "1.21.34" -description = "Type annotations for boto3.GlobalAccelerator 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GlobalAccelerator 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2748,8 +2748,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-glue" -version = "1.21.45" -description = "Type annotations for boto3.Glue 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.Glue 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2759,8 +2759,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-grafana" -version = "1.21.34" -description = "Type annotations for boto3.ManagedGrafana 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ManagedGrafana 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2770,8 +2770,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-greengrass" -version = "1.21.34" -description = "Type annotations for boto3.Greengrass 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Greengrass 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2781,8 +2781,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-greengrassv2" -version = "1.21.34" -description = "Type annotations for boto3.GreengrassV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GreengrassV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2792,8 +2792,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-groundstation" -version = "1.21.34" -description = "Type annotations for boto3.GroundStation 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GroundStation 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2803,8 +2803,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-guardduty" -version = "1.21.34" -description = "Type annotations for boto3.GuardDuty 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.GuardDuty 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2814,8 +2814,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-health" -version = "1.21.34" -description = "Type annotations for boto3.Health 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Health 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2825,8 +2825,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-healthlake" -version = "1.21.34" -description = "Type annotations for boto3.HealthLake 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.HealthLake 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2836,8 +2836,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-honeycode" -version = "1.21.34" -description = "Type annotations for boto3.Honeycode 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Honeycode 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2847,8 +2847,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iam" -version = "1.21.34" -description = "Type annotations for boto3.IAM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IAM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2858,8 +2858,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-identitystore" -version = "1.21.34" -description = "Type annotations for boto3.IdentityStore 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IdentityStore 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2869,8 +2869,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-imagebuilder" -version = "1.21.34" -description = "Type annotations for boto3.imagebuilder 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.imagebuilder 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2880,8 +2880,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-importexport" -version = "1.21.34" -description = "Type annotations for boto3.ImportExport 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ImportExport 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2891,8 +2891,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-inspector" -version = "1.21.34" -description = "Type annotations for boto3.Inspector 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Inspector 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2902,8 +2902,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-inspector2" -version = "1.21.34" -description = "Type annotations for boto3.Inspector2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Inspector2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2913,8 +2913,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iot" -version = "1.21.34" -description = "Type annotations for boto3.IoT 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoT 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2924,8 +2924,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iot-data" -version = "1.21.34" -description = "Type annotations for boto3.IoTDataPlane 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTDataPlane 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2935,8 +2935,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iot-jobs-data" -version = "1.21.34" -description = "Type annotations for boto3.IoTJobsDataPlane 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTJobsDataPlane 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2946,8 +2946,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iot1click-devices" -version = "1.21.34" -description = "Type annotations for boto3.IoT1ClickDevicesService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoT1ClickDevicesService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2957,8 +2957,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iot1click-projects" -version = "1.21.34" -description = "Type annotations for boto3.IoT1ClickProjects 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoT1ClickProjects 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2968,8 +2968,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotanalytics" -version = "1.21.34" -description = "Type annotations for boto3.IoTAnalytics 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTAnalytics 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2979,8 +2979,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotdeviceadvisor" -version = "1.21.34" -description = "Type annotations for boto3.IoTDeviceAdvisor 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTDeviceAdvisor 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -2990,8 +2990,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotevents" -version = "1.21.34" -description = "Type annotations for boto3.IoTEvents 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTEvents 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3001,8 +3001,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotevents-data" -version = "1.21.34" -description = "Type annotations for boto3.IoTEventsData 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTEventsData 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3012,8 +3012,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotfleethub" -version = "1.21.34" -description = "Type annotations for boto3.IoTFleetHub 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTFleetHub 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3023,8 +3023,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotsecuretunneling" -version = "1.21.34" -description = "Type annotations for boto3.IoTSecureTunneling 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTSecureTunneling 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3034,8 +3034,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotsitewise" -version = "1.21.45" -description = "Type annotations for boto3.IoTSiteWise 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTSiteWise 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3045,8 +3045,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotthingsgraph" -version = "1.21.34" -description = "Type annotations for boto3.IoTThingsGraph 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTThingsGraph 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3056,8 +3056,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iottwinmaker" -version = "1.21.45" -description = "Type annotations for boto3.IoTTwinMaker 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTTwinMaker 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3067,8 +3067,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-iotwireless" -version = "1.21.34" -description = "Type annotations for boto3.IoTWireless 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IoTWireless 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3078,8 +3078,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ivs" -version = "1.21.34" -description = "Type annotations for boto3.IVS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.IVS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3089,8 +3089,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kafka" -version = "1.21.34" -description = "Type annotations for boto3.Kafka 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Kafka 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3100,8 +3100,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kafkaconnect" -version = "1.21.34" -description = "Type annotations for boto3.KafkaConnect 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KafkaConnect 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3111,8 +3111,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kendra" -version = "1.21.43" -description = "Type annotations for boto3.kendra 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.kendra 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3122,8 +3122,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesis" -version = "1.21.34" -description = "Type annotations for boto3.Kinesis 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Kinesis 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3133,8 +3133,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesis-video-archived-media" -version = "1.21.34" -description = "Type annotations for boto3.KinesisVideoArchivedMedia 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisVideoArchivedMedia 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3144,8 +3144,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesis-video-media" -version = "1.21.34" -description = "Type annotations for boto3.KinesisVideoMedia 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisVideoMedia 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3155,8 +3155,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesis-video-signaling" -version = "1.21.34" -description = "Type annotations for boto3.KinesisVideoSignalingChannels 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisVideoSignalingChannels 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3166,8 +3166,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesisanalytics" -version = "1.21.34" -description = "Type annotations for boto3.KinesisAnalytics 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisAnalytics 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3177,8 +3177,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesisanalyticsv2" -version = "1.21.34" -description = "Type annotations for boto3.KinesisAnalyticsV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisAnalyticsV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3188,8 +3188,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kinesisvideo" -version = "1.21.34" -description = "Type annotations for boto3.KinesisVideo 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KinesisVideo 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3199,8 +3199,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-kms" -version = "1.21.43" -description = "Type annotations for boto3.KMS 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.KMS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3210,8 +3210,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lakeformation" -version = "1.21.34" -description = "Type annotations for boto3.LakeFormation 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LakeFormation 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3221,8 +3221,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lambda" -version = "1.21.35" -description = "Type annotations for boto3.Lambda 1.21.35 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Lambda 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3232,8 +3232,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lex-models" -version = "1.21.34" -description = "Type annotations for boto3.LexModelBuildingService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LexModelBuildingService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3243,8 +3243,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lex-runtime" -version = "1.21.34" -description = "Type annotations for boto3.LexRuntimeService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LexRuntimeService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3254,8 +3254,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lexv2-models" -version = "1.21.34" -description = "Type annotations for boto3.LexModelsV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LexModelsV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3265,8 +3265,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lexv2-runtime" -version = "1.21.34" -description = "Type annotations for boto3.LexRuntimeV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LexRuntimeV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3276,8 +3276,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-license-manager" -version = "1.21.34" -description = "Type annotations for boto3.LicenseManager 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LicenseManager 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3287,8 +3287,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lightsail" -version = "1.21.42" -description = "Type annotations for boto3.Lightsail 1.21.42 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Lightsail 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3298,8 +3298,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-location" -version = "1.21.34" -description = "Type annotations for boto3.LocationService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LocationService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3309,8 +3309,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-logs" -version = "1.21.34" -description = "Type annotations for boto3.CloudWatchLogs 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudWatchLogs 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3320,8 +3320,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lookoutequipment" -version = "1.21.34" -description = "Type annotations for boto3.LookoutEquipment 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LookoutEquipment 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3331,8 +3331,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lookoutmetrics" -version = "1.21.45" -description = "Type annotations for boto3.LookoutMetrics 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.LookoutMetrics 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3342,8 +3342,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-lookoutvision" -version = "1.21.34" -description = "Type annotations for boto3.LookoutforVision 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.LookoutforVision 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3353,8 +3353,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-machinelearning" -version = "1.21.34" -description = "Type annotations for boto3.MachineLearning 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MachineLearning 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3364,8 +3364,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-macie" -version = "1.21.34" -description = "Type annotations for boto3.Macie 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Macie 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3375,8 +3375,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-macie2" -version = "1.21.44" -description = "Type annotations for boto3.Macie2 1.21.44 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.Macie2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3386,8 +3386,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-managedblockchain" -version = "1.21.34" -description = "Type annotations for boto3.ManagedBlockchain 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ManagedBlockchain 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3397,8 +3397,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-marketplace-catalog" -version = "1.21.34" -description = "Type annotations for boto3.MarketplaceCatalog 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MarketplaceCatalog 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3408,8 +3408,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-marketplace-entitlement" -version = "1.21.34" -description = "Type annotations for boto3.MarketplaceEntitlementService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MarketplaceEntitlementService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3419,8 +3419,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-marketplacecommerceanalytics" -version = "1.21.34" -description = "Type annotations for boto3.MarketplaceCommerceAnalytics 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MarketplaceCommerceAnalytics 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3430,8 +3430,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediaconnect" -version = "1.21.34" -description = "Type annotations for boto3.MediaConnect 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaConnect 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3441,8 +3441,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediaconvert" -version = "1.21.37" -description = "Type annotations for boto3.MediaConvert 1.21.37 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaConvert 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3452,8 +3452,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-medialive" -version = "1.21.34" -description = "Type annotations for boto3.MediaLive 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaLive 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3463,8 +3463,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediapackage" -version = "1.21.34" -description = "Type annotations for boto3.MediaPackage 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaPackage 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3474,8 +3474,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediapackage-vod" -version = "1.21.37" -description = "Type annotations for boto3.MediaPackageVod 1.21.37 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaPackageVod 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3485,8 +3485,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediastore" -version = "1.21.34" -description = "Type annotations for boto3.MediaStore 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaStore 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3496,8 +3496,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediastore-data" -version = "1.21.34" -description = "Type annotations for boto3.MediaStoreData 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaStoreData 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3507,8 +3507,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mediatailor" -version = "1.21.45" -description = "Type annotations for boto3.MediaTailor 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.MediaTailor 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3518,8 +3518,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-memorydb" -version = "1.21.34" -description = "Type annotations for boto3.MemoryDB 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MemoryDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3529,8 +3529,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-meteringmarketplace" -version = "1.21.34" -description = "Type annotations for boto3.MarketplaceMetering 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MarketplaceMetering 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3540,8 +3540,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mgh" -version = "1.21.34" -description = "Type annotations for boto3.MigrationHub 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MigrationHub 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3551,8 +3551,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mgn" -version = "1.21.44" -description = "Type annotations for boto3.mgn 1.21.44 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.mgn 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3562,8 +3562,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-migration-hub-refactor-spaces" -version = "1.21.34" -description = "Type annotations for boto3.MigrationHubRefactorSpaces 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MigrationHubRefactorSpaces 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3573,8 +3573,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-migrationhub-config" -version = "1.21.34" -description = "Type annotations for boto3.MigrationHubConfig 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MigrationHubConfig 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3584,8 +3584,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-migrationhubstrategy" -version = "1.21.34" -description = "Type annotations for boto3.MigrationHubStrategyRecommendations 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MigrationHubStrategyRecommendations 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3595,8 +3595,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mobile" -version = "1.21.34" -description = "Type annotations for boto3.Mobile 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Mobile 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3606,8 +3606,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mq" -version = "1.21.34" -description = "Type annotations for boto3.MQ 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MQ 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3617,8 +3617,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mturk" -version = "1.21.34" -description = "Type annotations for boto3.MTurk 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MTurk 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3628,8 +3628,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-mwaa" -version = "1.21.34" -description = "Type annotations for boto3.MWAA 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.MWAA 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3639,8 +3639,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-neptune" -version = "1.21.34" -description = "Type annotations for boto3.Neptune 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Neptune 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3650,8 +3650,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-network-firewall" -version = "1.21.34" -description = "Type annotations for boto3.NetworkFirewall 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.NetworkFirewall 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3661,8 +3661,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-networkmanager" -version = "1.21.34" -description = "Type annotations for boto3.NetworkManager 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.NetworkManager 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3672,8 +3672,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-nimble" -version = "1.21.34" -description = "Type annotations for boto3.NimbleStudio 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.NimbleStudio 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3683,8 +3683,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-opensearch" -version = "1.21.34" -description = "Type annotations for boto3.OpenSearchService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.OpenSearchService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3694,8 +3694,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-opsworks" -version = "1.21.34" -description = "Type annotations for boto3.OpsWorks 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.OpsWorks 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3705,8 +3705,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-opsworkscm" -version = "1.21.34" -description = "Type annotations for boto3.OpsWorksCM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.OpsWorksCM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3716,8 +3716,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-organizations" -version = "1.21.34" -description = "Type annotations for boto3.Organizations 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Organizations 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3727,8 +3727,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-outposts" -version = "1.21.34" -description = "Type annotations for boto3.Outposts 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Outposts 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3738,8 +3738,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-panorama" -version = "1.21.35" -description = "Type annotations for boto3.Panorama 1.21.35 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Panorama 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3749,8 +3749,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-personalize" -version = "1.21.43" -description = "Type annotations for boto3.Personalize 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Personalize 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3760,8 +3760,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-personalize-events" -version = "1.21.34" -description = "Type annotations for boto3.PersonalizeEvents 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PersonalizeEvents 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3771,8 +3771,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-personalize-runtime" -version = "1.21.34" -description = "Type annotations for boto3.PersonalizeRuntime 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PersonalizeRuntime 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3782,8 +3782,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-pi" -version = "1.21.36" -description = "Type annotations for boto3.PI 1.21.36 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PI 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3793,8 +3793,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-pinpoint" -version = "1.21.34" -description = "Type annotations for boto3.Pinpoint 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Pinpoint 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3804,8 +3804,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-pinpoint-email" -version = "1.21.34" -description = "Type annotations for boto3.PinpointEmail 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PinpointEmail 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3815,8 +3815,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-pinpoint-sms-voice" -version = "1.21.34" -description = "Type annotations for boto3.PinpointSMSVoice 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PinpointSMSVoice 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3826,8 +3826,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-polly" -version = "1.21.43" -description = "Type annotations for boto3.Polly 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Polly 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3837,8 +3837,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-pricing" -version = "1.21.34" -description = "Type annotations for boto3.Pricing 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Pricing 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3848,8 +3848,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-proton" -version = "1.21.34" -description = "Type annotations for boto3.Proton 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Proton 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3859,8 +3859,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-qldb" -version = "1.21.34" -description = "Type annotations for boto3.QLDB 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.QLDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3870,8 +3870,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-qldb-session" -version = "1.21.34" -description = "Type annotations for boto3.QLDBSession 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.QLDBSession 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3881,8 +3881,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-quicksight" -version = "1.21.34" -description = "Type annotations for boto3.QuickSight 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.QuickSight 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3892,8 +3892,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ram" -version = "1.21.34" -description = "Type annotations for boto3.RAM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.RAM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3903,8 +3903,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-rbin" -version = "1.21.34" -description = "Type annotations for boto3.RecycleBin 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.RecycleBin 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3914,8 +3914,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-rds" -version = "1.21.44" -description = "Type annotations for boto3.RDS 1.21.44 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.RDS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3925,8 +3925,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-rds-data" -version = "1.21.34" -description = "Type annotations for boto3.RDSDataService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.RDSDataService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3936,8 +3936,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-redshift" -version = "1.21.43" -description = "Type annotations for boto3.Redshift 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Redshift 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3947,8 +3947,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-redshift-data" -version = "1.21.34" -description = "Type annotations for boto3.RedshiftDataAPIService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.RedshiftDataAPIService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3958,8 +3958,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-rekognition" -version = "1.21.34" -description = "Type annotations for boto3.Rekognition 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Rekognition 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3969,8 +3969,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-resiliencehub" -version = "1.21.34" -description = "Type annotations for boto3.ResilienceHub 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ResilienceHub 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3980,8 +3980,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-resource-groups" -version = "1.21.34" -description = "Type annotations for boto3.ResourceGroups 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ResourceGroups 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -3991,8 +3991,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-resourcegroupstaggingapi" -version = "1.21.34" -description = "Type annotations for boto3.ResourceGroupsTaggingAPI 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ResourceGroupsTaggingAPI 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4002,8 +4002,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-robomaker" -version = "1.21.34" -description = "Type annotations for boto3.RoboMaker 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.RoboMaker 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4013,8 +4013,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53" -version = "1.21.34" -description = "Type annotations for boto3.Route53 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4024,8 +4024,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53-recovery-cluster" -version = "1.21.34" -description = "Type annotations for boto3.Route53RecoveryCluster 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53RecoveryCluster 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4035,8 +4035,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53-recovery-control-config" -version = "1.21.34" -description = "Type annotations for boto3.Route53RecoveryControlConfig 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53RecoveryControlConfig 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4046,8 +4046,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53-recovery-readiness" -version = "1.21.34" -description = "Type annotations for boto3.Route53RecoveryReadiness 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53RecoveryReadiness 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4057,8 +4057,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53domains" -version = "1.21.34" -description = "Type annotations for boto3.Route53Domains 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53Domains 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4068,8 +4068,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-route53resolver" -version = "1.21.34" -description = "Type annotations for boto3.Route53Resolver 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Route53Resolver 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4079,8 +4079,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-rum" -version = "1.21.34" -description = "Type annotations for boto3.CloudWatchRUM 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.CloudWatchRUM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4090,8 +4090,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-s3" -version = "1.21.34" -description = "Type annotations for boto3.S3 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.S3 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4101,8 +4101,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-s3control" -version = "1.21.34.post1" -description = "Type annotations for boto3.S3Control 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.S3Control 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4112,8 +4112,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-s3outposts" -version = "1.21.34" -description = "Type annotations for boto3.S3Outposts 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.S3Outposts 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4123,8 +4123,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sagemaker" -version = "1.21.36" -description = "Type annotations for boto3.SageMaker 1.21.36 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SageMaker 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4134,8 +4134,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sagemaker-a2i-runtime" -version = "1.21.34" -description = "Type annotations for boto3.AugmentedAIRuntime 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AugmentedAIRuntime 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4145,8 +4145,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sagemaker-edge" -version = "1.21.34" -description = "Type annotations for boto3.SagemakerEdgeManager 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SagemakerEdgeManager 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4156,8 +4156,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sagemaker-featurestore-runtime" -version = "1.21.34" -description = "Type annotations for boto3.SageMakerFeatureStoreRuntime 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SageMakerFeatureStoreRuntime 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4167,8 +4167,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sagemaker-runtime" -version = "1.21.34" -description = "Type annotations for boto3.SageMakerRuntime 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SageMakerRuntime 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4178,8 +4178,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-savingsplans" -version = "1.21.34" -description = "Type annotations for boto3.SavingsPlans 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SavingsPlans 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4189,8 +4189,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-schemas" -version = "1.21.34" -description = "Type annotations for boto3.Schemas 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Schemas 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4200,8 +4200,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sdb" -version = "1.21.34" -description = "Type annotations for boto3.SimpleDB 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SimpleDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4211,8 +4211,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-secretsmanager" -version = "1.21.45" -description = "Type annotations for boto3.SecretsManager 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.SecretsManager 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4222,8 +4222,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-securityhub" -version = "1.21.34.post1" -description = "Type annotations for boto3.SecurityHub 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SecurityHub 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4233,8 +4233,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-serverlessrepo" -version = "1.21.34" -description = "Type annotations for boto3.ServerlessApplicationRepository 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ServerlessApplicationRepository 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4244,8 +4244,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-service-quotas" -version = "1.21.34" -description = "Type annotations for boto3.ServiceQuotas 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ServiceQuotas 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4255,8 +4255,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-servicecatalog" -version = "1.21.34" -description = "Type annotations for boto3.ServiceCatalog 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ServiceCatalog 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4266,8 +4266,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-servicecatalog-appregistry" -version = "1.21.34" -description = "Type annotations for boto3.AppRegistry 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.AppRegistry 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4277,8 +4277,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-servicediscovery" -version = "1.21.34" -description = "Type annotations for boto3.ServiceDiscovery 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.ServiceDiscovery 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4288,8 +4288,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ses" -version = "1.21.34" -description = "Type annotations for boto3.SES 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SES 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4299,8 +4299,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sesv2" -version = "1.21.34" -description = "Type annotations for boto3.SESV2 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SESV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4310,8 +4310,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-shield" -version = "1.21.34" -description = "Type annotations for boto3.Shield 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Shield 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4321,8 +4321,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-signer" -version = "1.21.34" -description = "Type annotations for boto3.signer 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.signer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4332,8 +4332,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sms" -version = "1.21.34" -description = "Type annotations for boto3.SMS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SMS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4343,8 +4343,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sms-voice" -version = "1.21.34" -description = "Type annotations for boto3.PinpointSMSVoice 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.PinpointSMSVoice 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4354,8 +4354,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-snow-device-management" -version = "1.21.34" -description = "Type annotations for boto3.SnowDeviceManagement 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SnowDeviceManagement 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4365,8 +4365,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-snowball" -version = "1.21.34" -description = "Type annotations for boto3.Snowball 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Snowball 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4376,8 +4376,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sns" -version = "1.21.34" -description = "Type annotations for boto3.SNS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SNS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4387,8 +4387,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sqs" -version = "1.21.34" -description = "Type annotations for boto3.SQS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SQS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4398,8 +4398,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ssm" -version = "1.21.43" -description = "Type annotations for boto3.SSM 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSM 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4409,8 +4409,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ssm-contacts" -version = "1.21.34" -description = "Type annotations for boto3.SSMContacts 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSMContacts 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4420,8 +4420,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ssm-incidents" -version = "1.21.34" -description = "Type annotations for boto3.SSMIncidents 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSMIncidents 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4431,8 +4431,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sso" -version = "1.21.34" -description = "Type annotations for boto3.SSO 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSO 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4442,8 +4442,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sso-admin" -version = "1.21.34" -description = "Type annotations for boto3.SSOAdmin 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSOAdmin 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4453,8 +4453,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sso-oidc" -version = "1.21.34" -description = "Type annotations for boto3.SSOOIDC 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SSOOIDC 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4464,8 +4464,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-stepfunctions" -version = "1.21.34" -description = "Type annotations for boto3.SFN 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SFN 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4475,8 +4475,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-storagegateway" -version = "1.21.45" -description = "Type annotations for boto3.StorageGateway 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.StorageGateway 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4486,8 +4486,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-sts" -version = "1.21.34" -description = "Type annotations for boto3.STS 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.STS 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4497,8 +4497,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-support" -version = "1.21.34" -description = "Type annotations for boto3.Support 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Support 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4508,8 +4508,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-swf" -version = "1.21.34" -description = "Type annotations for boto3.SWF 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.SWF 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4519,8 +4519,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-synthetics" -version = "1.21.34" -description = "Type annotations for boto3.Synthetics 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Synthetics 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4530,8 +4530,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-textract" -version = "1.21.43" -description = "Type annotations for boto3.Textract 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Textract 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4541,8 +4541,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-timestream-query" -version = "1.21.34" -description = "Type annotations for boto3.TimestreamQuery 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.TimestreamQuery 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4552,8 +4552,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-timestream-write" -version = "1.21.34" -description = "Type annotations for boto3.TimestreamWrite 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.TimestreamWrite 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4563,8 +4563,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-transcribe" -version = "1.21.34" -description = "Type annotations for boto3.TranscribeService 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.TranscribeService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4574,8 +4574,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-transfer" -version = "1.21.43" -description = "Type annotations for boto3.Transfer 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Transfer 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4585,8 +4585,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-translate" -version = "1.21.34" -description = "Type annotations for boto3.Translate 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.Translate 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4596,8 +4596,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-voice-id" -version = "1.21.34" -description = "Type annotations for boto3.VoiceID 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.VoiceID 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4607,8 +4607,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-waf" -version = "1.21.34" -description = "Type annotations for boto3.WAF 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WAF 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4618,8 +4618,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-waf-regional" -version = "1.21.34" -description = "Type annotations for boto3.WAFRegional 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WAFRegional 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4629,8 +4629,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-wafv2" -version = "1.21.37" -description = "Type annotations for boto3.WAFV2 1.21.37 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WAFV2 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4640,8 +4640,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-wellarchitected" -version = "1.21.34" -description = "Type annotations for boto3.WellArchitected 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WellArchitected 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4651,8 +4651,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-wisdom" -version = "1.21.45" -description = "Type annotations for boto3.ConnectWisdomService 1.21.45 service generated with mypy-boto3-builder 7.5.9" +version = "1.23.0.post1" +description = "Type annotations for boto3.ConnectWisdomService 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4662,8 +4662,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-workdocs" -version = "1.21.34" -description = "Type annotations for boto3.WorkDocs 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkDocs 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4673,8 +4673,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-worklink" -version = "1.21.43" -description = "Type annotations for boto3.WorkLink 1.21.43 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkLink 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4684,8 +4684,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-workmail" -version = "1.21.34" -description = "Type annotations for boto3.WorkMail 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkMail 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4695,8 +4695,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-workmailmessageflow" -version = "1.21.34" -description = "Type annotations for boto3.WorkMailMessageFlow 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkMailMessageFlow 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4706,8 +4706,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-workspaces" -version = "1.21.38" -description = "Type annotations for boto3.WorkSpaces 1.21.38 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkSpaces 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4717,8 +4717,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-workspaces-web" -version = "1.21.34" -description = "Type annotations for boto3.WorkSpacesWeb 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.WorkSpacesWeb 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4728,8 +4728,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-xray" -version = "1.21.34" -description = "Type annotations for boto3.XRay 1.21.34 service generated with mypy-boto3-builder 7.5.8" +version = "1.23.0.post1" +description = "Type annotations for boto3.XRay 1.23.0 service generated with mypy-boto3-builder 7.5.14" category = "dev" optional = false python-versions = ">=3.6" @@ -4766,7 +4766,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "pbr" -version = "5.8.1" +version = "5.9.0" description = "Python Build Reasonableness" category = "dev" optional = false @@ -4848,7 +4848,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pylic" -version = "3.0.1" +version = "3.0.2" description = "A Python license checker" category = "dev" optional = false @@ -4860,7 +4860,7 @@ toml = ">=0.10.2,<0.11.0" [[package]] name = "pyparsing" -version = "3.0.8" +version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "dev" optional = false @@ -5151,8 +5151,8 @@ attrs = [ {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] aws-lambda-typing = [ - {file = "aws-lambda-typing-2.10.1.tar.gz", hash = "sha256:f2ff5a3d120c3f66fe8e3aba003ce27274e9efa76b6b78edfceb98568c1a1602"}, - {file = "aws_lambda_typing-2.10.1-py3-none-any.whl", hash = "sha256:90a960421e1e97c8272d2f8b699876d2317b3ee6da7c63f54e9bd17468c5188c"}, + {file = "aws-lambda-typing-2.11.1.tar.gz", hash = "sha256:66effc483217bae65ca0aa3ba6cdbafe53f65d77c479181b730f080e9ae101f4"}, + {file = "aws_lambda_typing-2.11.1-py3-none-any.whl", hash = "sha256:c110077a3404454b931118d110be2a82b830dbe84de372671622ded05617c9ac"}, ] bandit = [ {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, @@ -5196,8 +5196,8 @@ botocore = [ {file = "botocore-1.23.54.tar.gz", hash = "sha256:4bb9ba16cccee5f5a2602049bc3e2db6865346b2550667f3013bdf33b0a01ceb"}, ] botocore-stubs = [ - {file = "botocore-stubs-1.24.46.tar.gz", hash = "sha256:694344139b1d3554b4f0eba9cfe51cbe65561e29e6bf384170fb3a994a80bc43"}, - {file = "botocore_stubs-1.24.46-py3-none-any.whl", hash = "sha256:7cdc64cf3848c8a86ddc20927c9734fe553dea5d5ef8752b4d226c42158f86b3"}, + {file = "botocore-stubs-1.26.0.post1.tar.gz", hash = "sha256:bd4d61f42656ccc0f73f65d61a22b1523f64c259c8110e9e9d287c7f566474e9"}, + {file = "botocore_stubs-1.26.0.post1-py3-none-any.whl", hash = "sha256:328ab5ea96f2ab834c904274c2ca5e32bb5ce31d97cc382b94e24eace96d7b6f"}, ] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, @@ -5208,8 +5208,8 @@ charset-normalizer = [ {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ - {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, - {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] cognitive-complexity = [ {file = "cognitive_complexity-1.2.0.tar.gz", hash = "sha256:3c2b433a9e41502932f6aa629e1f57a5e8f145956c54facbb5241a9492af6fb7"}, @@ -5219,47 +5219,47 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, - {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, - {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, - {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, - {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, - {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, - {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, - {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, - {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, - {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, - {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, - {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, - {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, - {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, - {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, - {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, - {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, - {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, - {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, - {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, - {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, - {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, - {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, + {file = "coverage-6.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df32ee0f4935a101e4b9a5f07b617d884a531ed5666671ff6ac66d2e8e8246d8"}, + {file = "coverage-6.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75b5dbffc334e0beb4f6c503fb95e6d422770fd2d1b40a64898ea26d6c02742d"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:114944e6061b68a801c5da5427b9173a0dd9d32cd5fcc18a13de90352843737d"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab88a01cd180b5640ccc9c47232e31924d5f9967ab7edd7e5c91c68eee47a69"}, + {file = "coverage-6.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad8f9068f5972a46d50fe5f32c09d6ee11da69c560fcb1b4c3baea246ca4109b"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4cd696aa712e6cd16898d63cf66139dc70d998f8121ab558f0e1936396dbc579"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c1a9942e282cc9d3ed522cd3e3cab081149b27ea3bda72d6f61f84eaf88c1a63"}, + {file = "coverage-6.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c06455121a089252b5943ea682187a4e0a5cf0a3fb980eb8e7ce394b144430a9"}, + {file = "coverage-6.3.3-cp310-cp310-win32.whl", hash = "sha256:cb5311d6ccbd22578c80028c5e292a7ab9adb91bd62c1982087fad75abe2e63d"}, + {file = "coverage-6.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:6d4a6f30f611e657495cc81a07ff7aa8cd949144e7667c5d3e680d73ba7a70e4"}, + {file = "coverage-6.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:79bf405432428e989cad7b8bc60581963238f7645ae8a404f5dce90236cc0293"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:338c417613f15596af9eb7a39353b60abec9d8ce1080aedba5ecee6a5d85f8d3"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db094a6a4ae6329ed322a8973f83630b12715654c197dd392410400a5bfa1a73"}, + {file = "coverage-6.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1414e8b124611bf4df8d77215bd32cba6e3425da8ce9c1f1046149615e3a9a31"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:93b16b08f94c92cab88073ffd185070cdcb29f1b98df8b28e6649145b7f2c90d"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbc86ae8cc129c801e7baaafe3addf3c8d49c9c1597c44bdf2d78139707c3c62"}, + {file = "coverage-6.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b5ba058610e8289a07db2a57bce45a1793ec0d3d11db28c047aae2aa1a832572"}, + {file = "coverage-6.3.3-cp37-cp37m-win32.whl", hash = "sha256:8329635c0781927a2c6ae068461e19674c564e05b86736ab8eb29c420ee7dc20"}, + {file = "coverage-6.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:e5af1feee71099ae2e3b086ec04f57f9950e1be9ecf6c420696fea7977b84738"}, + {file = "coverage-6.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e814a4a5a1d95223b08cdb0f4f57029e8eab22ffdbae2f97107aeef28554517e"}, + {file = "coverage-6.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:61f4fbf3633cb0713437291b8848634ea97f89c7e849c2be17a665611e433f53"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3401b0d2ed9f726fadbfa35102e00d1b3547b73772a1de5508ef3bdbcb36afe7"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8586b177b4407f988731eb7f41967415b2197f35e2a6ee1a9b9b561f6323c8e9"}, + {file = "coverage-6.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:892e7fe32191960da559a14536768a62e83e87bbb867e1b9c643e7e0fbce2579"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afb03f981fadb5aed1ac6e3dd34f0488e1a0875623d557b6fad09b97a942b38a"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cbe91bc84be4e5ef0b1480d15c7b18e29c73bdfa33e07d3725da7d18e1b0aff2"}, + {file = "coverage-6.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:91502bf27cbd5c83c95cfea291ef387469f2387508645602e1ca0fd8a4ba7548"}, + {file = "coverage-6.3.3-cp38-cp38-win32.whl", hash = "sha256:c488db059848702aff30aa1d90ef87928d4e72e4f00717343800546fdbff0a94"}, + {file = "coverage-6.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6534fcdfb5c503affb6b1130db7b5bfc8a0f77fa34880146f7a5c117987d0"}, + {file = "coverage-6.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc692c9ee18f0dd3214843779ba6b275ee4bb9b9a5745ba64265bce911aefd1a"}, + {file = "coverage-6.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:462105283de203df8de58a68c1bb4ba2a8a164097c2379f664fa81d6baf94b81"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc972d829ad5ef4d4c5fcabd2bbe2add84ce8236f64ba1c0c72185da3a273130"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06f54765cdbce99901871d50fe9f41d58213f18e98b170a30ca34f47de7dd5e8"}, + {file = "coverage-6.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7835f76a081787f0ca62a53504361b3869840a1620049b56d803a8cb3a9eeea3"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6f5fee77ec3384b934797f1873758f796dfb4f167e1296dc00f8b2e023ce6ee9"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:baa8be8aba3dd1e976e68677be68a960a633a6d44c325757aefaa4d66175050f"}, + {file = "coverage-6.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d06380e777dd6b35ee936f333d55b53dc4a8271036ff884c909cf6e94be8b6c"}, + {file = "coverage-6.3.3-cp39-cp39-win32.whl", hash = "sha256:f8cabc5fd0091976ab7b020f5708335033e422de25e20ddf9416bdce2b7e07d8"}, + {file = "coverage-6.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c9441d57b0963cf8340268ad62fc83de61f1613034b79c2b1053046af0c5284"}, + {file = "coverage-6.3.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:d522f1dc49127eab0bfbba4e90fa068ecff0899bbf61bf4065c790ddd6c177fe"}, + {file = "coverage-6.3.3.tar.gz", hash = "sha256:2781c43bffbbec2b8867376d4d61916f5e9c4cc168232528562a61d1b4b01879"}, ] crhelper = [ {file = "crhelper-2.0.10-py3-none-any.whl", hash = "sha256:8f05516ca8b7a340fbaedbc1a463e2cb8d53c0670cd2f7723c8b8098c65bf27d"}, @@ -5320,8 +5320,8 @@ flake8-cognitive-complexity = [ {file = "flake8_cognitive_complexity-0.1.0.tar.gz", hash = "sha256:f202df054e4f6ff182b659c261922b9c684628a47beb19cb0973c50d6a7831c1"}, ] flake8-comprehensions = [ - {file = "flake8-comprehensions-3.8.0.tar.gz", hash = "sha256:8e108707637b1d13734f38e03435984f6b7854fa6b5a4e34f93e69534be8e521"}, - {file = "flake8_comprehensions-3.8.0-py3-none-any.whl", hash = "sha256:9406314803abe1193c064544ab14fdc43c58424c0882f6ff8a581eb73fc9bb58"}, + {file = "flake8-comprehensions-3.9.0.tar.gz", hash = "sha256:20c2f6846090e8f265e757f0aa500614c88b0f9ffb0d954d330dcd8abd8f874e"}, + {file = "flake8_comprehensions-3.9.0-py3-none-any.whl", hash = "sha256:ef3a069809d4eb60805cd9b0ea2aa1aae21b527a460e704c01e0dd3416c99aeb"}, ] flake8-copyright = [ {file = "flake8-copyright-0.2.2.tar.gz", hash = "sha256:5c3632dd8c586547b25fff4272282005fdbcba56eeb77b7487564aa636b6e533"}, @@ -5333,8 +5333,8 @@ flake8-docstrings = [ {file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"}, ] flake8-eradicate = [ - {file = "flake8-eradicate-1.2.0.tar.gz", hash = "sha256:acaa1b6839ff00d284b805c432fdfa6047262bd15a5504ec945797e87b4de1fa"}, - {file = "flake8_eradicate-1.2.0-py3-none-any.whl", hash = "sha256:51dc660d0c1c1ed93af0f813540bbbf72ab2d3466c14e3f3bac371c618b6042f"}, + {file = "flake8-eradicate-1.2.1.tar.gz", hash = "sha256:e486f8ab7e2dba3667223688e9239158fbf4ecaa88125e2283bcda81171412b7"}, + {file = "flake8_eradicate-1.2.1-py3-none-any.whl", hash = "sha256:00d77faefb64cef18b3c1b48a004c3a2ad663aa3cf85650f422437d25ece6441"}, ] flake8-executable = [ {file = "flake8-executable-2.1.1.tar.gz", hash = "sha256:c6230a089ad49dbeef049d8e1e89591d9823f06c829cd9d6b1ca83b4b1d7f54f"}, @@ -5380,8 +5380,8 @@ flake8-polyfill = [ {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, ] flake8-print = [ - {file = "flake8-print-4.0.0.tar.gz", hash = "sha256:5afac374b7dc49aac2c36d04b5eb1d746d72e6f5df75a6ecaecd99e9f79c6516"}, - {file = "flake8_print-4.0.0-py3-none-any.whl", hash = "sha256:6c0efce658513169f96d7a24cf136c434dc711eb00ebd0a985eb1120103fe584"}, + {file = "flake8-print-4.0.1.tar.gz", hash = "sha256:12b3c3bf65329d8ca9acde949fb3b932ec113e9e5ffa6cb7cd55a7dbcd67dae1"}, + {file = "flake8_print-4.0.1-py3-none-any.whl", hash = "sha256:e246bcd5b07d5259af460b7eff148052c49114640380d7f22340f30920fabf02"}, ] flake8-printf-formatting = [ {file = "flake8-printf-formatting-1.1.2.tar.gz", hash = "sha256:0f9e1308ac290356e4b271d4f26adfc3f9165680a7b6c221503b0f3e155a2784"}, @@ -5475,8 +5475,8 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] more-itertools = [ - {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"}, - {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"}, + {file = "more-itertools-8.13.0.tar.gz", hash = "sha256:a42901a0a5b169d925f6f217cd5a190e32ef54360905b9c39ee7db5313bfec0f"}, + {file = "more_itertools-8.13.0-py3-none-any.whl", hash = "sha256:c5122bffc5f104d37c1626b8615b511f3427aa5389b94d61e5ef8236bfbc3ddb"}, ] mr-proper = [ {file = "mr_proper-0.0.7-py3-none-any.whl", hash = "sha256:74a1b60240c46f10ba518707ef72811a01e5c270da0a78b5dd2dd923d99fdb14"}, @@ -5508,1200 +5508,1200 @@ mypy = [ {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, ] mypy-boto3-accessanalyzer = [ - {file = "mypy-boto3-accessanalyzer-1.21.34.tar.gz", hash = "sha256:81d79de0b3ee8420178db2dc2b9b3134762da33ef5b8663cfd4ee1ee935a8f28"}, - {file = "mypy_boto3_accessanalyzer-1.21.34-py3-none-any.whl", hash = "sha256:c5124e382803ca251a5d5efa100d27d80526dca7340f4a0890af47fc1d0201b1"}, + {file = "mypy-boto3-accessanalyzer-1.23.0.post1.tar.gz", hash = "sha256:89078fb1ea772419dcebf79d0003c95bcedda07cf6b77a664ce57f64ef0bb31b"}, + {file = "mypy_boto3_accessanalyzer-1.23.0.post1-py3-none-any.whl", hash = "sha256:069efe6c16371aaf46954abc0528e34b79f7a129fc5006ba1d929de1ce190b21"}, ] mypy-boto3-account = [ - {file = "mypy-boto3-account-1.21.34.tar.gz", hash = "sha256:472f8de781742128e7c1da2ed38a0b5f7d4882be741d073ee78849c83e2f68eb"}, - {file = "mypy_boto3_account-1.21.34-py3-none-any.whl", hash = "sha256:efc167a06eca583f1381287c2da94efb7d66158fe5f5deb3c613bcb1668ed285"}, + {file = "mypy-boto3-account-1.23.0.post1.tar.gz", hash = "sha256:530d141a090525d8ca167ba1b5007f2f1d9f67f1181573475571996ab85224f4"}, + {file = "mypy_boto3_account-1.23.0.post1-py3-none-any.whl", hash = "sha256:b51f804f200f30c8d2dd2afdf56a29b05e958a5ca69ea7880c7b2292cc9f0b4d"}, ] mypy-boto3-acm = [ - {file = "mypy-boto3-acm-1.21.34.tar.gz", hash = "sha256:1f679dda627f9e9d76e510591df8043b9b944a1cc0ec06cfda00a9eefe0e8267"}, - {file = "mypy_boto3_acm-1.21.34-py3-none-any.whl", hash = "sha256:777a2b79bfa1161c5260110060a831e9ed31de0313bb2e216a4de58a40f1c9f3"}, + {file = "mypy-boto3-acm-1.23.0.post1.tar.gz", hash = "sha256:b307e08f37aa8957e2dc830d30a6f1ca24966f01a63dc8d0e9e7435466eedb95"}, + {file = "mypy_boto3_acm-1.23.0.post1-py3-none-any.whl", hash = "sha256:91223fcfb69df9357bd78257cf01b439e9a01051684c294d71098a55eac112c4"}, ] mypy-boto3-acm-pca = [ - {file = "mypy-boto3-acm-pca-1.21.34.tar.gz", hash = "sha256:0ab2eb2f45f0e742ac93409a04e358875edb592a5a7a4420dee48c71660ef096"}, - {file = "mypy_boto3_acm_pca-1.21.34-py3-none-any.whl", hash = "sha256:5db14a79c595ee5a0a158e012b443ab4d5eb8ddbe03b8b6ea6db329ed0a54fbe"}, + {file = "mypy-boto3-acm-pca-1.23.0.post1.tar.gz", hash = "sha256:35751ec44780c0c8883f4adc37547dc9186f3e6d07899cf84f5357bba7602d76"}, + {file = "mypy_boto3_acm_pca-1.23.0.post1-py3-none-any.whl", hash = "sha256:7d6e17c3ad637e5cf0061a4137dde42e4e1d8115553165de09b665ec7330660f"}, ] mypy-boto3-alexaforbusiness = [ - {file = "mypy-boto3-alexaforbusiness-1.21.34.tar.gz", hash = "sha256:9b50ff49a167b32515a76989896c2ca0e43c0936bb229552313c77b1bb63e36e"}, - {file = "mypy_boto3_alexaforbusiness-1.21.34-py3-none-any.whl", hash = "sha256:fa88581ae568535502c0a689f511f6eaee4f222f093b419d31464a363118f0cd"}, + {file = "mypy-boto3-alexaforbusiness-1.23.0.post1.tar.gz", hash = "sha256:727d441f1d6cb97a9359f191d1ee98768989d53e0ab5f9b6525348af298da991"}, + {file = "mypy_boto3_alexaforbusiness-1.23.0.post1-py3-none-any.whl", hash = "sha256:45df921b7c20df5456b30fa5ccb7dccb12c6ff6157398696b0108933540a3344"}, ] mypy-boto3-amp = [ - {file = "mypy-boto3-amp-1.21.34.tar.gz", hash = "sha256:156e024bb38635fc1b16460c2401679aee2741597400c004773849737199f476"}, - {file = "mypy_boto3_amp-1.21.34-py3-none-any.whl", hash = "sha256:ac026db70b089cc89aec6dbd0311aeea9297e5fb67d85efd36152414e22ad7f1"}, + {file = "mypy-boto3-amp-1.23.0.post1.tar.gz", hash = "sha256:629449ea578d77f7e71c92c5061e79887ac107b40826cfa249c2e7b025e9ba5d"}, + {file = "mypy_boto3_amp-1.23.0.post1-py3-none-any.whl", hash = "sha256:ad21d0076a1de7fe1d5edea87cf3fb090d414f0142f5d5984eff6c628dbc7714"}, ] mypy-boto3-amplify = [ - {file = "mypy-boto3-amplify-1.21.34.tar.gz", hash = "sha256:50bf5f968d7f13c3e59194d028951ac4f6bc8734957eaab4608727ab82a3e5ac"}, - {file = "mypy_boto3_amplify-1.21.34-py3-none-any.whl", hash = "sha256:007fcf0146566478f847c437da065a046b42558527c81e4119a601c7eae4be14"}, + {file = "mypy-boto3-amplify-1.23.0.post1.tar.gz", hash = "sha256:3f39449ba69eed20a486dd2b0a18111bcc8e1ee53769f7d80254c638d3e97f0b"}, + {file = "mypy_boto3_amplify-1.23.0.post1-py3-none-any.whl", hash = "sha256:caaf6a98b71159161e40249c2383decffa23a3a862b631172cf336ad208a1fc9"}, ] mypy-boto3-amplifybackend = [ - {file = "mypy-boto3-amplifybackend-1.21.34.tar.gz", hash = "sha256:528accea314f25c5c1c50bcbed589437897a4b636884e586435f1c345b916c91"}, - {file = "mypy_boto3_amplifybackend-1.21.34-py3-none-any.whl", hash = "sha256:6397d1d073fcd8bc3b6401ab59ebf99714958b51a8a2ec397a1c614cd692bf61"}, + {file = "mypy-boto3-amplifybackend-1.23.0.post1.tar.gz", hash = "sha256:cf0c8b83562794d48da1a9216efeb424c24029dd9bc3250a7d51e0121273aea9"}, + {file = "mypy_boto3_amplifybackend-1.23.0.post1-py3-none-any.whl", hash = "sha256:1b9c16275bc38ae6b4182609d1c1dd4dabe6a65eaedd18f67abfba620960253f"}, ] mypy-boto3-amplifyuibuilder = [ - {file = "mypy-boto3-amplifyuibuilder-1.21.38.tar.gz", hash = "sha256:005ba794a1141c82621860d99aaa72e2c6874367012a03b58cd00e6034ebf33a"}, - {file = "mypy_boto3_amplifyuibuilder-1.21.38-py3-none-any.whl", hash = "sha256:05f12d8914b2a04bdeab8e63b59f6cf822fb4b8fa785c9745c676dec0795e163"}, + {file = "mypy-boto3-amplifyuibuilder-1.23.0.post1.tar.gz", hash = "sha256:99a1b0983d3bf16f59ce8f79624f42baa3fb359c3604e866c35e134493b92f33"}, + {file = "mypy_boto3_amplifyuibuilder-1.23.0.post1-py3-none-any.whl", hash = "sha256:980f801a077d652d6a43fb9836b28363df91fdd09c2c1ae5d9e7666035343b8c"}, ] mypy-boto3-apigateway = [ - {file = "mypy-boto3-apigateway-1.21.36.tar.gz", hash = "sha256:da74f3b71713b8f636c235e8179535668378bde4d3d69c81b73964e8e6323789"}, - {file = "mypy_boto3_apigateway-1.21.36-py3-none-any.whl", hash = "sha256:746d0d79c3e01aee1f1e157c4ff2ccbcb478e05dde44b0fb231097a9af4e55a4"}, + {file = "mypy-boto3-apigateway-1.23.0.post1.tar.gz", hash = "sha256:5f181e659e60226741f2eff754cb190bbbc931e60100965a9772bce0e9c4fb96"}, + {file = "mypy_boto3_apigateway-1.23.0.post1-py3-none-any.whl", hash = "sha256:4b8751f74f3d24138106513f0f4b3338c6ff97e1fc4b25037c28389a830315cc"}, ] mypy-boto3-apigatewaymanagementapi = [ - {file = "mypy-boto3-apigatewaymanagementapi-1.21.34.tar.gz", hash = "sha256:d4e1eb2a565876aa1b97a1d312838f5fd086d315db01a9b24caff3ac3476656a"}, - {file = "mypy_boto3_apigatewaymanagementapi-1.21.34-py3-none-any.whl", hash = "sha256:24d1949142010eb6177af735f4e8c13c445cf008340bd33a9f3a2182c87c6a58"}, + {file = "mypy-boto3-apigatewaymanagementapi-1.23.0.post1.tar.gz", hash = "sha256:022af533642c987eed03ae7e309d21d93a35b93e50e0e9d4f794671e0b3d1ed2"}, + {file = "mypy_boto3_apigatewaymanagementapi-1.23.0.post1-py3-none-any.whl", hash = "sha256:5148d31d6c4ad60b69e1c70816de206edaed323fb2035472e6e986f2798f1f6e"}, ] mypy-boto3-apigatewayv2 = [ - {file = "mypy-boto3-apigatewayv2-1.21.34.tar.gz", hash = "sha256:e3d75a76195790681d5aba28fa42b81c7761342e53b04f40f074d1d63f4b7ebd"}, - {file = "mypy_boto3_apigatewayv2-1.21.34-py3-none-any.whl", hash = "sha256:170385c1b30ecdba06ad0719a639407e2291c29b6aa202a53da02c8e5518094f"}, + {file = "mypy-boto3-apigatewayv2-1.23.0.post1.tar.gz", hash = "sha256:8d3d35ee42d202f8aff7ae6b0303cc14882c15a66bd595f6d82a107ce83b8034"}, + {file = "mypy_boto3_apigatewayv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:f43b3fbce8f6abd88921080bca03c11f563dcc5fb15c5be35b91baa311d88c1d"}, ] mypy-boto3-appconfig = [ - {file = "mypy-boto3-appconfig-1.21.34.tar.gz", hash = "sha256:620350b576e7a5df62b30829f5b9760e4aa105e1b7b2455cccb2be32e529e950"}, - {file = "mypy_boto3_appconfig-1.21.34-py3-none-any.whl", hash = "sha256:1c9c20e5c9436f65989e35692497a3c1c19d6b28aeb9d6989cee3b0cfb1b3f7d"}, + {file = "mypy-boto3-appconfig-1.23.0.post1.tar.gz", hash = "sha256:78442ffc2850a5234f72a4c2b3d5eeae87e3e1cc67e689bb3bee33e35cbb31a9"}, + {file = "mypy_boto3_appconfig-1.23.0.post1-py3-none-any.whl", hash = "sha256:a3175229be86dc1aab8722a6338086ddcf941a61d1dd791344b8654b01075bfa"}, ] mypy-boto3-appconfigdata = [ - {file = "mypy-boto3-appconfigdata-1.21.34.tar.gz", hash = "sha256:c4fcce7d3a03585723652bbb69fe742c029fea217a8cae2f9199fe247775cec4"}, - {file = "mypy_boto3_appconfigdata-1.21.34-py3-none-any.whl", hash = "sha256:a139808c03ab13edcf6d41e0783197ed253dd2f23736d024876529d317c98917"}, + {file = "mypy-boto3-appconfigdata-1.23.0.post1.tar.gz", hash = "sha256:a97239b3556bc27f60c647cb791dd182b284fb3c07676735314394a0cb1a8887"}, + {file = "mypy_boto3_appconfigdata-1.23.0.post1-py3-none-any.whl", hash = "sha256:ff8552ff4e075e03fcd0de6d06db2d676216485f1177c9ee494101dc74f04545"}, ] mypy-boto3-appflow = [ - {file = "mypy-boto3-appflow-1.21.41.tar.gz", hash = "sha256:664653980d6b23a0290e37d13e0f1e333bfb16ee4252f9e736d2aeed59aaefba"}, - {file = "mypy_boto3_appflow-1.21.41-py3-none-any.whl", hash = "sha256:96629436207b53c4fb4770b70cf518666c8e35158a61b12b1fee788b09267b9d"}, + {file = "mypy-boto3-appflow-1.23.0.post1.tar.gz", hash = "sha256:17132bb766c2628d7d95c116fbcb4e20c95f390fc63b6124131270cb3a44dd4a"}, + {file = "mypy_boto3_appflow-1.23.0.post1-py3-none-any.whl", hash = "sha256:4dc376867adadd1c7e914c8253db4ca369453350af9ecc47322155a4c4e68fc4"}, ] mypy-boto3-appintegrations = [ - {file = "mypy-boto3-appintegrations-1.21.34.tar.gz", hash = "sha256:8ad93e5567cf61eb7fc0968da3d92ddccb75089359061c4127258658b37425cf"}, - {file = "mypy_boto3_appintegrations-1.21.34-py3-none-any.whl", hash = "sha256:d589f1044e1ed173613234f4fe94eea15410334d1fb331a47be635e50602221b"}, + {file = "mypy-boto3-appintegrations-1.23.0.post1.tar.gz", hash = "sha256:3824b38f819a6d8f2166f09b8a4cd226b008d6e76749f35d6d823f873f16de2e"}, + {file = "mypy_boto3_appintegrations-1.23.0.post1-py3-none-any.whl", hash = "sha256:fc75b5877c77f5e9f40b5620625eb1f945bc75cdb30818473ff314d72e3aace2"}, ] mypy-boto3-application-autoscaling = [ - {file = "mypy-boto3-application-autoscaling-1.21.34.tar.gz", hash = "sha256:18baf1aa96e7692e36efe042f00373c437e31e068967987fd5efdef7949e3b48"}, - {file = "mypy_boto3_application_autoscaling-1.21.34-py3-none-any.whl", hash = "sha256:735ccccc8fb745f6afc81a3cd78d2c211f1bbc6c577299022e64c5df3898e84a"}, + {file = "mypy-boto3-application-autoscaling-1.23.0.post1.tar.gz", hash = "sha256:a38cdcf9c48d542415f984b1e350ef61cb1a9c3b1416b1e69cbff08cdb9a3548"}, + {file = "mypy_boto3_application_autoscaling-1.23.0.post1-py3-none-any.whl", hash = "sha256:ade962fddc4c760d7de297390aee021fb4d2034c0f1d250d62101e5b19cc8579"}, ] mypy-boto3-application-insights = [ - {file = "mypy-boto3-application-insights-1.21.34.tar.gz", hash = "sha256:11a9afefbbc4184e32bcbf6b74e1209177d935ec4e9f216794c9ed1f7c7a3c3b"}, - {file = "mypy_boto3_application_insights-1.21.34-py3-none-any.whl", hash = "sha256:1a6f82cf23ebdace2ad7ee9a107fc2b7b438a7643ab869d526e996d582869c2a"}, + {file = "mypy-boto3-application-insights-1.23.0.post1.tar.gz", hash = "sha256:24b4dfb375618d81b642cfb8d155d91c54ee16677d443d1e4684bf53dfe70a00"}, + {file = "mypy_boto3_application_insights-1.23.0.post1-py3-none-any.whl", hash = "sha256:e774b6dd6e03ea42f9bbf820f879791287914d636d9a139e1894cfbb2cc8a778"}, ] mypy-boto3-applicationcostprofiler = [ - {file = "mypy-boto3-applicationcostprofiler-1.21.34.tar.gz", hash = "sha256:96591570c644c37ff598cdb2e1752f8dc03d43f2068ef93de2c9823cf2295d55"}, - {file = "mypy_boto3_applicationcostprofiler-1.21.34-py3-none-any.whl", hash = "sha256:dff9104b9df6ddf2affe791be1a4521be5e31de3d9ca6a0d58e45e88b152a566"}, + {file = "mypy-boto3-applicationcostprofiler-1.23.0.post1.tar.gz", hash = "sha256:38dcd1f555061c7c69b939d0f7dccc9e0374c2f54d3450b904a358c4939b1b45"}, + {file = "mypy_boto3_applicationcostprofiler-1.23.0.post1-py3-none-any.whl", hash = "sha256:518fc92011bcd67d11de53a3542d3fcb4d1239aa540d0b458a2863ebca9d07d7"}, ] mypy-boto3-appmesh = [ - {file = "mypy-boto3-appmesh-1.21.34.tar.gz", hash = "sha256:f59c73a4164bbbba79b86cde915691778e037138783b8dc7b36a0c50f041b471"}, - {file = "mypy_boto3_appmesh-1.21.34-py3-none-any.whl", hash = "sha256:69ce5b969d698953629e713c350e35e136d13a83560d4873a8ba14ee7aa56be7"}, + {file = "mypy-boto3-appmesh-1.23.0.post1.tar.gz", hash = "sha256:b7e3f521c070668d343f03b461efff01f864bc835bb2609e834dc03c1c21eae0"}, + {file = "mypy_boto3_appmesh-1.23.0.post1-py3-none-any.whl", hash = "sha256:33af5569919b3198dc76a399a734f8ffa9684cadc247663b8011bee31001ea98"}, ] mypy-boto3-apprunner = [ - {file = "mypy-boto3-apprunner-1.21.38.tar.gz", hash = "sha256:523a0b8d518769a33fc7096604510c004192cee291b7aa9a662bb8f5d17301c5"}, - {file = "mypy_boto3_apprunner-1.21.38-py3-none-any.whl", hash = "sha256:fed24c53e04e0b25aa973b3da99968ede8af8a4593ced37c0539ac99e602c626"}, + {file = "mypy-boto3-apprunner-1.23.0.post1.tar.gz", hash = "sha256:7080f49d9d19334f8740c72a27b2dd95cedff77488073c6d23dd3ea1966a991d"}, + {file = "mypy_boto3_apprunner-1.23.0.post1-py3-none-any.whl", hash = "sha256:4e9189cbb338060af109100e4c5082e147c729db3293ce3dca0759ce8c0ea44b"}, ] mypy-boto3-appstream = [ - {file = "mypy-boto3-appstream-1.21.41.tar.gz", hash = "sha256:22e1331f7c3f65ddf19b25f5fc543a958d301eb399b0cc491c3aee2242171022"}, - {file = "mypy_boto3_appstream-1.21.41-py3-none-any.whl", hash = "sha256:a4eba3e7a1cb7c5edde5ea0329941c053913e01cb22734036af05063a99cacca"}, + {file = "mypy-boto3-appstream-1.23.0.post1.tar.gz", hash = "sha256:21a6dca3625ad93e718f13f1dc1a1e6aa23d1357d48f3ac0174231c55ea9b2bd"}, + {file = "mypy_boto3_appstream-1.23.0.post1-py3-none-any.whl", hash = "sha256:17446e0af6fb1dac543b06c38aabc1c7c3c14ff6c593f62d14dab3eeca001679"}, ] mypy-boto3-appsync = [ - {file = "mypy-boto3-appsync-1.21.34.tar.gz", hash = "sha256:d0e2d4ce6c9d78d5c380701332481c1f996a1932f6900616a9ae4dc3c3f9e5be"}, - {file = "mypy_boto3_appsync-1.21.34-py3-none-any.whl", hash = "sha256:2979245f931b4a1b4e659c44e6761774dfa27de03c9f7686e22c17dc4339f997"}, + {file = "mypy-boto3-appsync-1.23.0.post1.tar.gz", hash = "sha256:a0cd5c33eba64dec40681a531e90c46ade5ee4fa0eec67c6300bc549ff3ce6e6"}, + {file = "mypy_boto3_appsync-1.23.0.post1-py3-none-any.whl", hash = "sha256:1599183dc8f8fafa229be650297c1c0b2e68c5b5e780e15dd1a20e7c025853e8"}, ] mypy-boto3-athena = [ - {file = "mypy-boto3-athena-1.21.42.tar.gz", hash = "sha256:63b184e8fd6fcd9d6e0e364fcfb1f9070fa39dbffacc7756417f5aca29e2151b"}, - {file = "mypy_boto3_athena-1.21.42-py3-none-any.whl", hash = "sha256:f1900aba025dcfefcda0780751e06fe1924cea652ecb83c9f2f9bfc06b3ac4db"}, + {file = "mypy-boto3-athena-1.23.0.post1.tar.gz", hash = "sha256:a71453ed20bae9648c86923452f5ca335350ce218f1274db31bc655a7be969f3"}, + {file = "mypy_boto3_athena-1.23.0.post1-py3-none-any.whl", hash = "sha256:4f69fcef55783ba34bb5355f20f81bdd0a04b4d27184543b050ad9428ff4b61a"}, ] mypy-boto3-auditmanager = [ - {file = "mypy-boto3-auditmanager-1.21.34.tar.gz", hash = "sha256:61084225b2788472c88f91a94f1132e33f604e76e6b2afb8b5410164f1bda529"}, - {file = "mypy_boto3_auditmanager-1.21.34-py3-none-any.whl", hash = "sha256:4702cd998e17a39b7eeb11b0f4888b04db2de132da76af702e93ca5d95691fd9"}, + {file = "mypy-boto3-auditmanager-1.23.0.post1.tar.gz", hash = "sha256:993dbf73ae8810915976fa7794142896bb70b86e10483f008a6c37072ea7a0b2"}, + {file = "mypy_boto3_auditmanager-1.23.0.post1-py3-none-any.whl", hash = "sha256:0104946879d63bd6af7e8bed6c61a4999ae6cb2629cafd3359919c0d8ff4c4c4"}, ] mypy-boto3-autoscaling = [ - {file = "mypy-boto3-autoscaling-1.21.43.tar.gz", hash = "sha256:bfedad9306b802d6df7ec6459e56323ed9b7bbcfd634b19176cbc2d2ee386f5a"}, - {file = "mypy_boto3_autoscaling-1.21.43-py3-none-any.whl", hash = "sha256:23259fcc7a415907e05a0960dad480fb8e12e271ce8787828843852e90fb2e27"}, + {file = "mypy-boto3-autoscaling-1.23.0.post1.tar.gz", hash = "sha256:3353c43b8052f1e9167ed2e1ceadfb7aff94feda2ff85bcccd525f1e3dfd17ab"}, + {file = "mypy_boto3_autoscaling-1.23.0.post1-py3-none-any.whl", hash = "sha256:3f293281b7314d6ce64cf5a3f810e336089fd1fd29e5acbfcc77a13a5f8ff262"}, ] mypy-boto3-autoscaling-plans = [ - {file = "mypy-boto3-autoscaling-plans-1.21.34.tar.gz", hash = "sha256:d2fb39976390c1b1e49ad1039c72491764bad0e1ccf06988662722e95f67862e"}, - {file = "mypy_boto3_autoscaling_plans-1.21.34-py3-none-any.whl", hash = "sha256:f4e36db336e079e9b45d2894d841b82b8fb64a028244e6fbb443e20576cd7072"}, + {file = "mypy-boto3-autoscaling-plans-1.23.0.post1.tar.gz", hash = "sha256:3e241db54caa48e25f2cd88b02cda2da96ab3cbb680708daa8e1e20f7c27b9ab"}, + {file = "mypy_boto3_autoscaling_plans-1.23.0.post1-py3-none-any.whl", hash = "sha256:58ac78e96dc62103af4d5c4306211b53805a90853acd561a93bcc027eb1a5f01"}, ] mypy-boto3-backup = [ - {file = "mypy-boto3-backup-1.21.34.tar.gz", hash = "sha256:24f129dec3c6300c7b36001cfcc8a0d2779572013c50a7574f2e687a5996ec22"}, - {file = "mypy_boto3_backup-1.21.34-py3-none-any.whl", hash = "sha256:f003f55e2c80417721c6b530f2838f3da0ad531cec45b3db8b9946405edeb631"}, + {file = "mypy-boto3-backup-1.23.0.post1.tar.gz", hash = "sha256:bc728420823b8f5ad725315809d0b225506a95926de22a09edd151197ae9e42d"}, + {file = "mypy_boto3_backup-1.23.0.post1-py3-none-any.whl", hash = "sha256:147b80a6240174adae08f88e2699e62692121664f29996e1dcb61ddd7ba8007d"}, ] mypy-boto3-backup-gateway = [ - {file = "mypy-boto3-backup-gateway-1.21.34.tar.gz", hash = "sha256:f4562e1276ab0c328666d664ebb6434deea00aafe1ef44cedbb678e72f984796"}, - {file = "mypy_boto3_backup_gateway-1.21.34-py3-none-any.whl", hash = "sha256:adf6e6d7ce8d52c0d5e12b4881690008a2c89aa80e25b06536a8a2526b760e23"}, + {file = "mypy-boto3-backup-gateway-1.23.0.post1.tar.gz", hash = "sha256:6ae5962ffdfa63ef608df369da1343fa9ca5626abca9cbbe4c33937c8544614f"}, + {file = "mypy_boto3_backup_gateway-1.23.0.post1-py3-none-any.whl", hash = "sha256:330ae80c9651139c2ca4d7b944221536ddbab7ec6bbd88e270f467ce289dcbcc"}, ] mypy-boto3-batch = [ - {file = "mypy-boto3-batch-1.21.41.tar.gz", hash = "sha256:b298527089774f8792a3cecac283b667a6f3650cd516998dc61fce7461adc2f0"}, - {file = "mypy_boto3_batch-1.21.41-py3-none-any.whl", hash = "sha256:04b40b2968248c0f18b82fc5661d32e1c611f1c7a8fb21bc87ff3c3dd4f8d677"}, + {file = "mypy-boto3-batch-1.23.0.post1.tar.gz", hash = "sha256:2e145ea6051b6e96d3312a8290feda3f7430053d0d8f2efe7de190d68eb8a855"}, + {file = "mypy_boto3_batch-1.23.0.post1-py3-none-any.whl", hash = "sha256:a0a1144a7f28b6973e81d992e62811b50a0e7a4649dd68adf44f2b05fdc1e105"}, ] mypy-boto3-braket = [ - {file = "mypy-boto3-braket-1.21.34.tar.gz", hash = "sha256:b67898f41033241b5b4fc5f29950f7786c90362460b4cc99be18bef0e9f28735"}, - {file = "mypy_boto3_braket-1.21.34-py3-none-any.whl", hash = "sha256:dff3b8485004d467adfb00f838c5e7687bf0cfe5ee7bb64c6e5771108a913a37"}, + {file = "mypy-boto3-braket-1.23.0.post1.tar.gz", hash = "sha256:a1d4ec9835eeb51c6b2b1b6f7baaabe4dc80e805fba7f09b80ac8b71f393d8b1"}, + {file = "mypy_boto3_braket-1.23.0.post1-py3-none-any.whl", hash = "sha256:6bf4ab0b78c4d10f9b374c897941f38da6c98babfcdaabfab84aad3364ee3579"}, ] mypy-boto3-budgets = [ - {file = "mypy-boto3-budgets-1.21.34.tar.gz", hash = "sha256:435abe6a347b1826eb616b1c76f35af337f9bb4df43cf65ec51778630983ba09"}, - {file = "mypy_boto3_budgets-1.21.34-py3-none-any.whl", hash = "sha256:6424c141aaed62f65cf950f47c4525170a7fd4471181f5d7c3362f81b75596a3"}, + {file = "mypy-boto3-budgets-1.23.0.post1.tar.gz", hash = "sha256:8d0226898ee4b2c89e0cbf4fd1003b937774f508fcae83c016c667c3ae5cdc16"}, + {file = "mypy_boto3_budgets-1.23.0.post1-py3-none-any.whl", hash = "sha256:0d1e1541a92f60746f4e40a13b23021ff1d14b21919eb76ddb3e310fd166b13e"}, ] mypy-boto3-ce = [ - {file = "mypy-boto3-ce-1.21.34.tar.gz", hash = "sha256:001d3546be8e1581da44b23bd8e3937ff1fac6588c6e8d4f747f94932f835354"}, - {file = "mypy_boto3_ce-1.21.34-py3-none-any.whl", hash = "sha256:9ab6a2935f2d321d4a7dda05d7808d84e569914a653ce337d64d96fafe45102e"}, + {file = "mypy-boto3-ce-1.23.0.post1.tar.gz", hash = "sha256:2d05e81c50eb6537749a119b16cba5f5b60d0be9f8a83e20b1cff2a92da5df53"}, + {file = "mypy_boto3_ce-1.23.0.post1-py3-none-any.whl", hash = "sha256:62e753cf2a5a1bab73a0a3ff4d5292b33ee6f785b18f96301acd88148837511c"}, ] mypy-boto3-chime = [ - {file = "mypy-boto3-chime-1.21.34.tar.gz", hash = "sha256:9114734f7b9249a24f2a90e2d2a325ba1b8daf7b491da7cefc99b1fcb0e2ef8b"}, - {file = "mypy_boto3_chime-1.21.34-py3-none-any.whl", hash = "sha256:a50531add102fd720f21dfb09784269e74837a479b3658b5f3f6463073b58300"}, + {file = "mypy-boto3-chime-1.23.0.post1.tar.gz", hash = "sha256:921ad71cba04bb0a5479a42775ace1cb1e282eaaccd5fec7204143146eecd3db"}, + {file = "mypy_boto3_chime-1.23.0.post1-py3-none-any.whl", hash = "sha256:1b2d1e5d9ce4cceccb5dec5cb71425e7d625ca2fb04d4f22948f3d8d9933f88a"}, ] mypy-boto3-chime-sdk-identity = [ - {file = "mypy-boto3-chime-sdk-identity-1.21.34.tar.gz", hash = "sha256:c22e397282d5dce9dc1c119be6f4254e43cc26a673dbc3d702d8991f42fab7cf"}, - {file = "mypy_boto3_chime_sdk_identity-1.21.34-py3-none-any.whl", hash = "sha256:9c2a17fd773657e9688aeeeedc6f247dab65a5e5facdd4f6be777db8969424b8"}, + {file = "mypy-boto3-chime-sdk-identity-1.23.0.post1.tar.gz", hash = "sha256:9c1496965d43bfc4d51773768ea15f9a946f4402a8450bfc6dbdd4addcb0e5b2"}, + {file = "mypy_boto3_chime_sdk_identity-1.23.0.post1-py3-none-any.whl", hash = "sha256:a8eaadf69d768877c70322db6aaf01e9078233f6194ecf612171882d4ed73b89"}, ] mypy-boto3-chime-sdk-meetings = [ - {file = "mypy-boto3-chime-sdk-meetings-1.21.46.tar.gz", hash = "sha256:d32a045c68810cc915faf5e11a2580b6e98a1a85dd4e5e14e8bc276746236a9c"}, - {file = "mypy_boto3_chime_sdk_meetings-1.21.46-py3-none-any.whl", hash = "sha256:3610df9578618e3c98e417175bd89c5802a64e49ecbf83a2f16fafe801c3a747"}, + {file = "mypy-boto3-chime-sdk-meetings-1.23.0.post1.tar.gz", hash = "sha256:3ea1f02a27408034e4d2aef14671cb3a01c4a50aed1bd0ae808afbc54fb9ffd5"}, + {file = "mypy_boto3_chime_sdk_meetings-1.23.0.post1-py3-none-any.whl", hash = "sha256:64d654085c3be443398b8f68b66055df0be06f43c9d1977ba22ef066dc32c6fd"}, ] mypy-boto3-chime-sdk-messaging = [ - {file = "mypy-boto3-chime-sdk-messaging-1.21.34.tar.gz", hash = "sha256:a0913759ea9391273486a3983566cf344082292178f9724b2d29d2c5119326cf"}, - {file = "mypy_boto3_chime_sdk_messaging-1.21.34-py3-none-any.whl", hash = "sha256:cb3d5b27b4ef165e01af4e11d8c1a4595af0a30cfef9599bc63ec6b4eca2b7d3"}, + {file = "mypy-boto3-chime-sdk-messaging-1.23.0.post1.tar.gz", hash = "sha256:52b41617aca19a700806c7f2442c26204792014abb061609f3c5f28bc3db2ee6"}, + {file = "mypy_boto3_chime_sdk_messaging-1.23.0.post1-py3-none-any.whl", hash = "sha256:3e3eff772a897de749b7a4c6e06e876ddb92aa3530c1d9ab72ff140d2cc604c9"}, ] mypy-boto3-cloud9 = [ - {file = "mypy-boto3-cloud9-1.21.34.tar.gz", hash = "sha256:9189cfea81552a02b37d58c8b9d426d5482b7e0c5b75d5905dd5740c7c61d7bf"}, - {file = "mypy_boto3_cloud9-1.21.34-py3-none-any.whl", hash = "sha256:944ab8aa53d4d24b7f81d1cabe48040164929748872a37d54f8b879f5f529640"}, + {file = "mypy-boto3-cloud9-1.23.0.post1.tar.gz", hash = "sha256:ab4cf72ef4a1b33a0c5104e36983faf84b01c45a063a0aa846bc11c383c67f0b"}, + {file = "mypy_boto3_cloud9-1.23.0.post1-py3-none-any.whl", hash = "sha256:66139a0b05df2bc88f7a78a849b30df170d0a20037c3274ec5bc56aded13d095"}, ] mypy-boto3-cloudcontrol = [ - {file = "mypy-boto3-cloudcontrol-1.21.34.tar.gz", hash = "sha256:335f80a9348da295f131638744da1005e8e396242c90a500470b4fe47adb408c"}, - {file = "mypy_boto3_cloudcontrol-1.21.34-py3-none-any.whl", hash = "sha256:6c23ef8050a4865f53b6c86850ba245a2774466136fe5c7bbe109f19add1678d"}, + {file = "mypy-boto3-cloudcontrol-1.23.0.post1.tar.gz", hash = "sha256:dc75d232021f3a7f0d02540d0e6e11f58e2da39043d19d0474798b1c2ae72ab2"}, + {file = "mypy_boto3_cloudcontrol-1.23.0.post1-py3-none-any.whl", hash = "sha256:3fdc2a4de133aa3e75f5d60cc3d38561f065a62ef2dc9a04a0c0eb08ea303384"}, ] mypy-boto3-clouddirectory = [ - {file = "mypy-boto3-clouddirectory-1.21.34.tar.gz", hash = "sha256:65005ca9ddf925c48cc70ca88f7a7fffc01d14e6d261ffd81d1021f327037437"}, - {file = "mypy_boto3_clouddirectory-1.21.34-py3-none-any.whl", hash = "sha256:f48114ec1eb4da8fcab46b811ef7294b50f4db96e16b40cb392613e89dabf5bc"}, + {file = "mypy-boto3-clouddirectory-1.23.0.post1.tar.gz", hash = "sha256:4adfba1e6ebebb6531124d8dd97bca7247771471dd045644e3ea0a407943cb5f"}, + {file = "mypy_boto3_clouddirectory-1.23.0.post1-py3-none-any.whl", hash = "sha256:4feede7da1b874cab2a1280ca789b64c89598f01ea5baf47376f73b5bee68378"}, ] mypy-boto3-cloudformation = [ - {file = "mypy-boto3-cloudformation-1.21.34.tar.gz", hash = "sha256:917ea9efca3571a52e15253af7d6230f7930fdaa8a896b59d42f938e799dd5d6"}, - {file = "mypy_boto3_cloudformation-1.21.34-py3-none-any.whl", hash = "sha256:e1100eb7885c15d48eb0fe0b7867d8245027b42a40a22c70fe62dc333e4c0f17"}, + {file = "mypy-boto3-cloudformation-1.23.0.post1.tar.gz", hash = "sha256:0ec7b1c837b1a7417a175fd38bae658283f4a7e23dfac434ecc68a0af007866b"}, + {file = "mypy_boto3_cloudformation-1.23.0.post1-py3-none-any.whl", hash = "sha256:e5780c54e2e75ece224d1bc9e07bf4d94e38a70c294fd22171d78c9da5351267"}, ] mypy-boto3-cloudfront = [ - {file = "mypy-boto3-cloudfront-1.21.34.tar.gz", hash = "sha256:de033d77997880ccf4869d19daa13c559c870a276cfb2fb3944963a85fa86afb"}, - {file = "mypy_boto3_cloudfront-1.21.34-py3-none-any.whl", hash = "sha256:dc37e37ee397eb93f64861b89a48bd42de8531ee393e4cc8ccee0ba5d340d1f9"}, + {file = "mypy-boto3-cloudfront-1.23.0.post1.tar.gz", hash = "sha256:cb345273941d11924922cb68bf82f7c8d57c862c355e8a5e0a8d859ce2683e91"}, + {file = "mypy_boto3_cloudfront-1.23.0.post1-py3-none-any.whl", hash = "sha256:f1fc78848b8f7f8324fc9fa01a592cea9802cb6f12cb56678bb277eddb09363f"}, ] mypy-boto3-cloudhsm = [ - {file = "mypy-boto3-cloudhsm-1.21.34.tar.gz", hash = "sha256:d0b20fa6b2c75c99f0abf67c84a5b01886800184345512348db4f26f3abbe7f4"}, - {file = "mypy_boto3_cloudhsm-1.21.34-py3-none-any.whl", hash = "sha256:fbd79cf588ca6857009c1496d6a5adcbb984950f06429ffb31b22fd6eba5f557"}, + {file = "mypy-boto3-cloudhsm-1.23.0.post1.tar.gz", hash = "sha256:a844fe170f79c70e772b61928c6d426d95437a665f5940c1f839ee870d748fa5"}, + {file = "mypy_boto3_cloudhsm-1.23.0.post1-py3-none-any.whl", hash = "sha256:698b5ec42d1d5472ef76c7640127880d346ccf5b6635a47e69a3204248645a82"}, ] mypy-boto3-cloudhsmv2 = [ - {file = "mypy-boto3-cloudhsmv2-1.21.34.tar.gz", hash = "sha256:228f25f50b667a1a90be1dd1f5f116d86352b62fdbbc563ffff96dcca78e3dc8"}, - {file = "mypy_boto3_cloudhsmv2-1.21.34-py3-none-any.whl", hash = "sha256:feb3931eab4accf257bce6761df089db7449574116307f43f2a1cac57a161d0b"}, + {file = "mypy-boto3-cloudhsmv2-1.23.0.post1.tar.gz", hash = "sha256:479e08640e0624a2a20e3795148de5c8470c15a6423fbdc7f2eb1bcf3750962f"}, + {file = "mypy_boto3_cloudhsmv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:64322932cefba56ffa5ab52f77e3a9ae748ce01a9824b461f02e4c1d90f39ce6"}, ] mypy-boto3-cloudsearch = [ - {file = "mypy-boto3-cloudsearch-1.21.34.tar.gz", hash = "sha256:6b5f865e57a7b41ec8d4e03df7f465e0384f1e359460d4f12a62131a1bdd1062"}, - {file = "mypy_boto3_cloudsearch-1.21.34-py3-none-any.whl", hash = "sha256:fff5ae0c65d362e7a2e5445f467a88fd95357e0ced0e2a89e6f57fd3dadd0d95"}, + {file = "mypy-boto3-cloudsearch-1.23.0.post1.tar.gz", hash = "sha256:d5b63d32703def240341a98410b3d5528ef868c76182f49480af899f50885a21"}, + {file = "mypy_boto3_cloudsearch-1.23.0.post1-py3-none-any.whl", hash = "sha256:0fa45849b15150783d890d125382c0772a3251e0745d52d21c5a68a96bd83f4f"}, ] mypy-boto3-cloudsearchdomain = [ - {file = "mypy-boto3-cloudsearchdomain-1.21.34.tar.gz", hash = "sha256:2c4fb330d4cb907c49ca401d11666ba6e2dec5f3450546bb0f987824117d5e6a"}, - {file = "mypy_boto3_cloudsearchdomain-1.21.34-py3-none-any.whl", hash = "sha256:4df4735f069effc83521d33d3543c89e0eb77934dcc4c608fd91aa4d88f3fae0"}, + {file = "mypy-boto3-cloudsearchdomain-1.23.0.post1.tar.gz", hash = "sha256:9efbe4da70c9c6a2c7151f1b1c7a2c957284049c0d570b72ed8beaa089982fa9"}, + {file = "mypy_boto3_cloudsearchdomain-1.23.0.post1-py3-none-any.whl", hash = "sha256:66af8f5654366b6e375b219a6ee5983c823834147ec3df455264a37cf885a8db"}, ] mypy-boto3-cloudtrail = [ - {file = "mypy-boto3-cloudtrail-1.21.34.tar.gz", hash = "sha256:8d56be609dd9111356f25764221a8e5323f7081064e27621b47308d1104bf689"}, - {file = "mypy_boto3_cloudtrail-1.21.34-py3-none-any.whl", hash = "sha256:5905187c641471fe5849be1edb857ec432ce7740b9ebfb8915b1507851e25776"}, + {file = "mypy-boto3-cloudtrail-1.23.0.post1.tar.gz", hash = "sha256:c53d77078efb5834f68009a1529f4f0dc693b5ea411cfe0de13e550e7b0e74dd"}, + {file = "mypy_boto3_cloudtrail-1.23.0.post1-py3-none-any.whl", hash = "sha256:dd482b23424e68efafde8a980c8bf0260a761bbec4c8cc8e8feb48835ff85362"}, ] mypy-boto3-cloudwatch = [ - {file = "mypy-boto3-cloudwatch-1.21.41.tar.gz", hash = "sha256:7b23c729dbbd463e598726d4067f9e3db53c614e84c88b47d63997731daaee87"}, - {file = "mypy_boto3_cloudwatch-1.21.41-py3-none-any.whl", hash = "sha256:1556a0f875717846a1937b38dde93b0117039019ccbf647a4434e48a65d10a62"}, + {file = "mypy-boto3-cloudwatch-1.23.0.post1.tar.gz", hash = "sha256:48215927dd5e801eb5bfdb50f79b370f6319b9437952a9d65266f554f50ee4c8"}, + {file = "mypy_boto3_cloudwatch-1.23.0.post1-py3-none-any.whl", hash = "sha256:6a96336ea8a1f4e172f63a1eebde46b7cb95f7b0accd4f09cbd6fe98a6673457"}, ] mypy-boto3-codeartifact = [ - {file = "mypy-boto3-codeartifact-1.21.34.tar.gz", hash = "sha256:d30684773ea235ca7622f75e8062476e1da424690a1690da1b9984db97e2c6bc"}, - {file = "mypy_boto3_codeartifact-1.21.34-py3-none-any.whl", hash = "sha256:1a03bb4943978476c3497f0e1f96dd01487b2503268739e88754848eca09bb71"}, + {file = "mypy-boto3-codeartifact-1.23.0.post1.tar.gz", hash = "sha256:4aad3622bd3363e0994928e3a958c4b68765e1c976e3478eeef8b157d53f54ef"}, + {file = "mypy_boto3_codeartifact-1.23.0.post1-py3-none-any.whl", hash = "sha256:02c1bcd6c013e8aacf12e7bb1089a1f982e42119e64ba286c85fc197e2a218c4"}, ] mypy-boto3-codebuild = [ - {file = "mypy-boto3-codebuild-1.21.34.tar.gz", hash = "sha256:9a90bf74be468b4f3683b530dd7552930df6b3ce57de92d9a5601fda9f832d06"}, - {file = "mypy_boto3_codebuild-1.21.34-py3-none-any.whl", hash = "sha256:052b4ff8521e1de531b186418c811ce5da6e23ffa84c9e8416f455a45a0d4a86"}, + {file = "mypy-boto3-codebuild-1.23.0.post1.tar.gz", hash = "sha256:ee7370c5282a4b44daa250bb40ae5aaaef6a496eb9d7530a5554a08ea737ff50"}, + {file = "mypy_boto3_codebuild-1.23.0.post1-py3-none-any.whl", hash = "sha256:e0495264842cf9a67091d2209cb037750456230721dcfe7870b6bb9043138db4"}, ] mypy-boto3-codecommit = [ - {file = "mypy-boto3-codecommit-1.21.34.tar.gz", hash = "sha256:ccc69bc92ae0629e402032c22f991895524a27abd8b7539d07371f0528cbb139"}, - {file = "mypy_boto3_codecommit-1.21.34-py3-none-any.whl", hash = "sha256:f3145cf398e2856163460d7233cd58c5725c32bc9487a777f680a641794a5ad0"}, + {file = "mypy-boto3-codecommit-1.23.0.post1.tar.gz", hash = "sha256:a72483591ad385a4e79bf948ebcdcf5efc1bc3af5d50e1c578a6368a95c66f72"}, + {file = "mypy_boto3_codecommit-1.23.0.post1-py3-none-any.whl", hash = "sha256:7fd7d29cd217526b3a0372aa1d96a4bdcfdb203e53b1846b16a70593c740a703"}, ] mypy-boto3-codedeploy = [ - {file = "mypy-boto3-codedeploy-1.21.34.tar.gz", hash = "sha256:2effc18ba68d48e12610a0c3246e60187928d58f56be8fa4c76087220c8bfea1"}, - {file = "mypy_boto3_codedeploy-1.21.34-py3-none-any.whl", hash = "sha256:7e78e13ac6b4c60f69b090bc1d4e9d5d2f304e15f07fbbee88b0b4b073f91934"}, + {file = "mypy-boto3-codedeploy-1.23.0.post1.tar.gz", hash = "sha256:804e3308a07eaed32909deeaef3adc5c6a487e6e3a63c9c7c6993f45eb7d7c3e"}, + {file = "mypy_boto3_codedeploy-1.23.0.post1-py3-none-any.whl", hash = "sha256:6cb0a9cebc535de25bbdc682e90377e24bc576cf2f649c4db6673bfdc75e4096"}, ] mypy-boto3-codeguru-reviewer = [ - {file = "mypy-boto3-codeguru-reviewer-1.21.34.tar.gz", hash = "sha256:441d65a480008517e885a197173e45ad2df3853e3b29839661fbbba812411fab"}, - {file = "mypy_boto3_codeguru_reviewer-1.21.34-py3-none-any.whl", hash = "sha256:6ecf3f989e45fccf63097b41eb015047bab29e1803533cf9c52b494fbd53b8aa"}, + {file = "mypy-boto3-codeguru-reviewer-1.23.0.post1.tar.gz", hash = "sha256:4c9e578721ac3e9fe0e6d7829f369e10f4aa0cc041dced9cc612ffb9a8b80a92"}, + {file = "mypy_boto3_codeguru_reviewer-1.23.0.post1-py3-none-any.whl", hash = "sha256:113411a70d42930930b937b5aeb5363bbd562c30dae824d6f1bf2fb805cbeb0c"}, ] mypy-boto3-codeguruprofiler = [ - {file = "mypy-boto3-codeguruprofiler-1.21.34.tar.gz", hash = "sha256:338009f2827ff51ef12a543318dc001b347a7d9d698d85d4eafc356a85d22e96"}, - {file = "mypy_boto3_codeguruprofiler-1.21.34-py3-none-any.whl", hash = "sha256:1652363e4fb74bca3ceeab9dde271b43bb65bf57bb51125a818553cc9e9c47e2"}, + {file = "mypy-boto3-codeguruprofiler-1.23.0.post1.tar.gz", hash = "sha256:d397632ad05486cd10b33fae1ce516482e83e27d7c060e97aeb3986a94873df0"}, + {file = "mypy_boto3_codeguruprofiler-1.23.0.post1-py3-none-any.whl", hash = "sha256:8d19d0fd65a784aac72871b540cc4249c4f79676cc66401cc03aab4389b50a15"}, ] mypy-boto3-codepipeline = [ - {file = "mypy-boto3-codepipeline-1.21.34.tar.gz", hash = "sha256:6fc664dae48dff73d4646de24e3da8457ae68be050f0c8a627f7c8cfb297adaa"}, - {file = "mypy_boto3_codepipeline-1.21.34-py3-none-any.whl", hash = "sha256:d120fb4e9ff266e0a72121afd72235e3dc0e53ec3ecc59b8bb0a71f4b82a6c40"}, + {file = "mypy-boto3-codepipeline-1.23.0.post1.tar.gz", hash = "sha256:98dad99437f5a8bf94c2e23dba7f79725c414a8b7f6975376da64054da84e989"}, + {file = "mypy_boto3_codepipeline-1.23.0.post1-py3-none-any.whl", hash = "sha256:1fafc20944a493e806a68becea49f7730f95021fc56442edc9fa554225725254"}, ] mypy-boto3-codestar = [ - {file = "mypy-boto3-codestar-1.21.34.tar.gz", hash = "sha256:9c99fb6afaddba809bcf790a6b301cb57ec96ebfd6e9fb2ed851ff0840f4cd3d"}, - {file = "mypy_boto3_codestar-1.21.34-py3-none-any.whl", hash = "sha256:b03d6166f83742cdc67ebbcdcfb75947b1a7b0890d054b3c0d9ceefd89547394"}, + {file = "mypy-boto3-codestar-1.23.0.post1.tar.gz", hash = "sha256:f6c95b39c5dde775b815fa2f2c833bf34835dfe90fdb303c71881267ad1a996f"}, + {file = "mypy_boto3_codestar-1.23.0.post1-py3-none-any.whl", hash = "sha256:0e2df7e92bbf8d04227fd29aadabd3d2bb07604a15c91a445258565e5e8aa80a"}, ] mypy-boto3-codestar-connections = [ - {file = "mypy-boto3-codestar-connections-1.21.34.tar.gz", hash = "sha256:20c1536899ea592c6cf5b07eabc1bc8996d7072c623442575f65b3adc5036b21"}, - {file = "mypy_boto3_codestar_connections-1.21.34-py3-none-any.whl", hash = "sha256:6f5b338077a0548abbddf5ab2a15b32cf53b779262ab3f98e7f824b0247475d2"}, + {file = "mypy-boto3-codestar-connections-1.23.0.post1.tar.gz", hash = "sha256:e83b4fb2dfc50f8108b89c1caf570021e350385e5bc32c52ef7143856d256bbe"}, + {file = "mypy_boto3_codestar_connections-1.23.0.post1-py3-none-any.whl", hash = "sha256:fe2ff441b9df5a69cab4614b70de5b2aa759886f797a5e575abbfe3b9ea4c839"}, ] mypy-boto3-codestar-notifications = [ - {file = "mypy-boto3-codestar-notifications-1.21.34.tar.gz", hash = "sha256:ded5da3219c3cedf6b70616590adf6311359b521c8724bc74e12bc63367d9a89"}, - {file = "mypy_boto3_codestar_notifications-1.21.34-py3-none-any.whl", hash = "sha256:d1ed610f542724f7bc7f59bacc21f33e241ef4c0903f77d179e8985d4a536287"}, + {file = "mypy-boto3-codestar-notifications-1.23.0.post1.tar.gz", hash = "sha256:ff1533831416313ae81fe3ef635f655cbb537f1f4fad2852c874b98fcd29e512"}, + {file = "mypy_boto3_codestar_notifications-1.23.0.post1-py3-none-any.whl", hash = "sha256:71e62286f58f24640d5c323728ad9316755dc89bffff7245998fa548bddbd15d"}, ] mypy-boto3-cognito-identity = [ - {file = "mypy-boto3-cognito-identity-1.21.34.tar.gz", hash = "sha256:3a782d7bc6fac329757ce5117841009594ae0efdb9030dbcaf2b660a7ddfcbcc"}, - {file = "mypy_boto3_cognito_identity-1.21.34-py3-none-any.whl", hash = "sha256:d9cacf36da8e7889f74088454f4e1d45232cc218117cf3ec17f23953cf047dfc"}, + {file = "mypy-boto3-cognito-identity-1.23.0.post1.tar.gz", hash = "sha256:62c9ac225e3cd274e31413e74de08f390b5048df20e3e2647db96a29e96de72a"}, + {file = "mypy_boto3_cognito_identity-1.23.0.post1-py3-none-any.whl", hash = "sha256:5c01f9e1b5fcbbb7156b98aa5f462ae8f37b326da2ca960f04ceda39bd9e6eb4"}, ] mypy-boto3-cognito-idp = [ - {file = "mypy-boto3-cognito-idp-1.21.34.tar.gz", hash = "sha256:c7081a55635de0d6d36540b0122bf93877d0b7d8ae5e86ce01e958288fc5a5d9"}, - {file = "mypy_boto3_cognito_idp-1.21.34-py3-none-any.whl", hash = "sha256:602ba446031ce986753a7d91f1cbd5a9bc859dadc125add972359ad105db2aff"}, + {file = "mypy-boto3-cognito-idp-1.23.0.post1.tar.gz", hash = "sha256:8474cc12482ac0eea8f1892b206779ff6c3589ec11db1ae5fc27ffaa17eca0d8"}, + {file = "mypy_boto3_cognito_idp-1.23.0.post1-py3-none-any.whl", hash = "sha256:0b863cdeb64a54c99a9200706dddd1952c097a79860f18814d247272274549a8"}, ] mypy-boto3-cognito-sync = [ - {file = "mypy-boto3-cognito-sync-1.21.34.tar.gz", hash = "sha256:5210c7a35bbb181d6a5093807b91aac045c4e84d40e6458a02894af5c2f536d4"}, - {file = "mypy_boto3_cognito_sync-1.21.34-py3-none-any.whl", hash = "sha256:b47014cd3a0913ec147818e5791315b7a3ed8c9d57e363d75a71a7b334c96fcf"}, + {file = "mypy-boto3-cognito-sync-1.23.0.post1.tar.gz", hash = "sha256:3cecb6a02efaa1ba84804fe35e28fa8f33e9050363c7e9afa806060979b91798"}, + {file = "mypy_boto3_cognito_sync-1.23.0.post1-py3-none-any.whl", hash = "sha256:e964e2736617c1a3aa467f942b64280e02eb181ddfda5adf2829cd7f36e48bcb"}, ] mypy-boto3-comprehend = [ - {file = "mypy-boto3-comprehend-1.21.34.tar.gz", hash = "sha256:7ec56a4c4a2381806a9f67c2dea7e29838480c9edcb7f56454a07e392b0062e5"}, - {file = "mypy_boto3_comprehend-1.21.34-py3-none-any.whl", hash = "sha256:66f3b64120685e84fcae6fb649b14123ed7252407c47947f6a35718b6d33493e"}, + {file = "mypy-boto3-comprehend-1.23.0.post1.tar.gz", hash = "sha256:7a17467c849b2ffed9ce74128466eaee8119a91b6cb8b77ca2bcd58375142691"}, + {file = "mypy_boto3_comprehend-1.23.0.post1-py3-none-any.whl", hash = "sha256:c29ab1f10bfbde0f808e4945fd6eb4f86a5eeb9b217d13ba673a28dceb90fdba"}, ] mypy-boto3-comprehendmedical = [ - {file = "mypy-boto3-comprehendmedical-1.21.34.tar.gz", hash = "sha256:731890d878e0a57dab6864b3303a4bbbe9288b8316ec10d2b40df340d46fc498"}, - {file = "mypy_boto3_comprehendmedical-1.21.34-py3-none-any.whl", hash = "sha256:c4dec5883e2ccf224d980ca6b312efff8160460dd96f27eef626996e946f7754"}, + {file = "mypy-boto3-comprehendmedical-1.23.0.post1.tar.gz", hash = "sha256:8c3ff45e519c81402f5be35b917a539cbce45cb7be1c0e971d7fd72a0c7c765b"}, + {file = "mypy_boto3_comprehendmedical-1.23.0.post1-py3-none-any.whl", hash = "sha256:439ac77bb5491965cd54640a4b1780ec9e33eecc6982b06f8c035a02d79be439"}, ] mypy-boto3-compute-optimizer = [ - {file = "mypy-boto3-compute-optimizer-1.21.34.tar.gz", hash = "sha256:b77f6acb6f715e7b8583d8ef6808884e39a41869df4707d1d855ed5e2661f07a"}, - {file = "mypy_boto3_compute_optimizer-1.21.34-py3-none-any.whl", hash = "sha256:3943809139dee98a895293a8a134cde1a8dc99ca554848285825dd5c9b5990d2"}, + {file = "mypy-boto3-compute-optimizer-1.23.0.post1.tar.gz", hash = "sha256:024a48065b9f38f10bff802d6dfd61714895841dbd4a20359b4cdd05fb6bcb1a"}, + {file = "mypy_boto3_compute_optimizer-1.23.0.post1-py3-none-any.whl", hash = "sha256:663c4ba32d82406176ad348b7f9657dbeffb0a5cde60515b759d29a22310ad21"}, ] mypy-boto3-config = [ - {file = "mypy-boto3-config-1.21.35.tar.gz", hash = "sha256:b515c62bbe5e40c5556cba1256064f9c66299aafb10809d5d6238c5b7027ca26"}, - {file = "mypy_boto3_config-1.21.35-py3-none-any.whl", hash = "sha256:f05731a038aada8075a5640a134958d787f92cc1131b304301d9d3ff0a615de7"}, + {file = "mypy-boto3-config-1.23.0.post1.tar.gz", hash = "sha256:84d9458394c90bb1a4293208deedac1837db765d62b0506c0783e06f9bd4ae12"}, + {file = "mypy_boto3_config-1.23.0.post1-py3-none-any.whl", hash = "sha256:bcf3ef1482437e5ea8d79a9f99d0ad2251f365786a6868ffca745da3732a5828"}, ] mypy-boto3-connect = [ - {file = "mypy-boto3-connect-1.21.44.tar.gz", hash = "sha256:1e4b8c082128c0975e53a480d505d8b2edef5ced20effdc435b38eb0e3a281a0"}, - {file = "mypy_boto3_connect-1.21.44-py3-none-any.whl", hash = "sha256:f4c669193898f7f9f74f04dd698fb8e7ca721a49562a780303b7ffdfb8247bd3"}, + {file = "mypy-boto3-connect-1.23.0.post1.tar.gz", hash = "sha256:c905a1dcf690ce88ee985f2ebbaf2b8732647129b61501b092e1c0dddeb6bea6"}, + {file = "mypy_boto3_connect-1.23.0.post1-py3-none-any.whl", hash = "sha256:d35ac313b219236e0e9c3aac5c968cc500cf406d029148af2112c0d90fc39f04"}, ] mypy-boto3-connect-contact-lens = [ - {file = "mypy-boto3-connect-contact-lens-1.21.34.tar.gz", hash = "sha256:f3d5de92be555e881e9b2e7729bfa4203fe69572f82ba20f01b844a932db756c"}, - {file = "mypy_boto3_connect_contact_lens-1.21.34-py3-none-any.whl", hash = "sha256:534a28e2ec9e834b1333b109d114932c0f7d1e01fa9d3c6f885ecf57787b7f00"}, + {file = "mypy-boto3-connect-contact-lens-1.23.0.post1.tar.gz", hash = "sha256:1ee2487fffa2ac9e29fb4d8c640030efe8ba3f8bff632a5ffc04583ec1e2b8a5"}, + {file = "mypy_boto3_connect_contact_lens-1.23.0.post1-py3-none-any.whl", hash = "sha256:4c733d5a6dfe1155df5bfb7b585f4afbb11aaf1b3ed6c55f481b313cb515943d"}, ] mypy-boto3-connectparticipant = [ - {file = "mypy-boto3-connectparticipant-1.21.34.tar.gz", hash = "sha256:7f0702b40c9c3d022d1ae1596b4f3f19ad7eb89633c833f8f0bdbad230952287"}, - {file = "mypy_boto3_connectparticipant-1.21.34-py3-none-any.whl", hash = "sha256:101435607372bcb29ddb9468f0141eb4d09626d3e362d1bb148838ccaab9e9d9"}, + {file = "mypy-boto3-connectparticipant-1.23.0.post1.tar.gz", hash = "sha256:b8f8af38e8d3e561192b1de2c900a8d69d5fef5e16617f5df7e733e4965ffec8"}, + {file = "mypy_boto3_connectparticipant-1.23.0.post1-py3-none-any.whl", hash = "sha256:2c97ca156dafaf1ce783bbaa1e9e399aedc6cb751de20837b5b6eacf71a0fe3f"}, ] mypy-boto3-cur = [ - {file = "mypy-boto3-cur-1.21.34.tar.gz", hash = "sha256:7a3fa135b5349f9722188ad1c91f3e9378ff942321893abac9affa429af6c2ee"}, - {file = "mypy_boto3_cur-1.21.34-py3-none-any.whl", hash = "sha256:9cc4836449e71fbfcd67cc4d2e70205bea5d8003e25c5cbc73882ac8f31d5b0a"}, + {file = "mypy-boto3-cur-1.23.0.post1.tar.gz", hash = "sha256:95726fd717b58ff00a96984d0b816ca30617d24f36f98ef1a0d88ff73ee37702"}, + {file = "mypy_boto3_cur-1.23.0.post1-py3-none-any.whl", hash = "sha256:8b628e0e0b21be00224d0ebb35b75f284434fc76fe972d8b3e53c413b5f29556"}, ] mypy-boto3-customer-profiles = [ - {file = "mypy-boto3-customer-profiles-1.21.34.tar.gz", hash = "sha256:da0980434735c20dd42179c1e47292c3322468167cf98d5d49113ba4479de2b3"}, - {file = "mypy_boto3_customer_profiles-1.21.34-py3-none-any.whl", hash = "sha256:3345ed733e8bd26be7b86a4426f21e9c9a0e84b383264a82fd1214c42b8cdaf4"}, + {file = "mypy-boto3-customer-profiles-1.23.0.post1.tar.gz", hash = "sha256:bd58e4d5034795516e000d2b2102fb1893cac69e4c94f625133966c54a1086bb"}, + {file = "mypy_boto3_customer_profiles-1.23.0.post1-py3-none-any.whl", hash = "sha256:825b78c8ec2b210c2089e9daab9a6e296133d6f4eed2b81290fe157ef7bc5765"}, ] mypy-boto3-databrew = [ - {file = "mypy-boto3-databrew-1.21.34.tar.gz", hash = "sha256:2ec295ccef2f6b3ebdb1ac75cd0cd577f5ab5caf8326732cb438e5f6a78a5cfe"}, - {file = "mypy_boto3_databrew-1.21.34-py3-none-any.whl", hash = "sha256:4b59dd556299faf0009e489298b8ece4d83a6ebb49871d4d7e8ac2f9586cc82b"}, + {file = "mypy-boto3-databrew-1.23.0.post1.tar.gz", hash = "sha256:ba3917d492cd187a53ccf93f3b585f4fe3a4bb954f38fb783bca0a49cfe90871"}, + {file = "mypy_boto3_databrew-1.23.0.post1-py3-none-any.whl", hash = "sha256:4b3129ce062573ffe7b785df0b6ee5d4d8b0cc09eb3f59eb8da5617d8e9beeab"}, ] mypy-boto3-dataexchange = [ - {file = "mypy-boto3-dataexchange-1.21.34.tar.gz", hash = "sha256:cbfee542bc6c1f12b78e3c723c5050022bf2f3a279f94cc6617cf07413721a17"}, - {file = "mypy_boto3_dataexchange-1.21.34-py3-none-any.whl", hash = "sha256:26a8e099a9090748b14bac77fd336df1b87d00798f2a285a60c317d7458f5bdc"}, + {file = "mypy-boto3-dataexchange-1.23.0.post1.tar.gz", hash = "sha256:4d27429e9cfec8ab33175734cc3c721bdf380b81e6cbe7669c3441274e0ce132"}, + {file = "mypy_boto3_dataexchange-1.23.0.post1-py3-none-any.whl", hash = "sha256:15cc8bd94f80ebf7eea4ebd13dff5304b501577a98dc8b836f7d13ce2a74cff3"}, ] mypy-boto3-datapipeline = [ - {file = "mypy-boto3-datapipeline-1.21.34.tar.gz", hash = "sha256:7937835c7e63d44fbfb73f4f176a426b2ffa4710ae21c6cc681e0226eddcbfbf"}, - {file = "mypy_boto3_datapipeline-1.21.34-py3-none-any.whl", hash = "sha256:d995ca7376d7ead430c2cd5b6fdb79aaf3dacba266afff7718b805f0691c5982"}, + {file = "mypy-boto3-datapipeline-1.23.0.post1.tar.gz", hash = "sha256:cebbf15bc6b03be8f7dcb371930f0a0939da2075e60f306b87fcd85db4e79663"}, + {file = "mypy_boto3_datapipeline-1.23.0.post1-py3-none-any.whl", hash = "sha256:5af65beabd03fc69e4e4b5424ea52a57ab6d04db88057422fa957d8bf837b023"}, ] mypy-boto3-datasync = [ - {file = "mypy-boto3-datasync-1.21.34.post1.tar.gz", hash = "sha256:e8c7fcace1722e6bbc79e69b8c920fa18172fe8f1d5b81e374422866c0494936"}, - {file = "mypy_boto3_datasync-1.21.34.post1-py3-none-any.whl", hash = "sha256:cdfaa9ec8d405f3f0360ca1c9f2f647d6cbae8a09c53cbd4f85e3fe57b440555"}, + {file = "mypy-boto3-datasync-1.23.0.post1.tar.gz", hash = "sha256:1786d012e7b9ff332ea8e5a35b0be04812d040871ab87feb5c6aa1a751acf0bf"}, + {file = "mypy_boto3_datasync-1.23.0.post1-py3-none-any.whl", hash = "sha256:3cb2e2d20a214884b87fddb7cdd0b8cbab10f99682eba5be5f121911770aa4e3"}, ] mypy-boto3-dax = [ - {file = "mypy-boto3-dax-1.21.34.tar.gz", hash = "sha256:8d599edf33320f3e5165a681eba9ed2ea0ad731f48a4a361c8703339e43b81a5"}, - {file = "mypy_boto3_dax-1.21.34-py3-none-any.whl", hash = "sha256:7786aac6b471a090226535708b9d1201fd9eba8a01db7227f2b921148d2bfa08"}, + {file = "mypy-boto3-dax-1.23.0.post1.tar.gz", hash = "sha256:e521a562d16dc1c1d5cb752381b135e041f00ba0755f211b31d10472d385e151"}, + {file = "mypy_boto3_dax-1.23.0.post1-py3-none-any.whl", hash = "sha256:9eb4d250edb53a29b63ba8efae5e59a5ff1559e92e61ddee57e3645758a19ff8"}, ] mypy-boto3-detective = [ - {file = "mypy-boto3-detective-1.21.34.tar.gz", hash = "sha256:a222a911378772a62d3569f5ef39c444fb8ac81182d6d85eb31d2a73aca993e4"}, - {file = "mypy_boto3_detective-1.21.34-py3-none-any.whl", hash = "sha256:6f5583444e221fd5770bdfe98477545eebdf9d463a8d3ff0fbdeb95e65d1deb3"}, + {file = "mypy-boto3-detective-1.23.0.post1.tar.gz", hash = "sha256:c06571071c7028ad5bc0d8c729d2625ca496eda8aee588f88ecd2229bea5f6c6"}, + {file = "mypy_boto3_detective-1.23.0.post1-py3-none-any.whl", hash = "sha256:79ad24c06521cba7e8ae01a10051c9f656216a224fa4bc4096539d897735ec42"}, ] mypy-boto3-devicefarm = [ - {file = "mypy-boto3-devicefarm-1.21.34.tar.gz", hash = "sha256:6a16f49dfba1e692b6913048d97f6b9c0fd48d4ccf216ac8777490dec75e1dbb"}, - {file = "mypy_boto3_devicefarm-1.21.34-py3-none-any.whl", hash = "sha256:7b6171b136770b86b83ec8e9b2b9d6bfb8de5f844b7873bc190066659b016bb5"}, + {file = "mypy-boto3-devicefarm-1.23.0.post1.tar.gz", hash = "sha256:ebf49365ae780ad6e41daca3690af3472f52ef89a502b0f04a148db392239212"}, + {file = "mypy_boto3_devicefarm-1.23.0.post1-py3-none-any.whl", hash = "sha256:3008eb8607d388bacd7c9f7630107e638b48d09b016a1b05c52fa042792f5d06"}, ] mypy-boto3-devops-guru = [ - {file = "mypy-boto3-devops-guru-1.21.39.tar.gz", hash = "sha256:9c099f1c3fab9205a2757b6783d76c63a08b9e324b6c8c6aca31e7f35ea602f8"}, - {file = "mypy_boto3_devops_guru-1.21.39-py3-none-any.whl", hash = "sha256:ecf92f97b5dcf39449823d5a955371cda01e4ae1cfd279284d71e82950120f02"}, + {file = "mypy-boto3-devops-guru-1.23.0.post1.tar.gz", hash = "sha256:222c435e1ab0dc02c0c628d3ed61e7778dd91967d20944efb0903691aa3af1fb"}, + {file = "mypy_boto3_devops_guru-1.23.0.post1-py3-none-any.whl", hash = "sha256:116a1040e1c98f3905458a47bb4e40d383c72d916b4776fc048b33b7c45ece40"}, ] mypy-boto3-directconnect = [ - {file = "mypy-boto3-directconnect-1.21.34.tar.gz", hash = "sha256:a740f270420654efb96f759a96faefb89838f1a1d6a14569926ad840f63556d5"}, - {file = "mypy_boto3_directconnect-1.21.34-py3-none-any.whl", hash = "sha256:0da47cedbb037d9eebfd80f425e512807e55ebffc654c04bd39f4ce97a6a02f7"}, + {file = "mypy-boto3-directconnect-1.23.0.post1.tar.gz", hash = "sha256:d52470a2b73917b7a167da0c2e476a00a11faff07a4b8c22a234f4e99bf83376"}, + {file = "mypy_boto3_directconnect-1.23.0.post1-py3-none-any.whl", hash = "sha256:60fe913b026dcd21d7a63c6aea4290cd3bf3119089892b2d840445de7ba788ff"}, ] mypy-boto3-discovery = [ - {file = "mypy-boto3-discovery-1.21.34.tar.gz", hash = "sha256:0d4c37b72f8c39e2a9a583000c6042e4baae64ee687e68a2bf4487cb532507e3"}, - {file = "mypy_boto3_discovery-1.21.34-py3-none-any.whl", hash = "sha256:165230726ba7d7e5a367cf6412294c83dd8e4becb39b74f3eab6fe8690ee4814"}, + {file = "mypy-boto3-discovery-1.23.0.post1.tar.gz", hash = "sha256:e571f6c2be02c5d666ee0e214551ffbfedd9825df19f803db0c93e637a024100"}, + {file = "mypy_boto3_discovery-1.23.0.post1-py3-none-any.whl", hash = "sha256:403818b200b57606de149c067e184a0341c4d72a8f4d87561570094914bd7fb9"}, ] mypy-boto3-dlm = [ - {file = "mypy-boto3-dlm-1.21.34.tar.gz", hash = "sha256:fffa96c100745704040cefff29a7ce5729a16777878f2bfe814a8e7570f4de37"}, - {file = "mypy_boto3_dlm-1.21.34-py3-none-any.whl", hash = "sha256:d5008430ec908b5fbf01f7673fb9382225c955d6bf0807a2322686807514225b"}, + {file = "mypy-boto3-dlm-1.23.0.post1.tar.gz", hash = "sha256:e2d4e68f064e2e5bc41d368a5f568e38273e322cde15405787ece6d330c05f69"}, + {file = "mypy_boto3_dlm-1.23.0.post1-py3-none-any.whl", hash = "sha256:d37117c1396708d2a624c261fc6e19884ee92d1b2f0459e60d970c6d654bec2a"}, ] mypy-boto3-dms = [ - {file = "mypy-boto3-dms-1.21.34.tar.gz", hash = "sha256:439d714d7ac91aa9046e49dadb252691fcd37f9a8f45151125dba3680fd39763"}, - {file = "mypy_boto3_dms-1.21.34-py3-none-any.whl", hash = "sha256:c36c52d3d3df39d6c00ef63aca4cf2e0a9094c9ef4ea1e5aba41f3449fc1ddcc"}, + {file = "mypy-boto3-dms-1.23.0.post1.tar.gz", hash = "sha256:cd484542c6a016d1f7ce53beea35eb96d5e90df7129808316254d3135ac7f519"}, + {file = "mypy_boto3_dms-1.23.0.post1-py3-none-any.whl", hash = "sha256:ae92e541973d493af5ac0355915d73c4f2d20fbea3561cd5342164b2056b6246"}, ] mypy-boto3-docdb = [ - {file = "mypy-boto3-docdb-1.21.36.tar.gz", hash = "sha256:a1eb1eba1c18bd149f6ab497c66e7770af66cc0500d673092d88d7ec256d70ba"}, - {file = "mypy_boto3_docdb-1.21.36-py3-none-any.whl", hash = "sha256:1a4f03d52462b6e2ab45b0f38a00ab72202bda0e58b4ef61255c8a6c1a442bfc"}, + {file = "mypy-boto3-docdb-1.23.0.post1.tar.gz", hash = "sha256:bc668ef1e0f571451fed1755954af2291774186ab35ebbdb3e9f82d244fc1db1"}, + {file = "mypy_boto3_docdb-1.23.0.post1-py3-none-any.whl", hash = "sha256:5808f41160d1dfb996ef16f6826bc6247865e60b04d986a03ebdaa84fe605dc0"}, ] mypy-boto3-drs = [ - {file = "mypy-boto3-drs-1.21.34.tar.gz", hash = "sha256:6a41e08c92a4c2ec05343515de8466de455904bb500ecb2cc3e33fae70110c30"}, - {file = "mypy_boto3_drs-1.21.34-py3-none-any.whl", hash = "sha256:e70ba2433a25131d7bbd26c0364c525d71e5111f07af717cc575cbd5a719a5eb"}, + {file = "mypy-boto3-drs-1.23.0.post1.tar.gz", hash = "sha256:e16eeb9eb038f987e27e7add0d5c98cada85d4b39ad2359b67c40f45d89df76f"}, + {file = "mypy_boto3_drs-1.23.0.post1-py3-none-any.whl", hash = "sha256:bdd0ce92f1106c56c8dc202d555a8d79d35a24b4758143cb0f59b147b21d6f5b"}, ] mypy-boto3-ds = [ - {file = "mypy-boto3-ds-1.21.34.tar.gz", hash = "sha256:56a165c4fd0dadfbef9f9cc17662ef8d686ca9892823dce0261e27dfa8731405"}, - {file = "mypy_boto3_ds-1.21.34-py3-none-any.whl", hash = "sha256:7129d08a3544c91ee22f39c3a60de259386554714890173e891dafb2e6925151"}, + {file = "mypy-boto3-ds-1.23.0.post1.tar.gz", hash = "sha256:c5929a1990d6a466bb6bb3cf82b0e2e44961d5e5af9d846a0e03a19d95ca2de6"}, + {file = "mypy_boto3_ds-1.23.0.post1-py3-none-any.whl", hash = "sha256:937ca32bf83826463463228abcd5c04205551babf92401993308f4166cbe8a01"}, ] mypy-boto3-dynamodb = [ - {file = "mypy-boto3-dynamodb-1.21.34.tar.gz", hash = "sha256:cc64ac08a60c24f2839d990605561a3bc5f61e4a5a947679f73c0e125e9c8d4c"}, - {file = "mypy_boto3_dynamodb-1.21.34-py3-none-any.whl", hash = "sha256:3edfdd25befc8efccba9807bf720d54d06dc948e434976ae3dd7f47189d3319c"}, + {file = "mypy-boto3-dynamodb-1.23.0.post1.tar.gz", hash = "sha256:4670825645d041881f3f37a70b38e4b771171942808e49a011a63a9ea6cf494c"}, + {file = "mypy_boto3_dynamodb-1.23.0.post1-py3-none-any.whl", hash = "sha256:fed40bd6e987d4dbe2551b2a33106f23965111570e0a84e9e7a3caf65d1c79f9"}, ] mypy-boto3-dynamodbstreams = [ - {file = "mypy-boto3-dynamodbstreams-1.21.34.tar.gz", hash = "sha256:33e758f12d752d35b66ed898e550a7254d4e5eab52ca917aa5298eb0dafdd8e7"}, - {file = "mypy_boto3_dynamodbstreams-1.21.34-py3-none-any.whl", hash = "sha256:3ec7b931726261339a9e10becdc7c8bcfc03d010d7b46e5ec9782253c3ce1a1b"}, + {file = "mypy-boto3-dynamodbstreams-1.23.0.post1.tar.gz", hash = "sha256:32e3134a3d330cf83f475e888f2e3bc6175f0d00ab3dbf1e804827e8be21367c"}, + {file = "mypy_boto3_dynamodbstreams-1.23.0.post1-py3-none-any.whl", hash = "sha256:97a01094e86d88b7c39beaeac33256851a9614da11adf5b6b6cf4ea7f805ba92"}, ] mypy-boto3-ebs = [ - {file = "mypy-boto3-ebs-1.21.34.tar.gz", hash = "sha256:464611aefefc83f59819958fde561fec0c23f0b2277cf1082b5db5b94edd2b3c"}, - {file = "mypy_boto3_ebs-1.21.34-py3-none-any.whl", hash = "sha256:b6b9a00783b91ab948ae724d9c01219e28101504e6dc35bdffc2c6edaef01567"}, + {file = "mypy-boto3-ebs-1.23.0.post1.tar.gz", hash = "sha256:beb292f38fb2d3217f18852c09ae62271721848fdf79dad7b5e32c498758a494"}, + {file = "mypy_boto3_ebs-1.23.0.post1-py3-none-any.whl", hash = "sha256:f22585c12dcc6b10124b4d0f30f301c014dc0f98aee768970e1066bb6f443f2a"}, ] mypy-boto3-ec2 = [ - {file = "mypy-boto3-ec2-1.21.46.tar.gz", hash = "sha256:d2f36766c8454763d34ba59ffca1ccf30cac5a8e84ffd46d9c73aea16fed5618"}, - {file = "mypy_boto3_ec2-1.21.46-py3-none-any.whl", hash = "sha256:bb52755f520c7db849cc47bd374405ed8abd6dcc5c864964118926cacc6d077b"}, + {file = "mypy-boto3-ec2-1.23.0.post1.tar.gz", hash = "sha256:2ae21cba9b1b2f22f6ef81290ae5cff65b1aac9bb31ef43c61aecd8411483ca5"}, + {file = "mypy_boto3_ec2-1.23.0.post1-py3-none-any.whl", hash = "sha256:0851229a0d3289d51ba554933a437427c7460ca2d2fd8fc959a3bd945f7583a7"}, ] mypy-boto3-ec2-instance-connect = [ - {file = "mypy-boto3-ec2-instance-connect-1.21.34.tar.gz", hash = "sha256:b9c6aaeae9ec352e39c980c5063647fe877df306985cc7d45f243b24494b642d"}, - {file = "mypy_boto3_ec2_instance_connect-1.21.34-py3-none-any.whl", hash = "sha256:32b774c761b3d61c842da1b4de5cdc8d2ebbe99959cea05939ad34d2276f1e95"}, + {file = "mypy-boto3-ec2-instance-connect-1.23.0.post1.tar.gz", hash = "sha256:a01779fdfce31f2b5448f55cf816517d97a5cedefa1b165b0db9d934f5b1cee9"}, + {file = "mypy_boto3_ec2_instance_connect-1.23.0.post1-py3-none-any.whl", hash = "sha256:fcfd420a5fa0bcc107907725239e6b77fed9dde103045f8ca15808648a12ab77"}, ] mypy-boto3-ecr = [ - {file = "mypy-boto3-ecr-1.21.34.tar.gz", hash = "sha256:90fee6eaf6da1688c8ab15c40e1f43e54d6ad56c5436e1ff4b8d78c2cc5f0d71"}, - {file = "mypy_boto3_ecr-1.21.34-py3-none-any.whl", hash = "sha256:e62d9c91c4e2d8a253e4620d58d6332b1495625175661ced3c773751d25930ab"}, + {file = "mypy-boto3-ecr-1.23.0.post1.tar.gz", hash = "sha256:ce62fdb8a5be694e7e5ed5d332f0cc84841898d5ef2a66877eb012a332f6be12"}, + {file = "mypy_boto3_ecr-1.23.0.post1-py3-none-any.whl", hash = "sha256:8e828c6f494fabf11498ecfa8e305ce1d5b68d7dd4021bb37bfb36d36385d2ea"}, ] mypy-boto3-ecr-public = [ - {file = "mypy-boto3-ecr-public-1.21.34.tar.gz", hash = "sha256:55488cc643ffb2590317cd0e2e1d315727292328e3c6e2b2874eea6b869ef82b"}, - {file = "mypy_boto3_ecr_public-1.21.34-py3-none-any.whl", hash = "sha256:2f996230806fed421324b4f83ba79b7eb5b3e63ecef5d4d6c5f446383fdbbecb"}, + {file = "mypy-boto3-ecr-public-1.23.0.post1.tar.gz", hash = "sha256:a9d6a14bd084bc26a55baaac74c3d96f092591464f3dc1bc51cda847deed6676"}, + {file = "mypy_boto3_ecr_public-1.23.0.post1-py3-none-any.whl", hash = "sha256:ea5b4073dfc373644fcec4e514e5fd7284ba4495398f5ab7f42d9c95daf7a235"}, ] mypy-boto3-ecs = [ - {file = "mypy-boto3-ecs-1.21.34.tar.gz", hash = "sha256:6398d50555fa07f6049585695f3cb57c58d561b6ec21a547ce15fbb7a210b967"}, - {file = "mypy_boto3_ecs-1.21.34-py3-none-any.whl", hash = "sha256:1d1b1f577de55d125bbcc29fdf1a902266212bb72186fa56f5c4d916ece9dad6"}, + {file = "mypy-boto3-ecs-1.23.0.post1.tar.gz", hash = "sha256:508643ef259013390ccfa141fd82689c193e0be03509ed546ab772af88eebc78"}, + {file = "mypy_boto3_ecs-1.23.0.post1-py3-none-any.whl", hash = "sha256:d24411a61832a7716b588a376801455123054ae7530aeec660041c29013c8d2d"}, ] mypy-boto3-efs = [ - {file = "mypy-boto3-efs-1.21.39.tar.gz", hash = "sha256:af00b7643857587ee414dd9588a08014321132a963bd7de380dd3f5fa3a28182"}, - {file = "mypy_boto3_efs-1.21.39-py3-none-any.whl", hash = "sha256:1f6023d32118b2ad4076387f26b34bb03c787fa307824f8905308f8b3262a50c"}, + {file = "mypy-boto3-efs-1.23.0.post1.tar.gz", hash = "sha256:ff28c177beb3ca784216b46cb54130fa64c4b9c82ea2e171795bda51c8d55e3a"}, + {file = "mypy_boto3_efs-1.23.0.post1-py3-none-any.whl", hash = "sha256:1e17d9be2fa9b4362db59d684661de19c2a66c70f4dc437bf5ed82e25d1b7d72"}, ] mypy-boto3-eks = [ - {file = "mypy-boto3-eks-1.21.34.tar.gz", hash = "sha256:f93eddaa41408c93a2506d51421f6dfa33984ada4720a9472ccabe93f4b6b0b1"}, - {file = "mypy_boto3_eks-1.21.34-py3-none-any.whl", hash = "sha256:e06ee2e422cd33112ad5217b04789700ae5481879babe362f0250b160ac99169"}, + {file = "mypy-boto3-eks-1.23.0.post1.tar.gz", hash = "sha256:698e2924cc844706556c2766fa8ed2d4d92f0e0cbf4f9c160010214ca3e5afbb"}, + {file = "mypy_boto3_eks-1.23.0.post1-py3-none-any.whl", hash = "sha256:3c0bc3bdeb7942ea1d8d85c16eff4e268057caf94680b63d0e68edc1cb41501f"}, ] mypy-boto3-elastic-inference = [ - {file = "mypy-boto3-elastic-inference-1.21.34.tar.gz", hash = "sha256:8b354fc018d89257a9e48237d2bf85fac7ed5a313ef56293d321dd13411e4430"}, - {file = "mypy_boto3_elastic_inference-1.21.34-py3-none-any.whl", hash = "sha256:de73928872b5fa71404910363309af5246357e679cd78f5cb390fd5e53f71bf5"}, + {file = "mypy-boto3-elastic-inference-1.23.0.post1.tar.gz", hash = "sha256:5401a779d4f4b6155c3c26d7339a9999514b84ac7cce78b6394e77b0b7c7bafd"}, + {file = "mypy_boto3_elastic_inference-1.23.0.post1-py3-none-any.whl", hash = "sha256:53769ddc20f0d198adc928cc8551a2942288e528957a8cfda72a86193e22ebae"}, ] mypy-boto3-elasticache = [ - {file = "mypy-boto3-elasticache-1.21.45.tar.gz", hash = "sha256:d6e7437c0c08c9ee81cd591755b2b3ef35e880cc5dacb11e4b3ea311407744ad"}, - {file = "mypy_boto3_elasticache-1.21.45-py3-none-any.whl", hash = "sha256:22cbacf6eb01b5bd1497087f8b2b2403ef990cb267083f445a53fd197161b193"}, + {file = "mypy-boto3-elasticache-1.23.0.post1.tar.gz", hash = "sha256:5ac63398411aef9a2705b84f84aea4a65cf48c9c83edea369062f214bdd213f1"}, + {file = "mypy_boto3_elasticache-1.23.0.post1-py3-none-any.whl", hash = "sha256:f34de48614db537543798c5eaf93b927af4299fd2a0163d9bd54f32757a680a5"}, ] mypy-boto3-elasticbeanstalk = [ - {file = "mypy-boto3-elasticbeanstalk-1.21.34.tar.gz", hash = "sha256:0284c510ca5f003ae0731b072ce41907cd1818d08718f6f2cd6ff53d97fe18b9"}, - {file = "mypy_boto3_elasticbeanstalk-1.21.34-py3-none-any.whl", hash = "sha256:d3194697f839436f3e14c15cf52fd250ddfa875d0fc9d75f6be8e736c6064be6"}, + {file = "mypy-boto3-elasticbeanstalk-1.23.0.post1.tar.gz", hash = "sha256:c42b0b8a67f876c339f081966c51ef59df7888fb7828a63d74033bef369b6a98"}, + {file = "mypy_boto3_elasticbeanstalk-1.23.0.post1-py3-none-any.whl", hash = "sha256:f826f125610fe6f22c174c61acfa20d0b35bb1d9c58cbbc5913f320362f7d562"}, ] mypy-boto3-elastictranscoder = [ - {file = "mypy-boto3-elastictranscoder-1.21.34.tar.gz", hash = "sha256:e3b525526413df4f92aa6d2fc2961bc951b89cfa02e8125e2d893cb7a24bd689"}, - {file = "mypy_boto3_elastictranscoder-1.21.34-py3-none-any.whl", hash = "sha256:36787111eae12bac19ca2a11f31c74cdf94b5bda83ab8e9f9b7c3573f85c1f01"}, + {file = "mypy-boto3-elastictranscoder-1.23.0.post1.tar.gz", hash = "sha256:26391b190dc15ef126f8519f0d7ba26837458bd51097b082d4fbe0a573c635af"}, + {file = "mypy_boto3_elastictranscoder-1.23.0.post1-py3-none-any.whl", hash = "sha256:d484595702f7fae6032e6c11cfefe7b682147bb940d153e7e0b22cfa19851a88"}, ] mypy-boto3-elb = [ - {file = "mypy-boto3-elb-1.21.34.tar.gz", hash = "sha256:2934beed0b9244f7421139b0fa8e83f00f586539f4b0b2f1f99d18158956d17c"}, - {file = "mypy_boto3_elb-1.21.34-py3-none-any.whl", hash = "sha256:ec0bee6550b66c5b9a300f146b5adc54e29212bc9b56cd479ea556b449a67965"}, + {file = "mypy-boto3-elb-1.23.0.post1.tar.gz", hash = "sha256:c50188e97dcf9d0951ac68f9c34dc19cd25a05a8d00a0652e6f07b4416db794f"}, + {file = "mypy_boto3_elb-1.23.0.post1-py3-none-any.whl", hash = "sha256:953e1d7d82c161f85fa8cee11155badaa76182f7305179dfd0ae3bc4384012d4"}, ] mypy-boto3-elbv2 = [ - {file = "mypy-boto3-elbv2-1.21.34.tar.gz", hash = "sha256:f3c754bc05b03f1e9e2a4842eacf7e145f2a8fa0d197da7904962593c0ee036a"}, - {file = "mypy_boto3_elbv2-1.21.34-py3-none-any.whl", hash = "sha256:2f24880e0ebca6be7d322f9be1f4973efe74febdeaff2eb3180a67513cd7da39"}, + {file = "mypy-boto3-elbv2-1.23.0.post1.tar.gz", hash = "sha256:a3e3077032fe29c7583497e848b7ab9e2ee7e39acb4bd9402c199972f5c67937"}, + {file = "mypy_boto3_elbv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:aa2d803b67686c503f69d9f8ccaa475e2b258c6be587a37de987b97b304a7f97"}, ] mypy-boto3-emr = [ - {file = "mypy-boto3-emr-1.21.34.tar.gz", hash = "sha256:402fcaaadc04d0227e83023e55260aad7c2c66f846cadceccf185b4a6c5c4253"}, - {file = "mypy_boto3_emr-1.21.34-py3-none-any.whl", hash = "sha256:354b49b59b36d454de2016243eb65bad647d93cc1e22df4fca07b94f39acee3c"}, + {file = "mypy-boto3-emr-1.23.0.post1.tar.gz", hash = "sha256:fb2c907b9c0bfde73591a1d038c100e17e9bdc7604aab4ec2a240a4bcded282f"}, + {file = "mypy_boto3_emr-1.23.0.post1-py3-none-any.whl", hash = "sha256:0cea170d1bbf39686a8d174c41d2d942fc3979c4bd8c9c86959be5718e90c5e7"}, ] mypy-boto3-emr-containers = [ - {file = "mypy-boto3-emr-containers-1.21.34.tar.gz", hash = "sha256:4e722c962490fea47b7541e018dfd3f77537778d1ce1b16be72e507ff5ca4185"}, - {file = "mypy_boto3_emr_containers-1.21.34-py3-none-any.whl", hash = "sha256:6ca3b67d44aebb23402b7f94735f18f534ca2b8e78133f06575529a901e0c53a"}, + {file = "mypy-boto3-emr-containers-1.23.0.post1.tar.gz", hash = "sha256:938d982fd97b41434d48e94ed2f619cd197ef69b5907e8f6fc93a403660684e7"}, + {file = "mypy_boto3_emr_containers-1.23.0.post1-py3-none-any.whl", hash = "sha256:7e8cc486bbd519ddab1ca69bb8fc217829d27ebb611f94efd3a2c8c1902d632c"}, ] mypy-boto3-es = [ - {file = "mypy-boto3-es-1.21.34.tar.gz", hash = "sha256:f5913a6b9aea2e37da13b3135b5be3fda3070e18f8caa15638871c0b676b600f"}, - {file = "mypy_boto3_es-1.21.34-py3-none-any.whl", hash = "sha256:4279ae7e6b6c9fa1870d0c05532db274052a154e86030b7215a5172e89071bdc"}, + {file = "mypy-boto3-es-1.23.0.post1.tar.gz", hash = "sha256:9c7e924905c27cdb6ea8b2b83f72ed91e50a6a64bd872d051bf7dd8333ee9787"}, + {file = "mypy_boto3_es-1.23.0.post1-py3-none-any.whl", hash = "sha256:8ff0766f861311086e4cdc2507913602e970ee2bec44bbfdb4b8927a66ecc9ac"}, ] mypy-boto3-events = [ - {file = "mypy-boto3-events-1.21.36.tar.gz", hash = "sha256:0e254d1e09652cec35efa58ec15c8329e395f117958c19510723686554ed0d23"}, - {file = "mypy_boto3_events-1.21.36-py3-none-any.whl", hash = "sha256:ec9d7280fb8eaaae24d9e998202b2c4e8a676b2e99b00f7013ea0332c2546a88"}, + {file = "mypy-boto3-events-1.23.0.post1.tar.gz", hash = "sha256:c9ef38a05da241876304758e23c6054162ac2c92c97c3ec03aa55b390f483205"}, + {file = "mypy_boto3_events-1.23.0.post1-py3-none-any.whl", hash = "sha256:074d129fbcd7be94055a23c8f878623f2598fe26a67ad891f9fb43361af6a6cd"}, ] mypy-boto3-evidently = [ - {file = "mypy-boto3-evidently-1.21.34.tar.gz", hash = "sha256:476ff645ab765452ace9d80da1dc1ee18fe80e5b922d2a7e43f47c5bf05f9aa6"}, - {file = "mypy_boto3_evidently-1.21.34-py3-none-any.whl", hash = "sha256:3c88afc1ef49cc018fc7a385b3ed1eb3cb9e1d283f5fce6c96d62fc81e1654d4"}, + {file = "mypy-boto3-evidently-1.23.0.post1.tar.gz", hash = "sha256:d4ccc9b871b7b343e4efa98a19469e51a655b97b233cab85ddf805cda96d6a88"}, + {file = "mypy_boto3_evidently-1.23.0.post1-py3-none-any.whl", hash = "sha256:beab1d2fd56599c4ce0e9445cb3185c672ccb57d4cdbb4ba6f58219c1b4ca6df"}, ] mypy-boto3-finspace = [ - {file = "mypy-boto3-finspace-1.21.34.tar.gz", hash = "sha256:69a1ee9f9e6b8d3b21ce76051e7ad93d97f942044e64b5ddcd5c5b52b123c419"}, - {file = "mypy_boto3_finspace-1.21.34-py3-none-any.whl", hash = "sha256:44e5d9edfd13fc67d5cdeeb25a6bc02e424d3c54718dd24cc9ffbd2f52387214"}, + {file = "mypy-boto3-finspace-1.23.0.post1.tar.gz", hash = "sha256:e08c03510fe820db113366c20ba5f0adeb1be767f5d253d43c3e27144a7f85c1"}, + {file = "mypy_boto3_finspace-1.23.0.post1-py3-none-any.whl", hash = "sha256:d66e947751a9ce4a7f537a777e618f9b150143e9a6ac0d758d06b34dc4a4d3f7"}, ] mypy-boto3-finspace-data = [ - {file = "mypy-boto3-finspace-data-1.21.34.tar.gz", hash = "sha256:41307b45ec46c7ea97783e842c9bda3fe251665d23a127b6bb0d9a93db4f95de"}, - {file = "mypy_boto3_finspace_data-1.21.34-py3-none-any.whl", hash = "sha256:037464668707fb84c3fe7d84bd8819c2732b6cefc15a7d2286de8f2cc9556a0d"}, + {file = "mypy-boto3-finspace-data-1.23.0.post1.tar.gz", hash = "sha256:fbb1c045204d2b2fb31e09d934977e34f8ff58552763dd2ecd77ed5325cda3a2"}, + {file = "mypy_boto3_finspace_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:8c87d5861118708a99f9a2217ed4c6855820ad4fc2c248e108600d1f5c445523"}, ] mypy-boto3-firehose = [ - {file = "mypy-boto3-firehose-1.21.34.tar.gz", hash = "sha256:00d0f441cce9c786b464217d658bee6253bf30ca24bf4d2918799627d231a069"}, - {file = "mypy_boto3_firehose-1.21.34-py3-none-any.whl", hash = "sha256:5159cbf67892246033e230d5a278048c797a3ece914b47fb059b6743a132118b"}, + {file = "mypy-boto3-firehose-1.23.0.post1.tar.gz", hash = "sha256:f79df996bb5241566894ef7407ba1cfac8844031938f87ba49a2f96caa249ba7"}, + {file = "mypy_boto3_firehose-1.23.0.post1-py3-none-any.whl", hash = "sha256:187ddea763ecb5d6487b602e500d58f5612257036aa275ff4ddef1a6cd6c5b3e"}, ] mypy-boto3-fis = [ - {file = "mypy-boto3-fis-1.21.34.tar.gz", hash = "sha256:3b890c9133bde6bf5785978101fb13f82313f950d23182ff05a9a16f57ce4f8d"}, - {file = "mypy_boto3_fis-1.21.34-py3-none-any.whl", hash = "sha256:efd0d8571efca636846e5b4d0f8b1f057181473655abcc9c822333b282380d7f"}, + {file = "mypy-boto3-fis-1.23.0.post1.tar.gz", hash = "sha256:7f903e55706414d19b0d64d4f61e3ce93def95bff9828d750d07ceb7a8e1dc78"}, + {file = "mypy_boto3_fis-1.23.0.post1-py3-none-any.whl", hash = "sha256:21fee920dc548100263a47e124ae7ecadb1616d91d3251af739f39710effde20"}, ] mypy-boto3-fms = [ - {file = "mypy-boto3-fms-1.21.34.tar.gz", hash = "sha256:dec01bf62bb966e2227666221bbb26db59291cc07a52e165453268422b85cbf5"}, - {file = "mypy_boto3_fms-1.21.34-py3-none-any.whl", hash = "sha256:925dffde90eaed6a480c8c081fcb2538aa6e50f67b18998d0619c10b8493105d"}, + {file = "mypy-boto3-fms-1.23.0.post1.tar.gz", hash = "sha256:73a31d176bd06eef93ef8d8bd2f6ad7a9c6e31bbdc51ae9bc89f0f6f50e8477a"}, + {file = "mypy_boto3_fms-1.23.0.post1-py3-none-any.whl", hash = "sha256:9995363b28818522db543f8062b66ccbae008134abba030a705fffad89ef7568"}, ] mypy-boto3-forecast = [ - {file = "mypy-boto3-forecast-1.21.34.tar.gz", hash = "sha256:a6b91f643090e3b9546ca8576d37d0bbb5cdef85967e6a20ffa5b7d6f7b61f66"}, - {file = "mypy_boto3_forecast-1.21.34-py3-none-any.whl", hash = "sha256:76ba022296a87284c20d08cf45b4dd06186a9703ce00aa7038a4c3d09690d232"}, + {file = "mypy-boto3-forecast-1.23.0.post1.tar.gz", hash = "sha256:f1802c592b22b679ed86ebd6337d34a6840194671bd5144497003edd2e042c09"}, + {file = "mypy_boto3_forecast-1.23.0.post1-py3-none-any.whl", hash = "sha256:15a8dab82692544939b923e996cb6bda4458a996de3efb714161770c2f782464"}, ] mypy-boto3-forecastquery = [ - {file = "mypy-boto3-forecastquery-1.21.34.tar.gz", hash = "sha256:d1ea6028a52895045541121f74184877a10d2959f371b0b98f9e3b51b4ed174e"}, - {file = "mypy_boto3_forecastquery-1.21.34-py3-none-any.whl", hash = "sha256:df235356fc7319df68676358ca4490f2a34c6d87880f55e1134f175f63e09602"}, + {file = "mypy-boto3-forecastquery-1.23.0.post1.tar.gz", hash = "sha256:fdceab0a824c82bffd8c46131fe78e805a8c84571d3fb0065c70d45e07fbe505"}, + {file = "mypy_boto3_forecastquery-1.23.0.post1-py3-none-any.whl", hash = "sha256:7741be33c8260de57562c1ee11a537e0232dec07080102c97aa2ec9ed2326b09"}, ] mypy-boto3-frauddetector = [ - {file = "mypy-boto3-frauddetector-1.21.34.tar.gz", hash = "sha256:ed062a85691b5a24425caa720b8a26fedf12a9ca88e9f4792d775ec1d6124020"}, - {file = "mypy_boto3_frauddetector-1.21.34-py3-none-any.whl", hash = "sha256:73511532a68200b7856be9bb7fa4efee117869727114df7c38f4467551a84eb7"}, + {file = "mypy-boto3-frauddetector-1.23.0.post1.tar.gz", hash = "sha256:ca2e06a7892ece3e6a920f89800b14f5bbea7e1645ab26de2ba3bd706dd2679c"}, + {file = "mypy_boto3_frauddetector-1.23.0.post1-py3-none-any.whl", hash = "sha256:c01515f044a48595c20777a059b073ef13c8034ca28ff0aa72e7e09badb791b4"}, ] mypy-boto3-fsx = [ - {file = "mypy-boto3-fsx-1.21.40.tar.gz", hash = "sha256:ca9c6b2f03cebbf54cd4b919932eae0f90db219bdd33bccf1e7c8c52d2aa174f"}, - {file = "mypy_boto3_fsx-1.21.40-py3-none-any.whl", hash = "sha256:5521422bb7325632ec3588cf7cf13f61e796ac854b46bd461d5f6c2eb50728e4"}, + {file = "mypy-boto3-fsx-1.23.0.post1.tar.gz", hash = "sha256:cecfa4ec573d94e691fbc88f559c35f8e864ce8498278b57172688d272bc4ee3"}, + {file = "mypy_boto3_fsx-1.23.0.post1-py3-none-any.whl", hash = "sha256:84f5cafab99f339c54ce6598a2a05969a0e878545fd98b7b6025a39f109a06c3"}, ] mypy-boto3-gamelift = [ - {file = "mypy-boto3-gamelift-1.21.34.tar.gz", hash = "sha256:b93664a2df34ecb0162f338841e058b2c2d499639e3fc921c91c9993a714cdc2"}, - {file = "mypy_boto3_gamelift-1.21.34-py3-none-any.whl", hash = "sha256:3035d3d9648e0fee1513946a3b14dfcff6b2b6386f013b717ac3259f61784f6c"}, + {file = "mypy-boto3-gamelift-1.23.0.post1.tar.gz", hash = "sha256:ac47b1048090a33eaac0098d60f2b11d74c0a6ce7b067f10a13eb44ebb71e932"}, + {file = "mypy_boto3_gamelift-1.23.0.post1-py3-none-any.whl", hash = "sha256:4bf30df71fb690469bb29438ade76033fd9955a92fe414ce428c98d339236e83"}, ] mypy-boto3-glacier = [ - {file = "mypy-boto3-glacier-1.21.34.tar.gz", hash = "sha256:ceb2b6327228c26be463d979aa35a87ebd9071746a84d7013715f3a2e8e8eea1"}, - {file = "mypy_boto3_glacier-1.21.34-py3-none-any.whl", hash = "sha256:e252c556eb917506ed4e71921cc06d80662d83b89014d32e05d2641765987a33"}, + {file = "mypy-boto3-glacier-1.23.0.post1.tar.gz", hash = "sha256:21666d11971c3b2cb9b91427597e5b00b2efdb4bef93f461a2ff46c55c991247"}, + {file = "mypy_boto3_glacier-1.23.0.post1-py3-none-any.whl", hash = "sha256:3ab73b80729f3c688f67f7895023f1f65ddce3bb0c7c20aa07051136bd66ab70"}, ] mypy-boto3-globalaccelerator = [ - {file = "mypy-boto3-globalaccelerator-1.21.34.tar.gz", hash = "sha256:57179fab03b2de9985dd3bd4bdeac968a14d8f8cf4d3a8e507841dcba657b93e"}, - {file = "mypy_boto3_globalaccelerator-1.21.34-py3-none-any.whl", hash = "sha256:b09d99c3d651435d285cdc95b568600645327895c8e5b2c9a9289d0b32a53b1e"}, + {file = "mypy-boto3-globalaccelerator-1.23.0.post1.tar.gz", hash = "sha256:056441639586ca962cfbc2d5bc6b4038b4a237538b87c66c59bb9ba0c0d44f6e"}, + {file = "mypy_boto3_globalaccelerator-1.23.0.post1-py3-none-any.whl", hash = "sha256:444c0651e470f50598d6c1a0ab479f9aefea5adcd125a68415e47c26d7d6a942"}, ] mypy-boto3-glue = [ - {file = "mypy-boto3-glue-1.21.45.tar.gz", hash = "sha256:8d1e347a97cd3ee78049079710b468e24c403e39b0436b9b63cfd15255259146"}, - {file = "mypy_boto3_glue-1.21.45-py3-none-any.whl", hash = "sha256:29229f5d7e95d8facd759dba0b03adfa7ba5d283e75a89c92f67d9b596a4e3ec"}, + {file = "mypy-boto3-glue-1.23.0.post1.tar.gz", hash = "sha256:28aa7043037c7c3924c984955664925c85dd71c05fd1f118edde9a2662715989"}, + {file = "mypy_boto3_glue-1.23.0.post1-py3-none-any.whl", hash = "sha256:0ac6baf5ba468b6ebecb529789b355d09a1838df543c1e84613afb35e8e155d8"}, ] mypy-boto3-grafana = [ - {file = "mypy-boto3-grafana-1.21.34.tar.gz", hash = "sha256:dc5971a52146f29c156b362676d7d969c0e390476a7305e91a96a9e9e31c22d1"}, - {file = "mypy_boto3_grafana-1.21.34-py3-none-any.whl", hash = "sha256:a9b3cfcae927f7887c67473248309aac1d87115cf53754ad09db2af1cde604c0"}, + {file = "mypy-boto3-grafana-1.23.0.post1.tar.gz", hash = "sha256:1c90248b2a183b7a04f6f85fd3395f8d163db6f0ffdfc6f1055287d9e56c688d"}, + {file = "mypy_boto3_grafana-1.23.0.post1-py3-none-any.whl", hash = "sha256:a0559096adfabf3e91d8b76afb2f58ecdb9909a6635a4d5dccc30182bfee916c"}, ] mypy-boto3-greengrass = [ - {file = "mypy-boto3-greengrass-1.21.34.tar.gz", hash = "sha256:868894911373d3a474670ad415044958c6bc5e828a09075bf11c4cbe2a21f04c"}, - {file = "mypy_boto3_greengrass-1.21.34-py3-none-any.whl", hash = "sha256:3d62f0639060f7776135b02e7760c5ca5c03082683092ca4633735a9c0d1d5c0"}, + {file = "mypy-boto3-greengrass-1.23.0.post1.tar.gz", hash = "sha256:178a3c10fd61efa8a4789b9d312a48fa644306cfac73cae5f24e6eb3cbf22dfb"}, + {file = "mypy_boto3_greengrass-1.23.0.post1-py3-none-any.whl", hash = "sha256:094286b1b1cbd0d288f39c753c7fcc353bbbbc7daec561ef1260e137df9d8973"}, ] mypy-boto3-greengrassv2 = [ - {file = "mypy-boto3-greengrassv2-1.21.34.tar.gz", hash = "sha256:f32bf68f7eb9099e90af352e36bf783b2b169d9559952c935f9f36785bdd3356"}, - {file = "mypy_boto3_greengrassv2-1.21.34-py3-none-any.whl", hash = "sha256:94d210f3bc1f83542529ce5b2c1947c55273335398458f68f4159ba4233c987f"}, + {file = "mypy-boto3-greengrassv2-1.23.0.post1.tar.gz", hash = "sha256:1a193aea19c47eea13fcd1a1e2d133bb1cb3b801f1fc9a5a0f43c5f9fbd85458"}, + {file = "mypy_boto3_greengrassv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:682e134a64e2bac13e2f467ecbe6ceb47dfda0385d96b924cb682f784af9a057"}, ] mypy-boto3-groundstation = [ - {file = "mypy-boto3-groundstation-1.21.34.tar.gz", hash = "sha256:a91a0a74f481ce41abdfe490373bab8bbd8e89c881c101d7b052e8f1a7dc3f0d"}, - {file = "mypy_boto3_groundstation-1.21.34-py3-none-any.whl", hash = "sha256:92c26564a913a2dd7a1d8047bb806dec71ec80629320791468ad194d33db0444"}, + {file = "mypy-boto3-groundstation-1.23.0.post1.tar.gz", hash = "sha256:c829023ce0d15f02204187abc2d6903ff172f7739222d74bb5430ab3d1cff505"}, + {file = "mypy_boto3_groundstation-1.23.0.post1-py3-none-any.whl", hash = "sha256:85baeba737e72a0203bbde344226c4c6f51ecf7522830fb82c8cd5f3a98c9311"}, ] mypy-boto3-guardduty = [ - {file = "mypy-boto3-guardduty-1.21.34.tar.gz", hash = "sha256:44665b2da6f9b6def5eda7d1e675cda25b95d99e74d66538f565709f0c1b33bb"}, - {file = "mypy_boto3_guardduty-1.21.34-py3-none-any.whl", hash = "sha256:65b3f5d2ce706a99267b5c92c501e89742929b1708c2045d34388ead5ea48afc"}, + {file = "mypy-boto3-guardduty-1.23.0.post1.tar.gz", hash = "sha256:82888c41d372dc1fe730b6cbaf7aed825ef8acecc4c5f684220f993c196cc7d9"}, + {file = "mypy_boto3_guardduty-1.23.0.post1-py3-none-any.whl", hash = "sha256:ad2b8079d14318173ab09a7ade571313b0c9968727dc021068f6fbf77dcfa69e"}, ] mypy-boto3-health = [ - {file = "mypy-boto3-health-1.21.34.tar.gz", hash = "sha256:7ec9c9a3e61f761a6d1e18104e31159f667c86d6e592d274e893609cab4aa64b"}, - {file = "mypy_boto3_health-1.21.34-py3-none-any.whl", hash = "sha256:53963d4ed90341c32d017598e3bd9a603d63a5ff1df267db056311572a414720"}, + {file = "mypy-boto3-health-1.23.0.post1.tar.gz", hash = "sha256:7a7c999a4a8bf91600c29f8f042aeee8a5ada13196ea337eddc738e442dbf0cc"}, + {file = "mypy_boto3_health-1.23.0.post1-py3-none-any.whl", hash = "sha256:d44eb108f8a5d8e1391351c61ebf062a6784a486d9148361b46d90225198d259"}, ] mypy-boto3-healthlake = [ - {file = "mypy-boto3-healthlake-1.21.34.tar.gz", hash = "sha256:06646926371448cc67145eda4a5572f4c6ca7aa5fc3053913121690866f52801"}, - {file = "mypy_boto3_healthlake-1.21.34-py3-none-any.whl", hash = "sha256:321e4dccda0481223cb1d57f99fa1da952bc167f8a312b51e6acb85b6b88625c"}, + {file = "mypy-boto3-healthlake-1.23.0.post1.tar.gz", hash = "sha256:5c676339c7c4c2ca5450566051d0df6d2885e77003616e794c5d6da6e63eef9a"}, + {file = "mypy_boto3_healthlake-1.23.0.post1-py3-none-any.whl", hash = "sha256:ad487bc03180bd67aec6a6755838fe861e1861e11ae7c740ff1b4122dda8e2e5"}, ] mypy-boto3-honeycode = [ - {file = "mypy-boto3-honeycode-1.21.34.tar.gz", hash = "sha256:111fd852cf9df741631e936e23e2f7fcb8ad58d69deeaec67c5d52acc72a7d69"}, - {file = "mypy_boto3_honeycode-1.21.34-py3-none-any.whl", hash = "sha256:f2f8f1b553292574c0b214ae58365e9b915c31e0c2bdcc2971c660564dd4b960"}, + {file = "mypy-boto3-honeycode-1.23.0.post1.tar.gz", hash = "sha256:6142202fa5ca01b478af97934261fd40887b5d2de17fe5c7071ba8abf7ec00ec"}, + {file = "mypy_boto3_honeycode-1.23.0.post1-py3-none-any.whl", hash = "sha256:3c9688f80f1a75f7f7172e0ae4dc78bc1a4223f20d14d93a13bb74c7abde2f73"}, ] mypy-boto3-iam = [ - {file = "mypy-boto3-iam-1.21.34.tar.gz", hash = "sha256:1f50ef2e66919c65483f9e24667c4927618209a91dfa723ff6024a9274cb172d"}, - {file = "mypy_boto3_iam-1.21.34-py3-none-any.whl", hash = "sha256:7e5bce59d3b71844faca43e418f6f0868b972d396d561bded57973b73bdb8fb6"}, + {file = "mypy-boto3-iam-1.23.0.post1.tar.gz", hash = "sha256:d0f8cc2f8c06b4e2c05c2145ff8649498e14aa7f445337917b63239264803561"}, + {file = "mypy_boto3_iam-1.23.0.post1-py3-none-any.whl", hash = "sha256:4a4162fbc8748de4a327bd959de9d1c2e2e4484a25a964650f37e1eb829ce4df"}, ] mypy-boto3-identitystore = [ - {file = "mypy-boto3-identitystore-1.21.34.tar.gz", hash = "sha256:a20c1574eae875585db3cb13ff8fbe3628c6efe5de13fe1f580c785bf35a9079"}, - {file = "mypy_boto3_identitystore-1.21.34-py3-none-any.whl", hash = "sha256:420dd3d5c9eb1497d5e3e06d574395c3fbdb81d1679b82dc968f8e834fa3df8b"}, + {file = "mypy-boto3-identitystore-1.23.0.post1.tar.gz", hash = "sha256:dd6777471a1eba4e2200f949fa438e3c67a5b4a740e8da1becae26281c5db5df"}, + {file = "mypy_boto3_identitystore-1.23.0.post1-py3-none-any.whl", hash = "sha256:f15164f1b747db83e6ec9ec285a6f88d3463696eeb7957df6b60160497a6d77f"}, ] mypy-boto3-imagebuilder = [ - {file = "mypy-boto3-imagebuilder-1.21.34.tar.gz", hash = "sha256:5515afa1135327806caf75a50ed8569fcea8c83878f178edff3b393a9bd159d9"}, - {file = "mypy_boto3_imagebuilder-1.21.34-py3-none-any.whl", hash = "sha256:2719cb100c3194de2e32c51d3a06f70fcd230dbf8ced025c3284e71a05242ea1"}, + {file = "mypy-boto3-imagebuilder-1.23.0.post1.tar.gz", hash = "sha256:d62f6f483ee4ef45883d5cf07aa2880b3415d98dad5647c2deb99c5865ee8170"}, + {file = "mypy_boto3_imagebuilder-1.23.0.post1-py3-none-any.whl", hash = "sha256:c72b72c7884df096738bfe6c5000bfce02cfe9d04ceaef04ad3b07c3e49ab0b1"}, ] mypy-boto3-importexport = [ - {file = "mypy-boto3-importexport-1.21.34.tar.gz", hash = "sha256:6ef1b2784c3c77842c762c4970e7241a5483555ba7c6118c90c9f0927c0a1d1e"}, - {file = "mypy_boto3_importexport-1.21.34-py3-none-any.whl", hash = "sha256:e40036d6dc36adc7fb58c991ba087fea67b0edfed348345b094b5358a7e87b36"}, + {file = "mypy-boto3-importexport-1.23.0.post1.tar.gz", hash = "sha256:1828a8996fa492af634c4cfd99858aff828afe90d1a0f6d3c0966e5fb073a9ea"}, + {file = "mypy_boto3_importexport-1.23.0.post1-py3-none-any.whl", hash = "sha256:0795d7fa287235029fc6d5b49ffa1e73e18aa6f625a18e07fdffd73a850c5014"}, ] mypy-boto3-inspector = [ - {file = "mypy-boto3-inspector-1.21.34.tar.gz", hash = "sha256:e1c65f6afa6a0ba6310a34b018bcadc39425f9730bac1c570243ddc58aa69e08"}, - {file = "mypy_boto3_inspector-1.21.34-py3-none-any.whl", hash = "sha256:27cea39f6a53f417837a052ca42338490313ede985c44af42ab539b7f45f4cf7"}, + {file = "mypy-boto3-inspector-1.23.0.post1.tar.gz", hash = "sha256:b5840a37f5e959f5fd76e4e1847d0a8ce8f882f70fe80fa61ede8ea944abc3cc"}, + {file = "mypy_boto3_inspector-1.23.0.post1-py3-none-any.whl", hash = "sha256:3d50f7ab40ec82e729174003753e0090e6f6cba0ac5b656d078cb5f238bc4392"}, ] mypy-boto3-inspector2 = [ - {file = "mypy-boto3-inspector2-1.21.34.tar.gz", hash = "sha256:54a91cd109ba3f74255609919036f294388e9705fca5528fa88bcb9f6f4a4ccf"}, - {file = "mypy_boto3_inspector2-1.21.34-py3-none-any.whl", hash = "sha256:70989b9ac2175abe6f47b2b094bdd1914e40082883321f55ebf630e51f73e57e"}, + {file = "mypy-boto3-inspector2-1.23.0.post1.tar.gz", hash = "sha256:fdacb5250cd76577fee4abb7b4b6700c8c799af4327305ad99d0c88c12de6139"}, + {file = "mypy_boto3_inspector2-1.23.0.post1-py3-none-any.whl", hash = "sha256:18f37ee6b4585a134d0cab23b458765d8521954952c8fa927bbf7e7cdac0f44e"}, ] mypy-boto3-iot = [ - {file = "mypy-boto3-iot-1.21.34.tar.gz", hash = "sha256:115542eb413353d0370aa2e1c0c8a846a1522b8a941de3a9bbd49b1fab78f3e5"}, - {file = "mypy_boto3_iot-1.21.34-py3-none-any.whl", hash = "sha256:d1c58569fb4add75e25afaf6328b6346b6426047db83787e80ecbb5ec41cde2d"}, + {file = "mypy-boto3-iot-1.23.0.post1.tar.gz", hash = "sha256:513fc8180de0c326440ccb11e34ef2b82dd7683fa43162b0b144e807224589f5"}, + {file = "mypy_boto3_iot-1.23.0.post1-py3-none-any.whl", hash = "sha256:600482c4881fd0dece54aebb7a174e2e5f59aad070a8125f0a7e977976f9b6ea"}, ] mypy-boto3-iot-data = [ - {file = "mypy-boto3-iot-data-1.21.34.tar.gz", hash = "sha256:868605213670fbb12c7bf2749b6253f0b96158ae5cfd93a68ab4e88427b354ad"}, - {file = "mypy_boto3_iot_data-1.21.34-py3-none-any.whl", hash = "sha256:11a61a16f2eab21145b11ba2d1d8068ebad2fb08ed45db2f78aa747dd759a1fe"}, + {file = "mypy-boto3-iot-data-1.23.0.post1.tar.gz", hash = "sha256:35fa309b7db0e6b933abee7c8603f6b042193f88479b9e0d3b714062f336044c"}, + {file = "mypy_boto3_iot_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:e7e9a24e972eb74e17690dbd46a91e42b5c074ed057c361aa913ae8853606fcc"}, ] mypy-boto3-iot-jobs-data = [ - {file = "mypy-boto3-iot-jobs-data-1.21.34.tar.gz", hash = "sha256:5a2eb5af629ad94376bcaf95ba82d437a80d1fe16d6dc6741b958207e12fb881"}, - {file = "mypy_boto3_iot_jobs_data-1.21.34-py3-none-any.whl", hash = "sha256:c8e31f723cb4716dc7115769402954e2e1c8480db0c6a59688a21fc7b0ad1a3f"}, + {file = "mypy-boto3-iot-jobs-data-1.23.0.post1.tar.gz", hash = "sha256:1992ca6ba56b788c603a3a347ccf7efa21d700373bb217c5fcd0740eb9ffaad5"}, + {file = "mypy_boto3_iot_jobs_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:b0a1cc0a552aff6ac434bebfb6cfaea3b31a58256b3ae3699bb1b4d414a32107"}, ] mypy-boto3-iot1click-devices = [ - {file = "mypy-boto3-iot1click-devices-1.21.34.tar.gz", hash = "sha256:dde90d825eb5b4fd54e2f9559aa001c17ff11376793b2e77dd630eb42638b1d6"}, - {file = "mypy_boto3_iot1click_devices-1.21.34-py3-none-any.whl", hash = "sha256:7e881849d6372e484f930458ca317c7f643cb8ce88e7d906e31bc14d39df32e2"}, + {file = "mypy-boto3-iot1click-devices-1.23.0.post1.tar.gz", hash = "sha256:831bf9a9bd398fe48daab83531b5b316b56ae02da9e8e217672d5f2b8a8c0f47"}, + {file = "mypy_boto3_iot1click_devices-1.23.0.post1-py3-none-any.whl", hash = "sha256:560ea634cfbd6644d41b639401b9e2327d88eba4bd76206df57d3eefed4a1fbe"}, ] mypy-boto3-iot1click-projects = [ - {file = "mypy-boto3-iot1click-projects-1.21.34.tar.gz", hash = "sha256:22555ba627dfbf7b06906a85b948f0941b27cf88fb2f651e8f493e5fc88a77d6"}, - {file = "mypy_boto3_iot1click_projects-1.21.34-py3-none-any.whl", hash = "sha256:7f18dec3b918f3b7acf305339a098b442852c944ba56d22083d2d9c3a6ffeae5"}, + {file = "mypy-boto3-iot1click-projects-1.23.0.post1.tar.gz", hash = "sha256:cd24431d41ddeb9ae7d453582f6ad0c68608a45356df9c13fabbe4323d81113a"}, + {file = "mypy_boto3_iot1click_projects-1.23.0.post1-py3-none-any.whl", hash = "sha256:479dddb5f5890b52f09a700893f63e54e4a734fcfb3f12790c416cf13f6fbf6a"}, ] mypy-boto3-iotanalytics = [ - {file = "mypy-boto3-iotanalytics-1.21.34.tar.gz", hash = "sha256:81a5ade7b4e061c07ebfbeb14cca6f78f92c11639a69187db87138c7050bdeba"}, - {file = "mypy_boto3_iotanalytics-1.21.34-py3-none-any.whl", hash = "sha256:2c248cc3d9174cd660a552d8fb7489660a60ee2df1bda6c871fa61357c8cff89"}, + {file = "mypy-boto3-iotanalytics-1.23.0.post1.tar.gz", hash = "sha256:1e90905e135f49c5759af59b23505d70e95f27798005a53177d238e3db48bed4"}, + {file = "mypy_boto3_iotanalytics-1.23.0.post1-py3-none-any.whl", hash = "sha256:81954ddf1b27e01041e555110a5642cb7fa70a5dd3afc454b067f781aad528b6"}, ] mypy-boto3-iotdeviceadvisor = [ - {file = "mypy-boto3-iotdeviceadvisor-1.21.34.tar.gz", hash = "sha256:ccab4a1ba560bf45301302c8267783b7472f1b251487ed8d1cdc131479ef30ac"}, - {file = "mypy_boto3_iotdeviceadvisor-1.21.34-py3-none-any.whl", hash = "sha256:9e8be15729e582f67c840449c49931e347312312f12ebf0f3e93b593cbe06469"}, + {file = "mypy-boto3-iotdeviceadvisor-1.23.0.post1.tar.gz", hash = "sha256:6b4fb32a7a2bfe097388d866d03beb07d33de6401fde2003292729d81470c5ae"}, + {file = "mypy_boto3_iotdeviceadvisor-1.23.0.post1-py3-none-any.whl", hash = "sha256:72973e2b45303fa6cc0a383408d3ae3e51e9881b3cf6605bedf01694e2a4b8cb"}, ] mypy-boto3-iotevents = [ - {file = "mypy-boto3-iotevents-1.21.34.tar.gz", hash = "sha256:78407531932124f50f4cac5fc517f86af32f32cf704df91c2df087f9c8a6b0ba"}, - {file = "mypy_boto3_iotevents-1.21.34-py3-none-any.whl", hash = "sha256:8089cadf59651e74e976a6496e9cbe78d20aa4f48e98fd77ba391bda30866e9f"}, + {file = "mypy-boto3-iotevents-1.23.0.post1.tar.gz", hash = "sha256:10c614cf9c642d57cd7b7b0dd722c6f7bfc5490246deee7a463c27aa705e8170"}, + {file = "mypy_boto3_iotevents-1.23.0.post1-py3-none-any.whl", hash = "sha256:08be7a2a7c79282315b4713855111f604a1840d38a8fbc847e4dfb3816db024e"}, ] mypy-boto3-iotevents-data = [ - {file = "mypy-boto3-iotevents-data-1.21.34.tar.gz", hash = "sha256:53f2d8a499ef95fc11dbc5865c7448646d9d4dbc2f90c94672bb2406bbc459ed"}, - {file = "mypy_boto3_iotevents_data-1.21.34-py3-none-any.whl", hash = "sha256:4575770d5a0a04e18f0756c50d963f44f091c8d0e3d4530faf768e83af712a50"}, + {file = "mypy-boto3-iotevents-data-1.23.0.post1.tar.gz", hash = "sha256:c9b85cfa0dd6480be83f99f84ee20af0a675d61aa73b76cee55583a721cf7408"}, + {file = "mypy_boto3_iotevents_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:0fb891b17b1debc2a7cd97203fedb53570e436261762d96e8a5e1415691b8cc0"}, ] mypy-boto3-iotfleethub = [ - {file = "mypy-boto3-iotfleethub-1.21.34.tar.gz", hash = "sha256:ea2c8452346750fce867cc98c72c72d37d09afb30d36c444838fd2de026ca73c"}, - {file = "mypy_boto3_iotfleethub-1.21.34-py3-none-any.whl", hash = "sha256:308d5c2fae7a617b8ff4bc820908c5ccb484d714b545da803b0887841e8bd177"}, + {file = "mypy-boto3-iotfleethub-1.23.0.post1.tar.gz", hash = "sha256:5ac847e13661ebb25034e9cc1840b6011beb6459e85615e4b1abc0725eaeea77"}, + {file = "mypy_boto3_iotfleethub-1.23.0.post1-py3-none-any.whl", hash = "sha256:c1042f185f0f8a43af4d208c5358b81ab28b78f0f60cf6ad9021d6a4a86fe67d"}, ] mypy-boto3-iotsecuretunneling = [ - {file = "mypy-boto3-iotsecuretunneling-1.21.34.tar.gz", hash = "sha256:fe34e12c5d186b91937a3f16b3f86119488fe7ad3acf60ea38ce30c01e158985"}, - {file = "mypy_boto3_iotsecuretunneling-1.21.34-py3-none-any.whl", hash = "sha256:b4d579b38de0723658b3134a2ae52f4f885efa8dc7fd4ca1b5e46f7c97db7d04"}, + {file = "mypy-boto3-iotsecuretunneling-1.23.0.post1.tar.gz", hash = "sha256:7c2c0b2534cb4c0213a1861ac9b8116354d1df8c4c98831b591d9023aed98615"}, + {file = "mypy_boto3_iotsecuretunneling-1.23.0.post1-py3-none-any.whl", hash = "sha256:c32b72fa04b9177c5ca57279f634d90533e78c085ec28b8d250e0cea538d4b5f"}, ] mypy-boto3-iotsitewise = [ - {file = "mypy-boto3-iotsitewise-1.21.45.tar.gz", hash = "sha256:f138431bb1db880af137ccee5371722256e288c7a7b16109a178de87a98b47d4"}, - {file = "mypy_boto3_iotsitewise-1.21.45-py3-none-any.whl", hash = "sha256:2d8ef5cf1c53750aa7061a47bdd517b9f06c0e9f14c54d00a41d2f67706e0bf5"}, + {file = "mypy-boto3-iotsitewise-1.23.0.post1.tar.gz", hash = "sha256:494b576e8441aa02577549697ac2d3e2ff48772eecf3bda7e3fd04421af01309"}, + {file = "mypy_boto3_iotsitewise-1.23.0.post1-py3-none-any.whl", hash = "sha256:0280d00e2e729695ef0bd61d8888d85243c49da7788b477e4471fa0a89f68271"}, ] mypy-boto3-iotthingsgraph = [ - {file = "mypy-boto3-iotthingsgraph-1.21.34.tar.gz", hash = "sha256:16ed4ac5ff040e57bdde83f0f2e1dd54c6948574803134a6d866850c6312ec36"}, - {file = "mypy_boto3_iotthingsgraph-1.21.34-py3-none-any.whl", hash = "sha256:f08f88b6b7d98552ff25a68236bf5f4fc3779bc337a45f2f04347064580de756"}, + {file = "mypy-boto3-iotthingsgraph-1.23.0.post1.tar.gz", hash = "sha256:47f21690eb2e190730a4b7ff1e70c660c2877bfbe9c6433665025c2d26df9ab9"}, + {file = "mypy_boto3_iotthingsgraph-1.23.0.post1-py3-none-any.whl", hash = "sha256:c953398aaba67569ab8690549a11854eba46a039d8e65038834f1c4ef48fda13"}, ] mypy-boto3-iottwinmaker = [ - {file = "mypy-boto3-iottwinmaker-1.21.45.tar.gz", hash = "sha256:04f3409a6030a7f72086c99f209d141d122c80747a22ed74ca5a9505a58c4838"}, - {file = "mypy_boto3_iottwinmaker-1.21.45-py3-none-any.whl", hash = "sha256:37154a6462c253097cacb86bea0f549d4164081b3f94882ccab2201e1037532a"}, + {file = "mypy-boto3-iottwinmaker-1.23.0.post1.tar.gz", hash = "sha256:ead9b642b23651a11cd889cd9c528f9e85cc25cfafe7085f4da8db3c123f1254"}, + {file = "mypy_boto3_iottwinmaker-1.23.0.post1-py3-none-any.whl", hash = "sha256:96bb5b74ea4949471b2181d973b197789fb08ee2c02ccc20d8ef0b87e6c8645c"}, ] mypy-boto3-iotwireless = [ - {file = "mypy-boto3-iotwireless-1.21.34.tar.gz", hash = "sha256:1d334050a51fca9a46a05e6481e44c9a0df57a18e369840cc41a57aa934b2585"}, - {file = "mypy_boto3_iotwireless-1.21.34-py3-none-any.whl", hash = "sha256:525e4705420f9d2bd9a02c881ca58f3684f82a9e46b193e357b32094932abd46"}, + {file = "mypy-boto3-iotwireless-1.23.0.post1.tar.gz", hash = "sha256:1c85e7b4dde5030cc76fb1748a4a7b0dc91c25e3307a03a77b4769f149cf6ed9"}, + {file = "mypy_boto3_iotwireless-1.23.0.post1-py3-none-any.whl", hash = "sha256:1f8bb0fd1c307e16fa57212d6f991923c177be284220f30597f1bd64385b978e"}, ] mypy-boto3-ivs = [ - {file = "mypy-boto3-ivs-1.21.34.tar.gz", hash = "sha256:7150415248eb86f38ec6142aa08f338f40f9a0112c5a9524084e67b4fdcd98a4"}, - {file = "mypy_boto3_ivs-1.21.34-py3-none-any.whl", hash = "sha256:2cfbfe65d0b47e6a14407bb0cc3a13d728b67f820d341cf63afb545a363ee81d"}, + {file = "mypy-boto3-ivs-1.23.0.post1.tar.gz", hash = "sha256:d07cc412cd5167bc353952cbf49a0080b1e9a0f630780ef8c1ae824409c626d6"}, + {file = "mypy_boto3_ivs-1.23.0.post1-py3-none-any.whl", hash = "sha256:23bf006dbe26ef716436ec671db64fdf0f0442945d818dc72568617e8600bed4"}, ] mypy-boto3-kafka = [ - {file = "mypy-boto3-kafka-1.21.34.tar.gz", hash = "sha256:ee15fb7733c3754f24b3ceecb54af76d41c41077ccdfbd4039242a7e5fa7f0cd"}, - {file = "mypy_boto3_kafka-1.21.34-py3-none-any.whl", hash = "sha256:8197ffadee3d5f43381dc9c89dd6b3d305b44a816d14985150452b2321be8898"}, + {file = "mypy-boto3-kafka-1.23.0.post1.tar.gz", hash = "sha256:2948d993b43ad05f61451382887ad1acfe29e0e80ad6cf97cf575ffb3f4767a4"}, + {file = "mypy_boto3_kafka-1.23.0.post1-py3-none-any.whl", hash = "sha256:b4aa4cb4642a93db90cf89c1a861c9bbfbacabff4bcd2e9b254b665700ffeb16"}, ] mypy-boto3-kafkaconnect = [ - {file = "mypy-boto3-kafkaconnect-1.21.34.tar.gz", hash = "sha256:b81c121f3abc6e901b5d830b4e3b6a8054087832d9939197ea59fac278aecbda"}, - {file = "mypy_boto3_kafkaconnect-1.21.34-py3-none-any.whl", hash = "sha256:cfb920300ed6f6f6284a7f421610aad06650b90e75712a6f79fff5dfbb8534b2"}, + {file = "mypy-boto3-kafkaconnect-1.23.0.post1.tar.gz", hash = "sha256:e218132974d0573047605ba945761fbc9c667881f3590484381438526fd06f91"}, + {file = "mypy_boto3_kafkaconnect-1.23.0.post1-py3-none-any.whl", hash = "sha256:533f778d2ea473af7a53bfd8a93ed8260bdb13596dd2f133bb339dc6aa42cfce"}, ] mypy-boto3-kendra = [ - {file = "mypy-boto3-kendra-1.21.43.tar.gz", hash = "sha256:e1a269065f692e5d9b96abab3db0fcf5fe1cfea340ce25aeafa21d130135fd53"}, - {file = "mypy_boto3_kendra-1.21.43-py3-none-any.whl", hash = "sha256:bb5df7629472347f5fd1b8e2fa39d621b59c3aa0cbcdfcba45f31ba66a63c7fa"}, + {file = "mypy-boto3-kendra-1.23.0.post1.tar.gz", hash = "sha256:3a980c46a9a161467b33ba081ebd189ae940baa9a2bdb6467b6b12a93141cde5"}, + {file = "mypy_boto3_kendra-1.23.0.post1-py3-none-any.whl", hash = "sha256:46da12dd3ca4fd990ec0f96ca193ac690d4e4ada7afa290c2176332be2d28939"}, ] mypy-boto3-kinesis = [ - {file = "mypy-boto3-kinesis-1.21.34.tar.gz", hash = "sha256:901a48f96ed10b8716d9cf73ba857ec557e928f3ae2edbbf5523ec89d530dd60"}, - {file = "mypy_boto3_kinesis-1.21.34-py3-none-any.whl", hash = "sha256:b59935a5cded592bdd88691e52e6fe83dc3a70964d44b4147d47086a0dc76d87"}, + {file = "mypy-boto3-kinesis-1.23.0.post1.tar.gz", hash = "sha256:7aadbee97d3dc7c1295eedf4c99c42901e61edf5578bc12d9a033d440ed99878"}, + {file = "mypy_boto3_kinesis-1.23.0.post1-py3-none-any.whl", hash = "sha256:d342e7e333f2efd5e32a8fe663bb3dce49525c4de437e25ebcfe233c094299fb"}, ] mypy-boto3-kinesis-video-archived-media = [ - {file = "mypy-boto3-kinesis-video-archived-media-1.21.34.tar.gz", hash = "sha256:4fb8358bf7d5b9b6792bad2d0cb93ff6a26ea17b2ff00d084447768a9a207c3b"}, - {file = "mypy_boto3_kinesis_video_archived_media-1.21.34-py3-none-any.whl", hash = "sha256:9682c072841ae0bfe3baaa266f2727ff591ceb504f56391e301eb0b60d3fe55e"}, + {file = "mypy-boto3-kinesis-video-archived-media-1.23.0.post1.tar.gz", hash = "sha256:e0fa0437e8cbfbf46cadc2eedbbf66d5e569816d0137ac26bda8a903991e69f0"}, + {file = "mypy_boto3_kinesis_video_archived_media-1.23.0.post1-py3-none-any.whl", hash = "sha256:f48a59c97ba7c9d9852e20a7ee43936a50de3040c88d80a1dd259f52e7bc6eda"}, ] mypy-boto3-kinesis-video-media = [ - {file = "mypy-boto3-kinesis-video-media-1.21.34.tar.gz", hash = "sha256:0c62b742a0d6d05e1acd99eb675f683e077cb21511feb192576641f1fadb0a05"}, - {file = "mypy_boto3_kinesis_video_media-1.21.34-py3-none-any.whl", hash = "sha256:89ca3bf5ee655dbca8d996c84bb252b3f615612bf501207c3ea96f0ea5f277fb"}, + {file = "mypy-boto3-kinesis-video-media-1.23.0.post1.tar.gz", hash = "sha256:91ce5c944fe541d2fcaff98715f9a34196851958d0c67aae541fb15e4018f548"}, + {file = "mypy_boto3_kinesis_video_media-1.23.0.post1-py3-none-any.whl", hash = "sha256:5d785ac52bf695e2a61fe046530bf470260361a19e0ea14c74db5bcac322f8e2"}, ] mypy-boto3-kinesis-video-signaling = [ - {file = "mypy-boto3-kinesis-video-signaling-1.21.34.tar.gz", hash = "sha256:e8ac37ba3a3eab515d363a52390662526daea98e3ab6b184e9e2976acf203b00"}, - {file = "mypy_boto3_kinesis_video_signaling-1.21.34-py3-none-any.whl", hash = "sha256:a3b75111f038a610ef3057145436f888c4777fcc58875371b030476f072b406c"}, + {file = "mypy-boto3-kinesis-video-signaling-1.23.0.post1.tar.gz", hash = "sha256:7408b36272ad27dc403d835f02eae75a0a4ee16fe09a7ebe279b278679e16f06"}, + {file = "mypy_boto3_kinesis_video_signaling-1.23.0.post1-py3-none-any.whl", hash = "sha256:f470c1cb2af90bd339df892274a582194713fb7e4475ccd8b4b52079233490ce"}, ] mypy-boto3-kinesisanalytics = [ - {file = "mypy-boto3-kinesisanalytics-1.21.34.tar.gz", hash = "sha256:0f09722ce3f628d4c1cf5d585d1380e8875c4e884f87b16539519ce060f47459"}, - {file = "mypy_boto3_kinesisanalytics-1.21.34-py3-none-any.whl", hash = "sha256:add08ac93144142367e4171cd61a61f9cb936fe389e750207e26819efbc83a98"}, + {file = "mypy-boto3-kinesisanalytics-1.23.0.post1.tar.gz", hash = "sha256:0d29b18596325f9047d884b2bfc6fdde7a1f2ebbbde77200be9698f996bd5caa"}, + {file = "mypy_boto3_kinesisanalytics-1.23.0.post1-py3-none-any.whl", hash = "sha256:f2f3dd512c39aa9f5e84689f2794c62b31ce96b0c9e5a2513d6862f857a9747c"}, ] mypy-boto3-kinesisanalyticsv2 = [ - {file = "mypy-boto3-kinesisanalyticsv2-1.21.34.tar.gz", hash = "sha256:4b3fe176490f52a9bcb1863c3ed343496f799059fa231dd119c22ea13e2fcfe7"}, - {file = "mypy_boto3_kinesisanalyticsv2-1.21.34-py3-none-any.whl", hash = "sha256:4896abbf127dec862a416c00b5d245e15a6b2629fecd650a5276cc2ed54b6408"}, + {file = "mypy-boto3-kinesisanalyticsv2-1.23.0.post1.tar.gz", hash = "sha256:1a5d0c179676db594b5774172e944f8f126ea0c41ed5e1a6110f6a7718ef4306"}, + {file = "mypy_boto3_kinesisanalyticsv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:43addbbf6862a334e93a1919df98ad75ae8e0229c56b076284dd5af682487251"}, ] mypy-boto3-kinesisvideo = [ - {file = "mypy-boto3-kinesisvideo-1.21.34.tar.gz", hash = "sha256:cd86cd96b904078ef9121c6c13e78afe8d2f8c1774da06a5c132229fd9bd2ac5"}, - {file = "mypy_boto3_kinesisvideo-1.21.34-py3-none-any.whl", hash = "sha256:52a3eaebe9aeaad8736afc662c39250e46005bdc14b341639c35b468bb4e98e4"}, + {file = "mypy-boto3-kinesisvideo-1.23.0.post1.tar.gz", hash = "sha256:6538883640f17e2d8cc6822b36c7c6c286ac178a92032bc16be9f81467a70d35"}, + {file = "mypy_boto3_kinesisvideo-1.23.0.post1-py3-none-any.whl", hash = "sha256:df5b4a105b57afd73155182d3c822c910fb9977fd18094a6379e15ccdc577c67"}, ] mypy-boto3-kms = [ - {file = "mypy-boto3-kms-1.21.43.tar.gz", hash = "sha256:e51bef023c773fba30a248b7254ab9ecf3b54397c9e8d067d5667e364899a6a6"}, - {file = "mypy_boto3_kms-1.21.43-py3-none-any.whl", hash = "sha256:7ea048298b49d1d8bb3ca45485d45151aa1a1867e7fe6294d3b5f3103458d78a"}, + {file = "mypy-boto3-kms-1.23.0.post1.tar.gz", hash = "sha256:93b1d3b0c3d8fa7e3aa3cf6ed84f95d27f7b36ff6881d9c80236946c0bf9ebee"}, + {file = "mypy_boto3_kms-1.23.0.post1-py3-none-any.whl", hash = "sha256:e332f692188d30282b95214d9cbdc53e610a2b2ff782e12d0ecdb71cdfc81128"}, ] mypy-boto3-lakeformation = [ - {file = "mypy-boto3-lakeformation-1.21.34.tar.gz", hash = "sha256:15dec6e36ede2d0589d0e42a60144b56c4daf3fcf032496626b08c5759f2e1ec"}, - {file = "mypy_boto3_lakeformation-1.21.34-py3-none-any.whl", hash = "sha256:8d87a9e25b8660c826e706ee103291c075921ae535fb83b02df21f744d9946f0"}, + {file = "mypy-boto3-lakeformation-1.23.0.post1.tar.gz", hash = "sha256:15c34ee63ac930f508bc6f6ab096947621ff6ce62b3b65042d27e7b26f46ac56"}, + {file = "mypy_boto3_lakeformation-1.23.0.post1-py3-none-any.whl", hash = "sha256:9e3b38b51ed8bbd2ac3737f12c048b0b799a1f00243080dcb4879af10aa05a85"}, ] mypy-boto3-lambda = [ - {file = "mypy-boto3-lambda-1.21.35.tar.gz", hash = "sha256:ea5c6f39875ffc705053f5e08230f26b05b85eff33c88aac25981e4e2747dcea"}, - {file = "mypy_boto3_lambda-1.21.35-py3-none-any.whl", hash = "sha256:3f4f752ee81b075675caec9b52294061cf6556210f2cfbfd3d8a88ac662d64fb"}, + {file = "mypy-boto3-lambda-1.23.0.post1.tar.gz", hash = "sha256:12a49331cd904f6a594343b3fa54b691ddd0ff3929b2a60eccee2d887c77f530"}, + {file = "mypy_boto3_lambda-1.23.0.post1-py3-none-any.whl", hash = "sha256:7779f6a8ef81c8425887cb4c6485da17dbc407da461c9674e86f2b2b6e4ca678"}, ] mypy-boto3-lex-models = [ - {file = "mypy-boto3-lex-models-1.21.34.tar.gz", hash = "sha256:5df1983db50db545944aa4744ac72bf0004d365c0a1ec77a7325058c25bf35b4"}, - {file = "mypy_boto3_lex_models-1.21.34-py3-none-any.whl", hash = "sha256:f7b837a3b4b45752f52c84cbabf54a4289d3fadd26eed8548b69bc35f83652af"}, + {file = "mypy-boto3-lex-models-1.23.0.post1.tar.gz", hash = "sha256:a77410122553e3e80435a863c87cba40829354e9fb2d8cd06e3da9cef63403e1"}, + {file = "mypy_boto3_lex_models-1.23.0.post1-py3-none-any.whl", hash = "sha256:7e9244d44678ed9a0e7dd4f2c9c3c1be412219cdb79ade175e1b3bf1bbf5901c"}, ] mypy-boto3-lex-runtime = [ - {file = "mypy-boto3-lex-runtime-1.21.34.tar.gz", hash = "sha256:caad1054552c3af2a9525488cad535134f19f2989b11e0f9858339a5fd5d383a"}, - {file = "mypy_boto3_lex_runtime-1.21.34-py3-none-any.whl", hash = "sha256:6006d63fd81248a3a5dd4ee9a6e5e76feb9e0949ff5136289041a919f84ce755"}, + {file = "mypy-boto3-lex-runtime-1.23.0.post1.tar.gz", hash = "sha256:fd6ef9f8b00eaf442c7d801fa898f26999517e8d6788962fa8b064402f72f7fd"}, + {file = "mypy_boto3_lex_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:2d5b27cb625cf1733ee6f757f0b073558a1c4141a53ae55ac9d1e449b9f9c9f7"}, ] mypy-boto3-lexv2-models = [ - {file = "mypy-boto3-lexv2-models-1.21.34.tar.gz", hash = "sha256:81f78ec8d03436971d7da84a6789d3ddf9a50024ed89517e806e276a30b50138"}, - {file = "mypy_boto3_lexv2_models-1.21.34-py3-none-any.whl", hash = "sha256:6d410f2bc9d3b2397ebf9ae7309c71e719715250b858f443788a5c1aca310925"}, + {file = "mypy-boto3-lexv2-models-1.23.0.post1.tar.gz", hash = "sha256:66ada5376a0f5ad9d4822fd219ba25d034d401218bf010e0f1c7845c0f838237"}, + {file = "mypy_boto3_lexv2_models-1.23.0.post1-py3-none-any.whl", hash = "sha256:32c28f66e6395c1d1e235b28d5e8c336ee5d60661a8fe52819e306bd3f8b67b2"}, ] mypy-boto3-lexv2-runtime = [ - {file = "mypy-boto3-lexv2-runtime-1.21.34.tar.gz", hash = "sha256:e394445ed4bec7fbdc6f05638ec071d36fe79aba289a980255765e0bdc57ac55"}, - {file = "mypy_boto3_lexv2_runtime-1.21.34-py3-none-any.whl", hash = "sha256:7f7bbaf06919859fdc1d9c5ac53d8ff8ef337362257b8f23041f65bc7e23a354"}, + {file = "mypy-boto3-lexv2-runtime-1.23.0.post1.tar.gz", hash = "sha256:1e48d1034413cb25a22ed6bed9e702c73788807aa4f07c5aa2fbcac2da9a0d1e"}, + {file = "mypy_boto3_lexv2_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:a99ba4ef4d3610b0e39fd481a1cff663b5cf8bf769c39a1c7ff805de347a19b7"}, ] mypy-boto3-license-manager = [ - {file = "mypy-boto3-license-manager-1.21.34.tar.gz", hash = "sha256:9329ae77aa8c4bfb1ce803639e99e8b78d2e7855cf5a52657abb1245f4564eb1"}, - {file = "mypy_boto3_license_manager-1.21.34-py3-none-any.whl", hash = "sha256:c1286c7945cb75b2faf611f6695fb1bf7b4e706700afd5bfb957fde852b0c143"}, + {file = "mypy-boto3-license-manager-1.23.0.post1.tar.gz", hash = "sha256:de3b37aebc2712ae7c0804e5ae1224db9a886fc9007d8c2a47d0f0f0f1776a4f"}, + {file = "mypy_boto3_license_manager-1.23.0.post1-py3-none-any.whl", hash = "sha256:676b2fe622f970b69c006932a86e103d4866188a421b1c30320cbf1ac69a35ec"}, ] mypy-boto3-lightsail = [ - {file = "mypy-boto3-lightsail-1.21.42.tar.gz", hash = "sha256:5984af84da607ff5dc28e5bfac7f8d03248fba0bab8ef9fa98bf6377f4e0011a"}, - {file = "mypy_boto3_lightsail-1.21.42-py3-none-any.whl", hash = "sha256:0014f68cc3bc0a0493146af68d54dff54ed5ca8c92b613c35af40958ba6fe7be"}, + {file = "mypy-boto3-lightsail-1.23.0.post1.tar.gz", hash = "sha256:e9b19c429b9049010f207941fdb6d47e81535ba3a8bd3db9ceccefba8b9c0706"}, + {file = "mypy_boto3_lightsail-1.23.0.post1-py3-none-any.whl", hash = "sha256:05841ca6df6ef41650f5a966d690b5af2260887a51e41c2eaa032cb0f07d1f9a"}, ] mypy-boto3-location = [ - {file = "mypy-boto3-location-1.21.34.tar.gz", hash = "sha256:483afdf317a8a2a0f07ac117ab490fc73e0e5e7b93d8b6d6e92b4ee18a3951b7"}, - {file = "mypy_boto3_location-1.21.34-py3-none-any.whl", hash = "sha256:1beeac060677d465262da3401a6c0e2720df99c4bd8f016f557911645ad4acff"}, + {file = "mypy-boto3-location-1.23.0.post1.tar.gz", hash = "sha256:04cbbc8421a52f1752e831c2060c3e60bd62e6d9452b8837e0381f5047146c5e"}, + {file = "mypy_boto3_location-1.23.0.post1-py3-none-any.whl", hash = "sha256:f90bba49f05b666e92c23ec259063b22bd1b1a523e2126ec559a450e49db5199"}, ] mypy-boto3-logs = [ - {file = "mypy-boto3-logs-1.21.34.tar.gz", hash = "sha256:2e5e1a2d77236d32ca54445058e8364d8b560727d59eb38f9ceb031a9bff8691"}, - {file = "mypy_boto3_logs-1.21.34-py3-none-any.whl", hash = "sha256:fc689545dbf3c8cba96210742dbe1f853629301ad208362876e38f3c495512e1"}, + {file = "mypy-boto3-logs-1.23.0.post1.tar.gz", hash = "sha256:296750d6674e7f30dd6fe19de166d1a609a156ae6135f2227ed7b00b6c96e41a"}, + {file = "mypy_boto3_logs-1.23.0.post1-py3-none-any.whl", hash = "sha256:513c2e1bc2dcc42bfff81bb60c21aa375dbf50e6ffbbc4447566ad77e9acddc0"}, ] mypy-boto3-lookoutequipment = [ - {file = "mypy-boto3-lookoutequipment-1.21.34.tar.gz", hash = "sha256:8d8348a67a30fb125848bda02375411c6ab769afbe418058101d882878a95418"}, - {file = "mypy_boto3_lookoutequipment-1.21.34-py3-none-any.whl", hash = "sha256:968a7077be0819225a0f49315d7d0427c364e336114cf6e021bd92304a22db0b"}, + {file = "mypy-boto3-lookoutequipment-1.23.0.post1.tar.gz", hash = "sha256:7a55d103b45f8f95ca22b27a546bad848b801cd16edabeeb656558372d4b2ca9"}, + {file = "mypy_boto3_lookoutequipment-1.23.0.post1-py3-none-any.whl", hash = "sha256:7d66e44544871249a81ef658bc56958a6907cb188c6a774444d365750da95e66"}, ] mypy-boto3-lookoutmetrics = [ - {file = "mypy-boto3-lookoutmetrics-1.21.45.tar.gz", hash = "sha256:a1ecbd7511e28c5025d9c97e82472b2f9846baca313c5b0956560a4896115ee2"}, - {file = "mypy_boto3_lookoutmetrics-1.21.45-py3-none-any.whl", hash = "sha256:2513507b1865a805162f23b7d31403e1ecaafd8bc0aa195d7b47b99b22855ce8"}, + {file = "mypy-boto3-lookoutmetrics-1.23.0.post1.tar.gz", hash = "sha256:9d94b79cfdeb5f65c4ceef8418cbf3445479bd0c4f5caf3d61cd8f2d37de7858"}, + {file = "mypy_boto3_lookoutmetrics-1.23.0.post1-py3-none-any.whl", hash = "sha256:6ce5caf4f85e5a95353b69a36f43c068f4d831004f6c4a31ea37d787a7f6cce4"}, ] mypy-boto3-lookoutvision = [ - {file = "mypy-boto3-lookoutvision-1.21.34.tar.gz", hash = "sha256:d2a27b3f3263c2d3ec1c242b8b08b2f29fd39be82e47bc1de1a0ce48c8508418"}, - {file = "mypy_boto3_lookoutvision-1.21.34-py3-none-any.whl", hash = "sha256:efe262f84aaa22eceef8c3f4e06238c3566313f42f8f3ffd0a6617e6be78b81f"}, + {file = "mypy-boto3-lookoutvision-1.23.0.post1.tar.gz", hash = "sha256:ddf474c249d4744a6156136ea8dc19a3fcffa6d4eb3274bbffd17825f3e105d0"}, + {file = "mypy_boto3_lookoutvision-1.23.0.post1-py3-none-any.whl", hash = "sha256:2d4b23ede0b6d421335f0580b8d669c97daade95d2c95a787aa74c697c7b3aae"}, ] mypy-boto3-machinelearning = [ - {file = "mypy-boto3-machinelearning-1.21.34.tar.gz", hash = "sha256:9efb7de7513aaa8784b5ee71f533702093e5c5e33cc7e1d452ef74783784fd44"}, - {file = "mypy_boto3_machinelearning-1.21.34-py3-none-any.whl", hash = "sha256:4810584dfbf28c02f4d636cf9cddaca748f8408e20a9fe388d1eff6ac95fb9cc"}, + {file = "mypy-boto3-machinelearning-1.23.0.post1.tar.gz", hash = "sha256:7007e34e6dce7a788c191b8204b7f0b3d249356237d27c0ee641c152bc1120bf"}, + {file = "mypy_boto3_machinelearning-1.23.0.post1-py3-none-any.whl", hash = "sha256:2493934a713367a615e128703632a9bacc2b9e750d7c41c739d9aad6a754f7f9"}, ] mypy-boto3-macie = [ - {file = "mypy-boto3-macie-1.21.34.tar.gz", hash = "sha256:48a1768e7e5b746cddbf3ddf366b80b38730fce29c98828c06b7156862e79c8d"}, - {file = "mypy_boto3_macie-1.21.34-py3-none-any.whl", hash = "sha256:dd0530a66eea6a7a1acd728ae33ad5d67787ab2388e2f9e462426629ba384220"}, + {file = "mypy-boto3-macie-1.23.0.post1.tar.gz", hash = "sha256:9b03e67245956c341a44ebccc86147e72011d11d7eed22dd53bfae18f920d6d1"}, + {file = "mypy_boto3_macie-1.23.0.post1-py3-none-any.whl", hash = "sha256:64ffedfde7f33fcbbf20ab5d57a9a1eb269601ac4c9482de1951cfd6eb7b391a"}, ] mypy-boto3-macie2 = [ - {file = "mypy-boto3-macie2-1.21.44.tar.gz", hash = "sha256:cae66f29cb0898870f4b7f484f83633d052d61386aa6b3fb1f0007dbcfdd566a"}, - {file = "mypy_boto3_macie2-1.21.44-py3-none-any.whl", hash = "sha256:e5d562558c99f12bedb6d2dd6b5f5bc7e1719579ef8694d3b4f5eaf7036bb635"}, + {file = "mypy-boto3-macie2-1.23.0.post1.tar.gz", hash = "sha256:14cf9138fd3c3973a264c8fb6a3aa47c585733a98fd9fcb6d1c709dfdf220048"}, + {file = "mypy_boto3_macie2-1.23.0.post1-py3-none-any.whl", hash = "sha256:363dec397942fcdbbf961b31146d9e1e576b55c7d6407d0230a6fdc85bdd6999"}, ] mypy-boto3-managedblockchain = [ - {file = "mypy-boto3-managedblockchain-1.21.34.tar.gz", hash = "sha256:fb5a31a8930b92e539962b7b8c68df3755af0c248e5142a22a3fec7e12dba35e"}, - {file = "mypy_boto3_managedblockchain-1.21.34-py3-none-any.whl", hash = "sha256:2fc1ea11fa2ef126c9dfa6d5ddabb31b7671fed5b38224f848a36e04778fcd04"}, + {file = "mypy-boto3-managedblockchain-1.23.0.post1.tar.gz", hash = "sha256:659f4f5f5bcf035eaba1de835a5a97a6380eb98ac56462303a7d3f101db9c0c1"}, + {file = "mypy_boto3_managedblockchain-1.23.0.post1-py3-none-any.whl", hash = "sha256:648794de4ea1f9932e33bfd315bf246101eaf8db1dc6e18f229be86e10b685a9"}, ] mypy-boto3-marketplace-catalog = [ - {file = "mypy-boto3-marketplace-catalog-1.21.34.tar.gz", hash = "sha256:3fba0befb936c249eab4c71054cc36569cf62de5ae1e94b8a0f369f5985d46d2"}, - {file = "mypy_boto3_marketplace_catalog-1.21.34-py3-none-any.whl", hash = "sha256:fbaa803bb084b94125bc12fdfa9469b729d98d2504b70eab03225dc8866170d4"}, + {file = "mypy-boto3-marketplace-catalog-1.23.0.post1.tar.gz", hash = "sha256:05413f53aeb16d001232d021256f7b4ebaa2fbac7959dfdbbe2a3d74d6697043"}, + {file = "mypy_boto3_marketplace_catalog-1.23.0.post1-py3-none-any.whl", hash = "sha256:351c236fa41eab5f3f18c8fc247bd1bd8a3139b3010bc20a36bf9e5e09a2ee9e"}, ] mypy-boto3-marketplace-entitlement = [ - {file = "mypy-boto3-marketplace-entitlement-1.21.34.tar.gz", hash = "sha256:a2b3f9873257abc62c69a861a9f7306aa5717b7e0bbc0a7ffd321190053ff9b2"}, - {file = "mypy_boto3_marketplace_entitlement-1.21.34-py3-none-any.whl", hash = "sha256:dcba21d16b3ac87700618c00df71e0130a4e6eaf18161fff3e75fdac30ef973a"}, + {file = "mypy-boto3-marketplace-entitlement-1.23.0.post1.tar.gz", hash = "sha256:a68e007525dd7e5dfe853e414d23b2f4f987835b45986f818ae6a19a546a9960"}, + {file = "mypy_boto3_marketplace_entitlement-1.23.0.post1-py3-none-any.whl", hash = "sha256:64b226e706ea0c041213bec3bed37a4fa14d519f78ac174f0aace23081cae5ef"}, ] mypy-boto3-marketplacecommerceanalytics = [ - {file = "mypy-boto3-marketplacecommerceanalytics-1.21.34.tar.gz", hash = "sha256:46989db4963de9a51bc22c314c425cef60bf6abbb76f8e95c6b0888ba71cb658"}, - {file = "mypy_boto3_marketplacecommerceanalytics-1.21.34-py3-none-any.whl", hash = "sha256:01e1f1f591255c6483d3ff83a0c55057a5642c7fe39549373b529780dbf50843"}, + {file = "mypy-boto3-marketplacecommerceanalytics-1.23.0.post1.tar.gz", hash = "sha256:e13cf44b7c5b8a94a19a6665b99e713eeb3390a17d7cdf8222eb8606fdff37ae"}, + {file = "mypy_boto3_marketplacecommerceanalytics-1.23.0.post1-py3-none-any.whl", hash = "sha256:ce18f27298b17863e8bb351e6d27e7f47c61aca9bc23f5d5a6852bd58c0dd5a6"}, ] mypy-boto3-mediaconnect = [ - {file = "mypy-boto3-mediaconnect-1.21.34.tar.gz", hash = "sha256:fb6c92f1bf452691c46ea07265f567b55cda8a19273db3e6f3378dae3d636fdb"}, - {file = "mypy_boto3_mediaconnect-1.21.34-py3-none-any.whl", hash = "sha256:760532d10cbbaac52897116fee4e7034aaa370533d6de049de011fc599627ad2"}, + {file = "mypy-boto3-mediaconnect-1.23.0.post1.tar.gz", hash = "sha256:ce0df54c8f75a8db1835604e41ed9f86a687917457fa8273d8a35b35f6aa53e3"}, + {file = "mypy_boto3_mediaconnect-1.23.0.post1-py3-none-any.whl", hash = "sha256:b80974447fa84ba8373fac3d5e46b399cf98d0f4f97c62425627e0a37c5bc1a0"}, ] mypy-boto3-mediaconvert = [ - {file = "mypy-boto3-mediaconvert-1.21.37.tar.gz", hash = "sha256:dbb52627a49c03d1a1598a4b60e502b13fbb7319adf9c2038709cdf48af0d33d"}, - {file = "mypy_boto3_mediaconvert-1.21.37-py3-none-any.whl", hash = "sha256:b49947108ef2eaa81ce1a4453f99d5af39acbac2a4e587dfd8c6563bd5df318a"}, + {file = "mypy-boto3-mediaconvert-1.23.0.post1.tar.gz", hash = "sha256:0be91b0966f85db7a8eb14d773b2de2a2095ff02187f89a1a9ad5f6361984efb"}, + {file = "mypy_boto3_mediaconvert-1.23.0.post1-py3-none-any.whl", hash = "sha256:ea517eaa5ade83b4cfc448207e0520c62837e025c0979d4d4e9bbb5009e14155"}, ] mypy-boto3-medialive = [ - {file = "mypy-boto3-medialive-1.21.34.tar.gz", hash = "sha256:8eb97515facd0936ba833ebc34535ad89583fd56eb4ceb24f8750899929c9bb4"}, - {file = "mypy_boto3_medialive-1.21.34-py3-none-any.whl", hash = "sha256:549052d466f8b04ce39b2639d5e8687e39a54f6ed8f9623942a922a5477094bd"}, + {file = "mypy-boto3-medialive-1.23.0.post1.tar.gz", hash = "sha256:8e7c290fe2629fc4cac29d83a66737011aa67fc7b2c23b2350026dadcd07df04"}, + {file = "mypy_boto3_medialive-1.23.0.post1-py3-none-any.whl", hash = "sha256:11122a07247801e54a535941a47eef98e0f9975326b2c2711b558c3fa689e46f"}, ] mypy-boto3-mediapackage = [ - {file = "mypy-boto3-mediapackage-1.21.34.tar.gz", hash = "sha256:249ac8d200eabf1eec34cc4de1fcf3fc216fc88735b05cad638f0978f1a5d3f5"}, - {file = "mypy_boto3_mediapackage-1.21.34-py3-none-any.whl", hash = "sha256:3d142a0d5f8bf9c769c041eadfff513ff5e5abf194df011f3e198c81a9666f58"}, + {file = "mypy-boto3-mediapackage-1.23.0.post1.tar.gz", hash = "sha256:a23c37e667cb20349dfa133e8a2f868e8ae2f37fc4ec19ec97424fef7db7a99a"}, + {file = "mypy_boto3_mediapackage-1.23.0.post1-py3-none-any.whl", hash = "sha256:d558f0c1499355419b428dcdb9bb186a8fe3bd75e25caa60b050a5a02ab7a391"}, ] mypy-boto3-mediapackage-vod = [ - {file = "mypy-boto3-mediapackage-vod-1.21.37.tar.gz", hash = "sha256:8e3c4f2757f1c8aa70d4333abbefcefde7f6278f333a834999d45a7ab710d1aa"}, - {file = "mypy_boto3_mediapackage_vod-1.21.37-py3-none-any.whl", hash = "sha256:264de2d097dceb539011957a45283bb4d4c90eda98227083ca3b0c45df988b68"}, + {file = "mypy-boto3-mediapackage-vod-1.23.0.post1.tar.gz", hash = "sha256:abcb8559d075a69ea13130cffed2c6fd082cb620236c2b25ac15f368a74f5edf"}, + {file = "mypy_boto3_mediapackage_vod-1.23.0.post1-py3-none-any.whl", hash = "sha256:bde94cdcddeb1e28c4b528d2794ead34cc6fb3507f77a0d61efd388511239a80"}, ] mypy-boto3-mediastore = [ - {file = "mypy-boto3-mediastore-1.21.34.tar.gz", hash = "sha256:95689b68a767fe6775108341795de11794a94b3c328fafc21efd257ba81652c5"}, - {file = "mypy_boto3_mediastore-1.21.34-py3-none-any.whl", hash = "sha256:01767754b7471a60931fd0748ff66f17208113180924f7cfe4e92c9d4a76f6dc"}, + {file = "mypy-boto3-mediastore-1.23.0.post1.tar.gz", hash = "sha256:0e3fbdd5f9d67dd9dad5dd1c2d175fba6738522971a56f75857c63f811752e89"}, + {file = "mypy_boto3_mediastore-1.23.0.post1-py3-none-any.whl", hash = "sha256:2421eab3b4b222ca88742d0ab4b04d1ff7511855425771fe9ffc852a712fa9bd"}, ] mypy-boto3-mediastore-data = [ - {file = "mypy-boto3-mediastore-data-1.21.34.tar.gz", hash = "sha256:6773b3168fd3f94d7db479c122c15853983152a406e243e9dbf976f777cd6829"}, - {file = "mypy_boto3_mediastore_data-1.21.34-py3-none-any.whl", hash = "sha256:c7c903cdedb4e561c2c94b26e957a2acee937ba6011f6acdcb9d652e6a93aa49"}, + {file = "mypy-boto3-mediastore-data-1.23.0.post1.tar.gz", hash = "sha256:e0d79d89d60e47510f47034014db3872a72babcf3666a29428eb0496b6fb4225"}, + {file = "mypy_boto3_mediastore_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:e4ba7795f2e178e6258c46e6952328998af7f2ab9f2d3346c6bc39e7aa3476c2"}, ] mypy-boto3-mediatailor = [ - {file = "mypy-boto3-mediatailor-1.21.45.tar.gz", hash = "sha256:c90e1ee223d770391411f6bca18df2615f3a523116c0a58d678abbb05c58ba58"}, - {file = "mypy_boto3_mediatailor-1.21.45-py3-none-any.whl", hash = "sha256:c8ca32565d3cf9359c6b2eb78ce33a39dab1f5557808a4df2cd2ad2380c88258"}, + {file = "mypy-boto3-mediatailor-1.23.0.post1.tar.gz", hash = "sha256:36461883d462249de4a69c57c122fa5275baf5bf4cf9954a427f49e17f5d131d"}, + {file = "mypy_boto3_mediatailor-1.23.0.post1-py3-none-any.whl", hash = "sha256:a83ad24041d623fb3bb82a7dc34bf962cd403c4a7e4060d182d3663134d792bc"}, ] mypy-boto3-memorydb = [ - {file = "mypy-boto3-memorydb-1.21.34.tar.gz", hash = "sha256:242a9b7a7943091928af0bb5f0eb564a435016964be8f021dafeccbc9cfe7aa5"}, - {file = "mypy_boto3_memorydb-1.21.34-py3-none-any.whl", hash = "sha256:5e28184b6c2a2a709420c461491b667cdb139c50f42f7d26dd5a5ef47a9c9d4b"}, + {file = "mypy-boto3-memorydb-1.23.0.post1.tar.gz", hash = "sha256:645ec7a30aab1a7f5535f8f8e4c6a55494af8d0c0f49bdbc7d3a59c14c996de0"}, + {file = "mypy_boto3_memorydb-1.23.0.post1-py3-none-any.whl", hash = "sha256:989b209db0eb4836a8f49050aad855164235c13bf9307d5cb25dbe182a1dc91c"}, ] mypy-boto3-meteringmarketplace = [ - {file = "mypy-boto3-meteringmarketplace-1.21.34.tar.gz", hash = "sha256:00b5745a0cee71da12ea246103d41451fd875eccb80e1fe2ee22d5ce3a3b0b16"}, - {file = "mypy_boto3_meteringmarketplace-1.21.34-py3-none-any.whl", hash = "sha256:17a9d950e914389a7be0ffe765ae594747c79c4bfaa03562a9ee3eb63988b1c4"}, + {file = "mypy-boto3-meteringmarketplace-1.23.0.post1.tar.gz", hash = "sha256:ad84b10e402e153e5a416cf59de12490ff4bc4379b339e3f544bf0e473312e78"}, + {file = "mypy_boto3_meteringmarketplace-1.23.0.post1-py3-none-any.whl", hash = "sha256:46fbfcb924a5cdfb0d2590a76753ef6b44f2f79b7daed6fc150e3fa1d1ce1d1c"}, ] mypy-boto3-mgh = [ - {file = "mypy-boto3-mgh-1.21.34.tar.gz", hash = "sha256:41a9a9068cca81a732acc3fa07044edaf8217ca7e77eb425df515fe1f15bb8a1"}, - {file = "mypy_boto3_mgh-1.21.34-py3-none-any.whl", hash = "sha256:3072452ccfb0abf78c4efe0f772f250a9992afd0a6e8d262c44fda2e939f9f1e"}, + {file = "mypy-boto3-mgh-1.23.0.post1.tar.gz", hash = "sha256:34cf4e024701a769642394423454eb452c0e2d81c39469bacf622a64a41e420c"}, + {file = "mypy_boto3_mgh-1.23.0.post1-py3-none-any.whl", hash = "sha256:cda78632f9c3e20628d49c42d3d572a5a81e6f5a59abc7155efd9934f364dfcc"}, ] mypy-boto3-mgn = [ - {file = "mypy-boto3-mgn-1.21.44.tar.gz", hash = "sha256:dd1570bcb73f0aead1977e0ba574ec71f77e0331e77fd20ab3f52d62c359ec52"}, - {file = "mypy_boto3_mgn-1.21.44-py3-none-any.whl", hash = "sha256:e28a358a20619907cb6fd8e701c0d942e8d4b451eebf4b284876c1040b199783"}, + {file = "mypy-boto3-mgn-1.23.0.post1.tar.gz", hash = "sha256:a29b49a21cc03a8fdea28ecf8e26ec86f2b4c91b292c37f11713bc668bd45670"}, + {file = "mypy_boto3_mgn-1.23.0.post1-py3-none-any.whl", hash = "sha256:a31477deaec2bdf16f53ee54a742e1641f9a012529a2141c7280d5fbdbe73c2e"}, ] mypy-boto3-migration-hub-refactor-spaces = [ - {file = "mypy-boto3-migration-hub-refactor-spaces-1.21.34.tar.gz", hash = "sha256:37ae4fb9f6d97ada13b7e9bf9621b7ce602745125be8dbec8ede2cb7d86453ba"}, - {file = "mypy_boto3_migration_hub_refactor_spaces-1.21.34-py3-none-any.whl", hash = "sha256:ce6c09190847bdaa44b09eff2a1cab4988223dfb02f7ce33656a1d70cbd20e8f"}, + {file = "mypy-boto3-migration-hub-refactor-spaces-1.23.0.post1.tar.gz", hash = "sha256:e02d5bf64b6b77a89b1766f2e822b158dccfc907a1abe3ab123c066d51a1ee67"}, + {file = "mypy_boto3_migration_hub_refactor_spaces-1.23.0.post1-py3-none-any.whl", hash = "sha256:77899e9f326322ccc0bdab878d5f3b5ccf78e9ecddfc2ffa3ecba2410310285b"}, ] mypy-boto3-migrationhub-config = [ - {file = "mypy-boto3-migrationhub-config-1.21.34.tar.gz", hash = "sha256:8309761c110acb58d3ec752c78bddd8c4cd37f4c25aa29c3bea96dffeaed8974"}, - {file = "mypy_boto3_migrationhub_config-1.21.34-py3-none-any.whl", hash = "sha256:0cd225e80205a391391222015cd43c35097cc72c0e102534b2c59e3edebf2452"}, + {file = "mypy-boto3-migrationhub-config-1.23.0.post1.tar.gz", hash = "sha256:4de230d1d7d3d630e5ba07ff6fb8c32ab52cc80cabd613fca382344d229259bf"}, + {file = "mypy_boto3_migrationhub_config-1.23.0.post1-py3-none-any.whl", hash = "sha256:687bfc39f4d451471d65b38fb05517df12754e0353497bec3e269a046d019030"}, ] mypy-boto3-migrationhubstrategy = [ - {file = "mypy-boto3-migrationhubstrategy-1.21.34.tar.gz", hash = "sha256:044c8c462bb3cee8cb293791fff8f442824e0024dcf40f35bc3fec2d0b649c7a"}, - {file = "mypy_boto3_migrationhubstrategy-1.21.34-py3-none-any.whl", hash = "sha256:bbde1ec2d5c151595f6f48cb21f31de27c912b49e0bc113e92492968d1ea4296"}, + {file = "mypy-boto3-migrationhubstrategy-1.23.0.post1.tar.gz", hash = "sha256:1c7e663bca6627a8392b0c1a8eb76b5f66366aeed8d11686b9ac11e7190e3aaf"}, + {file = "mypy_boto3_migrationhubstrategy-1.23.0.post1-py3-none-any.whl", hash = "sha256:1a76f5d81788a0e787cf58c70ccbb490d8142326405553f8bb9ac224ae9bd716"}, ] mypy-boto3-mobile = [ - {file = "mypy-boto3-mobile-1.21.34.tar.gz", hash = "sha256:a913620f33f8be774a62d57b27b96e4f76919255d1c13719c4641a44305cbee3"}, - {file = "mypy_boto3_mobile-1.21.34-py3-none-any.whl", hash = "sha256:621d57636905e01c81cc6e1e3a9be7687731a381c1f8b04494cb36f14a345a04"}, + {file = "mypy-boto3-mobile-1.23.0.post1.tar.gz", hash = "sha256:c2432863da475f09ee647a2d609bde4e2a5902938d55373eaf678fe40ddc6fa4"}, + {file = "mypy_boto3_mobile-1.23.0.post1-py3-none-any.whl", hash = "sha256:969aff56d3e991f2d23b1a32329ad6c1cb73ddb0182a5d64198b6afa46ee688d"}, ] mypy-boto3-mq = [ - {file = "mypy-boto3-mq-1.21.34.tar.gz", hash = "sha256:ca35139d18e1b89b94056d25e18c95bd0286298ef20f459b5219e72e73fa957f"}, - {file = "mypy_boto3_mq-1.21.34-py3-none-any.whl", hash = "sha256:d1ff750e0ce2ee12b7cbe5039509efe4996220606d8683e3e80368c33c8c53f1"}, + {file = "mypy-boto3-mq-1.23.0.post1.tar.gz", hash = "sha256:1452c34ca3e78647e42b56a9a478f0c6119a14cbe7af8eefdab3f391df0bd46f"}, + {file = "mypy_boto3_mq-1.23.0.post1-py3-none-any.whl", hash = "sha256:4faca40626031f86236e1aa6b2c2954c51ef754a243447a099ba1a5153b0c2cb"}, ] mypy-boto3-mturk = [ - {file = "mypy-boto3-mturk-1.21.34.tar.gz", hash = "sha256:a44e9782402ac873872c7ad4fd0a4477a1d10bd72094ce3c74df940138882cec"}, - {file = "mypy_boto3_mturk-1.21.34-py3-none-any.whl", hash = "sha256:57fbf1d7c22974316ebdf0c99f488096f420c80a958bbc11da8da1436c3884e7"}, + {file = "mypy-boto3-mturk-1.23.0.post1.tar.gz", hash = "sha256:c322ce82d49503a15f00e1ebac2cb41d11da3bf6d660a3343ad62ac815753f5c"}, + {file = "mypy_boto3_mturk-1.23.0.post1-py3-none-any.whl", hash = "sha256:3c44dd4ceddceed50db21caab427666a90585aff2bcaa144cc2212adf42bb3ca"}, ] mypy-boto3-mwaa = [ - {file = "mypy-boto3-mwaa-1.21.34.tar.gz", hash = "sha256:244e7eaf254b6235ac874b5688999a300168a3d868cd3b7ff9aff726470adb9a"}, - {file = "mypy_boto3_mwaa-1.21.34-py3-none-any.whl", hash = "sha256:8479e08b482edcba45be86ade0e6adeffa7345ae13efd610b1da88f231cefed5"}, + {file = "mypy-boto3-mwaa-1.23.0.post1.tar.gz", hash = "sha256:1354a342016ad93481ec3e69d37d2feced5dfd5dcf9ed1f4499956b81d470683"}, + {file = "mypy_boto3_mwaa-1.23.0.post1-py3-none-any.whl", hash = "sha256:8cf9d93aac010cb0671d7f19a9faf489e8e7372852b5612d39d7e3efbd149c17"}, ] mypy-boto3-neptune = [ - {file = "mypy-boto3-neptune-1.21.34.tar.gz", hash = "sha256:071954c094a145837f0e7a7073d1aff09e3700cbe08f79f3594a129b7097d882"}, - {file = "mypy_boto3_neptune-1.21.34-py3-none-any.whl", hash = "sha256:bef71931d6707bf615e19f3a79df0a4f4e0f7deb6ba0a5ed459788222a110db6"}, + {file = "mypy-boto3-neptune-1.23.0.post1.tar.gz", hash = "sha256:96cf2f8d54abb4bd3e02006119339c1d43dd1f1aa949563300a71a66596edd54"}, + {file = "mypy_boto3_neptune-1.23.0.post1-py3-none-any.whl", hash = "sha256:740775e85af41ec55c589b77b269d72c6a7585f67e7cda10555e473c0fab1cb1"}, ] mypy-boto3-network-firewall = [ - {file = "mypy-boto3-network-firewall-1.21.34.tar.gz", hash = "sha256:a635075d70b3892634a12e87df0cfeaf6d7bc988bc180d43dc6ec7f572bb0531"}, - {file = "mypy_boto3_network_firewall-1.21.34-py3-none-any.whl", hash = "sha256:6943e9c2009b193bf598b7a64cd21fd0b15546441dd79759804b1dd4bfeb22b6"}, + {file = "mypy-boto3-network-firewall-1.23.0.post1.tar.gz", hash = "sha256:d3b1c26ef8e94d74c017a153514ed5a913717bd476602bac26b90880af0aa04c"}, + {file = "mypy_boto3_network_firewall-1.23.0.post1-py3-none-any.whl", hash = "sha256:75953e905dfcb994d3f52b8f144fd1e8b668c9247219661390beb1f7d3467266"}, ] mypy-boto3-networkmanager = [ - {file = "mypy-boto3-networkmanager-1.21.34.tar.gz", hash = "sha256:2bf69d52025cdc18545ec1e36ec0979ff7955e7ae6d1f1a305d5790533703205"}, - {file = "mypy_boto3_networkmanager-1.21.34-py3-none-any.whl", hash = "sha256:8d0d1b57a8cfb29231d135f3f1c02530939735edc58a4640a390c8062200a4d6"}, + {file = "mypy-boto3-networkmanager-1.23.0.post1.tar.gz", hash = "sha256:c05c7ea13f3cecc9831c148c88983f9d6338b84e0b293cfaaa3438aafd67b935"}, + {file = "mypy_boto3_networkmanager-1.23.0.post1-py3-none-any.whl", hash = "sha256:2560030f5ce750463cef7d9695a11dff1f7db1692f631cf8644c7966dad04e32"}, ] mypy-boto3-nimble = [ - {file = "mypy-boto3-nimble-1.21.34.tar.gz", hash = "sha256:5d1d49849098b9cead5d7d0034354dbfc1110071dcf58b74508fb0f7eb1a492a"}, - {file = "mypy_boto3_nimble-1.21.34-py3-none-any.whl", hash = "sha256:90de705317b6cffb562228cffc6dc0e499093096acc6581ddb291abe18e1d516"}, + {file = "mypy-boto3-nimble-1.23.0.post1.tar.gz", hash = "sha256:f89732bf7e2be0b99da8ce37d8a0af35a7ae56fa46fd2366fc66653c40658056"}, + {file = "mypy_boto3_nimble-1.23.0.post1-py3-none-any.whl", hash = "sha256:f64bca2415353cc44e02efff4fb1b2760332cc5af75a4c03b2effac6fac61db9"}, ] mypy-boto3-opensearch = [ - {file = "mypy-boto3-opensearch-1.21.34.tar.gz", hash = "sha256:c35d1199748be9665c84aba4a52a230182958b10a24f7ab2ec1015f8644c119f"}, - {file = "mypy_boto3_opensearch-1.21.34-py3-none-any.whl", hash = "sha256:fbc0cf9193ff94589d4fabfc7f66645fa6a16a7decefb44d0b483d0f543149ed"}, + {file = "mypy-boto3-opensearch-1.23.0.post1.tar.gz", hash = "sha256:b394b86e39ab2d5a787153ef90fa7486e5506f5fc4e287d5adc8b98c2c215603"}, + {file = "mypy_boto3_opensearch-1.23.0.post1-py3-none-any.whl", hash = "sha256:efd89d12ea39d96a4700c32050a4aa3700161a99b7d763ab4adeb0025ee90ee2"}, ] mypy-boto3-opsworks = [ - {file = "mypy-boto3-opsworks-1.21.34.tar.gz", hash = "sha256:30b1734f8b9b234f6b5d6269b54b9d06a9ccf9261f062373cd9aef0cc61c0c14"}, - {file = "mypy_boto3_opsworks-1.21.34-py3-none-any.whl", hash = "sha256:a3d613753af578435c2cbbe72717f290694c6e66fe2b6cdf91d2e69bde8a4271"}, + {file = "mypy-boto3-opsworks-1.23.0.post1.tar.gz", hash = "sha256:cec7d3cd0c898fbfee8a157721875371414cadc5f0aac93535fbb2a1fc8b5efe"}, + {file = "mypy_boto3_opsworks-1.23.0.post1-py3-none-any.whl", hash = "sha256:ffea068817e5a0a1294cead22f70b9ae5568019d79217f4d820950d880a559ff"}, ] mypy-boto3-opsworkscm = [ - {file = "mypy-boto3-opsworkscm-1.21.34.tar.gz", hash = "sha256:daaf22099ee7955c75071057a5d999f984980e63c2775b273e145a4f9adacd30"}, - {file = "mypy_boto3_opsworkscm-1.21.34-py3-none-any.whl", hash = "sha256:a4cf58505f7f415c44e99ca432dcf676860990fccca3443bdf1992e92040b301"}, + {file = "mypy-boto3-opsworkscm-1.23.0.post1.tar.gz", hash = "sha256:974039f0cd325c3734e42c390e8ac65aacc5b369d0d799938723e34b24e4542a"}, + {file = "mypy_boto3_opsworkscm-1.23.0.post1-py3-none-any.whl", hash = "sha256:b6461c59702ba2d7b97a39544cdc0da11feeeb3be994f8f1a2ab0f153ba80afc"}, ] mypy-boto3-organizations = [ - {file = "mypy-boto3-organizations-1.21.34.tar.gz", hash = "sha256:7793d34a927bcdc21c78355952ba9514f199d82d28b9b50a55e3996262dea274"}, - {file = "mypy_boto3_organizations-1.21.34-py3-none-any.whl", hash = "sha256:5ba4517d6e9b419d889337722a02beec77fed5181391e7a9f4e5305b4828f302"}, + {file = "mypy-boto3-organizations-1.23.0.post1.tar.gz", hash = "sha256:26b21b7cf46743ad8f65aaf64f5aacf52e1c22823d9daa3040f145950ad830f6"}, + {file = "mypy_boto3_organizations-1.23.0.post1-py3-none-any.whl", hash = "sha256:668bd957a83d45d3b99c31b2c3d7decc2f0cd0d48f6d122122322faeb33079eb"}, ] mypy-boto3-outposts = [ - {file = "mypy-boto3-outposts-1.21.34.tar.gz", hash = "sha256:5676a8f2ca4c8afdfc0b994cc30a81ff2d3787d64422a5e21727a45d2ebd1932"}, - {file = "mypy_boto3_outposts-1.21.34-py3-none-any.whl", hash = "sha256:aaacb498095dac238384e6470e6158dccef6554df9248a05206278b70b68e874"}, + {file = "mypy-boto3-outposts-1.23.0.post1.tar.gz", hash = "sha256:36c9d28382008def646206a7c2f0e7275ceab89d75703e7ffc5b695111b4edb0"}, + {file = "mypy_boto3_outposts-1.23.0.post1-py3-none-any.whl", hash = "sha256:9da4c8737beb8b988770fbb78e566a0b410542704a85cca90325d6a5073294ef"}, ] mypy-boto3-panorama = [ - {file = "mypy-boto3-panorama-1.21.35.tar.gz", hash = "sha256:99be4ffff8bacff3147aa20f76f4823abc61e103da8b264b3cf71133b912fd74"}, - {file = "mypy_boto3_panorama-1.21.35-py3-none-any.whl", hash = "sha256:7671f22c672e0613b4baf0955a24c56dc705699a4a0bc022500c4cea52acaf48"}, + {file = "mypy-boto3-panorama-1.23.0.post1.tar.gz", hash = "sha256:62803058eb90898b0a9ddc8daebc7c7000e991aa2efe91e75610fe75c8185d42"}, + {file = "mypy_boto3_panorama-1.23.0.post1-py3-none-any.whl", hash = "sha256:100e86da5818cb36aadaa4b06f7282fecd2405f66d0f5ecd8fed73257b025fba"}, ] mypy-boto3-personalize = [ - {file = "mypy-boto3-personalize-1.21.43.tar.gz", hash = "sha256:2c1b845d9663342025fe9478f398353953edbd3e4af2846d45645ac3f795f1c6"}, - {file = "mypy_boto3_personalize-1.21.43-py3-none-any.whl", hash = "sha256:b02b147952ff21bba0b0f6394f26e536db5b3971321822a54e13ab0faa1e7832"}, + {file = "mypy-boto3-personalize-1.23.0.post1.tar.gz", hash = "sha256:c3c9ac875c9b20b0851812df4c95e463f038cfc1e143c51f91426a4784836dba"}, + {file = "mypy_boto3_personalize-1.23.0.post1-py3-none-any.whl", hash = "sha256:d7026ad5863e7270135709662c8454707c6f6037de78d0621496f7d77d86e2cc"}, ] mypy-boto3-personalize-events = [ - {file = "mypy-boto3-personalize-events-1.21.34.tar.gz", hash = "sha256:1cae4b953e11e29fb3907312c24ea78ff88935d86f2f5141ad1bbfbfb525a0e8"}, - {file = "mypy_boto3_personalize_events-1.21.34-py3-none-any.whl", hash = "sha256:acaa13537c9f75bddada7f61599596808b062ff1de2875dc293656cd82e8d382"}, + {file = "mypy-boto3-personalize-events-1.23.0.post1.tar.gz", hash = "sha256:b0a54b1bea2e217df5b7542e900ed2b4602a4cfab58740d5863f4cf31e87a9eb"}, + {file = "mypy_boto3_personalize_events-1.23.0.post1-py3-none-any.whl", hash = "sha256:d89ede9ae54a65011e13cd71ca5c102897f73b1183c078defc79704c714677f7"}, ] mypy-boto3-personalize-runtime = [ - {file = "mypy-boto3-personalize-runtime-1.21.34.tar.gz", hash = "sha256:fe442ed76a260f7531ebc15757714ec82db4008ce76acc3f3f628254c2325d5f"}, - {file = "mypy_boto3_personalize_runtime-1.21.34-py3-none-any.whl", hash = "sha256:d4f5e08304f77bdff7ac9a68b663b9c4cc5d827511d7ab17a1b080a0d72c27a2"}, + {file = "mypy-boto3-personalize-runtime-1.23.0.post1.tar.gz", hash = "sha256:a3b9d79c9adbefcdfde5991ad301ceeaf6445629ff12c66bf86781f315e9576e"}, + {file = "mypy_boto3_personalize_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:4563d6dc740da21c73e1053af8e6478e229ba6f20dee54dde19c47a75ceca7df"}, ] mypy-boto3-pi = [ - {file = "mypy-boto3-pi-1.21.36.tar.gz", hash = "sha256:5a3961d734edbf633fa0d9d01e0569de8bb131fd02695abe35983376cecba018"}, - {file = "mypy_boto3_pi-1.21.36-py3-none-any.whl", hash = "sha256:770d6f8328706c3dff11eeed8c85d9066c4e6a325363bc6580c2997238ef8c86"}, + {file = "mypy-boto3-pi-1.23.0.post1.tar.gz", hash = "sha256:c0d8dc45e5764f127ace5ec014de1f4df63ab4188ce1929d69d9159bc4859456"}, + {file = "mypy_boto3_pi-1.23.0.post1-py3-none-any.whl", hash = "sha256:5ecacd5d1ec194fc9d4137ccc694c00707434f2429c1f021b154efd4eea3e27c"}, ] mypy-boto3-pinpoint = [ - {file = "mypy-boto3-pinpoint-1.21.34.tar.gz", hash = "sha256:ae332f32ff359004986274d82381f28f0c2875854505ee84618ada1d7e7c3032"}, - {file = "mypy_boto3_pinpoint-1.21.34-py3-none-any.whl", hash = "sha256:e90ceb527422aad5adabd7bb3cb1b2f9a02dbb142c01c5fac0fb1d2b96e51c07"}, + {file = "mypy-boto3-pinpoint-1.23.0.post1.tar.gz", hash = "sha256:aa72d16c3828accaa08dda6bdf1528a4ab9671d35a2b64c31888030e243c2b4a"}, + {file = "mypy_boto3_pinpoint-1.23.0.post1-py3-none-any.whl", hash = "sha256:4819bbe309ae019255fb59eada8f7213c4a9e2b867f4dd4e2baffbe9bc2b934a"}, ] mypy-boto3-pinpoint-email = [ - {file = "mypy-boto3-pinpoint-email-1.21.34.tar.gz", hash = "sha256:01f38bb05087118c4e9114be58eca25073bb67930f82ddf3c8fa114fc85fda28"}, - {file = "mypy_boto3_pinpoint_email-1.21.34-py3-none-any.whl", hash = "sha256:2c6e9c868c9d065a564106495e3bc2530bda1b2c1feed5d980c349e9e7e0b9f8"}, + {file = "mypy-boto3-pinpoint-email-1.23.0.post1.tar.gz", hash = "sha256:112e4de03e5927c084246bf112b6e1b3da47642092f66e705543a39724f3ac3b"}, + {file = "mypy_boto3_pinpoint_email-1.23.0.post1-py3-none-any.whl", hash = "sha256:15980007717df963ed5084a4d7cadcdcf2d69eb7bbe5807b6e90d2cfd318ac01"}, ] mypy-boto3-pinpoint-sms-voice = [ - {file = "mypy-boto3-pinpoint-sms-voice-1.21.34.tar.gz", hash = "sha256:ab666cc9ca93b81f5ac13f348f0ddb1b384135db34ec10efaeda98cd8031a38e"}, - {file = "mypy_boto3_pinpoint_sms_voice-1.21.34-py3-none-any.whl", hash = "sha256:78c5dff28a06272b89a0b4c5af28f76321b47a13c00d8a5e5a0f221b8aeb2ab1"}, + {file = "mypy-boto3-pinpoint-sms-voice-1.23.0.post1.tar.gz", hash = "sha256:30436721ad7b438200acae6cfb7a59ba263b4b57a9e3872dea6223c775425923"}, + {file = "mypy_boto3_pinpoint_sms_voice-1.23.0.post1-py3-none-any.whl", hash = "sha256:d9abac517aa047faa21ddc3e68e5afe4af8fb233a9aba5862253d51c6d301d7e"}, ] mypy-boto3-polly = [ - {file = "mypy-boto3-polly-1.21.43.tar.gz", hash = "sha256:1a12c329dc317b1d56d07217b745ee36153dd2f6304cfb6828ef1864cbf56d63"}, - {file = "mypy_boto3_polly-1.21.43-py3-none-any.whl", hash = "sha256:a33a4765bb73250ff5f824158db8650d383fecb03e1539b81d5da86bbd2cde22"}, + {file = "mypy-boto3-polly-1.23.0.post1.tar.gz", hash = "sha256:7dd357561f2ea58a49c27382c835fdafc1570e9a3f2d9e909f29847b2299d5f5"}, + {file = "mypy_boto3_polly-1.23.0.post1-py3-none-any.whl", hash = "sha256:40fcf5054d78fe6081d67a7ab9f1063b28670d4729e8f2588516b7ecd820a795"}, ] mypy-boto3-pricing = [ - {file = "mypy-boto3-pricing-1.21.34.tar.gz", hash = "sha256:1b93cd1abdea772678ae5384a64949d8ceca6eba58959b7b94d5698bf95987df"}, - {file = "mypy_boto3_pricing-1.21.34-py3-none-any.whl", hash = "sha256:98dc919f731a81c3515564658ba522ab30a72666e54a8a327f28fb9e579bff07"}, + {file = "mypy-boto3-pricing-1.23.0.post1.tar.gz", hash = "sha256:5cb1f6070001da78355ccf138e51f6ad16a4692050713a8f4354af22ecba145c"}, + {file = "mypy_boto3_pricing-1.23.0.post1-py3-none-any.whl", hash = "sha256:a8a5568e4a70594a4489a7ac5b58fce2118c1effe5e330da2dfb4c00f0218ffe"}, ] mypy-boto3-proton = [ - {file = "mypy-boto3-proton-1.21.34.tar.gz", hash = "sha256:3d6e4380507960cd99136e48021b659dc0413ea6bbec999c96cfb5406ddce039"}, - {file = "mypy_boto3_proton-1.21.34-py3-none-any.whl", hash = "sha256:46b1f6a8aa792954540064868a967515fa3f816cc46a1ed198ed61e8d2800fb4"}, + {file = "mypy-boto3-proton-1.23.0.post1.tar.gz", hash = "sha256:34da15b7e22f91ad83d82549e89589782c0bd0b6ec583210451996f555b5ac99"}, + {file = "mypy_boto3_proton-1.23.0.post1-py3-none-any.whl", hash = "sha256:1373037fbeaac42eb06387c1c61d1bc8ba49f35020f8d25dbfd777c42d82b518"}, ] mypy-boto3-qldb = [ - {file = "mypy-boto3-qldb-1.21.34.tar.gz", hash = "sha256:a97b56d21712b0fde47cd3c5d0010907b81343da3790349faf00457f453796f5"}, - {file = "mypy_boto3_qldb-1.21.34-py3-none-any.whl", hash = "sha256:1f714bde68d3f7efcf843b7e194d0a9a0792ea01f0bdad13ff6abe16b6a0d4f7"}, + {file = "mypy-boto3-qldb-1.23.0.post1.tar.gz", hash = "sha256:69b261b9df31b1dc9f1428e8bf092371deefe58aeeaacec586c8e27d640248fc"}, + {file = "mypy_boto3_qldb-1.23.0.post1-py3-none-any.whl", hash = "sha256:7d81a158307d880c5370a3c8d6b32e7ae7d7e53292775703cc9c15130c17af74"}, ] mypy-boto3-qldb-session = [ - {file = "mypy-boto3-qldb-session-1.21.34.tar.gz", hash = "sha256:6b00f8922338e5070fda6c918341e3cb01917b07692ccdd1e655277ba019cf09"}, - {file = "mypy_boto3_qldb_session-1.21.34-py3-none-any.whl", hash = "sha256:60c68e2052e18872187a5b6d4e1f78f6e68048936381b08b65851b9cfe561ae5"}, + {file = "mypy-boto3-qldb-session-1.23.0.post1.tar.gz", hash = "sha256:0cd7d5cff41719ae743cb127995f9b7886736915873cc4386d55b238f940a393"}, + {file = "mypy_boto3_qldb_session-1.23.0.post1-py3-none-any.whl", hash = "sha256:e5516b8c2596a537044d9b3b1dbcca9fb75a169824230442a2ce471bf934505a"}, ] mypy-boto3-quicksight = [ - {file = "mypy-boto3-quicksight-1.21.34.tar.gz", hash = "sha256:b46b4f2dd7e7cf8f626e07c0184c0c44a33902c8ba693985cc55d5bb4d31a410"}, - {file = "mypy_boto3_quicksight-1.21.34-py3-none-any.whl", hash = "sha256:0070bf7ebff42c9a28a55a2163fb3048a16b3435d295564ecfc7e4b5c5e4368e"}, + {file = "mypy-boto3-quicksight-1.23.0.post1.tar.gz", hash = "sha256:4a5e67b36468e4f9be8fe7f9f8308d90abf0cfca9853ddd41c4afb058e49101a"}, + {file = "mypy_boto3_quicksight-1.23.0.post1-py3-none-any.whl", hash = "sha256:95bba1d6d3c762231c236094c0443e6a77de44f56fee855227f85cdffb7c15b6"}, ] mypy-boto3-ram = [ - {file = "mypy-boto3-ram-1.21.34.tar.gz", hash = "sha256:12070ec5b080fe933a1fe98dacc3fee0c097b434828806a3992033f216ed8caf"}, - {file = "mypy_boto3_ram-1.21.34-py3-none-any.whl", hash = "sha256:930938dae608053b17b2b2cc2d0b3232f08926e8c876c2c985bd5aaee9d4dca1"}, + {file = "mypy-boto3-ram-1.23.0.post1.tar.gz", hash = "sha256:1101f83a526b64bbf8d0306020637e01c615832cd9ab018c4f9d1d8741033976"}, + {file = "mypy_boto3_ram-1.23.0.post1-py3-none-any.whl", hash = "sha256:aa0bbfda8d4851d87cc0701b97748ca8895a87401cfd72631afbd4ab685c77b5"}, ] mypy-boto3-rbin = [ - {file = "mypy-boto3-rbin-1.21.34.tar.gz", hash = "sha256:0f1a1cb0bbd162d611aec9e093b3543e5bd97da97761a649996a530acbebdc4b"}, - {file = "mypy_boto3_rbin-1.21.34-py3-none-any.whl", hash = "sha256:e0fa9f8545db22140237dafa78c73ff269a758e3aaf2b614eefa4628a358e5ef"}, + {file = "mypy-boto3-rbin-1.23.0.post1.tar.gz", hash = "sha256:33cf2d6498d76cfd1006f8c7f8c19795ca7ade3ff2ccd06251cd2aa6b7a76d69"}, + {file = "mypy_boto3_rbin-1.23.0.post1-py3-none-any.whl", hash = "sha256:2bbd3ebc1de201afb742f91f7629bffbc1fabc886dc5f53218481f39628f4f8e"}, ] mypy-boto3-rds = [ - {file = "mypy-boto3-rds-1.21.44.tar.gz", hash = "sha256:a4b849297dca503a938e19fce2672149ae73cf908efcafae45fab6136d15a5af"}, - {file = "mypy_boto3_rds-1.21.44-py3-none-any.whl", hash = "sha256:86c19720be7c75db4b188f2177ed8ccb46c326615982fb6cc185feb05e39af46"}, + {file = "mypy-boto3-rds-1.23.0.post1.tar.gz", hash = "sha256:a205cb7c49a82e13d221d4e8ded7bab060338c3b7513a9b87cfa1f52da85c328"}, + {file = "mypy_boto3_rds-1.23.0.post1-py3-none-any.whl", hash = "sha256:789d00ed79713f43a1f4837b7ba7a8816096c649edd6be36c2754b69f475d1fd"}, ] mypy-boto3-rds-data = [ - {file = "mypy-boto3-rds-data-1.21.34.tar.gz", hash = "sha256:8a4743050018a79b1e055789dd14f610596b107a59c8e64aa635546ce047295d"}, - {file = "mypy_boto3_rds_data-1.21.34-py3-none-any.whl", hash = "sha256:54d5a3aca18c46d65c1627fa17b7ad0179a4cb7e273a2a65b7edc1aa0561f0a7"}, + {file = "mypy-boto3-rds-data-1.23.0.post1.tar.gz", hash = "sha256:fb87a9448aeefc6bc595c0ef66aee9dd0cd5044ce4b5464abedae9a5216471d1"}, + {file = "mypy_boto3_rds_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:c8baf4a61d4ab8c8c2d477734a9bd93899885bd3ef5350e45a338d5a0b57b489"}, ] mypy-boto3-redshift = [ - {file = "mypy-boto3-redshift-1.21.43.tar.gz", hash = "sha256:adf6eede4edbbb2e4b6e517a84d0c601b77b7ddb60b0b0c46bd4c338810fb630"}, - {file = "mypy_boto3_redshift-1.21.43-py3-none-any.whl", hash = "sha256:c88a868fcaeb821eef431b9836937480e980c56e81b56e7576cad4054fd3a4c4"}, + {file = "mypy-boto3-redshift-1.23.0.post1.tar.gz", hash = "sha256:3a8ed1305a7a823e99b2a37a785407e5191182a71f50faa9c7664291c9620933"}, + {file = "mypy_boto3_redshift-1.23.0.post1-py3-none-any.whl", hash = "sha256:f6dda44c43757f7937a42cb0efd9fb2f57ba0639b54cb0947e46da0a594f21bd"}, ] mypy-boto3-redshift-data = [ - {file = "mypy-boto3-redshift-data-1.21.34.tar.gz", hash = "sha256:bf9cfa00daf5ee289ccfba907d31894f7f700a2af790d93b6e6b75789ffe7874"}, - {file = "mypy_boto3_redshift_data-1.21.34-py3-none-any.whl", hash = "sha256:a1065161b98cf423286e3af5fc27d782aa89f09c74db811aa968a7c70939f899"}, + {file = "mypy-boto3-redshift-data-1.23.0.post1.tar.gz", hash = "sha256:f511fdbd4c1123d8464fcf59916674ac9ad43ff2bce5c5887de8659a15538979"}, + {file = "mypy_boto3_redshift_data-1.23.0.post1-py3-none-any.whl", hash = "sha256:22c892a5e4ba9ecea24fad211673018727dc81f06f9ce31f8460365a0f7af668"}, ] mypy-boto3-rekognition = [ - {file = "mypy-boto3-rekognition-1.21.34.tar.gz", hash = "sha256:a93d95563bfacb5805377a05c812caea8c927b63def56fc7e91775d0f9c0d045"}, - {file = "mypy_boto3_rekognition-1.21.34-py3-none-any.whl", hash = "sha256:4a14e266ea343ff9c6b32d98aac55574c2dc2118ecf44c15d17b59b7c0daf8db"}, + {file = "mypy-boto3-rekognition-1.23.0.post1.tar.gz", hash = "sha256:f57a8ea41c284a2780ae5b6c59e95bab4289442b0018d103de304208aa562f45"}, + {file = "mypy_boto3_rekognition-1.23.0.post1-py3-none-any.whl", hash = "sha256:35b84668562c706b0061b698db2fd26cce9cc8e5b322b8f9d1506467815fb6e2"}, ] mypy-boto3-resiliencehub = [ - {file = "mypy-boto3-resiliencehub-1.21.34.tar.gz", hash = "sha256:bc6068bf79cfb578397688517a8d530ec69f88bcf890e4675ab86161b91657d4"}, - {file = "mypy_boto3_resiliencehub-1.21.34-py3-none-any.whl", hash = "sha256:52db64c79a45cd1ffe87f277dab1d5765b26c59ab3b9078158b8efca8da69a76"}, + {file = "mypy-boto3-resiliencehub-1.23.0.post1.tar.gz", hash = "sha256:71185fb3944af16ee0a0d62651f50fd9ba1d86ffddc936f90be3bc5d9d04b461"}, + {file = "mypy_boto3_resiliencehub-1.23.0.post1-py3-none-any.whl", hash = "sha256:cdca51fd93de4649c531c4fce95d1506e879041a3d1890033116aafbd6de609c"}, ] mypy-boto3-resource-groups = [ - {file = "mypy-boto3-resource-groups-1.21.34.tar.gz", hash = "sha256:7e0351a7002bd0f584abeb68b74b33d2c186e7de90337b18fa29ea04775b319c"}, - {file = "mypy_boto3_resource_groups-1.21.34-py3-none-any.whl", hash = "sha256:2f8f75bfec2bbb3f418e0068be44e82fbaeba743bc38a9718af12b0f9e39402b"}, + {file = "mypy-boto3-resource-groups-1.23.0.post1.tar.gz", hash = "sha256:5421b2522a655543a0c6582f2555e5421c50b2c1f7a89dceb7a832b977ae5ca9"}, + {file = "mypy_boto3_resource_groups-1.23.0.post1-py3-none-any.whl", hash = "sha256:d5f2c61969478ff063def26db7881f6523b774c960170f79628a4f288f5790f0"}, ] mypy-boto3-resourcegroupstaggingapi = [ - {file = "mypy-boto3-resourcegroupstaggingapi-1.21.34.tar.gz", hash = "sha256:cb0e1ce9685637f29233b80ca87285ee6e361c81ba9c3355d837073f0558d256"}, - {file = "mypy_boto3_resourcegroupstaggingapi-1.21.34-py3-none-any.whl", hash = "sha256:ac0c24c857695229b588a5fec9dfd54c3c051503f0882e9ec41ff01d73dec471"}, + {file = "mypy-boto3-resourcegroupstaggingapi-1.23.0.post1.tar.gz", hash = "sha256:c810aa8e0dbda67cb5b0e99c296d28c2ddcc0b511e386ee0dd90b2f99270619d"}, + {file = "mypy_boto3_resourcegroupstaggingapi-1.23.0.post1-py3-none-any.whl", hash = "sha256:45f92bf015db6905c309b8f1f7aaa955b3655ae2a62d11f4b4155d539f778136"}, ] mypy-boto3-robomaker = [ - {file = "mypy-boto3-robomaker-1.21.34.tar.gz", hash = "sha256:dd4d41d0caeee665c6b7a2aa35a4e2cd4b4134e3469e01eda6929a219e6188ae"}, - {file = "mypy_boto3_robomaker-1.21.34-py3-none-any.whl", hash = "sha256:2aec970a417bff655835b49e1495d873d6491f5624e6881af3904ec87e3ac80d"}, + {file = "mypy-boto3-robomaker-1.23.0.post1.tar.gz", hash = "sha256:214d533187a5567bad88c702e7dc987db46c3cba3e472fb499f2516ea510d8ed"}, + {file = "mypy_boto3_robomaker-1.23.0.post1-py3-none-any.whl", hash = "sha256:eeae8adc9ed7c44459961ab8c046f8637c1d08f78e8f2e695bf4122b4c305eaa"}, ] mypy-boto3-route53 = [ - {file = "mypy-boto3-route53-1.21.34.tar.gz", hash = "sha256:6e4383e42182760973f698bbe92d656c44e9f06dda3327655321c49ee7c6de02"}, - {file = "mypy_boto3_route53-1.21.34-py3-none-any.whl", hash = "sha256:147cc00e250f93a5fe006591108100623989c23c01b589bc910dc5239932ed57"}, + {file = "mypy-boto3-route53-1.23.0.post1.tar.gz", hash = "sha256:89dcd3483eba2b4a1064beae86c19ed915daa076adc59bcda9bcd246a0417278"}, + {file = "mypy_boto3_route53-1.23.0.post1-py3-none-any.whl", hash = "sha256:22ef79b880e47341bb78422431ae4694f0b19bb82c3972e3c87ff6bd64537bb0"}, ] mypy-boto3-route53-recovery-cluster = [ - {file = "mypy-boto3-route53-recovery-cluster-1.21.34.tar.gz", hash = "sha256:b63f7390f2e69261a3bf92f874d41906166005fb4a923d968da50e6f71ee844b"}, - {file = "mypy_boto3_route53_recovery_cluster-1.21.34-py3-none-any.whl", hash = "sha256:44e4fff19bec0df4f96d9bf4bda03687325937c1c950831226545263e14e059b"}, + {file = "mypy-boto3-route53-recovery-cluster-1.23.0.post1.tar.gz", hash = "sha256:15cafed014abf3fc783e4ebeecddb8d1ab4573269a7b2fffd5f1118694a0beab"}, + {file = "mypy_boto3_route53_recovery_cluster-1.23.0.post1-py3-none-any.whl", hash = "sha256:e63ded00db5a79b70e82faa1687f5066350478cd5c9c70412de74b4ebc4d17ce"}, ] mypy-boto3-route53-recovery-control-config = [ - {file = "mypy-boto3-route53-recovery-control-config-1.21.34.tar.gz", hash = "sha256:4b1a3a2e12f2d8e1fd631f8b0adcb115bbecf3aea115c65877d5b7cf3b6acda7"}, - {file = "mypy_boto3_route53_recovery_control_config-1.21.34-py3-none-any.whl", hash = "sha256:44635a2a6108f67f9574f602c966e069df08c984142c97c53f847dabb354367a"}, + {file = "mypy-boto3-route53-recovery-control-config-1.23.0.post1.tar.gz", hash = "sha256:ccb2110a2d8395813b39b652897c51924cb9eb876a0cc956a6f2fc6ecff62b7f"}, + {file = "mypy_boto3_route53_recovery_control_config-1.23.0.post1-py3-none-any.whl", hash = "sha256:d27c43d2253e3deb81949d7717a58f6042b147dffd77a7dc4be7bcafe7055afa"}, ] mypy-boto3-route53-recovery-readiness = [ - {file = "mypy-boto3-route53-recovery-readiness-1.21.34.tar.gz", hash = "sha256:fb82cce2afd316ea642f8771487fa68e42c1df0e155a29c955a77d33e48ae907"}, - {file = "mypy_boto3_route53_recovery_readiness-1.21.34-py3-none-any.whl", hash = "sha256:657b16a468df250c4bfe81cf6cd6268f96f696fe7ad56ea9b6f1c4fc7271849e"}, + {file = "mypy-boto3-route53-recovery-readiness-1.23.0.post1.tar.gz", hash = "sha256:29da4df8fadd57c76c8b1f5957c058a7fc94a52f557c3f59adbdcedff1a02973"}, + {file = "mypy_boto3_route53_recovery_readiness-1.23.0.post1-py3-none-any.whl", hash = "sha256:adb2686df297b49aba86246b1ab4468e1b2148abac10c3ad2a7d9ab0db831714"}, ] mypy-boto3-route53domains = [ - {file = "mypy-boto3-route53domains-1.21.34.tar.gz", hash = "sha256:c66bda38618c3e8f8b814f3d339ffd5f09515711ec940163b72c06e0abbfb377"}, - {file = "mypy_boto3_route53domains-1.21.34-py3-none-any.whl", hash = "sha256:4222051ea03cf102f0f9185841d88a214e3347ce0a36860d61068849e6f74208"}, + {file = "mypy-boto3-route53domains-1.23.0.post1.tar.gz", hash = "sha256:150bb0040721b895489a9f7fadccad8934e9f83e6818fa90d0a25c17819bfa5d"}, + {file = "mypy_boto3_route53domains-1.23.0.post1-py3-none-any.whl", hash = "sha256:52ade436fd4b0bc24c44c6646bc2d267378148cf294b4fa38bcc4657bab5d1b1"}, ] mypy-boto3-route53resolver = [ - {file = "mypy-boto3-route53resolver-1.21.34.tar.gz", hash = "sha256:adbfa6329b87586d1c871f957e8344fc775b32dc95eb8ad9a4d35ccf9e7ee58a"}, - {file = "mypy_boto3_route53resolver-1.21.34-py3-none-any.whl", hash = "sha256:ae26efbfacb8f27a8489d2f8776741891075dbca72f17ebe097f2564571090fc"}, + {file = "mypy-boto3-route53resolver-1.23.0.post1.tar.gz", hash = "sha256:875fad7c631ce583d39370ee98e1fc7ebbdca3e5020877335e59a6cfcfd869b7"}, + {file = "mypy_boto3_route53resolver-1.23.0.post1-py3-none-any.whl", hash = "sha256:1f9e613966ba141663c470b1b95068a2d3f97b12b9c64396f99158c530ab0211"}, ] mypy-boto3-rum = [ - {file = "mypy-boto3-rum-1.21.34.tar.gz", hash = "sha256:d9c2968a0fa08be5260ff5b343680993b4ab83dfadf995776904e163982fc467"}, - {file = "mypy_boto3_rum-1.21.34-py3-none-any.whl", hash = "sha256:69142948f5ac99ba8ed224a157451715cd5dd3ac2498c297c84174a5d2295fc0"}, + {file = "mypy-boto3-rum-1.23.0.post1.tar.gz", hash = "sha256:0cca51adb0581f29575f64230088cd7d1ce45a829140657561cbe53712e3b1a8"}, + {file = "mypy_boto3_rum-1.23.0.post1-py3-none-any.whl", hash = "sha256:f81069c44badb8e66b216667f4f753b664681ea31eab404c75d723d1b0817fba"}, ] mypy-boto3-s3 = [ - {file = "mypy-boto3-s3-1.21.34.tar.gz", hash = "sha256:817bcc0be1999272fe8d81bd6500f5fdda9184cc17ad9bd71bc0af08563175ca"}, - {file = "mypy_boto3_s3-1.21.34-py3-none-any.whl", hash = "sha256:798eda3c7856a53ef3805314e8bd3ede55acbde5b0600493bfa6d7245a61958f"}, + {file = "mypy-boto3-s3-1.23.0.post1.tar.gz", hash = "sha256:785d0284c3aa8ac5ec3162e528201618cad351ee2c19f6715a8e6e73f64a0109"}, + {file = "mypy_boto3_s3-1.23.0.post1-py3-none-any.whl", hash = "sha256:2961986739b03dc9d7af00914bc22da130211ec8311a224d63456d4d126e24a6"}, ] mypy-boto3-s3control = [ - {file = "mypy-boto3-s3control-1.21.34.post1.tar.gz", hash = "sha256:4c27b712f1ca82a85c8d7a03797868c408584d89e4029c374c6f800b1c67e45b"}, - {file = "mypy_boto3_s3control-1.21.34.post1-py3-none-any.whl", hash = "sha256:a00fa261f7206b9c1d7ceee43d47e76a6bbea2d7bff0493eb5e22ea4528a18ca"}, + {file = "mypy-boto3-s3control-1.23.0.post1.tar.gz", hash = "sha256:3821612193bf6e37a38d62427c60d4e2aa39f7656d6790c12a838cf2ab335e0e"}, + {file = "mypy_boto3_s3control-1.23.0.post1-py3-none-any.whl", hash = "sha256:cd67aeb042f7dbab7c28adf81e60c62ec7d2d3f78b3d5ee5bcdfca2c1340ee54"}, ] mypy-boto3-s3outposts = [ - {file = "mypy-boto3-s3outposts-1.21.34.tar.gz", hash = "sha256:e48fd64829084c4e0103c128cd03c6d5480cf0359b8741e8f8c633ba35ae4cff"}, - {file = "mypy_boto3_s3outposts-1.21.34-py3-none-any.whl", hash = "sha256:d780ba8f9b3bc8638191a3458c75f10a55c27f5921655a278361ffd5383a6734"}, + {file = "mypy-boto3-s3outposts-1.23.0.post1.tar.gz", hash = "sha256:3c8e686e58c24e26a9ed327ca44ecf418ba8bae0b5367c5c9319288ffb5c3ae1"}, + {file = "mypy_boto3_s3outposts-1.23.0.post1-py3-none-any.whl", hash = "sha256:e99ce83031fcfb23ce885e87120fe30bae351df5898e80a1c39c2d8a5644ca27"}, ] mypy-boto3-sagemaker = [ - {file = "mypy-boto3-sagemaker-1.21.36.tar.gz", hash = "sha256:f427f6ac8a566731d256e6f70b5e1f05195a73ff07920d0e50108bc7a5559c8f"}, - {file = "mypy_boto3_sagemaker-1.21.36-py3-none-any.whl", hash = "sha256:abd58a1581a7e1fa9ce6281aafa6fc4dd92775556599aea59d523c742a455f30"}, + {file = "mypy-boto3-sagemaker-1.23.0.post1.tar.gz", hash = "sha256:b3d8bf0c78f1ebed900fbc99f7cf6746e94abe163e910d497620e8bc22b73412"}, + {file = "mypy_boto3_sagemaker-1.23.0.post1-py3-none-any.whl", hash = "sha256:c7746e2d05fa45f34cca0e5701cb5389daa62f3ec90c971b5630a03eaebe91a6"}, ] mypy-boto3-sagemaker-a2i-runtime = [ - {file = "mypy-boto3-sagemaker-a2i-runtime-1.21.34.tar.gz", hash = "sha256:4ae741cfb66dcd2b8d3e0e4dd8495494da79815ce83245fd0640e88ae4a00b79"}, - {file = "mypy_boto3_sagemaker_a2i_runtime-1.21.34-py3-none-any.whl", hash = "sha256:eaeac5f9ab3d03959e4d05432838a93e8a9477a02e5974bd770ab62ab99bc7ea"}, + {file = "mypy-boto3-sagemaker-a2i-runtime-1.23.0.post1.tar.gz", hash = "sha256:91dc0ee85f9223d6a78e4e31855808cdbb290f46bff7e61517a8ac2135724546"}, + {file = "mypy_boto3_sagemaker_a2i_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:cde5717e498988ea17635eeebfc6967272a2e2473b663a16dbc8138b91f91068"}, ] mypy-boto3-sagemaker-edge = [ - {file = "mypy-boto3-sagemaker-edge-1.21.34.tar.gz", hash = "sha256:f2f5a0de9fd3a13ed0ab8f2f355ce69dc9cd60c593e599053f8de2c688ec9900"}, - {file = "mypy_boto3_sagemaker_edge-1.21.34-py3-none-any.whl", hash = "sha256:df03db845a75a04eb5eae507ba0c42046295dcf53d4bc9ca4012da7ea9904d51"}, + {file = "mypy-boto3-sagemaker-edge-1.23.0.post1.tar.gz", hash = "sha256:8917e4f4a0db0a4926dcd31c69951a5c6f5f7abbaebce98aef8c23c58595f185"}, + {file = "mypy_boto3_sagemaker_edge-1.23.0.post1-py3-none-any.whl", hash = "sha256:6a714de5f44e9ad309d7427b8a22cb4f11638cf3d646cb14b1a1807520d2b107"}, ] mypy-boto3-sagemaker-featurestore-runtime = [ - {file = "mypy-boto3-sagemaker-featurestore-runtime-1.21.34.tar.gz", hash = "sha256:fc7f403e68b6fb00c246fc55219fa2c0a8da98ada2a5e7bcc90b43a8d6aaa74e"}, - {file = "mypy_boto3_sagemaker_featurestore_runtime-1.21.34-py3-none-any.whl", hash = "sha256:b6610b8c0f8e69bb87ccec52c58b11f8e352f318b82d1f511389e252c555f970"}, + {file = "mypy-boto3-sagemaker-featurestore-runtime-1.23.0.post1.tar.gz", hash = "sha256:c86fb0c325720f36b5ead90336f56acd3a67e04ba693b3ded2c99284c93b0da4"}, + {file = "mypy_boto3_sagemaker_featurestore_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:14f752ea375e677e08ae9da397fe26b3af2b7480d73d3ea2c04940e7109a3af4"}, ] mypy-boto3-sagemaker-runtime = [ - {file = "mypy-boto3-sagemaker-runtime-1.21.34.tar.gz", hash = "sha256:86654f552e741d67bc57f3b5e28b4bd213b065d3bf2b886cc94d2b6bbeeb6cbc"}, - {file = "mypy_boto3_sagemaker_runtime-1.21.34-py3-none-any.whl", hash = "sha256:663606c1fa67239ac6de5957b168a8551c79351bf87cbd3154e9dd20bbf86851"}, + {file = "mypy-boto3-sagemaker-runtime-1.23.0.post1.tar.gz", hash = "sha256:7b1885accf88ba6540938c39d9de96c511eeb995d7f51306591b149aadd81a56"}, + {file = "mypy_boto3_sagemaker_runtime-1.23.0.post1-py3-none-any.whl", hash = "sha256:f7bc36cc8359903b61c68029aee7fc8971ca8c682eae5527604c30a76e248c65"}, ] mypy-boto3-savingsplans = [ - {file = "mypy-boto3-savingsplans-1.21.34.tar.gz", hash = "sha256:edd9ad99a2f0428d77638b6c10001f608da5d0bacfb8b0d1852c1de6e67e1473"}, - {file = "mypy_boto3_savingsplans-1.21.34-py3-none-any.whl", hash = "sha256:58a4349a61942d86fdb161c981ec796e2def8653b4fb08c173302e446b4f9472"}, + {file = "mypy-boto3-savingsplans-1.23.0.post1.tar.gz", hash = "sha256:0f891803d0a97b3e7a671c2715ae7a5ad78d55ef8c3124069cdb6aeef5721e2b"}, + {file = "mypy_boto3_savingsplans-1.23.0.post1-py3-none-any.whl", hash = "sha256:480f7b64a723722a99eb3815d3185a2cc1b6de496cc9fabdcf36636d2b5e391b"}, ] mypy-boto3-schemas = [ - {file = "mypy-boto3-schemas-1.21.34.tar.gz", hash = "sha256:5cf7333f3df667deddd267f406786217b5a6659703af39af4d642156a8d96df6"}, - {file = "mypy_boto3_schemas-1.21.34-py3-none-any.whl", hash = "sha256:def6435f421390b0548daaca0e8d06208e464e6347260f709fe26b08f310f4be"}, + {file = "mypy-boto3-schemas-1.23.0.post1.tar.gz", hash = "sha256:b16d6b104adc5a1a3d5f3b08a12f43a665e0760d42333e2bf15c5cf368e5bf50"}, + {file = "mypy_boto3_schemas-1.23.0.post1-py3-none-any.whl", hash = "sha256:a2e35838f417d9878cded87ba16c7fe48da9b3d5d81dc2b27575ea6a42f34642"}, ] mypy-boto3-sdb = [ - {file = "mypy-boto3-sdb-1.21.34.tar.gz", hash = "sha256:298e99e39fdb79ef7b14d16729806895647e37a591e25de08cbcb82eb2d0f920"}, - {file = "mypy_boto3_sdb-1.21.34-py3-none-any.whl", hash = "sha256:28c5568660ce9457f945f1bb960047dfdea882fe7f1d7b1563296059ac0d7ad3"}, + {file = "mypy-boto3-sdb-1.23.0.post1.tar.gz", hash = "sha256:98ffcafa26375fc63a5b31172b372a80cd076010ba8a8a1bbad84a47342fd557"}, + {file = "mypy_boto3_sdb-1.23.0.post1-py3-none-any.whl", hash = "sha256:e3eb3eb965f661e6894245bccd7e11adfedbd37f9ab99e10b23d265faa05704f"}, ] mypy-boto3-secretsmanager = [ - {file = "mypy-boto3-secretsmanager-1.21.45.tar.gz", hash = "sha256:ca058590c4e6003ee769b7f32cbcbc9dc35f0297fb8723d680505a1d8a05b09f"}, - {file = "mypy_boto3_secretsmanager-1.21.45-py3-none-any.whl", hash = "sha256:6648b2ac0838e40f61137b1540c31c9b3fc7b47b481a6bcea435641653552020"}, + {file = "mypy-boto3-secretsmanager-1.23.0.post1.tar.gz", hash = "sha256:f411acaa90b2a84c6372ff81e038740d0cfb9f09b6280c3e1f0dc5468a7ef0f2"}, + {file = "mypy_boto3_secretsmanager-1.23.0.post1-py3-none-any.whl", hash = "sha256:3aa8970bcf2bdb756629b5b0accce44ac5ff58bd7c1258e20e2848bb36f200b6"}, ] mypy-boto3-securityhub = [ - {file = "mypy-boto3-securityhub-1.21.34.post1.tar.gz", hash = "sha256:327bcec2bd30ae835cd00d87bcc3862d31a49614d558d837e8fbc91b579e356c"}, - {file = "mypy_boto3_securityhub-1.21.34.post1-py3-none-any.whl", hash = "sha256:25468d706169630b0bb0d963483a8cbdf97bbf383390e15297e5aa1b2e1cee49"}, + {file = "mypy-boto3-securityhub-1.23.0.post1.tar.gz", hash = "sha256:53f895af8bac87726f66d89a9a39ea45b1bc8c9a1d79dca3b78d86b690979874"}, + {file = "mypy_boto3_securityhub-1.23.0.post1-py3-none-any.whl", hash = "sha256:6386b6456588fc6336106e90f59fd7577b158befae8b54d13f92d51801a1cfce"}, ] mypy-boto3-serverlessrepo = [ - {file = "mypy-boto3-serverlessrepo-1.21.34.tar.gz", hash = "sha256:8ab02b5a7b70f2e9ed4954a5a9c73e01b4dffc763328b042cd4f71a778d0657c"}, - {file = "mypy_boto3_serverlessrepo-1.21.34-py3-none-any.whl", hash = "sha256:f9e5b0d6711906c3d50514dc4d6e16557ebeaf158bac772b190aee2d97790c24"}, + {file = "mypy-boto3-serverlessrepo-1.23.0.post1.tar.gz", hash = "sha256:becab3edcc7ae04f699aea77f65645ab4da91501a72a47cca9f855e43598b343"}, + {file = "mypy_boto3_serverlessrepo-1.23.0.post1-py3-none-any.whl", hash = "sha256:28da416c11edb338ce18e013a9f594554d435d729f3b52f690ca250777239af3"}, ] mypy-boto3-service-quotas = [ - {file = "mypy-boto3-service-quotas-1.21.34.tar.gz", hash = "sha256:eabafcb9b13f37fcf0d21b45d14c829a1d9b670f9bc8b9a96cafd6574039c447"}, - {file = "mypy_boto3_service_quotas-1.21.34-py3-none-any.whl", hash = "sha256:95043fb6b5a43a0fe28dde47b1b58ad6b7b0cb13e07ade4d002883aa5595faed"}, + {file = "mypy-boto3-service-quotas-1.23.0.post1.tar.gz", hash = "sha256:29926dd04242a7b4e62786cd3138c5dc840fe3e78e91ac4750c868252d79555f"}, + {file = "mypy_boto3_service_quotas-1.23.0.post1-py3-none-any.whl", hash = "sha256:725b2547e52e1e5febebd045268aa4fa13756b2d71bc810e2134e61fa49e2407"}, ] mypy-boto3-servicecatalog = [ - {file = "mypy-boto3-servicecatalog-1.21.34.tar.gz", hash = "sha256:2c2eaee7f20a10b55c95d667944e42f0153f87f5e009c6aee8b4aada52230cf4"}, - {file = "mypy_boto3_servicecatalog-1.21.34-py3-none-any.whl", hash = "sha256:de4793ce87353c660cb96e7b0871a365a34e82ff264571b9b2182111c292e669"}, + {file = "mypy-boto3-servicecatalog-1.23.0.post1.tar.gz", hash = "sha256:20ad1697ccb9d7351d99c95286ffc00ebafdc9aec558ee5c3ffa71760a47edfc"}, + {file = "mypy_boto3_servicecatalog-1.23.0.post1-py3-none-any.whl", hash = "sha256:fa0a6e9ce2491152075c46ed9754cc978d69ff87bc76b0c055bd9c99e72d325d"}, ] mypy-boto3-servicecatalog-appregistry = [ - {file = "mypy-boto3-servicecatalog-appregistry-1.21.34.tar.gz", hash = "sha256:7c34f5500beed845e9e3c97b50899d9f9d3d1f51b965b3b6f1ae323adc100918"}, - {file = "mypy_boto3_servicecatalog_appregistry-1.21.34-py3-none-any.whl", hash = "sha256:89533c08d951e6876167cc032cbd5f82fd0faaabcf0e7c275541715555f83e93"}, + {file = "mypy-boto3-servicecatalog-appregistry-1.23.0.post1.tar.gz", hash = "sha256:45f4f3a7c0069de549c064937f8d10f102a69a6f9c4ef496381214223736c4b9"}, + {file = "mypy_boto3_servicecatalog_appregistry-1.23.0.post1-py3-none-any.whl", hash = "sha256:a8280bbbcf3639f7cd2b2a153b872159c15163f9aeabd7a6702202c2ac7efff1"}, ] mypy-boto3-servicediscovery = [ - {file = "mypy-boto3-servicediscovery-1.21.34.tar.gz", hash = "sha256:93b3424dfde1a68091dfe93b1c7982dda6eb319d7ecaa94f5b863fd4b365213d"}, - {file = "mypy_boto3_servicediscovery-1.21.34-py3-none-any.whl", hash = "sha256:6cd95081812a35d054852d62423050fd3941d9e508cceac009b9bac85496a49d"}, + {file = "mypy-boto3-servicediscovery-1.23.0.post1.tar.gz", hash = "sha256:66e0fa3d35d29fce58ce3f25fd1e92d91d9b55c497fba6af763db41da13f9dc1"}, + {file = "mypy_boto3_servicediscovery-1.23.0.post1-py3-none-any.whl", hash = "sha256:ba228ec11210cfe102bf616d1174da3f7a97ab839cbd46391e887acf92713a5e"}, ] mypy-boto3-ses = [ - {file = "mypy-boto3-ses-1.21.34.tar.gz", hash = "sha256:122efa1aca91d89ac60491a8597d4f4ffa58031f45a70692b10357bde941a957"}, - {file = "mypy_boto3_ses-1.21.34-py3-none-any.whl", hash = "sha256:95badc38b2de5c5a2b8387617391d27d05c69ff2e5772e0d11bb983a13c67f7d"}, + {file = "mypy-boto3-ses-1.23.0.post1.tar.gz", hash = "sha256:beac40033f125b7782301324f71346bb99d4eb05a1f344212ed518966f96db86"}, + {file = "mypy_boto3_ses-1.23.0.post1-py3-none-any.whl", hash = "sha256:5d9756857d0b7f7b6286fff3bb08327bac59ccdcacbe091e9f997155c241abea"}, ] mypy-boto3-sesv2 = [ - {file = "mypy-boto3-sesv2-1.21.34.tar.gz", hash = "sha256:20ec2934832e3f1ffd0d323a6d407fc6fc2fe94cc69aa2e876c4f89a09da26af"}, - {file = "mypy_boto3_sesv2-1.21.34-py3-none-any.whl", hash = "sha256:966ee7db41f2c2b52b9d4b076ffad22ade4ef5bc91eb8108f72e31107d1977e2"}, + {file = "mypy-boto3-sesv2-1.23.0.post1.tar.gz", hash = "sha256:b679af1d7afac1ec2cd6a3191505b8ec208c682a9fe2f21e63716b10bac19e95"}, + {file = "mypy_boto3_sesv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:17cf311bb5166db300a3bad8f44f7f4e9d859d573f6d5f6b26f25f51e01363b2"}, ] mypy-boto3-shield = [ - {file = "mypy-boto3-shield-1.21.34.tar.gz", hash = "sha256:71ee94f846ab78dd1dd6234c5a6f8138fbed56ae7baed1935395594bf7cc300e"}, - {file = "mypy_boto3_shield-1.21.34-py3-none-any.whl", hash = "sha256:32553c846e90ad59c431f9b03ac847839f0753965b83ba28046a5a74f175b6ab"}, + {file = "mypy-boto3-shield-1.23.0.post1.tar.gz", hash = "sha256:3307a018741e8e736d978eeb0734126b9c5524f05f0bae0dfe6c4b100c715cb4"}, + {file = "mypy_boto3_shield-1.23.0.post1-py3-none-any.whl", hash = "sha256:8e203a3ba342b45bad8985ba15218f07fd34bba060335d564aef48ae17b866f1"}, ] mypy-boto3-signer = [ - {file = "mypy-boto3-signer-1.21.34.tar.gz", hash = "sha256:e27abdcaef1627c5011b895b8ecf87c30b1c3f8a2ad5b4f50411b10aff85dac7"}, - {file = "mypy_boto3_signer-1.21.34-py3-none-any.whl", hash = "sha256:c5cbd476d67678bb814bb22122eb7991503b3abb291674e4f8ae5fecaf269848"}, + {file = "mypy-boto3-signer-1.23.0.post1.tar.gz", hash = "sha256:3397864280edbe0c77610d61a71f6b520cedb54d007a3527ce743aa82ceb3560"}, + {file = "mypy_boto3_signer-1.23.0.post1-py3-none-any.whl", hash = "sha256:616bb9289ba27e2595d5f1f1245cbb16fb34491dbf5d34d614cc9b386b38c5dd"}, ] mypy-boto3-sms = [ - {file = "mypy-boto3-sms-1.21.34.tar.gz", hash = "sha256:a42ebd3edf5d1965b5be107943ed47d4f3bd0643ffde4d970f90d84780187d1f"}, - {file = "mypy_boto3_sms-1.21.34-py3-none-any.whl", hash = "sha256:473c5c5843f789600ea1060cfdd27e27427f26fd54e4b2254abe5b8e5b5f8d85"}, + {file = "mypy-boto3-sms-1.23.0.post1.tar.gz", hash = "sha256:0021654badb75f86d216b192a09a5f0b760523deb07fc786fba481af4776c9fd"}, + {file = "mypy_boto3_sms-1.23.0.post1-py3-none-any.whl", hash = "sha256:a5d3d7d622f52efdc16e32f8e8d9a284b30f5f29abfe6124e0d6260456402c16"}, ] mypy-boto3-sms-voice = [ - {file = "mypy-boto3-sms-voice-1.21.34.tar.gz", hash = "sha256:10629ae2b2c7c32ad1abea8f13b54554e15af30fc5ed6a227ec149bc5d7bed34"}, - {file = "mypy_boto3_sms_voice-1.21.34-py3-none-any.whl", hash = "sha256:b8b64ce219544995efb70ba34d35ec3f52075e9261eebc05094a18d14f8e6fff"}, + {file = "mypy-boto3-sms-voice-1.23.0.post1.tar.gz", hash = "sha256:d89923b13c48d02f4da542d1b79f6dc7cb4d075fae13f4bcba7946b4d311c73f"}, + {file = "mypy_boto3_sms_voice-1.23.0.post1-py3-none-any.whl", hash = "sha256:789fb00e64b8fd105f650ae74f4239c647b9ab7173b0b0529a1dd48a20236e3d"}, ] mypy-boto3-snow-device-management = [ - {file = "mypy-boto3-snow-device-management-1.21.34.tar.gz", hash = "sha256:4debe2f08b36ea2bbcb8bad07134a68ef589cd6c56d4fb3087752ab41a2692bc"}, - {file = "mypy_boto3_snow_device_management-1.21.34-py3-none-any.whl", hash = "sha256:b94f8594c4c69693458fd1e75c660d330a060d9a150232a8e9107ef2acfeeb2d"}, + {file = "mypy-boto3-snow-device-management-1.23.0.post1.tar.gz", hash = "sha256:91fc0dbbfdbe191dd6894f5932f90c2c9c66201c16847f5a52c2abaae1123827"}, + {file = "mypy_boto3_snow_device_management-1.23.0.post1-py3-none-any.whl", hash = "sha256:8621b85b389fde59aebe35906a06d911af0f377cfb2893ff7c1f0b81c0108d28"}, ] mypy-boto3-snowball = [ - {file = "mypy-boto3-snowball-1.21.34.tar.gz", hash = "sha256:ee2e5eba6512ad2b87f06eb06a9e772cf176a9e7fb292dc6394b9509e12f0940"}, - {file = "mypy_boto3_snowball-1.21.34-py3-none-any.whl", hash = "sha256:f289752145128a6ba1318609550eb46072cd6a005eb0b3f112dec4d269e4a4c4"}, + {file = "mypy-boto3-snowball-1.23.0.post1.tar.gz", hash = "sha256:b4dac8e035ef74227741d8642c66354bd1c5ea3c97493e0f7c34f5209d7a03b7"}, + {file = "mypy_boto3_snowball-1.23.0.post1-py3-none-any.whl", hash = "sha256:c1d4e1675e19b5254148c77bcf936484337e5b9f3dea25b3cdeeb3297ac514df"}, ] mypy-boto3-sns = [ - {file = "mypy-boto3-sns-1.21.34.tar.gz", hash = "sha256:88b29ea197c3bd576fd85d8e1929d3249dd9826ae0e7cba401d1ec30ce6375c5"}, - {file = "mypy_boto3_sns-1.21.34-py3-none-any.whl", hash = "sha256:c20c767e79dc540b4178b949a3243d0a78031b72748b79b8752d610d0110ebfe"}, + {file = "mypy-boto3-sns-1.23.0.post1.tar.gz", hash = "sha256:c9af7ef6918ac0a2df3fa6fb8d55eb27410a65aba202e94e7bbbf6a3335bcd5a"}, + {file = "mypy_boto3_sns-1.23.0.post1-py3-none-any.whl", hash = "sha256:27bedc844edb5b6b4e3900a9e84d30a28b849c7502c66358389421d3e78f809a"}, ] mypy-boto3-sqs = [ - {file = "mypy-boto3-sqs-1.21.34.tar.gz", hash = "sha256:657ff28bfb644d96f524151ad309f83d737d7b962789825be3dd521856fb4fae"}, - {file = "mypy_boto3_sqs-1.21.34-py3-none-any.whl", hash = "sha256:42158c3f969729e7ac0b30c833089f0f795f06f24e8dd5d51ed8e4d3fdaade5b"}, + {file = "mypy-boto3-sqs-1.23.0.post1.tar.gz", hash = "sha256:7cc040aea583453cf0018ccb4721cde2af660f7fdbb4b6022f348e87e6cfd67c"}, + {file = "mypy_boto3_sqs-1.23.0.post1-py3-none-any.whl", hash = "sha256:1c1c28fc005c76f065f694a65af994f9c4a7778ba5678579b567c6b957ef5df8"}, ] mypy-boto3-ssm = [ - {file = "mypy-boto3-ssm-1.21.43.tar.gz", hash = "sha256:960e394fccf8af0102691ce160c96a9b109c8f779569c9a387367d97ddcd1c0d"}, - {file = "mypy_boto3_ssm-1.21.43-py3-none-any.whl", hash = "sha256:68bea4b872eb101716feea160deb35851d6c7fdac4fda9b38610f42539653bda"}, + {file = "mypy-boto3-ssm-1.23.0.post1.tar.gz", hash = "sha256:78333811d184432ddfaa1d14bfb9586badc763d5ff8c876b7a224ebe629f9de8"}, + {file = "mypy_boto3_ssm-1.23.0.post1-py3-none-any.whl", hash = "sha256:f6a21fdd2c8d34be3b621c9ec1b7fb981221a1125cc61945cfacd634f065c951"}, ] mypy-boto3-ssm-contacts = [ - {file = "mypy-boto3-ssm-contacts-1.21.34.tar.gz", hash = "sha256:ae68556d8957a910ec1aabc17da4b69413654d46091794cd60b93cf31153dbd9"}, - {file = "mypy_boto3_ssm_contacts-1.21.34-py3-none-any.whl", hash = "sha256:eeb5ad2da52226e8730258783b42b5c84d8c04bd893f095c236b6c24e401a82b"}, + {file = "mypy-boto3-ssm-contacts-1.23.0.post1.tar.gz", hash = "sha256:0d9c1a5bf8121e1c05efac660ff0bd57c53e75af2f00431e0032445336b8ac97"}, + {file = "mypy_boto3_ssm_contacts-1.23.0.post1-py3-none-any.whl", hash = "sha256:4c6009eac51d8ee33c8ab47a58c9d4bb7d612e1abcb41da147849d9322b65182"}, ] mypy-boto3-ssm-incidents = [ - {file = "mypy-boto3-ssm-incidents-1.21.34.tar.gz", hash = "sha256:e0b77412ba66865756bb9354cb55b86fa8d4f9ce89b9db3087848f170c546a24"}, - {file = "mypy_boto3_ssm_incidents-1.21.34-py3-none-any.whl", hash = "sha256:cc6730bcf4df8d8431691af398254762a45562642d15cc98d389fbefab8dcc95"}, + {file = "mypy-boto3-ssm-incidents-1.23.0.post1.tar.gz", hash = "sha256:d9a769626c757a29519a73dfb5f45eb0024c793ae4134df0272bf6fb290b6783"}, + {file = "mypy_boto3_ssm_incidents-1.23.0.post1-py3-none-any.whl", hash = "sha256:ecda708f6b1ff9fd18fa947bc407d2ab45fd16a7568ac2f472894ade05208966"}, ] mypy-boto3-sso = [ - {file = "mypy-boto3-sso-1.21.34.tar.gz", hash = "sha256:e718bc0b1cc8203146b319a7233bf13cee1c9c5b3186766127a0d4bcb4b851d0"}, - {file = "mypy_boto3_sso-1.21.34-py3-none-any.whl", hash = "sha256:d362c64a4dd8a6d504629cdd34dc110679239d179f217f1accb95c3a259ae4c4"}, + {file = "mypy-boto3-sso-1.23.0.post1.tar.gz", hash = "sha256:ecdaa91b00ca798ca3cfb6df94b862018bea5bba311195987c33f56ca6b1a92a"}, + {file = "mypy_boto3_sso-1.23.0.post1-py3-none-any.whl", hash = "sha256:b45dcff338d24356e59b5018912c20af561816b160c75fb8289cab7f164e3159"}, ] mypy-boto3-sso-admin = [ - {file = "mypy-boto3-sso-admin-1.21.34.tar.gz", hash = "sha256:e287a7a9009bacca083ff9324c45e35a67babdc8d7606b8282139f43e85b7f75"}, - {file = "mypy_boto3_sso_admin-1.21.34-py3-none-any.whl", hash = "sha256:0e4f5b5cd7073f5b9c661668925e10ee80cd6e836b85803e9db8731fa6fc5a7c"}, + {file = "mypy-boto3-sso-admin-1.23.0.post1.tar.gz", hash = "sha256:539bed787fa7514a06da0d80da84a0850d31ebaa8cbcdfc9fa98f258a611b3fb"}, + {file = "mypy_boto3_sso_admin-1.23.0.post1-py3-none-any.whl", hash = "sha256:2b60cdd9b6d10cc5f56e9617be0684cdaac84f49e304e0397547767ea9c57f06"}, ] mypy-boto3-sso-oidc = [ - {file = "mypy-boto3-sso-oidc-1.21.34.tar.gz", hash = "sha256:f47c54e24320c18610815f2ec716bc1aec615114a50173a9fe2258f423b6d3a7"}, - {file = "mypy_boto3_sso_oidc-1.21.34-py3-none-any.whl", hash = "sha256:ce57d5debaca18a71c74fb36f3eda4c5c9672e27c0c6af86b7e0e1f3c74e2881"}, + {file = "mypy-boto3-sso-oidc-1.23.0.post1.tar.gz", hash = "sha256:95842ffd0cbce6a2ff6636ad219c4f5fb9082e72d2275bd11714e0699f1a9ed5"}, + {file = "mypy_boto3_sso_oidc-1.23.0.post1-py3-none-any.whl", hash = "sha256:f06a2fffaf2cd1da8c381b801540719e60efd7e4ea1fd0e3c32eb706635c5bf1"}, ] mypy-boto3-stepfunctions = [ - {file = "mypy-boto3-stepfunctions-1.21.34.tar.gz", hash = "sha256:e13c53f955e173afbf366b33e0e0f71d548b501e153b4e5d32c142a97d9252a2"}, - {file = "mypy_boto3_stepfunctions-1.21.34-py3-none-any.whl", hash = "sha256:a7e1e655905ffa7426351dceb7a5f05648b55a5815cbf689d95b6eeeb3c5dba9"}, + {file = "mypy-boto3-stepfunctions-1.23.0.post1.tar.gz", hash = "sha256:7d0de34f5a6e82b41f40e676264b7d83acf6f69a290302ba2314b7da71e99d76"}, + {file = "mypy_boto3_stepfunctions-1.23.0.post1-py3-none-any.whl", hash = "sha256:035b9af86d110bb3c3eabc7124a86b71d5652210ec52351a0e81e0c164ac3ab8"}, ] mypy-boto3-storagegateway = [ - {file = "mypy-boto3-storagegateway-1.21.45.tar.gz", hash = "sha256:8a145f5653f4fff696915381fb482413442abb2f96937d9f8a7368d48c819c28"}, - {file = "mypy_boto3_storagegateway-1.21.45-py3-none-any.whl", hash = "sha256:f0d80da946b41d28a8b640704e51b4266a5a20d83cb5555e9b7af6ce2a4fbafa"}, + {file = "mypy-boto3-storagegateway-1.23.0.post1.tar.gz", hash = "sha256:81e0c32bc2b678922159adfea73f24b0364f86f40daa4471cf3cabff9389f7a0"}, + {file = "mypy_boto3_storagegateway-1.23.0.post1-py3-none-any.whl", hash = "sha256:8e62c9460fbb5cd09f507d31a35b5e8a4313e4d240adddf68a3b3ac34dee1e78"}, ] mypy-boto3-sts = [ - {file = "mypy-boto3-sts-1.21.34.tar.gz", hash = "sha256:3eebe63a267909c088adcca6fb1a9e0e6f4a5eb57d55bdc462d00ef5c8beb670"}, - {file = "mypy_boto3_sts-1.21.34-py3-none-any.whl", hash = "sha256:5c65bc443e5b8aff2e864834e3be8e3cc3cccc2672fb305b1fdb5e432983af38"}, + {file = "mypy-boto3-sts-1.23.0.post1.tar.gz", hash = "sha256:11be87ff20112b16fa9f4fb68cd12b75a6e90c36dcba6b99e0fb5fc71577eda2"}, + {file = "mypy_boto3_sts-1.23.0.post1-py3-none-any.whl", hash = "sha256:4c26beeaa0a7e94baf4d4c14d6111da1787e2fc1e4ddcb622ee37822a890fbc8"}, ] mypy-boto3-support = [ - {file = "mypy-boto3-support-1.21.34.tar.gz", hash = "sha256:38570bd72fc21da5dfb5eb7dde69f804c9d7d90ddc984683e953d30c5dca4ee4"}, - {file = "mypy_boto3_support-1.21.34-py3-none-any.whl", hash = "sha256:67f4fdea0c0ca8b131e886437a297ae6f24b47d31f5552841db6bab27215878f"}, + {file = "mypy-boto3-support-1.23.0.post1.tar.gz", hash = "sha256:fff08aace8122ea257e58bdd5721d8c6d3b3a73458b3fb2eb158247018ca0809"}, + {file = "mypy_boto3_support-1.23.0.post1-py3-none-any.whl", hash = "sha256:72864e7b51956ed6cea13f18e30c12724ead1528214d5b61648d73bf02d3da39"}, ] mypy-boto3-swf = [ - {file = "mypy-boto3-swf-1.21.34.tar.gz", hash = "sha256:4e261d7bb752d045856ef9d6375fc983a970ce1d81ef9c733d2032847dd202f5"}, - {file = "mypy_boto3_swf-1.21.34-py3-none-any.whl", hash = "sha256:abb79630023e69b4bac10eee8faf725d2919defb0a399498fb4e4a96c6164e88"}, + {file = "mypy-boto3-swf-1.23.0.post1.tar.gz", hash = "sha256:29c4a4dd30e4893277e13e9af36ded0f6a3a7de1fb10a644bc4b6d20c9802d28"}, + {file = "mypy_boto3_swf-1.23.0.post1-py3-none-any.whl", hash = "sha256:02eb1d01dc9add66a92aefa7b92344648c15bf06d34e77d74b354224f3fcd3ea"}, ] mypy-boto3-synthetics = [ - {file = "mypy-boto3-synthetics-1.21.34.tar.gz", hash = "sha256:34d413b9617ffb96f52f7e373ab7ffa227a66d0a85b2a10d4eada52e89248148"}, - {file = "mypy_boto3_synthetics-1.21.34-py3-none-any.whl", hash = "sha256:88ba10b7894cc93a575238e6dce677b1176db214f95e8ad71307f7d37b62323f"}, + {file = "mypy-boto3-synthetics-1.23.0.post1.tar.gz", hash = "sha256:edc2005d5ec650e3fc351c982e98067004b03c6528668cd75358ff7c2bd116f7"}, + {file = "mypy_boto3_synthetics-1.23.0.post1-py3-none-any.whl", hash = "sha256:6d442e9bd638add472043e1ed70b1b8f8c1fa309ddb9a090195d1c55abde4e0d"}, ] mypy-boto3-textract = [ - {file = "mypy-boto3-textract-1.21.43.tar.gz", hash = "sha256:414d4a63ee505a9a63b9f78dd5fb9336ba15b6e2c59b6b49f33d029c1a908b1b"}, - {file = "mypy_boto3_textract-1.21.43-py3-none-any.whl", hash = "sha256:c250733cb7b29e6a05456c7186fdeb2e349df229fd30d6a4df6d35b2655cd871"}, + {file = "mypy-boto3-textract-1.23.0.post1.tar.gz", hash = "sha256:0c9f84dc5fda2e1f8f5ffed2a4f1e5bf05f14ee6e1a15e75a31edf72250b2a8f"}, + {file = "mypy_boto3_textract-1.23.0.post1-py3-none-any.whl", hash = "sha256:106a0f5f1ce25bba92fcf3f6d61277c1975619d00cc8a302de0cee3d8aee943d"}, ] mypy-boto3-timestream-query = [ - {file = "mypy-boto3-timestream-query-1.21.34.tar.gz", hash = "sha256:74a26c38720f79d339446039df388679c4803a8201bd40a703acdf108f9accc6"}, - {file = "mypy_boto3_timestream_query-1.21.34-py3-none-any.whl", hash = "sha256:7fba582a2e25702f1a4a6f1f9d528beba63c7f6b32f01e3b08ed31fc1a068b1a"}, + {file = "mypy-boto3-timestream-query-1.23.0.post1.tar.gz", hash = "sha256:2e40689fa42c9950a963ce265261f664fe626cf4b21e21880c9c9bfac71973d6"}, + {file = "mypy_boto3_timestream_query-1.23.0.post1-py3-none-any.whl", hash = "sha256:a4eba8f4bc4e28f0fd1011a430a7620a2b9f7238f81a0ff21a1013ecfb5a55c7"}, ] mypy-boto3-timestream-write = [ - {file = "mypy-boto3-timestream-write-1.21.34.tar.gz", hash = "sha256:b842fe21da05feaadf6bccf667a90539faf2a58a743b47b9996a4fcc2a4be684"}, - {file = "mypy_boto3_timestream_write-1.21.34-py3-none-any.whl", hash = "sha256:d1fa7179973132373437ce3181b02a0838762c5d3158cd5f2135f46d3a3e9517"}, + {file = "mypy-boto3-timestream-write-1.23.0.post1.tar.gz", hash = "sha256:c59e0b00b211527a7a2d31b7f394ee7278999a43547d6ba7db78623960ccee70"}, + {file = "mypy_boto3_timestream_write-1.23.0.post1-py3-none-any.whl", hash = "sha256:d4958626f1b17d3b70db31dae5b1ab29bf3b1ded87fa06900deaabfd8ab15742"}, ] mypy-boto3-transcribe = [ - {file = "mypy-boto3-transcribe-1.21.34.tar.gz", hash = "sha256:53a9371061ec63cf66b3b10dcaf9a99ca820cdc651f86f7076c4b145217d3f5b"}, - {file = "mypy_boto3_transcribe-1.21.34-py3-none-any.whl", hash = "sha256:84f4a1d8fc4a5e22bdbc68fa8916bf0bd49aeff4d81a4842716ce5275382473b"}, + {file = "mypy-boto3-transcribe-1.23.0.post1.tar.gz", hash = "sha256:ab53e9d9fcdab3bf09085709b0128ae0d780a4c9a090a557a2b65231c2d35243"}, + {file = "mypy_boto3_transcribe-1.23.0.post1-py3-none-any.whl", hash = "sha256:1d0a52305cbc19fc495b6e20a9d1d3e44e3b40606eb780325f09193040ccaa32"}, ] mypy-boto3-transfer = [ - {file = "mypy-boto3-transfer-1.21.43.tar.gz", hash = "sha256:ff680231e3163d9023a963d44ef3330b66dacd04bab6e955da6d85a31d6870ee"}, - {file = "mypy_boto3_transfer-1.21.43-py3-none-any.whl", hash = "sha256:7e9d2751b0d21474907c6b33571e12957b50f69bec2df530149717c905b9ec09"}, + {file = "mypy-boto3-transfer-1.23.0.post1.tar.gz", hash = "sha256:3cb26a5199f7483daa2b36f7e9ecb31af9a40fcc2f499d4137fc9c6ee9b442fc"}, + {file = "mypy_boto3_transfer-1.23.0.post1-py3-none-any.whl", hash = "sha256:4fc9208ccf82255d7e7bd5e2e3caeefece7b9e898185640f36d52f2b67e571fe"}, ] mypy-boto3-translate = [ - {file = "mypy-boto3-translate-1.21.34.tar.gz", hash = "sha256:8680605e4e3a5ea28f92c4eb3fcca8555127c9c6e27fd184f461230a184f3e4b"}, - {file = "mypy_boto3_translate-1.21.34-py3-none-any.whl", hash = "sha256:b9625f5f73c560d6b851d771b1eaf0ac589121605129742ecbc5786e261c849c"}, + {file = "mypy-boto3-translate-1.23.0.post1.tar.gz", hash = "sha256:ed6e042bff8c88649e1601328c4c8c5c721b75b80726c4526501630b75228f7d"}, + {file = "mypy_boto3_translate-1.23.0.post1-py3-none-any.whl", hash = "sha256:38c7205f85d7d2a8ba404211aa702410ddd98599ff9ad6784ae1faa6892671df"}, ] mypy-boto3-voice-id = [ - {file = "mypy-boto3-voice-id-1.21.34.tar.gz", hash = "sha256:162c6b64ee2e6a55618cd6d1e7649bd564d6b962fbc372d6c21991becd6b4c2d"}, - {file = "mypy_boto3_voice_id-1.21.34-py3-none-any.whl", hash = "sha256:dda1a44c27e067a426aa3e4c3c43bafcfb9a7bbf32474b4e79ea638f6377bda1"}, + {file = "mypy-boto3-voice-id-1.23.0.post1.tar.gz", hash = "sha256:57af0e7c9c6120bc8450a066a25679238cedece1db4b8e2608b9e2b5c44d9ade"}, + {file = "mypy_boto3_voice_id-1.23.0.post1-py3-none-any.whl", hash = "sha256:972c15b6802d33122c7068cddd71e681ce4a099f90325206742bc331091efd63"}, ] mypy-boto3-waf = [ - {file = "mypy-boto3-waf-1.21.34.tar.gz", hash = "sha256:ebad0d9f3e7d84a325249ea546b1c1bafd76f5ec479998ccf1b8a5ff9b2be579"}, - {file = "mypy_boto3_waf-1.21.34-py3-none-any.whl", hash = "sha256:99295163ce24a8b02bb75a057a5d6f6e65906e37268127a5cd74b1955b6b28a5"}, + {file = "mypy-boto3-waf-1.23.0.post1.tar.gz", hash = "sha256:468d94eb0c20fc6b508c59b5cc8d27b5ef29b92864d45a872f2f9c005f7480bc"}, + {file = "mypy_boto3_waf-1.23.0.post1-py3-none-any.whl", hash = "sha256:e1429cf80700169a9c1f3a9a1887bb305006d700e177dcdf1c52f98cd8baf10b"}, ] mypy-boto3-waf-regional = [ - {file = "mypy-boto3-waf-regional-1.21.34.tar.gz", hash = "sha256:cdeebe9051d2f937fa24d647686ef3e9f5dafe843082ecad1f9b3933cae68a26"}, - {file = "mypy_boto3_waf_regional-1.21.34-py3-none-any.whl", hash = "sha256:fefcd3f10d80fb061d2ccfb2c6816b262b613b9496de9f0cff3cff350a3883ab"}, + {file = "mypy-boto3-waf-regional-1.23.0.post1.tar.gz", hash = "sha256:43715bc5614b1c301f03e20f7fcb108088536a5c0965a6d152bb4bad41e60025"}, + {file = "mypy_boto3_waf_regional-1.23.0.post1-py3-none-any.whl", hash = "sha256:7ad894d7635efbbd17ebf2be0a5e85beef7a4ac764f26c120b7560d54656d77f"}, ] mypy-boto3-wafv2 = [ - {file = "mypy-boto3-wafv2-1.21.37.tar.gz", hash = "sha256:ba288bbc05156843142b7ca439b36de135171058d1af9f9ba57ec2c89c1ddaf7"}, - {file = "mypy_boto3_wafv2-1.21.37-py3-none-any.whl", hash = "sha256:1b5448533b2539d70643f6029806ad260ff32e46f3267d0a44d06273387c01ad"}, + {file = "mypy-boto3-wafv2-1.23.0.post1.tar.gz", hash = "sha256:63de6c2a298d69b1364dffd29b90da41812d2aaa96cf414d0460d3f9c344e815"}, + {file = "mypy_boto3_wafv2-1.23.0.post1-py3-none-any.whl", hash = "sha256:5aa7db223a379b994685b00f8432641ed1ff3447ed9de7507b4f29d913009718"}, ] mypy-boto3-wellarchitected = [ - {file = "mypy-boto3-wellarchitected-1.21.34.tar.gz", hash = "sha256:a0ebbf90ed7c4d8df94c99aff61c4c36a6a52f6e354456da691cce025a87d28a"}, - {file = "mypy_boto3_wellarchitected-1.21.34-py3-none-any.whl", hash = "sha256:08db129f5767c8080d6334075bed20cf27c1b61cb7aeb358e6704cebef776424"}, + {file = "mypy-boto3-wellarchitected-1.23.0.post1.tar.gz", hash = "sha256:935c375cccb508713cf7fe32475dea75d3131940e7b133cf886e13f4fed6e99b"}, + {file = "mypy_boto3_wellarchitected-1.23.0.post1-py3-none-any.whl", hash = "sha256:1b27babeeb00b3a4b4dbe63e918de10a26183a06d7b7fe53dcedad15b6cdfc5a"}, ] mypy-boto3-wisdom = [ - {file = "mypy-boto3-wisdom-1.21.45.tar.gz", hash = "sha256:cb4f63c4e867641e23f75f4f183ab2d3ddbc4a80548ef9a2dab6f3e3848eba05"}, - {file = "mypy_boto3_wisdom-1.21.45-py3-none-any.whl", hash = "sha256:dc941289a60e74c34e6cb1a522cbb482c3734e90e1ca8595010c5882c826c4c9"}, + {file = "mypy-boto3-wisdom-1.23.0.post1.tar.gz", hash = "sha256:04ced93748566e94abc07dc7616dda0e17544165f2b08fe320c690000b4dcf27"}, + {file = "mypy_boto3_wisdom-1.23.0.post1-py3-none-any.whl", hash = "sha256:411c8fa1abd6441fc2744384e4d432be31e8285977597e8acc4f8e7264d25640"}, ] mypy-boto3-workdocs = [ - {file = "mypy-boto3-workdocs-1.21.34.tar.gz", hash = "sha256:70d2cff979bc1c6a8c903d0a2023fd501e9f9f6d281e9db3142096f9da59d3d6"}, - {file = "mypy_boto3_workdocs-1.21.34-py3-none-any.whl", hash = "sha256:7e6ff51977c1e2591a857fa5ac6a0c64b809606ab919609c0631d6eaf6f2ebc6"}, + {file = "mypy-boto3-workdocs-1.23.0.post1.tar.gz", hash = "sha256:dec474d6a9561590d80456774b902071e4e249d819c701af4c7746fe005267d6"}, + {file = "mypy_boto3_workdocs-1.23.0.post1-py3-none-any.whl", hash = "sha256:33267b0efce908f3c8c63ad4a1613783d7f1751bf6f372c37d680f06cb37a996"}, ] mypy-boto3-worklink = [ - {file = "mypy-boto3-worklink-1.21.43.tar.gz", hash = "sha256:1eee54dc54ba8d88153285daf0c943c5178e04a228975e0d6b8ee132611989b5"}, - {file = "mypy_boto3_worklink-1.21.43-py3-none-any.whl", hash = "sha256:2c5ec65aa31cda92241bd24cc1395900ced12d1416240ff3ae2f18de213172dd"}, + {file = "mypy-boto3-worklink-1.23.0.post1.tar.gz", hash = "sha256:f7c2c95864e38020d0308de7764b9e61d5591f275497a7d655949eddb76cfd06"}, + {file = "mypy_boto3_worklink-1.23.0.post1-py3-none-any.whl", hash = "sha256:f9c808d65920f9aa68b0f80f08a92c20719765ac1a0365e10953f5e1e92620e0"}, ] mypy-boto3-workmail = [ - {file = "mypy-boto3-workmail-1.21.34.tar.gz", hash = "sha256:81017dba364f8b87b1308dadeeee0d1fc8217ae0a259cb060121ed6d40412eb6"}, - {file = "mypy_boto3_workmail-1.21.34-py3-none-any.whl", hash = "sha256:ef860e5403b2f6919b8a8fe6b3bf10117dbac472dc103beb190561058b12a7d2"}, + {file = "mypy-boto3-workmail-1.23.0.post1.tar.gz", hash = "sha256:88cd91c273ab78e766522400a19b6053906432bfc24eb47f0af7ae6d35c194ad"}, + {file = "mypy_boto3_workmail-1.23.0.post1-py3-none-any.whl", hash = "sha256:0e83f91606cd2012333a65de2d99c58361f6c1047bc2966f5b56cb5ee11d1354"}, ] mypy-boto3-workmailmessageflow = [ - {file = "mypy-boto3-workmailmessageflow-1.21.34.tar.gz", hash = "sha256:9af6ebb1a27c544fa4ac628bf4f181ea4145c18dca356577ad6f92e555d22d6b"}, - {file = "mypy_boto3_workmailmessageflow-1.21.34-py3-none-any.whl", hash = "sha256:2a51af6b17532341891b5b27a79b0efd58f488d62c89e11a3ff3e99a8e499cfc"}, + {file = "mypy-boto3-workmailmessageflow-1.23.0.post1.tar.gz", hash = "sha256:6dc62794e7bc4882fcc72f20bda27544a79ae2493547079100106376f6960367"}, + {file = "mypy_boto3_workmailmessageflow-1.23.0.post1-py3-none-any.whl", hash = "sha256:bfe6e00f0a65e750797fef0450f879f3aff922114a4a40621b01cbd21fd29ca0"}, ] mypy-boto3-workspaces = [ - {file = "mypy-boto3-workspaces-1.21.38.tar.gz", hash = "sha256:98f99951693de8782d95248db66036ec47d81f193a0eff99d1f8be91a175b120"}, - {file = "mypy_boto3_workspaces-1.21.38-py3-none-any.whl", hash = "sha256:79d4ab544bb40bf321c4574af650b95aed13808b512dee7f219a09c1878d76af"}, + {file = "mypy-boto3-workspaces-1.23.0.post1.tar.gz", hash = "sha256:351862efbe3673c98d7b3516492c3d1048045ad06f225b042c8b3c91d5ac2b44"}, + {file = "mypy_boto3_workspaces-1.23.0.post1-py3-none-any.whl", hash = "sha256:90397426f50e88b5356cab3f65c96d38b8e8760ac831cf469f36c3c58ca28a29"}, ] mypy-boto3-workspaces-web = [ - {file = "mypy-boto3-workspaces-web-1.21.34.tar.gz", hash = "sha256:bf34e2cc79a9ea2a09cce3a307204ab05cdc8d6ec9f0c6ffc9e2a95765a87b1f"}, - {file = "mypy_boto3_workspaces_web-1.21.34-py3-none-any.whl", hash = "sha256:bbafd4608ed73a0895b9d9d30dca1e5b742b2f751e98b81d9f79b56bad4d7774"}, + {file = "mypy-boto3-workspaces-web-1.23.0.post1.tar.gz", hash = "sha256:5d29d46d10deac1b3d07e74c6a2a1e5225883a185e71780c27448630dae8a92d"}, + {file = "mypy_boto3_workspaces_web-1.23.0.post1-py3-none-any.whl", hash = "sha256:bd0f9675636c39cdd3c797bbe50039edabfc6910de32c0b673e1de78231c44da"}, ] mypy-boto3-xray = [ - {file = "mypy-boto3-xray-1.21.34.tar.gz", hash = "sha256:f4b8b9ec19e06a17471f876284dbd0fcc551b5e3c275b723a6af879f31d2724c"}, - {file = "mypy_boto3_xray-1.21.34-py3-none-any.whl", hash = "sha256:4178f572d3a04e42eec750a47fbc2a909e252a84550df23a5cc9e846a20198ae"}, + {file = "mypy-boto3-xray-1.23.0.post1.tar.gz", hash = "sha256:38978b4c96c3e80821e7b592e1a99178190aa201f3c7fef60886678c42ddc3a0"}, + {file = "mypy_boto3_xray-1.23.0.post1-py3-none-any.whl", hash = "sha256:b6c7a43787a3176598fa4da1161c60b664a04f83c5b5254fd9f89b985e73ccb8"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -6716,8 +6716,8 @@ pathspec = [ {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] pbr = [ - {file = "pbr-5.8.1-py2.py3-none-any.whl", hash = "sha256:27108648368782d07bbf1cb468ad2e2eeef29086affd14087a6d04b7de8af4ec"}, - {file = "pbr-5.8.1.tar.gz", hash = "sha256:66bc5a34912f408bb3925bf21231cb6f59206267b7f63f3503ef865c1a292e25"}, + {file = "pbr-5.9.0-py2.py3-none-any.whl", hash = "sha256:e547125940bcc052856ded43be8e101f63828c2d94239ffbe2b327ba3d5ccf0a"}, + {file = "pbr-5.9.0.tar.gz", hash = "sha256:e8dca2f4b43560edef58813969f52a56cef023146cbb8931626db80e6c1c4308"}, ] pep8-naming = [ {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"}, @@ -6748,12 +6748,12 @@ pyflakes = [ {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] pylic = [ - {file = "pylic-3.0.1-py3-none-any.whl", hash = "sha256:fcbf7c43e2b8d3ca08cef3f99b1c92c62dc7aedba4c8d2306d2dfdddae11b420"}, - {file = "pylic-3.0.1.tar.gz", hash = "sha256:407237dae61e26b02362531f10350209ffa02054d66bec8a6eacebd3f4f42d4f"}, + {file = "pylic-3.0.2-py3-none-any.whl", hash = "sha256:b5ceb0f7a9ac1ebccea4ba88f10e7b53d7d0d8e8f9e006fbdbb82c186dea9bf1"}, + {file = "pylic-3.0.2.tar.gz", hash = "sha256:ca19eeb6bfea9b86869aeda38964cd65c6983250a8782601acf3ffa4e7fc72f2"}, ] pyparsing = [ - {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, - {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pytest = [ {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, diff --git a/pyproject.toml b/pyproject.toml index 7fa2f5fd3..7cf093d27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_sra_examples" -version = "2.1.0" +version = "2.1.1" description = "AWS Security Reference Architecture Examples" authors = ["Amazon Web Services "] license = "MIT-0 License" @@ -32,10 +32,10 @@ flake8-broken-line = "^0.4.0" flake8-bugbear = "^22.4.25" flake8-builtins = "^1.5.3" flake8-cognitive-complexity = "^0.1.0" -flake8-comprehensions = "^3.8.0" +flake8-comprehensions = "^3.9.0" flake8-copyright = "^0.2.2" flake8-docstrings = "^1.6.0" -flake8-eradicate = "^1.2.0" +flake8-eradicate = "^1.2.1" flake8-executable = "^2.1.1" flake8-expression-complexity = "^0.0.11" flake8-fixme = "^1.1.1" @@ -44,7 +44,7 @@ flake8-markdown = "^0.3.0" flake8-mock = "^0.3" flake8-mutable = "^1.2.0" flake8-no-implicit-concat = "^0.3.3" -flake8-print = "^4.0.0" +flake8-print = "^4.0.1" flake8-printf-formatting = "^1.1.2" flake8-pytest-style = "^1.6.0" flake8-raise = "^0.0.5" @@ -60,9 +60,9 @@ flake8-use-fstring = "^1.3" flake8-use-pathlib = "^0.2.1" flake8-variables-names = "^0.0.5" pep8-naming = "^0.12.1" -aws-lambda-typing = "^2.10.1" +aws-lambda-typing = "^2.11.1" safety = "^1.10.3" -pylic = "^3.0.1" +pylic = "^3.0.2" [tool.black]