Repository: getmoto/moto
Pull request #7231 (2024-01-19 16:52:59)

Feature: Backup api
Please provide feedback on this initial draft of Backup API. 
I have added the following API endpoints.
1. create_backup_plan
2. create_backup_vault
3. get_backup_plan - in progress
4. describe_backup_vault - in progress
5. delete_backup_plan
6. list_backup_plans
7. list_backup_vaults - in progress
8. list_tags
9. tag_resource
10. untag_resource

Things yet to be implemented
1. describe_backup_vault
2. Deletion_date and LastExecutionDate in get_backup_plan, list_backup_plans
3. NumberOfRecoveryPoints, MinRetentionDays, MaxRetentionDays, LockDate in list_backup_vaults
4. Pagination
5. Exceptions


Patch:
diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index c45abd1ba..63b41d97c 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -364,7 +364,7 @@
 
 ## appsync
 <details>
-<summary>24% implemented</summary>
+<summary>25% implemented</summary>
 
 - [ ] associate_api
 - [ ] associate_merged_graphql_api
@@ -394,7 +394,6 @@
 - [ ] get_api_association
 - [ ] get_api_cache
 - [ ] get_data_source
-- [ ] get_data_source_introspection
 - [ ] get_domain_name
 - [ ] get_function
 - [X] get_graphql_api
@@ -414,7 +413,6 @@
 - [X] list_tags_for_resource
 - [ ] list_types
 - [ ] list_types_by_association
-- [ ] start_data_source_introspection
 - [X] start_schema_creation
 - [ ] start_schema_merge
 - [X] tag_resource
@@ -575,6 +573,89 @@
 - [X] update_auto_scaling_group
 </details>
 
+## backup
+<details>
+<summary>11% implemented</summary>
+
+- [ ] cancel_legal_hold
+- [X] create_backup_plan
+- [ ] create_backup_selection
+- [X] create_backup_vault
+- [ ] create_framework
+- [ ] create_legal_hold
+- [ ] create_logically_air_gapped_backup_vault
+- [ ] create_report_plan
+- [X] delete_backup_plan
+- [ ] delete_backup_selection
+- [ ] delete_backup_vault
+- [ ] delete_backup_vault_access_policy
+- [ ] delete_backup_vault_lock_configuration
+- [ ] delete_backup_vault_notifications
+- [ ] delete_framework
+- [ ] delete_recovery_point
+- [ ] delete_report_plan
+- [ ] describe_backup_job
+- [ ] describe_backup_vault
+- [ ] describe_copy_job
+- [ ] describe_framework
+- [ ] describe_global_settings
+- [ ] describe_protected_resource
+- [ ] describe_recovery_point
+- [ ] describe_region_settings
+- [ ] describe_report_job
+- [ ] describe_report_plan
+- [ ] describe_restore_job
+- [ ] disassociate_recovery_point
+- [ ] disassociate_recovery_point_from_parent
+- [ ] export_backup_plan_template
+- [X] get_backup_plan
+- [ ] get_backup_plan_from_json
+- [ ] get_backup_plan_from_template
+- [ ] get_backup_selection
+- [ ] get_backup_vault_access_policy
+- [ ] get_backup_vault_notifications
+- [ ] get_legal_hold
+- [ ] get_recovery_point_restore_metadata
+- [ ] get_supported_resource_types
+- [ ] list_backup_job_summaries
+- [ ] list_backup_jobs
+- [ ] list_backup_plan_templates
+- [ ] list_backup_plan_versions
+- [X] list_backup_plans
+- [ ] list_backup_selections
+- [X] list_backup_vaults
+- [ ] list_copy_job_summaries
+- [ ] list_copy_jobs
+- [ ] list_frameworks
+- [ ] list_legal_holds
+- [ ] list_protected_resources
+- [ ] list_protected_resources_by_backup_vault
+- [ ] list_recovery_points_by_backup_vault
+- [ ] list_recovery_points_by_legal_hold
+- [ ] list_recovery_points_by_resource
+- [ ] list_report_jobs
+- [ ] list_report_plans
+- [ ] list_restore_job_summaries
+- [ ] list_restore_jobs
+- [X] list_tags
+- [ ] put_backup_vault_access_policy
+- [ ] put_backup_vault_lock_configuration
+- [ ] put_backup_vault_notifications
+- [ ] start_backup_job
+- [ ] start_copy_job
+- [ ] start_report_job
+- [ ] start_restore_job
+- [ ] stop_backup_job
+- [X] tag_resource
+- [X] untag_resource
+- [ ] update_backup_plan
+- [ ] update_framework
+- [ ] update_global_settings
+- [ ] update_recovery_point_lifecycle
+- [ ] update_region_settings
+- [ ] update_report_plan
+</details>
+
 ## batch
 <details>
 <summary>100% implemented</summary>
@@ -1101,7 +1182,6 @@
 - [ ] update_pull_request_status
 - [ ] update_pull_request_title
 - [ ] update_repository_description
-- [ ] update_repository_encryption_key
 - [ ] update_repository_name
 </details>
 
@@ -2653,7 +2733,7 @@
 
 ## efs
 <details>
-<summary>54% implemented</summary>
+<summary>56% implemented</summary>
 
 - [X] create_access_point
 - [X] create_file_system
@@ -2685,24 +2765,20 @@
 - [X] tag_resource
 - [X] untag_resource
 - [ ] update_file_system
-- [ ] update_file_system_protection
 </details>
 
 ## eks
 <details>
-<summary>26% implemented</summary>
+<summary>33% implemented</summary>
 
-- [ ] associate_access_policy
 - [ ] associate_encryption_config
 - [ ] associate_identity_provider_config
-- [ ] create_access_entry
 - [ ] create_addon
 - [X] create_cluster
 - [ ] create_eks_anywhere_subscription
 - [X] create_fargate_profile
 - [X] create_nodegroup
 - [ ] create_pod_identity_association
-- [ ] delete_access_entry
 - [ ] delete_addon
 - [X] delete_cluster
 - [ ] delete_eks_anywhere_subscription
@@ -2710,7 +2786,6 @@
 - [X] delete_nodegroup
 - [ ] delete_pod_identity_association
 - [ ] deregister_cluster
-- [ ] describe_access_entry
 - [ ] describe_addon
 - [ ] describe_addon_configuration
 - [ ] describe_addon_versions
@@ -2718,21 +2793,15 @@
 - [ ] describe_eks_anywhere_subscription
 - [X] describe_fargate_profile
 - [ ] describe_identity_provider_config
-- [ ] describe_insight
 - [X] describe_nodegroup
 - [ ] describe_pod_identity_association
 - [ ] describe_update
-- [ ] disassociate_access_policy
 - [ ] disassociate_identity_provider_config
-- [ ] list_access_entries
-- [ ] list_access_policies
 - [ ] list_addons
-- [ ] list_associated_access_policies
 - [X] list_clusters
 - [ ] list_eks_anywhere_subscriptions
 - [X] list_fargate_profiles
 - [ ] list_identity_provider_configs
-- [ ] list_insights
 - [X] list_nodegroups
 - [ ] list_pod_identity_associations
 - [X] list_tags_for_resource
@@ -2740,7 +2809,6 @@
 - [ ] register_cluster
 - [X] tag_resource
 - [X] untag_resource
-- [ ] update_access_entry
 - [ ] update_addon
 - [ ] update_cluster_config
 - [ ] update_cluster_version
@@ -2752,14 +2820,13 @@
 
 ## elasticache
 <details>
-<summary>8% implemented</summary>
+<summary>9% implemented</summary>
 
 - [ ] add_tags_to_resource
 - [ ] authorize_cache_security_group_ingress
 - [ ] batch_apply_update_action
 - [ ] batch_stop_update_action
 - [ ] complete_migration
-- [ ] copy_serverless_cache_snapshot
 - [ ] copy_snapshot
 - [X] create_cache_cluster
 - [ ] create_cache_parameter_group
@@ -2767,8 +2834,6 @@
 - [ ] create_cache_subnet_group
 - [ ] create_global_replication_group
 - [ ] create_replication_group
-- [ ] create_serverless_cache
-- [ ] create_serverless_cache_snapshot
 - [ ] create_snapshot
 - [X] create_user
 - [ ] create_user_group
@@ -2780,8 +2845,6 @@
 - [ ] delete_cache_subnet_group
 - [ ] delete_global_replication_group
 - [ ] delete_replication_group
-- [ ] delete_serverless_cache
-- [ ] delete_serverless_cache_snapshot
 - [ ] delete_snapshot
 - [X] delete_user
 - [ ] delete_user_group
@@ -2797,15 +2860,12 @@
 - [ ] describe_replication_groups
 - [ ] describe_reserved_cache_nodes
 - [ ] describe_reserved_cache_nodes_offerings
-- [ ] describe_serverless_cache_snapshots
-- [ ] describe_serverless_caches
 - [ ] describe_service_updates
 - [ ] describe_snapshots
 - [ ] describe_update_actions
 - [ ] describe_user_groups
 - [X] describe_users
 - [ ] disassociate_global_replication_group
-- [ ] export_serverless_cache_snapshot
 - [ ] failover_global_replication_group
 - [ ] increase_node_groups_in_global_replication_group
 - [ ] increase_replica_count
@@ -2817,7 +2877,6 @@
 - [ ] modify_global_replication_group
 - [ ] modify_replication_group
 - [ ] modify_replication_group_shard_configuration
-- [ ] modify_serverless_cache
 - [ ] modify_user
 - [ ] modify_user_group
 - [ ] purchase_reserved_cache_nodes_offering
@@ -3043,7 +3102,6 @@
 - [ ] remove_managed_scaling_policy
 - [X] remove_tags
 - [X] run_job_flow
-- [ ] set_keep_job_flow_alive_when_no_steps
 - [X] set_termination_protection
 - [X] set_visible_to_all_users
 - [ ] start_notebook_execution
@@ -3663,7 +3721,7 @@
 
 ## guardduty
 <details>
-<summary>15% implemented</summary>
+<summary>16% implemented</summary>
 
 - [ ] accept_administrator_invitation
 - [ ] accept_invitation
@@ -3703,7 +3761,6 @@
 - [ ] get_master_account
 - [ ] get_member_detectors
 - [ ] get_members
-- [ ] get_organization_statistics
 - [ ] get_remaining_free_trial_days
 - [ ] get_threat_intel_set
 - [ ] get_usage_statistics
@@ -3980,7 +4037,7 @@
 
 ## iot
 <details>
-<summary>31% implemented</summary>
+<summary>32% implemented</summary>
 
 - [ ] accept_certificate_transfer
 - [ ] add_thing_to_billing_group
@@ -4002,7 +4059,6 @@
 - [ ] create_authorizer
 - [ ] create_billing_group
 - [X] create_certificate_from_csr
-- [ ] create_certificate_provider
 - [ ] create_custom_metric
 - [ ] create_dimension
 - [X] create_domain_configuration
@@ -4035,7 +4091,6 @@
 - [ ] delete_billing_group
 - [X] delete_ca_certificate
 - [X] delete_certificate
-- [ ] delete_certificate_provider
 - [ ] delete_custom_metric
 - [ ] delete_dimension
 - [X] delete_domain_configuration
@@ -4073,7 +4128,6 @@
 - [ ] describe_billing_group
 - [X] describe_ca_certificate
 - [X] describe_certificate
-- [ ] describe_certificate_provider
 - [ ] describe_custom_metric
 - [ ] describe_default_authorizer
 - [ ] describe_detect_mitigation_actions_task
@@ -4133,7 +4187,6 @@
 - [ ] list_authorizers
 - [ ] list_billing_groups
 - [ ] list_ca_certificates
-- [ ] list_certificate_providers
 - [X] list_certificates
 - [X] list_certificates_by_ca
 - [ ] list_custom_metrics
@@ -4214,7 +4267,6 @@
 - [ ] update_billing_group
 - [X] update_ca_certificate
 - [X] update_certificate
-- [ ] update_certificate_provider
 - [ ] update_custom_metric
 - [ ] update_dimension
 - [X] update_domain_configuration
@@ -4630,7 +4682,6 @@
 - [X] put_resource_policy
 - [X] put_retention_policy
 - [X] put_subscription_filter
-- [ ] start_live_tail
 - [X] start_query
 - [ ] stop_query
 - [X] tag_log_group
@@ -4677,7 +4728,7 @@
 
 ## mediaconnect
 <details>
-<summary>35% implemented</summary>
+<summary>36% implemented</summary>
 
 - [ ] add_bridge_outputs
 - [ ] add_bridge_sources
@@ -4694,7 +4745,6 @@
 - [ ] deregister_gateway_instance
 - [ ] describe_bridge
 - [X] describe_flow
-- [ ] describe_flow_source_metadata
 - [ ] describe_gateway
 - [ ] describe_gateway_instance
 - [ ] describe_offering
@@ -4981,10 +5031,9 @@
 
 ## opensearch
 <details>
-<summary>16% implemented</summary>
+<summary>17% implemented</summary>
 
 - [ ] accept_inbound_connection
-- [ ] add_data_source
 - [X] add_tags
 - [ ] associate_package
 - [ ] authorize_vpc_endpoint_access
@@ -4993,7 +5042,6 @@
 - [ ] create_outbound_connection
 - [ ] create_package
 - [ ] create_vpc_endpoint
-- [ ] delete_data_source
 - [X] delete_domain
 - [ ] delete_inbound_connection
 - [ ] delete_outbound_connection
@@ -5016,12 +5064,10 @@
 - [ ] describe_vpc_endpoints
 - [ ] dissociate_package
 - [X] get_compatible_versions
-- [ ] get_data_source
 - [ ] get_domain_maintenance_status
 - [ ] get_package_version_history
 - [ ] get_upgrade_history
 - [ ] get_upgrade_status
-- [ ] list_data_sources
 - [ ] list_domain_maintenances
 - [X] list_domain_names
 - [ ] list_domains_for_package
@@ -5039,7 +5085,6 @@
 - [ ] revoke_vpc_endpoint_access
 - [ ] start_domain_maintenance
 - [ ] start_service_software_update
-- [ ] update_data_source
 - [X] update_domain_config
 - [ ] update_package
 - [ ] update_scheduled_action
@@ -5592,7 +5637,6 @@
 - [ ] update_analysis
 - [ ] update_analysis_permissions
 - [ ] update_dashboard
-- [ ] update_dashboard_links
 - [ ] update_dashboard_permissions
 - [ ] update_dashboard_published_version
 - [ ] update_data_set
@@ -5663,7 +5707,7 @@
 
 ## rds
 <details>
-<summary>35% implemented</summary>
+<summary>37% implemented</summary>
 
 - [ ] add_role_to_db_cluster
 - [ ] add_role_to_db_instance
@@ -5739,7 +5783,6 @@
 - [ ] describe_db_proxy_endpoints
 - [ ] describe_db_proxy_target_groups
 - [ ] describe_db_proxy_targets
-- [ ] describe_db_recommendations
 - [ ] describe_db_security_groups
 - [ ] describe_db_snapshot_attributes
 - [ ] describe_db_snapshot_tenant_databases
@@ -5762,9 +5805,7 @@
 - [ ] describe_source_regions
 - [ ] describe_tenant_databases
 - [ ] describe_valid_db_instance_modifications
-- [ ] disable_http_endpoint
 - [ ] download_db_log_file_portion
-- [ ] enable_http_endpoint
 - [ ] failover_db_cluster
 - [ ] failover_global_cluster
 - [X] list_tags_for_resource
@@ -5781,7 +5822,6 @@
 - [ ] modify_db_proxy
 - [ ] modify_db_proxy_endpoint
 - [ ] modify_db_proxy_target_group
-- [ ] modify_db_recommendation
 - [ ] modify_db_snapshot
 - [ ] modify_db_snapshot_attribute
 - [X] modify_db_subnet_group
@@ -6323,14 +6363,13 @@
 
 ## s3
 <details>
-<summary>66% implemented</summary>
+<summary>68% implemented</summary>
 
 - [X] abort_multipart_upload
 - [X] complete_multipart_upload
 - [X] copy_object
 - [X] create_bucket
 - [X] create_multipart_upload
-- [ ] create_session
 - [X] delete_bucket
 - [ ] delete_bucket_analytics_configuration
 - [X] delete_bucket_cors
@@ -6386,7 +6425,6 @@
 - [ ] list_bucket_inventory_configurations
 - [ ] list_bucket_metrics_configurations
 - [X] list_buckets
-- [ ] list_directory_buckets
 - [ ] list_multipart_uploads
 - [X] list_object_versions
 - [X] list_objects
@@ -6526,7 +6564,7 @@
 
 ## sagemaker
 <details>
-<summary>19% implemented</summary>
+<summary>20% implemented</summary>
 
 - [ ] add_association
 - [X] add_tags
@@ -6539,7 +6577,6 @@
 - [ ] create_artifact
 - [ ] create_auto_ml_job
 - [ ] create_auto_ml_job_v2
-- [ ] create_cluster
 - [ ] create_code_repository
 - [ ] create_compilation_job
 - [ ] create_context
@@ -6559,7 +6596,6 @@
 - [ ] create_hyper_parameter_tuning_job
 - [ ] create_image
 - [ ] create_image_version
-- [ ] create_inference_component
 - [ ] create_inference_experiment
 - [ ] create_inference_recommendations_job
 - [ ] create_labeling_job
@@ -6594,9 +6630,7 @@
 - [ ] delete_app_image_config
 - [ ] delete_artifact
 - [ ] delete_association
-- [ ] delete_cluster
 - [ ] delete_code_repository
-- [ ] delete_compilation_job
 - [ ] delete_context
 - [ ] delete_data_quality_job_definition
 - [ ] delete_device_fleet
@@ -6613,7 +6647,6 @@
 - [ ] delete_human_task_ui
 - [ ] delete_image
 - [ ] delete_image_version
-- [ ] delete_inference_component
 - [ ] delete_inference_experiment
 - [X] delete_model
 - [ ] delete_model_bias_job_definition
@@ -6644,8 +6677,6 @@
 - [ ] describe_artifact
 - [ ] describe_auto_ml_job
 - [ ] describe_auto_ml_job_v2
-- [ ] describe_cluster
-- [ ] describe_cluster_node
 - [ ] describe_code_repository
 - [ ] describe_compilation_job
 - [ ] describe_context
@@ -6667,7 +6698,6 @@
 - [ ] describe_hyper_parameter_tuning_job
 - [ ] describe_image
 - [ ] describe_image_version
-- [ ] describe_inference_component
 - [ ] describe_inference_experiment
 - [ ] describe_inference_recommendations_job
 - [ ] describe_labeling_job
@@ -6717,8 +6747,6 @@
 - [ ] list_associations
 - [ ] list_auto_ml_jobs
 - [ ] list_candidates_for_auto_ml_job
-- [ ] list_cluster_nodes
-- [ ] list_clusters
 - [ ] list_code_repositories
 - [ ] list_compilation_jobs
 - [ ] list_contexts
@@ -6740,7 +6768,6 @@
 - [ ] list_hyper_parameter_tuning_jobs
 - [ ] list_image_versions
 - [ ] list_images
-- [ ] list_inference_components
 - [ ] list_inference_experiments
 - [ ] list_inference_recommendations_job_steps
 - [ ] list_inference_recommendations_jobs
@@ -6813,7 +6840,6 @@
 - [ ] update_action
 - [ ] update_app_image_config
 - [ ] update_artifact
-- [ ] update_cluster
 - [ ] update_code_repository
 - [ ] update_context
 - [ ] update_device_fleet
@@ -6827,8 +6853,6 @@
 - [ ] update_hub
 - [ ] update_image
 - [ ] update_image_version
-- [ ] update_inference_component
-- [ ] update_inference_component_runtime_config
 - [ ] update_inference_experiment
 - [ ] update_model_card
 - [X] update_model_package
@@ -7658,7 +7682,7 @@
 
 ## transcribe
 <details>
-<summary>37% implemented</summary>
+<summary>41% implemented</summary>
 
 - [ ] create_call_analytics_category
 - [ ] create_language_model
@@ -7668,7 +7692,6 @@
 - [ ] delete_call_analytics_category
 - [ ] delete_call_analytics_job
 - [ ] delete_language_model
-- [ ] delete_medical_scribe_job
 - [X] delete_medical_transcription_job
 - [X] delete_medical_vocabulary
 - [X] delete_transcription_job
@@ -7677,7 +7700,6 @@
 - [ ] describe_language_model
 - [ ] get_call_analytics_category
 - [ ] get_call_analytics_job
-- [ ] get_medical_scribe_job
 - [X] get_medical_transcription_job
 - [X] get_medical_vocabulary
 - [X] get_transcription_job
@@ -7686,7 +7708,6 @@
 - [ ] list_call_analytics_categories
 - [ ] list_call_analytics_jobs
 - [ ] list_language_models
-- [ ] list_medical_scribe_jobs
 - [X] list_medical_transcription_jobs
 - [X] list_medical_vocabularies
 - [ ] list_tags_for_resource
@@ -7694,7 +7715,6 @@
 - [X] list_vocabularies
 - [ ] list_vocabulary_filters
 - [ ] start_call_analytics_job
-- [ ] start_medical_scribe_job
 - [X] start_medical_transcription_job
 - [X] start_transcription_job
 - [ ] tag_resource
@@ -7785,14 +7805,10 @@
 - arc-zonal-shift
 - auditmanager
 - autoscaling-plans
-- b2bi
-- backup
 - backup-gateway
 - backupstorage
 - bcm-data-exports
 - bedrock
-- bedrock-agent
-- bedrock-agent-runtime
 - bedrock-runtime
 - billingconductor
 - braket
@@ -7803,7 +7819,6 @@
 - chime-sdk-messaging
 - chime-sdk-voice
 - cleanrooms
-- cleanroomsml
 - cloud9
 - cloudcontrol
 - clouddirectory
@@ -7915,9 +7930,7 @@
 - machinelearning
 - macie2
 - managedblockchain-query
-- marketplace-agreement
 - marketplace-catalog
-- marketplace-deployment
 - marketplace-entitlement
 - marketplacecommerceanalytics
 - mediaconvert
@@ -7935,11 +7948,9 @@
 - mobile
 - mturk
 - mwaa
-- neptune-graph
 - neptunedata
 - network-firewall
 - networkmanager
-- networkmonitor
 - nimble
 - oam
 - omics
@@ -7960,8 +7971,6 @@
 - pricing
 - privatenetworks
 - proton
-- qbusiness
-- qconnect
 - qldb
 - qldb-session
 - rbin
diff --git a/Makefile b/Makefile
index aa403f097..9c80b4c46 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,7 @@ lint:
 
 format:
 	black moto/ tests/
+	ruff --fix moto/ tests/
 
 test-only:
 	rm -f .coverage
diff --git a/docs/docs/services/appsync.rst b/docs/docs/services/appsync.rst
index 83d0540c7..bd2e16dd2 100644
--- a/docs/docs/services/appsync.rst
+++ b/docs/docs/services/appsync.rst
@@ -55,7 +55,6 @@ appsync
 - [ ] get_api_association
 - [ ] get_api_cache
 - [ ] get_data_source
-- [ ] get_data_source_introspection
 - [ ] get_domain_name
 - [ ] get_function
 - [X] get_graphql_api
@@ -83,7 +82,6 @@ appsync
 - [X] list_tags_for_resource
 - [ ] list_types
 - [ ] list_types_by_association
-- [ ] start_data_source_introspection
 - [X] start_schema_creation
 - [ ] start_schema_merge
 - [X] tag_resource
diff --git a/docs/docs/services/backup.rst b/docs/docs/services/backup.rst
new file mode 100644
index 000000000..108d2c522
--- /dev/null
+++ b/docs/docs/services/backup.rst
@@ -0,0 +1,119 @@
+.. _implementedservice_backup:
+
+.. |start-h3| raw:: html
+
+    <h3>
+
+.. |end-h3| raw:: html
+
+    </h3>
+
+======
+backup
+======
+
+.. autoclass:: moto.backup.models.BackupBackend
+
+|start-h3| Example usage |end-h3|
+
+.. sourcecode:: python
+
+            @mock_backup
+            def test_backup_behaviour:
+                boto3.client("backup")
+                ...
+
+
+
+|start-h3| Implemented features for this service |end-h3|
+
+- [ ] cancel_legal_hold
+- [X] create_backup_plan
+- [ ] create_backup_selection
+- [X] create_backup_vault
+- [ ] create_framework
+- [ ] create_legal_hold
+- [ ] create_logically_air_gapped_backup_vault
+- [ ] create_report_plan
+- [X] delete_backup_plan
+- [ ] delete_backup_selection
+- [ ] delete_backup_vault
+- [ ] delete_backup_vault_access_policy
+- [ ] delete_backup_vault_lock_configuration
+- [ ] delete_backup_vault_notifications
+- [ ] delete_framework
+- [ ] delete_recovery_point
+- [ ] delete_report_plan
+- [ ] describe_backup_job
+- [ ] describe_backup_vault
+- [ ] describe_copy_job
+- [ ] describe_framework
+- [ ] describe_global_settings
+- [ ] describe_protected_resource
+- [ ] describe_recovery_point
+- [ ] describe_region_settings
+- [ ] describe_report_job
+- [ ] describe_report_plan
+- [ ] describe_restore_job
+- [ ] disassociate_recovery_point
+- [ ] disassociate_recovery_point_from_parent
+- [ ] export_backup_plan_template
+- [X] get_backup_plan
+- [ ] get_backup_plan_from_json
+- [ ] get_backup_plan_from_template
+- [ ] get_backup_selection
+- [ ] get_backup_vault_access_policy
+- [ ] get_backup_vault_notifications
+- [ ] get_legal_hold
+- [ ] get_recovery_point_restore_metadata
+- [ ] get_supported_resource_types
+- [ ] list_backup_job_summaries
+- [ ] list_backup_jobs
+- [ ] list_backup_plan_templates
+- [ ] list_backup_plan_versions
+- [X] list_backup_plans
+  
+        Pagination is not yet implemented
+        
+
+- [ ] list_backup_selections
+- [X] list_backup_vaults
+  
+        Pagination is not yet implemented
+        
+
+- [ ] list_copy_job_summaries
+- [ ] list_copy_jobs
+- [ ] list_frameworks
+- [ ] list_legal_holds
+- [ ] list_protected_resources
+- [ ] list_protected_resources_by_backup_vault
+- [ ] list_recovery_points_by_backup_vault
+- [ ] list_recovery_points_by_legal_hold
+- [ ] list_recovery_points_by_resource
+- [ ] list_report_jobs
+- [ ] list_report_plans
+- [ ] list_restore_job_summaries
+- [ ] list_restore_jobs
+- [X] list_tags
+  
+        Pagination is not yet implemented
+        
+
+- [ ] put_backup_vault_access_policy
+- [ ] put_backup_vault_lock_configuration
+- [ ] put_backup_vault_notifications
+- [ ] start_backup_job
+- [ ] start_copy_job
+- [ ] start_report_job
+- [ ] start_restore_job
+- [ ] stop_backup_job
+- [X] tag_resource
+- [X] untag_resource
+- [ ] update_backup_plan
+- [ ] update_framework
+- [ ] update_global_settings
+- [ ] update_recovery_point_lifecycle
+- [ ] update_region_settings
+- [ ] update_report_plan
+
diff --git a/docs/docs/services/codecommit.rst b/docs/docs/services/codecommit.rst
index dd09e58fd..47368ba04 100644
--- a/docs/docs/services/codecommit.rst
+++ b/docs/docs/services/codecommit.rst
@@ -102,6 +102,5 @@ codecommit
 - [ ] update_pull_request_status
 - [ ] update_pull_request_title
 - [ ] update_repository_description
-- [ ] update_repository_encryption_key
 - [ ] update_repository_name
 
diff --git a/docs/docs/services/efs.rst b/docs/docs/services/efs.rst
index bad8c2223..47d76e667 100644
--- a/docs/docs/services/efs.rst
+++ b/docs/docs/services/efs.rst
@@ -98,5 +98,4 @@ efs
 - [X] tag_resource
 - [X] untag_resource
 - [ ] update_file_system
-- [ ] update_file_system_protection
 
diff --git a/docs/docs/services/eks.rst b/docs/docs/services/eks.rst
index ecb31c1bb..ac7c261be 100644
--- a/docs/docs/services/eks.rst
+++ b/docs/docs/services/eks.rst
@@ -25,17 +25,14 @@ eks
 
 |start-h3| Implemented features for this service |end-h3|
 
-- [ ] associate_access_policy
 - [ ] associate_encryption_config
 - [ ] associate_identity_provider_config
-- [ ] create_access_entry
 - [ ] create_addon
 - [X] create_cluster
 - [ ] create_eks_anywhere_subscription
 - [X] create_fargate_profile
 - [X] create_nodegroup
 - [ ] create_pod_identity_association
-- [ ] delete_access_entry
 - [ ] delete_addon
 - [X] delete_cluster
 - [ ] delete_eks_anywhere_subscription
@@ -43,7 +40,6 @@ eks
 - [X] delete_nodegroup
 - [ ] delete_pod_identity_association
 - [ ] deregister_cluster
-- [ ] describe_access_entry
 - [ ] describe_addon
 - [ ] describe_addon_configuration
 - [ ] describe_addon_versions
@@ -51,21 +47,15 @@ eks
 - [ ] describe_eks_anywhere_subscription
 - [X] describe_fargate_profile
 - [ ] describe_identity_provider_config
-- [ ] describe_insight
 - [X] describe_nodegroup
 - [ ] describe_pod_identity_association
 - [ ] describe_update
-- [ ] disassociate_access_policy
 - [ ] disassociate_identity_provider_config
-- [ ] list_access_entries
-- [ ] list_access_policies
 - [ ] list_addons
-- [ ] list_associated_access_policies
 - [X] list_clusters
 - [ ] list_eks_anywhere_subscriptions
 - [X] list_fargate_profiles
 - [ ] list_identity_provider_configs
-- [ ] list_insights
 - [X] list_nodegroups
 - [ ] list_pod_identity_associations
 - [X] list_tags_for_resource
@@ -85,7 +75,6 @@ eks
         This function currently will remove tags on an EKS cluster only.  It does not remove tags from a managed node group
         
 
-- [ ] update_access_entry
 - [ ] update_addon
 - [ ] update_cluster_config
 - [ ] update_cluster_version
diff --git a/docs/docs/services/elasticache.rst b/docs/docs/services/elasticache.rst
index ff44a3044..227bf1204 100644
--- a/docs/docs/services/elasticache.rst
+++ b/docs/docs/services/elasticache.rst
@@ -32,7 +32,6 @@ elasticache
 - [ ] batch_apply_update_action
 - [ ] batch_stop_update_action
 - [ ] complete_migration
-- [ ] copy_serverless_cache_snapshot
 - [ ] copy_snapshot
 - [X] create_cache_cluster
 - [ ] create_cache_parameter_group
@@ -40,8 +39,6 @@ elasticache
 - [ ] create_cache_subnet_group
 - [ ] create_global_replication_group
 - [ ] create_replication_group
-- [ ] create_serverless_cache
-- [ ] create_serverless_cache_snapshot
 - [ ] create_snapshot
 - [X] create_user
 - [ ] create_user_group
@@ -53,8 +50,6 @@ elasticache
 - [ ] delete_cache_subnet_group
 - [ ] delete_global_replication_group
 - [ ] delete_replication_group
-- [ ] delete_serverless_cache
-- [ ] delete_serverless_cache_snapshot
 - [ ] delete_snapshot
 - [X] delete_user
 - [ ] delete_user_group
@@ -70,8 +65,6 @@ elasticache
 - [ ] describe_replication_groups
 - [ ] describe_reserved_cache_nodes
 - [ ] describe_reserved_cache_nodes_offerings
-- [ ] describe_serverless_cache_snapshots
-- [ ] describe_serverless_caches
 - [ ] describe_service_updates
 - [ ] describe_snapshots
 - [ ] describe_update_actions
@@ -83,7 +76,6 @@ elasticache
         
 
 - [ ] disassociate_global_replication_group
-- [ ] export_serverless_cache_snapshot
 - [ ] failover_global_replication_group
 - [ ] increase_node_groups_in_global_replication_group
 - [ ] increase_replica_count
@@ -95,7 +87,6 @@ elasticache
 - [ ] modify_global_replication_group
 - [ ] modify_replication_group
 - [ ] modify_replication_group_shard_configuration
-- [ ] modify_serverless_cache
 - [ ] modify_user
 - [ ] modify_user_group
 - [ ] purchase_reserved_cache_nodes_offering
diff --git a/docs/docs/services/emr.rst b/docs/docs/services/emr.rst
index 595fb150c..4a1d8fc06 100644
--- a/docs/docs/services/emr.rst
+++ b/docs/docs/services/emr.rst
@@ -72,7 +72,6 @@ emr
 - [ ] remove_managed_scaling_policy
 - [X] remove_tags
 - [X] run_job_flow
-- [ ] set_keep_job_flow_alive_when_no_steps
 - [X] set_termination_protection
 - [X] set_visible_to_all_users
 - [ ] start_notebook_execution
diff --git a/docs/docs/services/guardduty.rst b/docs/docs/services/guardduty.rst
index c339fb57c..4dbcdd873 100644
--- a/docs/docs/services/guardduty.rst
+++ b/docs/docs/services/guardduty.rst
@@ -63,7 +63,6 @@ guardduty
 - [ ] get_master_account
 - [ ] get_member_detectors
 - [ ] get_members
-- [ ] get_organization_statistics
 - [ ] get_remaining_free_trial_days
 - [ ] get_threat_intel_set
 - [ ] get_usage_statistics
diff --git a/docs/docs/services/iot.rst b/docs/docs/services/iot.rst
index 5b9c1c847..b52b080f4 100644
--- a/docs/docs/services/iot.rst
+++ b/docs/docs/services/iot.rst
@@ -49,7 +49,6 @@ iot
 - [ ] create_authorizer
 - [ ] create_billing_group
 - [X] create_certificate_from_csr
-- [ ] create_certificate_provider
 - [ ] create_custom_metric
 - [ ] create_dimension
 - [X] create_domain_configuration
@@ -86,7 +85,6 @@ iot
 - [ ] delete_billing_group
 - [X] delete_ca_certificate
 - [X] delete_certificate
-- [ ] delete_certificate_provider
 - [ ] delete_custom_metric
 - [ ] delete_dimension
 - [X] delete_domain_configuration
@@ -132,7 +130,6 @@ iot
 - [ ] describe_billing_group
 - [X] describe_ca_certificate
 - [X] describe_certificate
-- [ ] describe_certificate_provider
 - [ ] describe_custom_metric
 - [ ] describe_default_authorizer
 - [ ] describe_detect_mitigation_actions_task
@@ -196,7 +193,6 @@ iot
 - [ ] list_authorizers
 - [ ] list_billing_groups
 - [ ] list_ca_certificates
-- [ ] list_certificate_providers
 - [X] list_certificates
   
         Pagination is not yet implemented
@@ -325,7 +321,6 @@ iot
         
 
 - [X] update_certificate
-- [ ] update_certificate_provider
 - [ ] update_custom_metric
 - [ ] update_dimension
 - [X] update_domain_configuration
diff --git a/docs/docs/services/logs.rst b/docs/docs/services/logs.rst
index 395c1e82d..cfb7f4bfd 100644
--- a/docs/docs/services/logs.rst
+++ b/docs/docs/services/logs.rst
@@ -126,7 +126,6 @@ logs
 
 - [X] put_retention_policy
 - [X] put_subscription_filter
-- [ ] start_live_tail
 - [X] start_query
 - [ ] stop_query
 - [X] tag_log_group
diff --git a/docs/docs/services/mediaconnect.rst b/docs/docs/services/mediaconnect.rst
index 4c415253d..08fc5177e 100644
--- a/docs/docs/services/mediaconnect.rst
+++ b/docs/docs/services/mediaconnect.rst
@@ -40,7 +40,6 @@ mediaconnect
 - [ ] deregister_gateway_instance
 - [ ] describe_bridge
 - [X] describe_flow
-- [ ] describe_flow_source_metadata
 - [ ] describe_gateway
 - [ ] describe_gateway_instance
 - [ ] describe_offering
diff --git a/docs/docs/services/opensearch.rst b/docs/docs/services/opensearch.rst
index 7402bf828..6a608a250 100644
--- a/docs/docs/services/opensearch.rst
+++ b/docs/docs/services/opensearch.rst
@@ -28,7 +28,6 @@ opensearch
 |start-h3| Implemented features for this service |end-h3|
 
 - [ ] accept_inbound_connection
-- [ ] add_data_source
 - [X] add_tags
 - [ ] associate_package
 - [ ] authorize_vpc_endpoint_access
@@ -37,7 +36,6 @@ opensearch
 - [ ] create_outbound_connection
 - [ ] create_package
 - [ ] create_vpc_endpoint
-- [ ] delete_data_source
 - [X] delete_domain
 - [ ] delete_inbound_connection
 - [ ] delete_outbound_connection
@@ -60,12 +58,10 @@ opensearch
 - [ ] describe_vpc_endpoints
 - [ ] dissociate_package
 - [X] get_compatible_versions
-- [ ] get_data_source
 - [ ] get_domain_maintenance_status
 - [ ] get_package_version_history
 - [ ] get_upgrade_history
 - [ ] get_upgrade_status
-- [ ] list_data_sources
 - [ ] list_domain_maintenances
 - [X] list_domain_names
 - [ ] list_domains_for_package
@@ -83,7 +79,6 @@ opensearch
 - [ ] revoke_vpc_endpoint_access
 - [ ] start_domain_maintenance
 - [ ] start_service_software_update
-- [ ] update_data_source
 - [X] update_domain_config
 - [ ] update_package
 - [ ] update_scheduled_action
diff --git a/docs/docs/services/quicksight.rst b/docs/docs/services/quicksight.rst
index 0690940e3..848a1bbfe 100644
--- a/docs/docs/services/quicksight.rst
+++ b/docs/docs/services/quicksight.rst
@@ -188,7 +188,6 @@ quicksight
 - [ ] update_analysis
 - [ ] update_analysis_permissions
 - [ ] update_dashboard
-- [ ] update_dashboard_links
 - [ ] update_dashboard_permissions
 - [ ] update_dashboard_published_version
 - [ ] update_data_set
diff --git a/docs/docs/services/rds.rst b/docs/docs/services/rds.rst
index 6542a8319..ac345da2b 100644
--- a/docs/docs/services/rds.rst
+++ b/docs/docs/services/rds.rst
@@ -99,7 +99,6 @@ rds
 - [ ] describe_db_proxy_endpoints
 - [ ] describe_db_proxy_target_groups
 - [ ] describe_db_proxy_targets
-- [ ] describe_db_recommendations
 - [ ] describe_db_security_groups
 - [ ] describe_db_snapshot_attributes
 - [ ] describe_db_snapshot_tenant_databases
@@ -126,9 +125,7 @@ rds
 - [ ] describe_source_regions
 - [ ] describe_tenant_databases
 - [ ] describe_valid_db_instance_modifications
-- [ ] disable_http_endpoint
 - [ ] download_db_log_file_portion
-- [ ] enable_http_endpoint
 - [ ] failover_db_cluster
 - [ ] failover_global_cluster
 - [X] list_tags_for_resource
@@ -145,7 +142,6 @@ rds
 - [ ] modify_db_proxy
 - [ ] modify_db_proxy_endpoint
 - [ ] modify_db_proxy_target_group
-- [ ] modify_db_recommendation
 - [ ] modify_db_snapshot
 - [ ] modify_db_snapshot_attribute
 - [X] modify_db_subnet_group
@@ -171,7 +167,7 @@ rds
 - [ ] restore_db_cluster_to_point_in_time
 - [X] restore_db_instance_from_db_snapshot
 - [ ] restore_db_instance_from_s3
-- [ ] restore_db_instance_to_point_in_time
+- [X] restore_db_instance_to_point_in_time
 - [ ] revoke_db_security_group_ingress
 - [ ] start_activity_stream
 - [X] start_db_cluster
diff --git a/docs/docs/services/s3.rst b/docs/docs/services/s3.rst
index 88eef2c87..969b9f7c2 100644
--- a/docs/docs/services/s3.rst
+++ b/docs/docs/services/s3.rst
@@ -32,7 +32,6 @@ s3
 - [X] copy_object
 - [X] create_bucket
 - [X] create_multipart_upload
-- [ ] create_session
 - [X] delete_bucket
 - [ ] delete_bucket_analytics_configuration
 - [X] delete_bucket_cors
@@ -92,7 +91,6 @@ s3
 - [ ] list_bucket_inventory_configurations
 - [ ] list_bucket_metrics_configurations
 - [X] list_buckets
-- [ ] list_directory_buckets
 - [ ] list_multipart_uploads
 - [X] list_object_versions
 - [X] list_objects
diff --git a/docs/docs/services/sagemaker.rst b/docs/docs/services/sagemaker.rst
index 87b2d2827..52d099cea 100644
--- a/docs/docs/services/sagemaker.rst
+++ b/docs/docs/services/sagemaker.rst
@@ -36,7 +36,6 @@ sagemaker
 - [ ] create_artifact
 - [ ] create_auto_ml_job
 - [ ] create_auto_ml_job_v2
-- [ ] create_cluster
 - [ ] create_code_repository
 - [ ] create_compilation_job
 - [ ] create_context
@@ -56,7 +55,6 @@ sagemaker
 - [ ] create_hyper_parameter_tuning_job
 - [ ] create_image
 - [ ] create_image_version
-- [ ] create_inference_component
 - [ ] create_inference_experiment
 - [ ] create_inference_recommendations_job
 - [ ] create_labeling_job
@@ -91,9 +89,7 @@ sagemaker
 - [ ] delete_app_image_config
 - [ ] delete_artifact
 - [ ] delete_association
-- [ ] delete_cluster
 - [ ] delete_code_repository
-- [ ] delete_compilation_job
 - [ ] delete_context
 - [ ] delete_data_quality_job_definition
 - [ ] delete_device_fleet
@@ -110,7 +106,6 @@ sagemaker
 - [ ] delete_human_task_ui
 - [ ] delete_image
 - [ ] delete_image_version
-- [ ] delete_inference_component
 - [ ] delete_inference_experiment
 - [X] delete_model
 - [ ] delete_model_bias_job_definition
@@ -141,8 +136,6 @@ sagemaker
 - [ ] describe_artifact
 - [ ] describe_auto_ml_job
 - [ ] describe_auto_ml_job_v2
-- [ ] describe_cluster
-- [ ] describe_cluster_node
 - [ ] describe_code_repository
 - [ ] describe_compilation_job
 - [ ] describe_context
@@ -164,7 +157,6 @@ sagemaker
 - [ ] describe_hyper_parameter_tuning_job
 - [ ] describe_image
 - [ ] describe_image_version
-- [ ] describe_inference_component
 - [ ] describe_inference_experiment
 - [ ] describe_inference_recommendations_job
 - [ ] describe_labeling_job
@@ -214,8 +206,6 @@ sagemaker
 - [ ] list_associations
 - [ ] list_auto_ml_jobs
 - [ ] list_candidates_for_auto_ml_job
-- [ ] list_cluster_nodes
-- [ ] list_clusters
 - [ ] list_code_repositories
 - [ ] list_compilation_jobs
 - [ ] list_contexts
@@ -237,7 +227,6 @@ sagemaker
 - [ ] list_hyper_parameter_tuning_jobs
 - [ ] list_image_versions
 - [ ] list_images
-- [ ] list_inference_components
 - [ ] list_inference_experiments
 - [ ] list_inference_recommendations_job_steps
 - [ ] list_inference_recommendations_jobs
@@ -315,7 +304,6 @@ sagemaker
 - [ ] update_action
 - [ ] update_app_image_config
 - [ ] update_artifact
-- [ ] update_cluster
 - [ ] update_code_repository
 - [ ] update_context
 - [ ] update_device_fleet
@@ -329,8 +317,6 @@ sagemaker
 - [ ] update_hub
 - [ ] update_image
 - [ ] update_image_version
-- [ ] update_inference_component
-- [ ] update_inference_component_runtime_config
 - [ ] update_inference_experiment
 - [ ] update_model_card
 - [X] update_model_package
diff --git a/docs/docs/services/transcribe.rst b/docs/docs/services/transcribe.rst
index 4d3536203..df61d80c0 100644
--- a/docs/docs/services/transcribe.rst
+++ b/docs/docs/services/transcribe.rst
@@ -33,7 +33,6 @@ transcribe
 - [ ] delete_call_analytics_category
 - [ ] delete_call_analytics_job
 - [ ] delete_language_model
-- [ ] delete_medical_scribe_job
 - [X] delete_medical_transcription_job
 - [X] delete_medical_vocabulary
 - [X] delete_transcription_job
@@ -42,7 +41,6 @@ transcribe
 - [ ] describe_language_model
 - [ ] get_call_analytics_category
 - [ ] get_call_analytics_job
-- [ ] get_medical_scribe_job
 - [X] get_medical_transcription_job
 - [X] get_medical_vocabulary
 - [X] get_transcription_job
@@ -51,7 +49,6 @@ transcribe
 - [ ] list_call_analytics_categories
 - [ ] list_call_analytics_jobs
 - [ ] list_language_models
-- [ ] list_medical_scribe_jobs
 - [X] list_medical_transcription_jobs
 - [X] list_medical_vocabularies
 - [ ] list_tags_for_resource
@@ -59,7 +56,6 @@ transcribe
 - [X] list_vocabularies
 - [ ] list_vocabulary_filters
 - [ ] start_call_analytics_job
-- [ ] start_medical_scribe_job
 - [X] start_medical_transcription_job
 - [X] start_transcription_job
 - [ ] tag_resource
diff --git a/moto/__init__.py b/moto/__init__.py
index 72865ad29..7c1b02e69 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -235,6 +235,7 @@ XRaySegment = load_xray_segment()
 mock_xray = lazy_load(".xray", "mock_xray")
 mock_xray_client = lazy_load(".xray", "mock_xray_client")
 mock_wafv2 = lazy_load(".wafv2", "mock_wafv2")
+mock_backup = lazy_load(".backup", "mock_backup", boto3_name="backup")
 
 
 class MockAll(ContextDecorator):
diff --git a/moto/acm/models.py b/moto/acm/models.py
index 8d7bcf4c8..95435983c 100644
--- a/moto/acm/models.py
+++ b/moto/acm/models.py
@@ -343,24 +343,22 @@ class CertBundle(BaseModel):
         domain_names = set(sans + [self.common_name])
         validation_options = []
 
-        if self.status == "PENDING_VALIDATION":
-            for san in domain_names:
-                resource_record = {
-                    "Name": f"_d930b28be6c5927595552b219965053e.{san}.",
-                    "Type": "CNAME",
-                    "Value": "_c9edd76ee4a0e2a74388032f3861cc50.ykybfrwcxw.acm-validations.aws.",
+        for san in domain_names:
+            resource_record = {
+                "Name": f"_d930b28be6c5927595552b219965053e.{san}.",
+                "Type": "CNAME",
+                "Value": "_c9edd76ee4a0e2a74388032f3861cc50.ykybfrwcxw.acm-validations.aws.",
+            }
+            validation_options.append(
+                {
+                    "DomainName": san,
+                    "ValidationDomain": san,
+                    "ValidationStatus": self.status,
+                    "ValidationMethod": "DNS",
+                    "ResourceRecord": resource_record,
                 }
-                validation_options.append(
-                    {
-                        "DomainName": san,
-                        "ValidationDomain": san,
-                        "ValidationStatus": self.status,
-                        "ValidationMethod": "DNS",
-                        "ResourceRecord": resource_record,
-                    }
-                )
-        else:
-            validation_options = [{"DomainName": name} for name in domain_names]
+            )
+
         result["Certificate"]["DomainValidationOptions"] = validation_options
 
         if self.type == "IMPORTED":
diff --git a/moto/backend_index.py b/moto/backend_index.py
index 300784891..91c8e707a 100644
--- a/moto/backend_index.py
+++ b/moto/backend_index.py
@@ -1,4 +1,4 @@
-# autogenerated by moto/scripts/update_backend_index.py
+# autogenerated by /Users/oxh252/workspace/moto_contribution/moto/scripts/update_backend_index.py
 import re
 
 backend_url_patterns = [
@@ -18,6 +18,7 @@ backend_url_patterns = [
     ("appsync", re.compile("https?://appsync\\.(.+)\\.amazonaws\\.com")),
     ("athena", re.compile("https?://athena\\.(.+)\\.amazonaws\\.com")),
     ("autoscaling", re.compile("https?://autoscaling\\.(.+)\\.amazonaws\\.com")),
+    ("backup", re.compile("https?://backup\\.(.+)\\.amazonaws\\.com")),
     ("batch", re.compile("https?://batch\\.(.+)\\.amazonaws.com")),
     ("budgets", re.compile("https?://budgets\\.amazonaws\\.com")),
     ("ce", re.compile("https?://ce\\.(.+)\\.amazonaws\\.com")),
diff --git a/moto/backup/__init__.py b/moto/backup/__init__.py
new file mode 100644
index 000000000..092556a72
--- /dev/null
+++ b/moto/backup/__init__.py
@@ -0,0 +1,5 @@
+"""backup module initialization; sets value for base decorator."""
+from ..core.models import base_decorator
+from .models import backup_backends
+
+mock_backup = base_decorator(backup_backends)
diff --git a/moto/backup/exceptions.py b/moto/backup/exceptions.py
new file mode 100644
index 000000000..dc0e1ad12
--- /dev/null
+++ b/moto/backup/exceptions.py
@@ -0,0 +1,16 @@
+"""Exceptions raised by the backup service."""
+from moto.core.exceptions import JsonRESTError
+
+
+class BackupClientError(JsonRESTError):
+    code = 400
+
+
+class AlreadyExistsException(BackupClientError):
+    def __init__(self, msg: str):
+        super().__init__("AlreadyExistsException", f"{msg}")
+
+
+class ResourceNotFoundException(JsonRESTError):
+    def __init__(self, msg: str):
+        super().__init__("ResourceNotFoundException", f"{msg}")
diff --git a/moto/backup/models.py b/moto/backup/models.py
new file mode 100644
index 000000000..f2f040aed
--- /dev/null
+++ b/moto/backup/models.py
@@ -0,0 +1,236 @@
+"""BackupBackend class with methods for supported APIs."""
+from copy import deepcopy
+from typing import Any, Dict, List, Optional, Tuple
+
+from moto.core import BackendDict, BaseBackend, BaseModel
+from moto.core.utils import unix_time
+from moto.moto_api._internal import mock_random
+from moto.utilities.tagging_service import TaggingService
+
+from .exceptions import AlreadyExistsException, ResourceNotFoundException
+
+
+class Plan(BaseModel):
+    def __init__(
+        self,
+        backup_plan: Dict[str, Any],
+        creator_request_id: str,
+        backend: "BackupBackend",
+    ):
+
+        self.backup_plan_id = str(mock_random.uuid4())
+        self.backup_plan_arn = f"arn:aws:backup:{backend.region_name}:{backend.account_id}:backup-plan:{self.backup_plan_id}"
+        self.creation_date = unix_time()
+        ran_str = mock_random.get_random_string(length=48)
+        self.version_id = ran_str
+        self.creator_request_id = creator_request_id
+        self.backup_plan = backup_plan
+        adv_settings = backup_plan.get("AdvancedBackupSettings")
+        self.advanced_backup_settings = adv_settings or []
+        self.deletion_date: Optional[float] = None
+        # Deletion Date is updated when the backup_plan is deleted
+        self.last_execution_date = None  # start_restore_job not yet supported
+        rules = backup_plan["Rules"]
+        for rule in rules:
+            rule["ScheduleExpression"] = rule.get(
+                "ScheduleExpression", "cron(0 5 ? * * *)"
+            )  # Default CRON expression in UTC
+            rule["StartWindowMinutes"] = rule.get(
+                "StartWindowMinutes", 480
+            )  # Default=480
+            rule["CompletionWindowMinutes"] = rule.get(
+                "CompletionWindowMinutes", 10080
+            )  # Default=10080
+            rule["ScheduleExpressionTimezone"] = rule.get(
+                "ScheduleExpressionTimezone", "Etc/UTC"
+            )  # set to Etc/UTc by default
+            rule["RuleId"] = str(mock_random.uuid4())
+
+    def to_dict(self) -> Dict[str, Any]:
+        dct = {
+            "BackupPlanId": self.backup_plan_id,
+            "BackupPlanArn": self.backup_plan_arn,
+            "CreationDate": self.creation_date,
+            "VersionId": self.version_id,
+            "AdvancedBackupSettings": self.advanced_backup_settings,
+        }
+        return {k: v for k, v in dct.items() if v}
+
+    def to_get_dict(self) -> Dict[str, Any]:
+        dct = self.to_dict()
+        dct_options = {
+            "BackupPlan": self.backup_plan,
+            "CreatorRequestId": self.creator_request_id,
+            "DeletionDate": self.deletion_date,
+            "LastExecutionDate": self.last_execution_date,
+        }
+        for key, value in dct_options.items():
+            if value is not None:
+                dct[key] = value
+        return dct
+
+    def to_list_dict(self) -> Dict[str, Any]:
+        dct = self.to_get_dict()
+        dct.pop("BackupPlan")
+        dct["BackupPlanName"] = self.backup_plan.get("BackupPlanName")
+        return dct
+
+
+class Vault(BaseModel):
+    def __init__(
+        self,
+        backup_vault_name: str,
+        encryption_key_arn: str,
+        creator_request_id: str,
+        backend: "BackupBackend",
+    ):
+        self.backup_vault_name = backup_vault_name
+        self.backup_vault_arn = f"arn:aws:backup:{backend.region_name}:{backend.account_id}:backup-vault:{backup_vault_name}"
+        self.creation_date = unix_time()
+        self.encryption_key_arn = encryption_key_arn
+        self.creator_request_id = creator_request_id
+        self.num_of_recovery_points = 0  # start_backup_job not yet supported
+        self.locked = False  # put_backup_vault_lock_configuration
+        self.min_retention_days = 0  # put_backup_vault_lock_configuration
+        self.max_retention_days = 0  # put_backup_vault_lock_configuration
+        self.lock_date = None  # put_backup_vault_lock_configuration
+
+    def to_dict(self) -> Dict[str, Any]:
+        dct = {
+            "BackupVaultName": self.backup_vault_name,
+            "BackupVaultArn": self.backup_vault_arn,
+            "CreationDate": self.creation_date,
+        }
+        return dct
+
+    def to_list_dict(self) -> Dict[str, Any]:
+        dct = self.to_dict()
+        dct_options: Dict[str, Any] = dict()
+        dct_options = {
+            "EncryptionKeyArn": self.encryption_key_arn,
+            "CreatorRequestId": self.creator_request_id,
+            "NumberOfRecoveryPoints": self.num_of_recovery_points,
+            "Locked": self.locked,
+            "MinRetentionDays": self.min_retention_days,
+            "MaxRetentionDays": self.max_retention_days,
+            "LockDate": self.lock_date,
+        }
+        for key, value in dct_options.items():
+            if value is not None:
+                dct[key] = value
+        return dct
+
+
+class BackupBackend(BaseBackend):
+    """Implementation of Backup APIs."""
+
+    def __init__(self, region_name: str, account_id: str):
+        super().__init__(region_name, account_id)
+
+        self.vaults: Dict[str, Vault] = dict()
+        self.plans: Dict[str, Plan] = dict()
+        self.tagger = TaggingService()
+
+    def create_backup_plan(
+        self,
+        backup_plan: Dict[str, Any],
+        backup_plan_tags: Dict[str, str],
+        creator_request_id: str,
+    ) -> Plan:
+
+        if backup_plan["BackupPlanName"] in list(
+            p.backup_plan["BackupPlanName"] for p in list(self.plans.values())
+        ):
+            raise AlreadyExistsException(
+                msg="Backup plan with the same plan document already exists"
+            )
+        plan = Plan(
+            backup_plan=backup_plan,
+            creator_request_id=creator_request_id,
+            backend=self,
+        )
+        if backup_plan_tags:
+            self.tag_resource(plan.backup_plan_arn, backup_plan_tags)
+        self.plans[plan.backup_plan_id] = plan
+        return plan
+
+    def get_backup_plan(self, backup_plan_id: str, version_id: Optional[Any]) -> Plan:
+        msg = "Failed reading Backup plan with provided version"
+        if backup_plan_id not in self.plans:
+            raise ResourceNotFoundException(msg=msg)
+        plan = self.plans[backup_plan_id]
+        if version_id:
+            if plan.version_id == version_id:
+                return plan
+            else:
+                raise ResourceNotFoundException(msg=msg)
+        return plan
+
+    def delete_backup_plan(self, backup_plan_id: str) -> Tuple[str, str, float, str]:
+        if backup_plan_id not in self.plans:
+            raise ResourceNotFoundException(
+                msg="Failed reading Backup plan with provided version"
+            )
+        deletion_date = unix_time()
+        res = self.plans[backup_plan_id]
+        res.deletion_date = deletion_date
+        return res.backup_plan_id, res.backup_plan_arn, deletion_date, res.version_id
+
+    def list_backup_plans(self, include_deleted: Any) -> List[Plan]:
+        """
+        Pagination is not yet implemented
+        """
+        plans_list = deepcopy(self.plans)
+
+        for plan in list(plans_list.values()):
+            backup_plan_id = plan.backup_plan_id
+            if plan.deletion_date is not None:
+                plans_list.pop(backup_plan_id)
+        if include_deleted:
+            return list(self.plans.values())
+        return list(plans_list.values())
+
+    def create_backup_vault(
+        self,
+        backup_vault_name: str,
+        backup_vault_tags: Dict[str, str],
+        encryption_key_arn: str,
+        creator_request_id: str,
+    ) -> Vault:
+
+        if backup_vault_name in self.vaults:
+            raise AlreadyExistsException(
+                msg="Backup vault with the same name already exists"
+            )
+        vault = Vault(
+            backup_vault_name=backup_vault_name,
+            encryption_key_arn=encryption_key_arn,
+            creator_request_id=creator_request_id,
+            backend=self,
+        )
+        if backup_vault_tags:
+            self.tag_resource(vault.backup_vault_arn, backup_vault_tags)
+        self.vaults[backup_vault_name] = vault
+        return vault
+
+    def list_backup_vaults(self) -> List[Vault]:
+        """
+        Pagination is not yet implemented
+        """
+        return list(self.vaults.values())
+
+    def list_tags(self, resource_arn: str) -> Dict[str, str]:
+        """
+        Pagination is not yet implemented
+        """
+        return self.tagger.get_tag_dict_for_resource(resource_arn)
+
+    def tag_resource(self, resource_arn: str, tags: Dict[str, str]) -> None:
+        tags_input = TaggingService.convert_dict_to_tags_input(tags or {})
+        self.tagger.tag_resource(resource_arn, tags_input)
+
+    def untag_resource(self, resource_arn: str, tag_key_list: List[str]) -> None:
+        self.tagger.untag_resource_using_names(resource_arn, tag_key_list)
+
+
+backup_backends = BackendDict(BackupBackend, "backup")
diff --git a/moto/backup/responses.py b/moto/backup/responses.py
new file mode 100644
index 000000000..42483740b
--- /dev/null
+++ b/moto/backup/responses.py
@@ -0,0 +1,116 @@
+"""Handles incoming backup requests, invokes methods, returns responses."""
+import json
+from urllib.parse import unquote
+
+from moto.core.responses import BaseResponse
+
+from .models import BackupBackend, backup_backends
+
+
+class BackupResponse(BaseResponse):
+    """Handler for Backup requests and responses."""
+
+    def __init__(self) -> None:
+        super().__init__(service_name="backup")
+
+    @property
+    def backup_backend(self) -> BackupBackend:
+        """Return backend instance specific for this region."""
+        return backup_backends[self.current_account][self.region]
+
+    def create_backup_plan(self) -> str:
+        params = json.loads(self.body)
+        backup_plan = params.get("BackupPlan")
+        backup_plan_tags = params.get("BackupPlanTags")
+        creator_request_id = params.get("CreatorRequestId")
+        plan = self.backup_backend.create_backup_plan(
+            backup_plan=backup_plan,
+            backup_plan_tags=backup_plan_tags,
+            creator_request_id=creator_request_id,
+        )
+        return json.dumps(dict(plan.to_dict()))
+
+    def get_backup_plan(self) -> str:
+        params = self._get_params()
+        backup_plan_id = self.path.split("/")[-2]
+        version_id = params.get("versionId")
+        plan = self.backup_backend.get_backup_plan(
+            backup_plan_id=backup_plan_id, version_id=version_id
+        )
+        return json.dumps(dict(plan.to_get_dict()))
+
+    def delete_backup_plan(self) -> str:
+        backup_plan_id = self.path.split("/")[-1]
+        (
+            backup_plan_id,
+            backup_plan_arn,
+            deletion_date,
+            version_id,
+        ) = self.backup_backend.delete_backup_plan(
+            backup_plan_id=backup_plan_id,
+        )
+        return json.dumps(
+            dict(
+                BackupPlanId=backup_plan_id,
+                BackupPlanArn=backup_plan_arn,
+                DeletionDate=deletion_date,
+                VersionId=version_id,
+            )
+        )
+
+    def list_backup_plans(self) -> str:
+        params = self._get_params()
+        include_deleted = params.get("includeDeleted")
+        backup_plans_list = self.backup_backend.list_backup_plans(
+            include_deleted=include_deleted
+        )
+        return json.dumps(
+            dict(BackupPlansList=[p.to_list_dict() for p in backup_plans_list])
+        )
+
+    def create_backup_vault(self) -> str:
+        params = json.loads(self.body)
+        backup_vault_name = self.path.split("/")[-1]
+        backup_vault_tags = params.get("BackupVaultTags")
+        encryption_key_arn = params.get("EncryptionKeyArn")
+        creator_request_id = params.get("CreatorRequestId")
+        backup_vault = self.backup_backend.create_backup_vault(
+            backup_vault_name=backup_vault_name,
+            backup_vault_tags=backup_vault_tags,
+            encryption_key_arn=encryption_key_arn,
+            creator_request_id=creator_request_id,
+        )
+        return json.dumps(dict(backup_vault.to_dict()))
+
+    def list_backup_vaults(self) -> str:
+        backup_vault_list = self.backup_backend.list_backup_vaults()
+        return json.dumps(
+            dict(BackupVaultList=[v.to_list_dict() for v in backup_vault_list])
+        )
+
+    def list_tags(self) -> str:
+        resource_arn = unquote(self.path.split("/")[-2])
+        tags = self.backup_backend.list_tags(
+            resource_arn=resource_arn,
+        )
+        return json.dumps(dict(Tags=tags))
+
+    def tag_resource(self) -> str:
+        params = json.loads(self.body)
+        resource_arn = unquote(self.path.split("/")[-1])
+        tags = params.get("Tags")
+        self.backup_backend.tag_resource(
+            resource_arn=resource_arn,
+            tags=tags,
+        )
+        return "{}"
+
+    def untag_resource(self) -> str:
+        params = json.loads(self.body)
+        resource_arn = unquote(self.path.split("/")[-1])
+        tag_key_list = params.get("TagKeyList")
+        self.backup_backend.untag_resource(
+            resource_arn=resource_arn,
+            tag_key_list=tag_key_list,
+        )
+        return "{}"
diff --git a/moto/backup/urls.py b/moto/backup/urls.py
new file mode 100644
index 000000000..5b4b7c84b
--- /dev/null
+++ b/moto/backup/urls.py
@@ -0,0 +1,19 @@
+"""backup base URL and path."""
+from .responses import BackupResponse
+
+url_bases = [
+    r"https?://backup\.(.+)\.amazonaws\.com",
+]
+
+
+response = BackupResponse()
+
+
+url_paths = {
+    "{0}/backup/plans/?$": response.dispatch,
+    "{0}/backup/plans/(?P<name>.+)/?$": response.dispatch,
+    "{0}/backup-vaults/$": response.dispatch,
+    "{0}/backup-vaults/(?P<name>[^/]+)$": response.dispatch,
+    "{0}/tags/(?P<resource_arn>.+)$": response.dispatch,
+    "{0}/untag/(?P<resource_arn>.+)$": response.dispatch,
+}
diff --git a/moto/core/utils.py b/moto/core/utils.py
index 8f3ddfce0..8e817dda2 100644
--- a/moto/core/utils.py
+++ b/moto/core/utils.py
@@ -170,10 +170,36 @@ def iso_8601_datetime_without_milliseconds_s3(
 
 
 RFC1123 = "%a, %d %b %Y %H:%M:%S GMT"
+EN_WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
+EN_MONTHS = [
+    "Jan",
+    "Feb",
+    "Mar",
+    "Apr",
+    "May",
+    "Jun",
+    "Jul",
+    "Aug",
+    "Sep",
+    "Oct",
+    "Nov",
+    "Dec",
+]
 
 
 def rfc_1123_datetime(src: datetime.datetime) -> str:
-    return src.strftime(RFC1123)
+    """
+    Returns the datetime in the RFC-1123 format
+    Names of weekdays/months are in English
+    """
+    # strftime uses the current locale to translate values
+    # So weekday/month values may not be in English
+    # For our usecase, we need these values to always be in English, otherwise botocore is unable to parse it
+    # Having a hardcoded list ensures this always works, even if the user does not have an English locale installed
+    eng_weekday = EN_WEEKDAYS[src.isoweekday() - 1]
+    eng_month = EN_MONTHS[src.month - 1]
+    non_locallized_rfc1123 = RFC1123.replace("%a", "{}").replace("%b", "{}")
+    return src.strftime(non_locallized_rfc1123).format(eng_weekday, eng_month)
 
 
 def str_to_rfc_1123_datetime(value: str) -> datetime.datetime:
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-1.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-1.json
index db3be8416..ff1a1e89b 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-1.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-1.json
@@ -4647,6 +4647,50 @@
   "InstanceType": "r7gd.xlarge",
   "Location": "apne1-az2"
  },
+ {
+  "InstanceType": "r7i.12xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.16xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.24xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.2xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.48xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.4xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.8xlarge",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.large",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.metal-24xl",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.metal-48xl",
+  "Location": "apne1-az2"
+ },
+ {
+  "InstanceType": "r7i.xlarge",
+  "Location": "apne1-az2"
+ },
  {
   "InstanceType": "t2.2xlarge",
   "Location": "apne1-az2"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-2.json
index e6093bb26..6ef98b9a7 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/ap-northeast-2.json
@@ -1763,6 +1763,10 @@
   "InstanceType": "t4g.xlarge",
   "Location": "apne2-az1"
  },
+ {
+  "InstanceType": "u-12tb1.112xlarge",
+  "Location": "apne2-az1"
+ },
  {
   "InstanceType": "u-6tb1.112xlarge",
   "Location": "apne2-az1"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/eu-west-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/eu-west-2.json
index c88c855a7..28313c772 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/eu-west-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/eu-west-2.json
@@ -1667,6 +1667,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "euw2-az1"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "euw2-az1"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "euw2-az1"
@@ -3795,6 +3799,50 @@
   "InstanceType": "c5n.xlarge",
   "Location": "euw2-az3"
  },
+ {
+  "InstanceType": "c6a.12xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.16xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.24xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.2xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.32xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.48xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.4xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.8xlarge",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.large",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.metal",
+  "Location": "euw2-az3"
+ },
+ {
+  "InstanceType": "c6a.xlarge",
+  "Location": "euw2-az3"
+ },
  {
   "InstanceType": "c6g.12xlarge",
   "Location": "euw2-az3"
@@ -5211,6 +5259,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "euw2-az3"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "euw2-az3"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "euw2-az3"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-1.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-1.json
index 9078869ef..3a9fc7b19 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-1.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-1.json
@@ -1287,6 +1287,86 @@
   "InstanceType": "m6id.xlarge",
   "Location": "use1-az1"
  },
+ {
+  "InstanceType": "m6idn.12xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.16xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.24xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.2xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.32xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.4xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.8xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.large",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.metal",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6idn.xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.12xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.16xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.24xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.2xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.32xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.4xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.8xlarge",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.large",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.metal",
+  "Location": "use1-az1"
+ },
+ {
+  "InstanceType": "m6in.xlarge",
+  "Location": "use1-az1"
+ },
  {
   "InstanceType": "m7g.12xlarge",
   "Location": "use1-az1"
@@ -3035,6 +3115,38 @@
   "InstanceType": "c7gd.xlarge",
   "Location": "use1-az2"
  },
+ {
+  "InstanceType": "c7gn.12xlarge",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.16xlarge",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.2xlarge",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.4xlarge",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.8xlarge",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.large",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.medium",
+  "Location": "use1-az2"
+ },
+ {
+  "InstanceType": "c7gn.xlarge",
+  "Location": "use1-az2"
+ },
  {
   "InstanceType": "c7i.12xlarge",
   "Location": "use1-az2"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-2.json
index f8eeb40bb..8c9296d40 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-east-2.json
@@ -2671,6 +2671,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "use2-az1"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "use2-az1"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "use2-az1"
@@ -5479,6 +5483,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "use2-az2"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "use2-az2"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "use2-az2"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-west-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-west-2.json
index 23164d255..cbda318c0 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-west-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone-id/us-west-2.json
@@ -9955,6 +9955,86 @@
   "InstanceType": "m6id.xlarge",
   "Location": "usw2-az4"
  },
+ {
+  "InstanceType": "m6idn.12xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.16xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.24xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.2xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.32xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.4xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.8xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.large",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.metal",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6idn.xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.12xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.16xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.24xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.2xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.32xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.4xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.8xlarge",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.large",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.metal",
+  "Location": "usw2-az4"
+ },
+ {
+  "InstanceType": "m6in.xlarge",
+  "Location": "usw2-az4"
+ },
  {
   "InstanceType": "m7g.12xlarge",
   "Location": "usw2-az4"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-1.json b/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-1.json
index 247aef8c3..009570a03 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-1.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-1.json
@@ -7367,6 +7367,50 @@
   "InstanceType": "r7gd.xlarge",
   "Location": "ap-northeast-1d"
  },
+ {
+  "InstanceType": "r7i.12xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.16xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.24xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.2xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.48xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.4xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.8xlarge",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.large",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.metal-24xl",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.metal-48xl",
+  "Location": "ap-northeast-1d"
+ },
+ {
+  "InstanceType": "r7i.xlarge",
+  "Location": "ap-northeast-1d"
+ },
  {
   "InstanceType": "t2.2xlarge",
   "Location": "ap-northeast-1d"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-2.json
index 777f39289..1cd4edecd 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/ap-northeast-2.json
@@ -1763,6 +1763,10 @@
   "InstanceType": "t4g.xlarge",
   "Location": "ap-northeast-2a"
  },
+ {
+  "InstanceType": "u-12tb1.112xlarge",
+  "Location": "ap-northeast-2a"
+ },
  {
   "InstanceType": "u-6tb1.112xlarge",
   "Location": "ap-northeast-2a"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/eu-west-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone/eu-west-2.json
index 38dc1dc3b..18986d104 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/eu-west-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/eu-west-2.json
@@ -2043,6 +2043,50 @@
   "InstanceType": "c5n.xlarge",
   "Location": "eu-west-2b"
  },
+ {
+  "InstanceType": "c6a.12xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.16xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.24xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.2xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.32xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.48xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.4xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.8xlarge",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.large",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.metal",
+  "Location": "eu-west-2b"
+ },
+ {
+  "InstanceType": "c6a.xlarge",
+  "Location": "eu-west-2b"
+ },
  {
   "InstanceType": "c6g.12xlarge",
   "Location": "eu-west-2b"
@@ -3459,6 +3503,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "eu-west-2b"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "eu-west-2b"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "eu-west-2b"
@@ -5211,6 +5259,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "eu-west-2c"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "eu-west-2c"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "eu-west-2c"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-1.json b/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-1.json
index 8e94fa4c6..ee2e4ab36 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-1.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-1.json
@@ -1287,6 +1287,86 @@
   "InstanceType": "m6id.xlarge",
   "Location": "us-east-1a"
  },
+ {
+  "InstanceType": "m6idn.12xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.16xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.24xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.2xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.32xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.4xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.8xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.large",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.metal",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6idn.xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.12xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.16xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.24xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.2xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.32xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.4xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.8xlarge",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.large",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.metal",
+  "Location": "us-east-1a"
+ },
+ {
+  "InstanceType": "m6in.xlarge",
+  "Location": "us-east-1a"
+ },
  {
   "InstanceType": "m7g.12xlarge",
   "Location": "us-east-1a"
@@ -3035,6 +3115,38 @@
   "InstanceType": "c7gd.xlarge",
   "Location": "us-east-1b"
  },
+ {
+  "InstanceType": "c7gn.12xlarge",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.16xlarge",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.2xlarge",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.4xlarge",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.8xlarge",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.large",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.medium",
+  "Location": "us-east-1b"
+ },
+ {
+  "InstanceType": "c7gn.xlarge",
+  "Location": "us-east-1b"
+ },
  {
   "InstanceType": "c7i.12xlarge",
   "Location": "us-east-1b"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-2.json
index 2b0e332c3..488c5a672 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/us-east-2.json
@@ -2671,6 +2671,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "us-east-2a"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "us-east-2a"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "us-east-2a"
@@ -5479,6 +5483,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "us-east-2b"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "us-east-2b"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "us-east-2b"
diff --git a/moto/ec2/resources/instance_type_offerings/availability-zone/us-west-2.json b/moto/ec2/resources/instance_type_offerings/availability-zone/us-west-2.json
index 031ade678..21772f1bb 100644
--- a/moto/ec2/resources/instance_type_offerings/availability-zone/us-west-2.json
+++ b/moto/ec2/resources/instance_type_offerings/availability-zone/us-west-2.json
@@ -9955,6 +9955,86 @@
   "InstanceType": "m6id.xlarge",
   "Location": "us-west-2d"
  },
+ {
+  "InstanceType": "m6idn.12xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.16xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.24xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.2xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.32xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.4xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.8xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.large",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.metal",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6idn.xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.12xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.16xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.24xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.2xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.32xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.4xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.8xlarge",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.large",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.metal",
+  "Location": "us-west-2d"
+ },
+ {
+  "InstanceType": "m6in.xlarge",
+  "Location": "us-west-2d"
+ },
  {
   "InstanceType": "m7g.12xlarge",
   "Location": "us-west-2d"
diff --git a/moto/ec2/resources/instance_type_offerings/region/ap-northeast-2.json b/moto/ec2/resources/instance_type_offerings/region/ap-northeast-2.json
index 88b68bc9f..a212d8624 100644
--- a/moto/ec2/resources/instance_type_offerings/region/ap-northeast-2.json
+++ b/moto/ec2/resources/instance_type_offerings/region/ap-northeast-2.json
@@ -1767,6 +1767,10 @@
   "InstanceType": "t4g.xlarge",
   "Location": "ap-northeast-2"
  },
+ {
+  "InstanceType": "u-12tb1.112xlarge",
+  "Location": "ap-northeast-2"
+ },
  {
   "InstanceType": "u-24tb1.112xlarge",
   "Location": "ap-northeast-2"
diff --git a/moto/ec2/resources/instance_type_offerings/region/eu-west-2.json b/moto/ec2/resources/instance_type_offerings/region/eu-west-2.json
index 0175f2c56..a2fd6f4a0 100644
--- a/moto/ec2/resources/instance_type_offerings/region/eu-west-2.json
+++ b/moto/ec2/resources/instance_type_offerings/region/eu-west-2.json
@@ -1815,6 +1815,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "eu-west-2"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "eu-west-2"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "eu-west-2"
diff --git a/moto/ec2/resources/instance_type_offerings/region/us-east-2.json b/moto/ec2/resources/instance_type_offerings/region/us-east-2.json
index c18be1999..bcb7d751b 100644
--- a/moto/ec2/resources/instance_type_offerings/region/us-east-2.json
+++ b/moto/ec2/resources/instance_type_offerings/region/us-east-2.json
@@ -2723,6 +2723,10 @@
   "InstanceType": "u-6tb1.56xlarge",
   "Location": "us-east-2"
  },
+ {
+  "InstanceType": "u-9tb1.112xlarge",
+  "Location": "us-east-2"
+ },
  {
   "InstanceType": "x1.16xlarge",
   "Location": "us-east-2"
diff --git a/moto/ec2/resources/instance_types.json b/moto/ec2/resources/instance_types.json
index 637563102..7cba4d3f7 100644
--- a/moto/ec2/resources/instance_types.json
+++ b/moto/ec2/resources/instance_types.json
@@ -13861,7 +13861,12 @@
    "NetworkPerformance": "Up to 12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -14184,7 +14189,12 @@
    "NetworkPerformance": "Up to 12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -14283,7 +14293,12 @@
    "NetworkPerformance": "12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -48303,7 +48318,12 @@
    "NetworkPerformance": "Up to 12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -48401,7 +48421,12 @@
    "NetworkPerformance": "50 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -48831,7 +48856,12 @@
    "NetworkPerformance": "Up to 12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -69829,7 +69859,12 @@
    "NetworkPerformance": "18.75 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -69932,7 +69967,12 @@
    "NetworkPerformance": "25 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -70366,7 +70406,12 @@
    "NetworkPerformance": "50 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
@@ -70781,7 +70826,12 @@
    "NetworkPerformance": "Up to 12.5 Gigabit"
   },
   "NitroEnclavesSupport": "unsupported",
-  "NitroTpmSupport": "unsupported",
+  "NitroTpmInfo": {
+   "SupportedVersions": [
+    "2.0"
+   ]
+  },
+  "NitroTpmSupport": "supported",
   "PlacementGroupInfo": {
    "SupportedStrategies": [
     "cluster",
diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py
index 4b3cf67ea..a748103e9 100644
--- a/moto/elbv2/models.py
+++ b/moto/elbv2/models.py
@@ -576,6 +576,9 @@ class FakeLoadBalancer(CloudFormationModel):
         "access_logs.s3.enabled",
         "access_logs.s3.bucket",
         "access_logs.s3.prefix",
+        "connection_logs.s3.bucket",
+        "connection_logs.s3.enabled",
+        "connection_logs.s3.prefix",
         "deletion_protection.enabled",
         "idle_timeout.timeout_seconds",
         "ipv6.deny_all_igw_traffic",
diff --git a/moto/elbv2/responses.py b/moto/elbv2/responses.py
index 2df73d292..8b50ab7bb 100644
--- a/moto/elbv2/responses.py
+++ b/moto/elbv2/responses.py
@@ -1578,40 +1578,6 @@ DESCRIBE_ATTRIBUTES_TEMPLATE = """<DescribeLoadBalancerAttributesResponse  xmlns
 </DescribeLoadBalancerAttributesResponse>
 """
 
-MODIFY_ATTRIBUTES_TEMPLATE = """<ModifyLoadBalancerAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
-  <ModifyLoadBalancerAttributesResult>
-  <LoadBalancerName>{{ load_balancer.name }}</LoadBalancerName>
-    <LoadBalancerAttributes>
-      <AccessLog>
-        <Enabled>{{ attributes.access_log.enabled }}</Enabled>
-        {% if attributes.access_log.enabled %}
-        <S3BucketName>{{ attributes.access_log.s3_bucket_name }}</S3BucketName>
-        <S3BucketPrefix>{{ attributes.access_log.s3_bucket_prefix }}</S3BucketPrefix>
-        <EmitInterval>{{ attributes.access_log.emit_interval }}</EmitInterval>
-        {% endif %}
-      </AccessLog>
-      <ConnectionSettings>
-        <IdleTimeout>{{ attributes.connecting_settings.idle_timeout }}</IdleTimeout>
-      </ConnectionSettings>
-      <CrossZoneLoadBalancing>
-        <Enabled>{{ attributes.cross_zone_load_balancing.enabled }}</Enabled>
-      </CrossZoneLoadBalancing>
-      <ConnectionDraining>
-        {% if attributes.connection_draining.enabled %}
-        <Enabled>true</Enabled>
-        <Timeout>{{ attributes.connection_draining.timeout }}</Timeout>
-        {% else %}
-        <Enabled>false</Enabled>
-        {% endif %}
-      </ConnectionDraining>
-    </LoadBalancerAttributes>
-  </ModifyLoadBalancerAttributesResult>
-  <ResponseMetadata>
-    <RequestId>{{ request_id }}</RequestId>
-  </ResponseMetadata>
-</ModifyLoadBalancerAttributesResponse>
-"""
-
 CREATE_LOAD_BALANCER_POLICY_TEMPLATE = """<CreateLoadBalancerPolicyResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
   <CreateLoadBalancerPolicyResult/>
   <ResponseMetadata>
diff --git a/moto/events/notifications.py b/moto/events/notifications.py
index 67e13049d..3dd94fcad 100644
--- a/moto/events/notifications.py
+++ b/moto/events/notifications.py
@@ -59,10 +59,10 @@ def _send_safe_notification(
 def _invoke_lambda(account_id: str, fn_arn: str, event: Any) -> None:
     from moto.awslambda import lambda_backends
 
-    lmbda_region = fn_arn.split(":")[3]
+    lambda_region = fn_arn.split(":")[3]
 
     body = json.dumps(event)
-    lambda_backends[account_id][lmbda_region].invoke(
+    lambda_backends[account_id][lambda_region].invoke(
         function_name=fn_arn,
         qualifier=None,  # type: ignore[arg-type]
         body=body,
diff --git a/moto/rds/models.py b/moto/rds/models.py
index 0bfc1b259..1237d167e 100644
--- a/moto/rds/models.py
+++ b/moto/rds/models.py
@@ -229,6 +229,15 @@ class Cluster:
         self.replication_source_identifier = kwargs.get("replication_source_identifier")
         self.read_replica_identifiers: List[str] = list()
         self.is_writer: bool = False
+        self.storage_encrypted = kwargs.get("storage_encrypted", False)
+        if self.storage_encrypted:
+            self.kms_key_id = kwargs.get("kms_key_id", "default_kms_key_id")
+        else:
+            self.kms_key_id = kwargs.get("kms_key_id")
+        if self.engine == "aurora-mysql" or self.engine == "aurora-postgresql":
+            self.global_write_forwarding_requested = kwargs.get(
+                "enable_global_write_forwarding"
+            )
 
     @property
     def is_multi_az(self) -> bool:
@@ -361,7 +370,8 @@ class Cluster:
               {% endfor %}
               </VpcSecurityGroups>
               <HostedZoneId>{{ cluster.hosted_zone_id }}</HostedZoneId>
-              <StorageEncrypted>false</StorageEncrypted>
+              <StorageEncrypted>{{ 'true' if cluster.storage_encrypted else 'false' }}</StorageEncrypted>
+              <GlobalWriteForwardingRequested>{{ cluster.global_write_forwarding_requested }}</GlobalWriteForwardingRequested>
               <DbClusterResourceId>{{ cluster.resource_id }}</DbClusterResourceId>
               <DBClusterArn>{{ cluster.db_cluster_arn }}</DBClusterArn>
               <AssociatedRoles></AssociatedRoles>
@@ -485,6 +495,7 @@ class ClusterSnapshot(BaseModel):
         self.tags = tags
         self.status = "available"
         self.created_at = iso_8601_datetime_with_milliseconds()
+        self.attributes: List[Dict[str, Any]] = []
 
     @property
     def arn(self) -> str:
@@ -1122,6 +1133,7 @@ class DatabaseSnapshot(BaseModel):
         self.tags = tags
         self.status = "available"
         self.created_at = iso_8601_datetime_with_milliseconds()
+        self.attributes: List[Dict[str, Any]] = []
 
     @property
     def arn(self) -> str:
@@ -1806,7 +1818,13 @@ class RDSBackend(BaseBackend):
         db_instance = self.describe_db_instances(
             db_instance_identifier=source_db_identifier
         )[0]
-        new_instance_props = copy.deepcopy(db_instance.__dict__)
+
+        # remove the db subnet group as it cannot be copied
+        # and is not used in the restored instance
+        source_dict = db_instance.__dict__
+        del source_dict["db_subnet_group"]
+
+        new_instance_props = copy.deepcopy(source_dict)
         if not db_instance.option_group_supplied:
             # If the option group is not supplied originally, the 'option_group_name' will receive a default value
             # Force this reconstruction, and prevent any validation on the default value
@@ -2803,6 +2821,92 @@ class RDSBackend(BaseBackend):
             pass
         return None
 
+    def describe_db_snapshot_attributes(
+        self, db_snapshot_identifier: str
+    ) -> List[Dict[str, Any]]:
+        snapshot = self.describe_db_snapshots(
+            db_instance_identifier=None, db_snapshot_identifier=db_snapshot_identifier
+        )[0]
+        return snapshot.attributes
+
+    def modify_db_snapshot_attribute(
+        self,
+        db_snapshot_identifier: str,
+        attribute_name: str,
+        values_to_add: Optional[Dict[str, Dict[str, str]]] = None,
+        values_to_remove: Optional[Dict[str, Dict[str, str]]] = None,
+    ) -> List[Dict[str, Any]]:
+        snapshot = self.describe_db_snapshots(
+            db_instance_identifier=None, db_snapshot_identifier=db_snapshot_identifier
+        )[0]
+        attribute_present = False
+        for attribute in snapshot.attributes:
+            if attribute["AttributeName"] == attribute_name:
+                attribute_present = True
+                if values_to_add:
+                    attribute["AttributeValues"] = (
+                        values_to_add["AttributeValue"].values()
+                        + attribute["AttributeValues"]
+                    )
+                if values_to_remove:
+                    attribute["AttributeValues"] = [
+                        i
+                        for i in attribute["AttributeValues"]
+                        if i not in values_to_remove["AttributeValue"].values()
+                    ]
+        if not attribute_present and values_to_add:
+            snapshot.attributes.append(
+                {
+                    "AttributeName": attribute_name,
+                    "AttributeValues": values_to_add["AttributeValue"].values(),
+                }
+            )
+        return snapshot.attributes
+
+    def describe_db_cluster_snapshot_attributes(
+        self, db_cluster_snapshot_identifier: str
+    ) -> List[Dict[str, Any]]:
+        snapshot = self.describe_db_cluster_snapshots(
+            db_cluster_identifier=None,
+            db_snapshot_identifier=db_cluster_snapshot_identifier,
+        )[0]
+        return snapshot.attributes
+
+    def modify_db_cluster_snapshot_attribute(
+        self,
+        db_cluster_snapshot_identifier: str,
+        attribute_name: str,
+        values_to_add: Optional[Dict[str, Dict[str, str]]] = None,
+        values_to_remove: Optional[Dict[str, Dict[str, str]]] = None,
+    ) -> List[Dict[str, Any]]:
+        snapshot = self.describe_db_cluster_snapshots(
+            db_cluster_identifier=None,
+            db_snapshot_identifier=db_cluster_snapshot_identifier,
+        )[0]
+        attribute_present = False
+        for attribute in snapshot.attributes:
+            if attribute["AttributeName"] == attribute_name:
+                attribute_present = True
+                if values_to_add:
+                    attribute["AttributeValues"] = (
+                        values_to_add["AttributeValue"].values()
+                        + attribute["AttributeValues"]
+                    )
+                if values_to_remove:
+                    attribute["AttributeValues"] = [
+                        i
+                        for i in attribute["AttributeValues"]
+                        if i not in values_to_remove["AttributeValue"].values()
+                    ]
+        if not attribute_present and values_to_add:
+            snapshot.attributes.append(
+                {
+                    "AttributeName": attribute_name,
+                    "AttributeValues": values_to_add["AttributeValue"].values(),
+                }
+            )
+        return snapshot.attributes
+
 
 class OptionGroup:
     def __init__(
diff --git a/moto/rds/responses.py b/moto/rds/responses.py
index a68484f57..e3dbbe1cc 100644
--- a/moto/rds/responses.py
+++ b/moto/rds/responses.py
@@ -195,6 +195,10 @@ class RDSResponse(BaseResponse):
             "allocated_storage": self._get_param("AllocatedStorage"),
             "global_cluster_identifier": self._get_param("GlobalClusterIdentifier"),
             "iops": self._get_param("Iops"),
+            "storage_encrypted": self._get_param("StorageEncrypted"),
+            "enable_global_write_forwarding": self._get_param(
+                "EnableGlobalWriteForwarding"
+            ),
             "storage_type": self._get_param("StorageType"),
             "kms_key_id": self._get_param("KmsKeyId"),
             "master_username": self._get_param("MasterUsername"),
@@ -818,6 +822,66 @@ class RDSResponse(BaseResponse):
         template = self.response_template(PROMOTE_READ_REPLICA_DB_CLUSTER_TEMPLATE)
         return template.render(cluster=cluster)
 
+    def describe_db_snapshot_attributes(self) -> str:
+        params = self._get_params()
+        db_snapshot_identifier = params["DBSnapshotIdentifier"]
+        db_snapshot_attributes_result = self.backend.describe_db_snapshot_attributes(
+            db_snapshot_identifier=db_snapshot_identifier,
+        )
+        template = self.response_template(DESCRIBE_DB_SNAPSHOT_ATTRIBUTES_TEMPLATE)
+        return template.render(
+            db_snapshot_attributes_result=db_snapshot_attributes_result,
+            db_snapshot_identifier=db_snapshot_identifier,
+        )
+
+    def modify_db_snapshot_attribute(self) -> str:
+        params = self._get_params()
+        db_snapshot_identifier = params["DBSnapshotIdentifier"]
+        db_snapshot_attributes_result = self.backend.modify_db_snapshot_attribute(
+            db_snapshot_identifier=db_snapshot_identifier,
+            attribute_name=params["AttributeName"],
+            values_to_add=params.get("ValuesToAdd"),
+            values_to_remove=params.get("ValuesToRemove"),
+        )
+        template = self.response_template(MODIFY_DB_SNAPSHOT_ATTRIBUTE_TEMPLATE)
+        return template.render(
+            db_snapshot_attributes_result=db_snapshot_attributes_result,
+            db_snapshot_identifier=db_snapshot_identifier,
+        )
+
+    def describe_db_cluster_snapshot_attributes(self) -> str:
+        params = self._get_params()
+        db_cluster_snapshot_identifier = params["DBClusterSnapshotIdentifier"]
+        db_cluster_snapshot_attributes_result = (
+            self.backend.describe_db_cluster_snapshot_attributes(
+                db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
+            )
+        )
+        template = self.response_template(
+            DESCRIBE_DB_CLUSTER_SNAPSHOT_ATTRIBUTES_TEMPLATE
+        )
+        return template.render(
+            db_cluster_snapshot_attributes_result=db_cluster_snapshot_attributes_result,
+            db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
+        )
+
+    def modify_db_cluster_snapshot_attribute(self) -> str:
+        params = self._get_params()
+        db_cluster_snapshot_identifier = params["DBClusterSnapshotIdentifier"]
+        db_cluster_snapshot_attributes_result = (
+            self.backend.modify_db_cluster_snapshot_attribute(
+                db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
+                attribute_name=params["AttributeName"],
+                values_to_add=params.get("ValuesToAdd"),
+                values_to_remove=params.get("ValuesToRemove"),
+            )
+        )
+        template = self.response_template(MODIFY_DB_CLUSTER_SNAPSHOT_ATTRIBUTE_TEMPLATE)
+        return template.render(
+            db_cluster_snapshot_attributes_result=db_cluster_snapshot_attributes_result,
+            db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
+        )
+
 
 CREATE_DATABASE_TEMPLATE = """<CreateDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
   <CreateDBInstanceResult>
@@ -1474,3 +1538,95 @@ PROMOTE_READ_REPLICA_DB_CLUSTER_TEMPLATE = """<PromoteReadReplicaDBClusterRespon
     <RequestId>7369556f-b70d-11c3-faca-6ba18376ea1b</RequestId>
   </ResponseMetadata>
 </PromoteReadReplicaDBClusterResponse>"""
+
+DESCRIBE_DB_SNAPSHOT_ATTRIBUTES_TEMPLATE = """<DescribeDBSnapshotAttributesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
+  <DescribeDBSnapshotAttributesResult>
+    <DBSnapshotAttributesResult>
+      <DBSnapshotAttributes>
+        {%- for attribute in db_snapshot_attributes_result -%}
+          <DBSnapshotAttribute>
+            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
+            <AttributeValues>
+              {%- for value in attribute["AttributeValues"] -%}
+                <AttributeValue>{{ value }}</AttributeValue>
+              {%- endfor -%}
+            </AttributeValues>
+          </DBSnapshotAttribute>
+        {%- endfor -%}
+      </DBSnapshotAttributes>
+      <DBSnapshotIdentifier>{{ db_snapshot_identifier }}</DBSnapshotIdentifier>
+    </DBSnapshotAttributesResult>
+  </DescribeDBSnapshotAttributesResult>
+  <ResponseMetadata>
+    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
+  </ResponseMetadata>
+</DescribeDBSnapshotAttributesResponse>"""
+
+MODIFY_DB_SNAPSHOT_ATTRIBUTE_TEMPLATE = """<ModifyDBSnapshotAttributeResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
+  <ModifyDBSnapshotAttributeResult>
+    <DBSnapshotAttributesResult>
+      <DBSnapshotAttributes>
+        {%- for attribute in db_snapshot_attributes_result -%}
+          <DBSnapshotAttribute>
+            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
+            <AttributeValues>
+              {%- for value in attribute["AttributeValues"] -%}
+                <AttributeValue>{{ value }}</AttributeValue>
+              {%- endfor -%}
+            </AttributeValues>
+          </DBSnapshotAttribute>
+        {%- endfor -%}
+      </DBSnapshotAttributes>
+      <DBSnapshotIdentifier>{{ db_snapshot_identifier }}</DBSnapshotIdentifier>
+    </DBSnapshotAttributesResult>
+  </ModifyDBSnapshotAttributeResult>
+  <ResponseMetadata>
+    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
+  </ResponseMetadata>
+</ModifyDBSnapshotAttributeResponse>"""
+
+MODIFY_DB_CLUSTER_SNAPSHOT_ATTRIBUTE_TEMPLATE = """<ModifyDBClusterSnapshotAttributeResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
+  <ModifyDBClusterSnapshotAttributeResult>
+    <DBClusterSnapshotAttributesResult>
+      <DBClusterSnapshotAttributes>
+        {%- for attribute in db_cluster_snapshot_attributes_result -%}
+          <DBClusterSnapshotAttribute>
+            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
+            <AttributeValues>
+              {%- for value in attribute["AttributeValues"] -%}
+                <AttributeValue>{{ value }}</AttributeValue>
+              {%- endfor -%}
+            </AttributeValues>
+          </DBClusterSnapshotAttribute>
+        {%- endfor -%}
+      </DBClusterSnapshotAttributes>
+      <DBClusterSnapshotIdentifier>{{ db_cluster_snapshot_identifier }}</DBClusterSnapshotIdentifier>
+    </DBClusterSnapshotAttributesResult>
+  </ModifyDBClusterSnapshotAttributeResult>
+  <ResponseMetadata>
+    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
+  </ResponseMetadata>
+</ModifyDBClusterSnapshotAttributeResponse>"""
+
+DESCRIBE_DB_CLUSTER_SNAPSHOT_ATTRIBUTES_TEMPLATE = """<DescribeDBClusterSnapshotAttributesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
+  <DescribeDBClusterSnapshotAttributesResult>
+    <DBClusterSnapshotAttributesResult>
+      <DBClusterSnapshotAttributes>
+        {%- for attribute in db_cluster_snapshot_attributes_result -%}
+          <DBClusterSnapshotAttribute>
+            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
+            <AttributeValues>
+              {%- for value in attribute["AttributeValues"] -%}
+                <AttributeValue>{{ value }}</AttributeValue>
+              {%- endfor -%}
+            </AttributeValues>
+          </DBClusterSnapshotAttribute> 
+        {%- endfor -%}
+      </DBClusterSnapshotAttributes>
+      <DBClusterSnapshotIdentifier>{{ db_cluster_snapshot_identifier }}</DBClusterSnapshotIdentifier>
+    </DBClusterSnapshotAttributesResult>
+  </DescribeDBClusterSnapshotAttributesResult>
+  <ResponseMetadata>
+    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
+  </ResponseMetadata>
+</DescribeDBClusterSnapshotAttributesResponse>"""
diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py
index 41219e4d5..90c7a76ab 100644
--- a/moto/resourcegroupstaggingapi/models.py
+++ b/moto/resourcegroupstaggingapi/models.py
@@ -2,6 +2,7 @@ from typing import Any, Dict, Iterator, List, Optional, Tuple
 
 from moto.acm.models import AWSCertificateManagerBackend, acm_backends
 from moto.awslambda.models import LambdaBackend, lambda_backends
+from moto.backup.models import BackupBackend, backup_backends
 from moto.core import BackendDict, BaseBackend
 from moto.core.exceptions import RESTError
 from moto.ec2 import ec2_backends
@@ -100,6 +101,10 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
     def sqs_backend(self) -> SQSBackend:
         return sqs_backends[self.account_id][self.region_name]
 
+    @property
+    def backup_backend(self) -> BackupBackend:
+        return backup_backends[self.account_id][self.region_name]
+
     def _get_resources_generator(
         self,
         tag_filters: Optional[List[Dict[str, Any]]] = None,
@@ -165,6 +170,19 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
                     continue
                 yield {"ResourceARN": f"{certificate.arn}", "Tags": tags}
 
+        # Backup
+        if not resource_type_filters or "backup" in resource_type_filters:
+            for vault in self.backup_backend.vaults.values():
+                tags = self.backup_backend.tagger.list_tags_for_resource(
+                    vault.backup_vault_arn
+                )["Tags"]
+                if not tags or not tag_filter(
+                    tags
+                ):  # Skip if no tags, or invalid filter
+                    continue
+
+                yield {"ResourceARN": f"{vault.backup_vault_arn}", "Tags": tags}
+
         # S3
         if not resource_type_filters or "s3" in resource_type_filters:
             for bucket in self.s3_backend.buckets.values():
diff --git a/moto/route53/models.py b/moto/route53/models.py
index 409d992ff..ccfd5dc4d 100644
--- a/moto/route53/models.py
+++ b/moto/route53/models.py
@@ -208,6 +208,7 @@ class RecordSet(CloudFormationModel):
         self.alias_target = kwargs.get("AliasTarget", [])
         self.failover = kwargs.get("Failover", [])
         self.geo_location = kwargs.get("GeoLocation", [])
+        self.multi_value = kwargs.get("MultiValueAnswer")
 
     @staticmethod
     def cloudformation_name_type() -> str:
diff --git a/moto/route53/responses.py b/moto/route53/responses.py
index 7227f85f5..6350c71bc 100644
--- a/moto/route53/responses.py
+++ b/moto/route53/responses.py
@@ -562,6 +562,9 @@ LIST_RRSET_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
            {% if record.failover %}
                <Failover>{{ record.failover }}</Failover>
            {% endif %}
+           {% if record.multi_value %}
+               <MultiValueAnswer>{{ record.multi_value }}</MultiValueAnswer>
+           {% endif %}
            {% if record.geo_location %}
            <GeoLocation>
            {% for geo_key in ['ContinentCode','CountryCode','SubdivisionCode'] %}
diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py
index 337a9492e..dfea0dec6 100644
--- a/moto/s3/exceptions.py
+++ b/moto/s3/exceptions.py
@@ -2,6 +2,8 @@ from typing import TYPE_CHECKING, Any, Optional, Union
 
 from moto.core.exceptions import RESTError
 
+from .notifications import S3NotificationEvent
+
 if TYPE_CHECKING:
     from moto.s3.models import FakeDeleteMarker
 
@@ -281,10 +283,13 @@ class InvalidNotificationDestination(S3ClientError):
 class InvalidNotificationEvent(S3ClientError):
     code = 400
 
-    def __init__(self) -> None:
+    def __init__(self, event_name: str) -> None:
         super().__init__(
             "InvalidArgument",
-            "The event is not supported for notifications",
+            (
+                f"The event '{event_name}' is not supported for notifications. "
+                f"Supported events are as follows: {S3NotificationEvent.events()}"
+            ),
         )
 
 
diff --git a/moto/s3/models.py b/moto/s3/models.py
index c115f96c1..480601e47 100644
--- a/moto/s3/models.py
+++ b/moto/s3/models.py
@@ -2088,7 +2088,10 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
         bucket.keys.setlist(key_name, keys)
 
         notifications.send_event(
-            self.account_id, notifications.S3_OBJECT_CREATE_PUT, bucket, new_key
+            self.account_id,
+            notifications.S3NotificationEvent.OBJECT_CREATED_PUT_EVENT,
+            bucket,
+            new_key,
         )
 
         return new_key
@@ -2640,7 +2643,10 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
 
         # Send notifications that an object was copied
         notifications.send_event(
-            self.account_id, notifications.S3_OBJECT_CREATE_COPY, bucket, new_key
+            self.account_id,
+            notifications.S3NotificationEvent.OBJECT_CREATED_COPY_EVENT,
+            bucket,
+            new_key,
         )
 
     def put_bucket_acl(self, bucket_name: str, acl: Optional[FakeAcl]) -> None:
diff --git a/moto/s3/notifications.py b/moto/s3/notifications.py
index b43ab1908..389b60070 100644
--- a/moto/s3/notifications.py
+++ b/moto/s3/notifications.py
@@ -1,11 +1,53 @@
 import json
 from datetime import datetime
+from enum import Enum
 from typing import Any, Dict, List
 
 _EVENT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
 
-S3_OBJECT_CREATE_COPY = "s3:ObjectCreated:Copy"
-S3_OBJECT_CREATE_PUT = "s3:ObjectCreated:Put"
+
+class S3NotificationEvent(str, Enum):
+    REDUCED_REDUNDANCY_LOST_OBJECT_EVENT = "s3:ReducedRedundancyLostObject"
+    OBJCET_CREATED_EVENT = "s3:ObjectCreated:*"
+    OBJECT_CREATED_PUT_EVENT = "s3:ObjectCreated:Put"
+    OBJECT_CREATED_POST_EVENT = "s3:ObjectCreated:Post"
+    OBJECT_CREATED_COPY_EVENT = "s3:ObjectCreated:Copy"
+    OBJECT_CREATED_COMPLETE_MULTIPART_UPLOAD_EVENT = (
+        "s3:ObjectCreated:CompleteMultipartUpload"
+    )
+    OBJECT_REMOVED_EVENT = "s3:ObjectRemoved:*"
+    OBJECTREMOVED_DELETE_EVENT = "s3:ObjectRemoved:Delete"
+    OBJECTREMOVED_DELETE_MARKER_CREATED_EVENT = "s3:ObjectRemoved:DeleteMarkerCreated"
+    OBJECT_RESTORE_EVENT = "s3:ObjectRestore:*"
+    OBJECT_RESTORE_POST_EVENT = "s3:ObjectRestore:Post"
+    OBJECT_RESTORE_COMPLETED_EVENT = "s3:ObjectRestore:Completed"
+    REPLICATION_EVENT = "s3:Replication:*"
+    REPLICATION_OPERATION_FAILED_REPLICATION_EVENT = (
+        "s3:Replication:OperationFailedReplication"
+    )
+    REPLICATION_OPERATION_NOT_TRACKED_EVENT = "s3:Replication:OperationNotTracked"
+    REPLICATION_OPERATION_MISSED_THRESHOLD_EVENT = (
+        "s3:Replication:OperationMissedThreshold"
+    )
+    REPLICATION_OPERATION_REPLICATED_AFTER_THRESHOLD_EVENT = (
+        "s3:Replication:OperationReplicatedAfterThreshold"
+    )
+    OBJECT_RESTORE_DELETE_EVENT = "s3:ObjectRestore:Delete"
+    LIFECYCLE_TRANSITION_EVENT = "s3:LifecycleTransition"
+    INTELLIGENT_TIERING_EVENT = "s3:IntelligentTiering"
+    OBJECT_ACL_EVENT = "s3:ObjectAcl:Put"
+    LIFECYCLE_EXPIRATION_EVENT = "s3:LifecycleExpiration:*"
+    LIFECYCLEEXPIRATION_DELETE_EVENT = "s3:LifecycleExpiration:Delete"
+    LIFECYCLE_EXPIRATION_DELETE_MARKER_CREATED_EVENT = (
+        "s3:LifecycleExpiration:DeleteMarkerCreated"
+    )
+    OBJECT_TAGGING_EVENT = "s3:ObjectTagging:*"
+    OBJECT_TAGGING_PUT_EVENT = "s3:ObjectTagging:Put"
+    OBJECTTAGGING_DELETE_EVENT = "s3:ObjectTagging:Delete"
+
+    @classmethod
+    def events(self) -> List[str]:
+        return sorted([item.value for item in S3NotificationEvent])
 
 
 def _get_s3_event(
@@ -41,7 +83,9 @@ def _get_region_from_arn(arn: str) -> str:
     return arn.split(":")[3]
 
 
-def send_event(account_id: str, event_name: str, bucket: Any, key: Any) -> None:
+def send_event(
+    account_id: str, event_name: S3NotificationEvent, bucket: Any, key: Any
+) -> None:
     if bucket.notification_configuration is None:
         return
 
diff --git a/moto/s3/responses.py b/moto/s3/responses.py
index efde8dea1..8d666ebf1 100644
--- a/moto/s3/responses.py
+++ b/moto/s3/responses.py
@@ -63,6 +63,7 @@ from .models import (
     get_canned_acl,
     s3_backends,
 )
+from .notifications import S3NotificationEvent
 from .select_object_content import serialize_select
 from .utils import (
     ARCHIVE_STORAGE_CLASSES,
@@ -2113,18 +2114,6 @@ class S3Response(BaseResponse):
             ("CloudFunction", "lambda"),
         ]
 
-        event_names = [
-            "s3:ReducedRedundancyLostObject",
-            "s3:ObjectCreated:*",
-            "s3:ObjectCreated:Put",
-            "s3:ObjectCreated:Post",
-            "s3:ObjectCreated:Copy",
-            "s3:ObjectCreated:CompleteMultipartUpload",
-            "s3:ObjectRemoved:*",
-            "s3:ObjectRemoved:Delete",
-            "s3:ObjectRemoved:DeleteMarkerCreated",
-        ]
-
         found_notifications = (
             0  # Tripwire -- if this is not ever set, then there were no notifications
         )
@@ -2151,8 +2140,8 @@ class S3Response(BaseResponse):
                         n["Event"] = [n["Event"]]
 
                     for event in n["Event"]:
-                        if event not in event_names:
-                            raise InvalidNotificationEvent()
+                        if event not in S3NotificationEvent.events():
+                            raise InvalidNotificationEvent(event)
 
                     # Parse out the filters:
                     if n.get("Filter"):
diff --git a/moto/sagemaker/exceptions.py b/moto/sagemaker/exceptions.py
index 8f5750573..c2286b9fe 100644
--- a/moto/sagemaker/exceptions.py
+++ b/moto/sagemaker/exceptions.py
@@ -41,6 +41,10 @@ class AWSValidationException(AWSError):
     TYPE = "ValidationException"
 
 
+class ResourceInUseException(AWSError):
+    TYPE = "ResourceInUse"
+
+
 class ResourceNotFound(JsonRESTError):
     def __init__(self, message: str):
         super().__init__(__class__.__name__, message)  # type: ignore
diff --git a/moto/sagemaker/models.py b/moto/sagemaker/models.py
index 06f5896cc..a828ee3a2 100644
--- a/moto/sagemaker/models.py
+++ b/moto/sagemaker/models.py
@@ -14,6 +14,7 @@ from moto.utilities.paginator import paginate
 from .exceptions import (
     AWSValidationException,
     MissingModel,
+    ResourceInUseException,
     ResourceNotFound,
     ValidationError,
 )
@@ -980,6 +981,63 @@ class ModelPackageGroup(BaseObject):
         return {k: v for k, v in response_object.items() if k in response_values}
 
 
+class FeatureGroup(BaseObject):
+    def __init__(
+        self,
+        region_name: str,
+        account_id: str,
+        feature_group_name: str,
+        record_identifier_feature_name: str,
+        event_time_feature_name: str,
+        feature_definitions: List[Dict[str, str]],
+        offline_store_config: Dict[str, Any],
+        role_arn: str,
+        tags: Optional[List[Dict[str, str]]] = None,
+    ) -> None:
+        self.feature_group_name = feature_group_name
+        self.record_identifier_feature_name = record_identifier_feature_name
+        self.event_time_feature_name = event_time_feature_name
+        self.feature_definitions = feature_definitions
+
+        table_name = (
+            f"{feature_group_name.replace('-','_')}_{int(datetime.now().timestamp())}"
+        )
+        offline_store_config["DataCatalogConfig"] = {
+            "TableName": table_name,
+            "Catalog": "AwsDataCatalog",
+            "Database": "sagemaker_featurestore",
+        }
+        offline_store_config["S3StorageConfig"][
+            "ResolvedOutputS3Uri"
+        ] = f'{offline_store_config["S3StorageConfig"]["S3Uri"]}/{account_id}/{region_name}/offline-store/{feature_group_name}-{int(datetime.now().timestamp())}/data'
+
+        self.offline_store_config = offline_store_config
+        self.role_arn = role_arn
+
+        self.creation_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+        self.feature_group_arn = arn_formatter(
+            region_name=region_name,
+            account_id=account_id,
+            _type="feature-group",
+            _id=f"{self.feature_group_name.lower()}",
+        )
+        self.tags = tags
+
+    def describe(self) -> Dict[str, Any]:
+        return {
+            "FeatureGroupArn": self.feature_group_arn,
+            "FeatureGroupName": self.feature_group_name,
+            "RecordIdentifierFeatureName": self.record_identifier_feature_name,
+            "EventTimeFeatureName": self.event_time_feature_name,
+            "FeatureDefinitions": self.feature_definitions,
+            "CreationTime": self.creation_time,
+            "OfflineStoreConfig": self.offline_store_config,
+            "RoleArn": self.role_arn,
+            "ThroughputConfig": {"ThroughputMode": "OnDemand"},
+            "FeatureGroupStatus": "Created",
+        }
+
+
 class ModelPackage(BaseObject):
     def __init__(
         self,
@@ -1768,6 +1826,7 @@ class SageMakerModelBackend(BaseBackend):
         self.model_package_groups: Dict[str, ModelPackageGroup] = {}
         self.model_packages: Dict[str, ModelPackage] = {}
         self.model_package_name_mapping: Dict[str, str] = {}
+        self.feature_groups: Dict[str, FeatureGroup] = {}
 
     @staticmethod
     def default_vpc_endpoint_service(
@@ -3275,8 +3334,14 @@ class SageMakerModelBackend(BaseBackend):
     ) -> ModelPackageGroup:
         model_package_group = self.model_package_groups.get(model_package_group_name)
         if model_package_group is None:
+            model_package_group_arn = arn_formatter(
+                region_name=self.region_name,
+                account_id=self.account_id,
+                _type="model-package-group",
+                _id=f"{model_package_group_name}",
+            )
             raise ValidationError(
-                f"Model package group {model_package_group_name} not found"
+                f"ModelPackageGroup {model_package_group_arn} does not exist."
             )
         return model_package_group
 
@@ -3464,6 +3529,55 @@ class SageMakerModelBackend(BaseBackend):
         self.model_packages[model_package.model_package_arn] = model_package
         return model_package.model_package_arn
 
+    def create_feature_group(
+        self,
+        feature_group_name: str,
+        record_identifier_feature_name: str,
+        event_time_feature_name: str,
+        feature_definitions: List[Dict[str, str]],
+        offline_store_config: Dict[str, Any],
+        role_arn: str,
+        tags: Any,
+    ) -> str:
+        feature_group_arn = arn_formatter(
+            region_name=self.region_name,
+            account_id=self.account_id,
+            _type="feature-group",
+            _id=f"{feature_group_name.lower()}",
+        )
+        if feature_group_arn in self.feature_groups:
+            raise ResourceInUseException(
+                message=f"An error occurred (ResourceInUse) when calling the CreateFeatureGroup operation: Resource Already Exists: FeatureGroup with name {feature_group_name} already exists. Choose a different name.\nInfo: Feature Group '{feature_group_name}' already exists."
+            )
+
+        feature_group = FeatureGroup(
+            feature_group_name=feature_group_name,
+            record_identifier_feature_name=record_identifier_feature_name,
+            event_time_feature_name=event_time_feature_name,
+            feature_definitions=feature_definitions,
+            offline_store_config=offline_store_config,
+            role_arn=role_arn,
+            region_name=self.region_name,
+            account_id=self.account_id,
+            tags=tags,
+        )
+        self.feature_groups[feature_group.feature_group_arn] = feature_group
+        return feature_group.feature_group_arn
+
+    def describe_feature_group(
+        self,
+        feature_group_name: str,
+    ) -> Dict[str, Any]:
+        feature_group_arn = arn_formatter(
+            region_name=self.region_name,
+            account_id=self.account_id,
+            _type="feature-group",
+            _id=f"{feature_group_name.lower()}",
+        )
+
+        feature_group = self.feature_groups[feature_group_arn]
+        return feature_group.describe()
+
 
 class FakeExperiment(BaseObject):
     def __init__(
diff --git a/moto/sagemaker/responses.py b/moto/sagemaker/responses.py
index f260130d1..fa63920b0 100644
--- a/moto/sagemaker/responses.py
+++ b/moto/sagemaker/responses.py
@@ -959,3 +959,23 @@ class SageMakerResponse(BaseResponse):
             tags=tags,
         )
         return json.dumps(dict(ModelPackageGroupArn=model_package_group_arn))
+
+    def create_feature_group(self) -> str:
+        feature_group_arn = self.sagemaker_backend.create_feature_group(
+            feature_group_name=self._get_param("FeatureGroupName"),
+            record_identifier_feature_name=self._get_param(
+                "RecordIdentifierFeatureName"
+            ),
+            event_time_feature_name=self._get_param("EventTimeFeatureName"),
+            feature_definitions=self._get_param("FeatureDefinitions"),
+            offline_store_config=self._get_param("OfflineStoreConfig"),
+            role_arn=self._get_param("RoleArn"),
+            tags=self._get_param("Tags"),
+        )
+        return json.dumps(dict(FeatureGroupArn=feature_group_arn))
+
+    def describe_feature_group(self) -> str:
+        resp = self.sagemaker_backend.describe_feature_group(
+            feature_group_name=self._get_param("FeatureGroupName"),
+        )
+        return json.dumps(resp)
diff --git a/moto/ssm/resources/regions.json b/moto/ssm/resources/regions.json
index 6a8aaf3d1..7b262e620 100644
--- a/moto/ssm/resources/regions.json
+++ b/moto/ssm/resources/regions.json
@@ -20166,6 +20166,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "appsync": {
+                "Value": "appsync",
+                "endpoint": {
+                  "Value": "appsync.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "arc-zonal-shift": {
                 "Value": "arc-zonal-shift",
                 "endpoint": {
@@ -43149,6 +43158,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "appsync": {
+                "Value": "appsync",
+                "endpoint": {
+                  "Value": "appsync.il-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "arc-zonal-shift": {
                 "Value": "arc-zonal-shift",
                 "endpoint": {
@@ -44935,6 +44953,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "identity-center": {
+                "Value": "identity-center",
+                "endpoint": {
+                  "Value": "sso.me-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "identitystore": {
                 "Value": "identitystore",
                 "endpoint": {
@@ -45472,6 +45499,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "sso-oidc": {
+                "Value": "sso-oidc",
+                "endpoint": {
+                  "Value": "oidc.me-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "stepfunctions": {
                 "Value": "stepfunctions",
                 "endpoint": {
diff --git a/moto/ssm/resources/services.json b/moto/ssm/resources/services.json
index f8047029a..b39e62979 100644
--- a/moto/ssm/resources/services.json
+++ b/moto/ssm/resources/services.json
@@ -4477,6 +4477,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ap-southeast-4": {
+                "Value": "ap-southeast-4",
+                "endpoint": {
+                  "Value": "appsync.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "ca-central-1": {
                 "Value": "ca-central-1",
                 "endpoint": {
@@ -4576,6 +4585,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "il-central-1": {
+                "Value": "il-central-1",
+                "endpoint": {
+                  "Value": "appsync.il-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "me-central-1": {
                 "Value": "me-central-1",
                 "endpoint": {
@@ -29724,6 +29742,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "me-central-1": {
+                "Value": "me-central-1",
+                "endpoint": {
+                  "Value": "sso.me-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "me-south-1": {
                 "Value": "me-south-1",
                 "endpoint": {
@@ -59405,6 +59432,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "me-central-1": {
+                "Value": "me-central-1",
+                "endpoint": {
+                  "Value": "oidc.me-central-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "me-south-1": {
                 "Value": "me-south-1",
                 "endpoint": {


Test patch:
diff --git a/.github/workflows/tests_terraform_examples.yml b/.github/workflows/tests_terraform_examples.yml
index b1a5f7054..12790048e 100644
--- a/.github/workflows/tests_terraform_examples.yml
+++ b/.github/workflows/tests_terraform_examples.yml
@@ -33,4 +33,9 @@ jobs:
         cd other_langs/terraform/${{ matrix.service }}
         terraform init
         terraform apply --auto-approve
+        echo "Verify nothing changes when ACM certificates are validated"
+        sleep 30
+        terraform plan -detailed-exitcode
+        sleep 30
+        terraform plan -detailed-exitcode
         terraform apply -destroy --auto-approve
diff --git a/tests/test_acm/test_acm.py b/tests/test_acm/test_acm.py
index d2943d801..c6704c5ed 100644
--- a/tests/test_acm/test_acm.py
+++ b/tests/test_acm/test_acm.py
@@ -1,5 +1,6 @@
 import os
 import uuid
+from time import sleep
 from unittest import SkipTest, mock
 
 import boto3
@@ -180,7 +181,6 @@ def test_describe_certificate():
     assert len(resp["Certificate"]["DomainValidationOptions"]) == 1
     validation_option = resp["Certificate"]["DomainValidationOptions"][0]
     assert validation_option["DomainName"] == SERVER_COMMON_NAME
-    assert "ValidationDomain" not in validation_option
 
 
 @mock_acm
@@ -388,7 +388,10 @@ def test_request_certificate():
 
 
 @mock_acm
+@mock.patch("moto.settings.ACM_VALIDATION_WAIT", 1)
 def test_request_certificate_with_optional_arguments():
+    if not settings.TEST_DECORATOR_MODE:
+        raise SkipTest("Can only change setting in DecoratorMode")
     client = boto3.client("acm", region_name="eu-central-1")
 
     token = str(uuid.uuid4())
@@ -406,12 +409,21 @@ def test_request_certificate_with_optional_arguments():
     arn_1 = resp["CertificateArn"]
 
     cert = client.describe_certificate(CertificateArn=arn_1)["Certificate"]
+    assert cert["Status"] == "PENDING_VALIDATION"
     assert len(cert["SubjectAlternativeNames"]) == 3
-    assert len(cert["DomainValidationOptions"]) == 3
-    assert {option["DomainName"] for option in cert["DomainValidationOptions"]} == set(
+    validation_options = cert["DomainValidationOptions"].copy()
+    assert len(validation_options) == 3
+    assert {option["DomainName"] for option in validation_options} == set(
         cert["SubjectAlternativeNames"]
     )
 
+    # Verify SAN's are still the same, even after the Certificate is validated
+    sleep(2)
+    for opt in validation_options:
+        opt["ValidationStatus"] = "ISSUED"
+    cert = client.describe_certificate(CertificateArn=arn_1)["Certificate"]
+    assert cert["DomainValidationOptions"] == validation_options
+
     resp = client.list_tags_for_certificate(CertificateArn=arn_1)
     tags = {item["Key"]: item.get("Value", "__NONE__") for item in resp["Tags"]}
     assert len(tags) == 2
diff --git a/tests/test_backup/__init__.py b/tests/test_backup/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_backup/test_backup.py b/tests/test_backup/test_backup.py
new file mode 100644
index 000000000..030bd9eb9
--- /dev/null
+++ b/tests/test_backup/test_backup.py
@@ -0,0 +1,359 @@
+"""Unit tests for backup-supported APIs."""
+import boto3
+import pytest
+from botocore.exceptions import ClientError
+
+from moto import mock_backup
+
+
+@mock_backup
+def test_create_backup_plan():
+    client = boto3.client("backup", region_name="eu-west-1")
+    response = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+    )
+    resp = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "foobar",
+                    "TargetBackupVaultName": response["BackupVaultName"],
+                },
+            ],
+        },
+    )
+    assert "BackupPlanId" in resp
+    assert "BackupPlanArn" in resp
+    assert "CreationDate" in resp
+    assert "VersionId" in resp
+
+
+@mock_backup
+def test_create_backup_plan_already_exists():
+    client = boto3.client("backup", region_name="eu-west-1")
+    backup_plan_name = "backup_plan_foobar"
+    rules = [
+        {
+            "RuleName": "foobar",
+            "TargetBackupVaultName": "backup-vault-foobar",
+        },
+    ]
+    client.create_backup_plan(
+        BackupPlan={"BackupPlanName": backup_plan_name, "Rules": rules}
+    )
+
+    with pytest.raises(ClientError) as exc:
+        client.create_backup_plan(
+            BackupPlan={"BackupPlanName": backup_plan_name, "Rules": rules}
+        )
+    err = exc.value.response["Error"]
+    assert err["Code"] == "AlreadyExistsException"
+
+
+@mock_backup
+def test_get_backup_plan():
+    client = boto3.client("backup", region_name="eu-west-1")
+    response = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+    )
+    plan = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "foobar",
+                    "TargetBackupVaultName": response["BackupVaultName"],
+                },
+            ],
+        },
+    )
+    resp = client.get_backup_plan(
+        BackupPlanId=plan["BackupPlanId"], VersionId=plan["VersionId"]
+    )
+    assert "BackupPlan" in resp
+
+
+@mock_backup
+def test_get_backup_plan_invalid_id():
+    client = boto3.client("backup", region_name="eu-west-1")
+
+    with pytest.raises(ClientError) as exc:
+        client.get_backup_plan(BackupPlanId="foobar")
+    err = exc.value.response["Error"]
+    assert err["Code"] == "ResourceNotFoundException"
+
+
+@mock_backup
+def test_get_backup_plan_invalid_version_id():
+    client = boto3.client("backup", region_name="eu-west-1")
+
+    plan = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "foobar",
+                    "TargetBackupVaultName": "Backup-vault-foobar",
+                },
+            ],
+        },
+    )
+    with pytest.raises(ClientError) as exc:
+        client.get_backup_plan(BackupPlanId=plan["BackupPlanId"], VersionId="foobar")
+    err = exc.value.response["Error"]
+    assert err["Code"] == "ResourceNotFoundException"
+
+
+@mock_backup
+def test_get_backup_plan_with_multiple_rules():
+    client = boto3.client("backup", region_name="eu-west-1")
+    plan = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "rule1",
+                    "TargetBackupVaultName": "backupvault-foobar",
+                    "ScheduleExpression": "cron(0 1 ? * * *)",
+                    "StartWindowMinutes": 60,
+                    "CompletionWindowMinutes": 120,
+                },
+                {
+                    "RuleName": "rule2",
+                    "TargetBackupVaultName": "backupvault-foobar",
+                },
+            ],
+        },
+    )
+    resp = client.get_backup_plan(BackupPlanId=plan["BackupPlanId"])
+    for rule in resp["BackupPlan"]["Rules"]:
+        assert "ScheduleExpression" in rule
+        assert "StartWindowMinutes" in rule
+        assert "CompletionWindowMinutes" in rule
+        assert "RuleId" in rule
+
+
+@mock_backup
+def test_delete_backup_plan():
+    client = boto3.client("backup", region_name="eu-west-1")
+    response = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+    )
+    plan = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "foobar",
+                    "TargetBackupVaultName": response["BackupVaultName"],
+                },
+            ],
+        },
+    )
+
+    resp = client.delete_backup_plan(BackupPlanId=plan["BackupPlanId"])
+    assert "BackupPlanId" in resp
+    assert "BackupPlanArn" in resp
+    assert "DeletionDate" in resp
+    assert "VersionId" in resp
+
+    resp = client.get_backup_plan(
+        BackupPlanId=plan["BackupPlanId"], VersionId=plan["VersionId"]
+    )
+    assert "DeletionDate" in resp
+
+
+@mock_backup
+def test_delete_backup_plan_invalid_id():
+    client = boto3.client("backup", region_name="eu-west-1")
+
+    with pytest.raises(ClientError) as exc:
+        client.delete_backup_plan(BackupPlanId="foobar")
+    err = exc.value.response["Error"]
+    assert err["Code"] == "ResourceNotFoundException"
+
+
+@mock_backup
+def test_list_backup_plans():
+    client = boto3.client("backup", region_name="eu-west-1")
+    for i in range(1, 3):
+        client.create_backup_plan(
+            BackupPlan={
+                "BackupPlanName": f"backup-plan-{i}",
+                "Rules": [
+                    {
+                        "RuleName": "foobar",
+                        "TargetBackupVaultName": "backupvault-foobar",
+                    },
+                ],
+            },
+        )
+    resp = client.list_backup_plans()
+    backup_plans = resp["BackupPlansList"]
+    assert backup_plans[0]["BackupPlanName"] == "backup-plan-1"
+    assert backup_plans[1]["BackupPlanName"] == "backup-plan-2"
+    assert len(backup_plans) == 2
+    assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
+
+
+@mock_backup
+def test_list_backup_plans_without_include_deleted():
+    client = boto3.client("backup", region_name="eu-west-1")
+
+    for i in range(1, 3):
+        client.create_backup_plan(
+            BackupPlan={
+                "BackupPlanName": f"backup-plan-{i}",
+                "Rules": [
+                    {
+                        "RuleName": "foobar",
+                        "TargetBackupVaultName": "backupvault-foobar",
+                    },
+                ],
+            },
+        )
+    resp = client.list_backup_plans()
+    client.delete_backup_plan(BackupPlanId=resp["BackupPlansList"][0]["BackupPlanId"])
+    resp_list = client.list_backup_plans()
+    backup_plans = resp_list["BackupPlansList"]
+    assert backup_plans[0]["BackupPlanName"] == "backup-plan-2"
+    assert len(backup_plans) == 1
+
+
+@mock_backup
+def test_list_backup_plans_with_include_deleted():
+    client = boto3.client("backup", region_name="eu-west-1")
+    for i in range(1, 3):
+        client.create_backup_plan(
+            BackupPlan={
+                "BackupPlanName": f"backup-plan-{i}",
+                "Rules": [
+                    {
+                        "RuleName": "foobar",
+                        "TargetBackupVaultName": "backupvault-foobar",
+                    },
+                ],
+            },
+        )
+    resp = client.list_backup_plans()
+    client.delete_backup_plan(BackupPlanId=resp["BackupPlansList"][0]["BackupPlanId"])
+    resp_list = client.list_backup_plans(IncludeDeleted=True)
+    backup_plans = resp_list["BackupPlansList"]
+    assert backup_plans[0]["BackupPlanName"] == "backup-plan-1"
+    assert backup_plans[1]["BackupPlanName"] == "backup-plan-2"
+    assert len(backup_plans) == 2
+
+
+@mock_backup
+def test_create_backup_vault():
+    client = boto3.client("backup", region_name="eu-west-1")
+    resp = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+        BackupVaultTags={
+            "foo": "bar",
+        },
+    )
+    assert "BackupVaultName" in resp
+    assert "BackupVaultArn" in resp
+    assert "CreationDate" in resp
+
+
+@mock_backup
+def test_create_backup_vault_already_exists():
+    client = boto3.client("backup", region_name="eu-west-1")
+    backup_vault_name = "backup_vault_foobar"
+    client.create_backup_vault(BackupVaultName=backup_vault_name)
+
+    with pytest.raises(ClientError) as exc:
+        client.create_backup_vault(BackupVaultName=backup_vault_name)
+    err = exc.value.response["Error"]
+    assert err["Code"] == "AlreadyExistsException"
+
+
+@mock_backup
+def test_list_backup_vaults():
+    client = boto3.client("backup", region_name="eu-west-1")
+    for i in range(1, 3):
+        client.create_backup_vault(
+            BackupVaultName=f"backup-vault-{i}",
+        )
+    resp = client.list_backup_vaults()
+    backup_plans = resp["BackupVaultList"]
+    assert backup_plans[0]["BackupVaultName"] == "backup-vault-1"
+    assert backup_plans[1]["BackupVaultName"] == "backup-vault-2"
+    assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
+
+
+@mock_backup
+def test_list_tags_vault():
+    client = boto3.client("backup", region_name="eu-west-1")
+    vault = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+        BackupVaultTags={
+            "key1": "value1",
+            "key2": "value2",
+        },
+    )
+    resp = client.list_tags(ResourceArn=vault["BackupVaultArn"])
+    assert resp["Tags"] == {"key1": "value1", "key2": "value2"}
+
+
+@mock_backup
+def test_list_tags_plan():
+    client = boto3.client("backup", region_name="eu-west-1")
+    response = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+    )
+    plan = client.create_backup_plan(
+        BackupPlan={
+            "BackupPlanName": "backupplan-foobar",
+            "Rules": [
+                {
+                    "RuleName": "foobar",
+                    "TargetBackupVaultName": response["BackupVaultName"],
+                },
+            ],
+        },
+        BackupPlanTags={
+            "key1": "value1",
+            "key2": "value2",
+        },
+    )
+    resp = client.list_tags(ResourceArn=plan["BackupPlanArn"])
+    assert resp["Tags"] == {"key1": "value1", "key2": "value2"}
+
+
+@mock_backup
+def test_tag_resource():
+    client = boto3.client("backup", region_name="eu-west-1")
+    vault = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+        BackupVaultTags={
+            "key1": "value1",
+        },
+    )
+    resource_arn = vault["BackupVaultArn"]
+    client.tag_resource(
+        ResourceArn=resource_arn, Tags={"key2": "value2", "key3": "value3"}
+    )
+    resp = client.list_tags(ResourceArn=resource_arn)
+    assert resp["Tags"] == {"key1": "value1", "key2": "value2", "key3": "value3"}
+
+
+@mock_backup
+def test_untag_resource():
+    client = boto3.client("backup", region_name="eu-west-1")
+    vault = client.create_backup_vault(
+        BackupVaultName="backupvault-foobar",
+        BackupVaultTags={
+            "key1": "value1",
+        },
+    )
+    resource_arn = vault["BackupVaultArn"]
+    client.tag_resource(
+        ResourceArn=resource_arn, Tags={"key2": "value2", "key3": "value3"}
+    )
+    resp = client.untag_resource(ResourceArn=resource_arn, TagKeyList=["key2"])
+    resp = client.list_tags(ResourceArn=resource_arn)
+    assert resp["Tags"] == {"key1": "value1", "key3": "value3"}
diff --git a/tests/test_core/test_utils.py b/tests/test_core/test_utils.py
index cc2e86749..7a8915b91 100644
--- a/tests/test_core/test_utils.py
+++ b/tests/test_core/test_utils.py
@@ -1,3 +1,5 @@
+import datetime
+
 import pytest
 from freezegun import freeze_time
 
@@ -5,6 +7,8 @@ from moto.core.utils import (
     camelcase_to_pascal,
     camelcase_to_underscores,
     pascal_to_camelcase,
+    rfc_1123_datetime,
+    str_to_rfc_1123_datetime,
     underscores_to_camelcase,
     unix_time,
 )
@@ -50,3 +54,10 @@ def test_camelcase_to_pascal(_input: str, expected: str) -> None:
 @freeze_time("2015-01-01 12:00:00")
 def test_unix_time() -> None:  # type: ignore[misc]
     assert unix_time() == 1420113600.0
+
+
+def test_rfc1123_dates() -> None:
+    with freeze_time("2012-03-04 05:00:05"):
+        x = rfc_1123_datetime(datetime.datetime.now())
+        assert x == "Sun, 04 Mar 2012 05:00:05 GMT"
+        assert str_to_rfc_1123_datetime(x) == datetime.datetime.now()
diff --git a/tests/test_elbv2/test_elbv2.py b/tests/test_elbv2/test_elbv2.py
index cd933cb5a..4da6b059c 100644
--- a/tests/test_elbv2/test_elbv2.py
+++ b/tests/test_elbv2/test_elbv2.py
@@ -1291,6 +1291,28 @@ def test_modify_load_balancer_attributes_routing_http_drop_invalid_header_fields
     assert routing_http_drop_invalid_header_fields_enabled["Value"] == "false"
 
 
+@mock_elbv2
+@mock_ec2
+def test_modify_load_balancer_attributes_connection_logs_s3():
+    response, _, _, _, _, client = create_load_balancer()
+    arn = response["LoadBalancers"][0]["LoadBalancerArn"]
+
+    client.modify_load_balancer_attributes(
+        LoadBalancerArn=arn,
+        Attributes=[
+            {"Key": "connection_logs.s3.enabled", "Value": "true"},
+            {"Key": "connection_logs.s3.bucket", "Value": "s3bucket"},
+            {"Key": "connection_logs.s3.prefix", "Value": "test_prefix"},
+        ],
+    )
+
+    response = client.describe_load_balancer_attributes(LoadBalancerArn=arn)
+    attrs = client.describe_load_balancer_attributes(LoadBalancerArn=arn)["Attributes"]
+    assert {"Key": "connection_logs.s3.enabled", "Value": "true"} in attrs
+    assert {"Key": "connection_logs.s3.bucket", "Value": "s3bucket"} in attrs
+    assert {"Key": "connection_logs.s3.prefix", "Value": "test_prefix"} in attrs
+
+
 @mock_elbv2
 @mock_ec2
 @mock_acm
diff --git a/tests/test_rds/test_rds.py b/tests/test_rds/test_rds.py
index 5b3d75ef0..fd2551550 100644
--- a/tests/test_rds/test_rds.py
+++ b/tests/test_rds/test_rds.py
@@ -2694,6 +2694,106 @@ def test_createdb_instance_engine_with_invalid_value():
     )
 
 
+@mock_rds
+def test_describe_db_snapshot_attributes_default():
+    client = boto3.client("rds", region_name="us-east-2")
+    client.create_db_instance(
+        DBInstanceIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DBName="staging-postgres",
+        DBInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2",
+        Port=1234,
+        DBSecurityGroups=["my_sg"],
+    )
+
+    client.create_db_snapshot(
+        DBInstanceIdentifier="db-primary-1", DBSnapshotIdentifier="snapshot-1"
+    ).get("DBSnapshot")
+
+    resp = client.describe_db_snapshot_attributes(DBSnapshotIdentifier="snapshot-1")
+
+    assert resp["DBSnapshotAttributesResult"]["DBSnapshotIdentifier"] == "snapshot-1"
+    assert resp["DBSnapshotAttributesResult"]["DBSnapshotAttributes"] == []
+
+
+@mock_rds
+def test_describe_db_snapshot_attributes():
+    client = boto3.client("rds", region_name="us-east-2")
+    client.create_db_instance(
+        DBInstanceIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DBName="staging-postgres",
+        DBInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2",
+        Port=1234,
+        DBSecurityGroups=["my_sg"],
+    )
+
+    client.create_db_snapshot(
+        DBInstanceIdentifier="db-primary-1", DBSnapshotIdentifier="snapshot-1"
+    ).get("DBSnapshot")
+
+    resp = client.modify_db_snapshot_attribute(
+        DBSnapshotIdentifier="snapshot-1",
+        AttributeName="restore",
+        ValuesToAdd=["Test", "Test2"],
+    )
+
+    resp = client.describe_db_snapshot_attributes(DBSnapshotIdentifier="snapshot-1")
+
+    assert (
+        resp["DBSnapshotAttributesResult"]["DBSnapshotAttributes"][0]["AttributeName"]
+        == "restore"
+    )
+    assert resp["DBSnapshotAttributesResult"]["DBSnapshotAttributes"][0][
+        "AttributeValues"
+    ] == ["Test", "Test2"]
+
+
+@mock_rds
+def test_modify_db_snapshot_attribute():
+    client = boto3.client("rds", region_name="us-east-2")
+    client.create_db_instance(
+        DBInstanceIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DBName="staging-postgres",
+        DBInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2",
+        Port=1234,
+        DBSecurityGroups=["my_sg"],
+    )
+
+    client.create_db_snapshot(
+        DBInstanceIdentifier="db-primary-1", DBSnapshotIdentifier="snapshot-1"
+    ).get("DBSnapshot")
+
+    resp = client.modify_db_snapshot_attribute(
+        DBSnapshotIdentifier="snapshot-1",
+        AttributeName="restore",
+        ValuesToAdd=["Test", "Test2"],
+    )
+    resp = client.modify_db_snapshot_attribute(
+        DBSnapshotIdentifier="snapshot-1",
+        AttributeName="restore",
+        ValuesToRemove=["Test"],
+    )
+
+    assert (
+        resp["DBSnapshotAttributesResult"]["DBSnapshotAttributes"][0]["AttributeName"]
+        == "restore"
+    )
+    assert resp["DBSnapshotAttributesResult"]["DBSnapshotAttributes"][0][
+        "AttributeValues"
+    ] == ["Test2"]
+
+
 def validation_helper(exc):
     err = exc.value.response["Error"]
     assert err["Code"] == "InvalidParameterValue"
diff --git a/tests/test_rds/test_rds_clusters.py b/tests/test_rds/test_rds_clusters.py
index d1f6a702c..14dde421d 100644
--- a/tests/test_rds/test_rds_clusters.py
+++ b/tests/test_rds/test_rds_clusters.py
@@ -215,6 +215,8 @@ def test_create_db_cluster__verify_default_properties():
     assert cluster["TagList"] == []
     assert "ClusterCreateTime" in cluster
     assert cluster["EarliestRestorableTime"] >= cluster["ClusterCreateTime"]
+    assert cluster["StorageEncrypted"] is False
+    assert cluster["GlobalWriteForwardingRequested"] is False
 
 
 @mock_rds
@@ -236,6 +238,8 @@ def test_create_db_cluster_additional_parameters():
         KmsKeyId="some:kms:arn",
         NetworkType="IPV4",
         DBSubnetGroupName="subnetgroupname",
+        StorageEncrypted=True,
+        EnableGlobalWriteForwarding=True,
         ScalingConfiguration={
             "MinCapacity": 5,
             "AutoPause": True,
@@ -260,6 +264,8 @@ def test_create_db_cluster_additional_parameters():
     assert cluster["KmsKeyId"] == "some:kms:arn"
     assert cluster["NetworkType"] == "IPV4"
     assert cluster["DBSubnetGroup"] == "subnetgroupname"
+    assert cluster["StorageEncrypted"] is True
+    assert cluster["GlobalWriteForwardingRequested"] is True
     assert cluster["ScalingConfigurationInfo"] == {"MinCapacity": 5, "AutoPause": True}
     assert cluster["ServerlessV2ScalingConfiguration"] == {
         "MaxCapacity": 4.0,
@@ -977,3 +983,120 @@ def test_createdb_instance_engine_mismatch_fail():
         == "The engine name requested for your DB instance (mysql) doesn't match "
         "the engine name of your DB cluster (aurora-postgresql)."
     )
+
+
+@mock_rds
+def test_describe_db_cluster_snapshot_attributes_default():
+    conn = boto3.client("rds", region_name="us-west-2")
+    conn.create_db_cluster(
+        DBClusterIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DatabaseName="staging-postgres",
+        DBClusterInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2000",
+        Port=1234,
+    )
+
+    conn.create_db_cluster_snapshot(
+        DBClusterIdentifier="db-primary-1", DBClusterSnapshotIdentifier="g-1"
+    ).get("DBClusterSnapshot")
+
+    resp = conn.describe_db_cluster_snapshot_attributes(
+        DBClusterSnapshotIdentifier="g-1"
+    )
+
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotIdentifier"]
+        == "g-1"
+    )
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotAttributes"] == []
+    )
+
+
+@mock_rds
+def test_describe_db_cluster_snapshot_attributes():
+    conn = boto3.client("rds", region_name="us-west-2")
+    conn.create_db_cluster(
+        DBClusterIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DatabaseName="staging-postgres",
+        DBClusterInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2000",
+        Port=1234,
+    )
+
+    conn.create_db_cluster_snapshot(
+        DBClusterIdentifier="db-primary-1", DBClusterSnapshotIdentifier="g-1"
+    ).get("DBClusterSnapshot")
+
+    conn.modify_db_cluster_snapshot_attribute(
+        DBClusterSnapshotIdentifier="g-1",
+        AttributeName="restore",
+        ValuesToAdd=["test", "test2"],
+    )
+
+    resp = conn.describe_db_cluster_snapshot_attributes(
+        DBClusterSnapshotIdentifier="g-1"
+    )
+
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotIdentifier"]
+        == "g-1"
+    )
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotAttributes"][0][
+            "AttributeName"
+        ]
+        == "restore"
+    )
+    assert resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotAttributes"][0][
+        "AttributeValues"
+    ] == ["test", "test2"]
+
+
+@mock_rds
+def test_modify_db_cluster_snapshot_attribute():
+    conn = boto3.client("rds", region_name="us-west-2")
+    conn.create_db_cluster(
+        DBClusterIdentifier="db-primary-1",
+        AllocatedStorage=10,
+        Engine="postgres",
+        DatabaseName="staging-postgres",
+        DBClusterInstanceClass="db.m1.small",
+        MasterUsername="root",
+        MasterUserPassword="hunter2000",
+        Port=1234,
+    )
+
+    conn.create_db_cluster_snapshot(
+        DBClusterIdentifier="db-primary-1", DBClusterSnapshotIdentifier="g-1"
+    ).get("DBClusterSnapshot")
+
+    resp = conn.modify_db_cluster_snapshot_attribute(
+        DBClusterSnapshotIdentifier="g-1",
+        AttributeName="restore",
+        ValuesToAdd=["test", "test2"],
+    )
+    resp = conn.modify_db_cluster_snapshot_attribute(
+        DBClusterSnapshotIdentifier="g-1",
+        AttributeName="restore",
+        ValuesToRemove=["test"],
+    )
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotIdentifier"]
+        == "g-1"
+    )
+    assert (
+        resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotAttributes"][0][
+            "AttributeName"
+        ]
+        == "restore"
+    )
+    assert resp["DBClusterSnapshotAttributesResult"]["DBClusterSnapshotAttributes"][0][
+        "AttributeValues"
+    ] == ["test2"]
diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
index 88fc908c1..079466116 100644
--- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
+++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py
@@ -5,6 +5,7 @@ from botocore.client import ClientError
 
 from moto import (
     mock_acm,
+    mock_backup,
     mock_cloudformation,
     mock_ec2,
     mock_ecs,
@@ -117,6 +118,37 @@ def test_get_resources_acm():
     )
 
 
+@mock_backup
+@mock_resourcegroupstaggingapi
+def test_get_resources_backup():
+    backup = boto3.client("backup", region_name="eu-central-1")
+
+    # Create two tagged Backup Vaults
+    for i in range(1, 3):
+        i_str = str(i)
+
+        backup.create_backup_vault(
+            BackupVaultName="backup-vault-tag-" + i_str,
+            BackupVaultTags={
+                "Test": i_str,
+            },
+        )
+
+    rtapi = boto3.client("resourcegroupstaggingapi", region_name="eu-central-1")
+
+    # Basic test
+    resp = rtapi.get_resources(ResourceTypeFilters=["backup"])
+    assert len(resp["ResourceTagMappingList"]) == 2
+
+    # Test tag filtering
+    resp = rtapi.get_resources(
+        ResourceTypeFilters=["backup"],
+        TagFilters=[{"Key": "Test", "Values": ["1"]}],
+    )
+    assert len(resp["ResourceTagMappingList"]) == 1
+    assert {"Key": "Test", "Value": "1"} in resp["ResourceTagMappingList"][0]["Tags"]
+
+
 @mock_ecs
 @mock_ec2
 @mock_resourcegroupstaggingapi
diff --git a/tests/test_route53/test_route53.py b/tests/test_route53/test_route53.py
index 5838cc5a1..149e34958 100644
--- a/tests/test_route53/test_route53.py
+++ b/tests/test_route53/test_route53.py
@@ -809,6 +809,7 @@ def test_change_resource_record_sets_crud_valid_with_special_xml_chars(
     assert cname_record_detail["ResourceRecords"] == [
         {"Value": "SomeInitialValue&NewValue"}
     ]
+    assert cname_record_detail.get("MultiValueAnswer") == multi_value_answer
 
     # Delete record.
     delete_payload = {
diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py
index f9deba6bc..6b6312355 100644
--- a/tests/test_s3/test_s3.py
+++ b/tests/test_s3/test_s3.py
@@ -2336,7 +2336,7 @@ def test_put_bucket_notification_errors():
     assert err.value.response["Error"]["Code"] == "InvalidArgument"
     assert (
         err.value.response["Error"]["Message"]
-        == "The event is not supported for notifications"
+        == "The event 'notarealeventname' is not supported for notifications. Supported events are as follows: ['s3:IntelligentTiering', 's3:LifecycleExpiration:*', 's3:LifecycleExpiration:Delete', 's3:LifecycleExpiration:DeleteMarkerCreated', 's3:LifecycleTransition', 's3:ObjectAcl:Put', 's3:ObjectCreated:*', 's3:ObjectCreated:CompleteMultipartUpload', 's3:ObjectCreated:Copy', 's3:ObjectCreated:Post', 's3:ObjectCreated:Put', 's3:ObjectRemoved:*', 's3:ObjectRemoved:Delete', 's3:ObjectRemoved:DeleteMarkerCreated', 's3:ObjectRestore:*', 's3:ObjectRestore:Completed', 's3:ObjectRestore:Delete', 's3:ObjectRestore:Post', 's3:ObjectTagging:*', 's3:ObjectTagging:Delete', 's3:ObjectTagging:Put', 's3:ReducedRedundancyLostObject', 's3:Replication:*', 's3:Replication:OperationFailedReplication', 's3:Replication:OperationMissedThreshold', 's3:Replication:OperationNotTracked', 's3:Replication:OperationReplicatedAfterThreshold']"
     )
 
 
diff --git a/tests/test_s3/test_s3_locales.py b/tests/test_s3/test_s3_locales.py
new file mode 100644
index 000000000..06aca5c36
--- /dev/null
+++ b/tests/test_s3/test_s3_locales.py
@@ -0,0 +1,30 @@
+from datetime import datetime
+from unittest import SkipTest
+
+import boto3
+from freezegun import freeze_time
+
+from moto import mock_s3, settings
+
+
+@mock_s3
+def test_rfc_returns_valid_date_for_every_possible_weekday_and_month():
+    if not settings.TEST_DECORATOR_MODE:
+        raise SkipTest("Freezing time only possible in DecoratorMode")
+    client = boto3.client("s3", region_name="us-east-1")
+    client.create_bucket(Bucket="bucket_")
+    for weekday in range(1, 8):
+        with freeze_time(f"2023-02-{weekday} 12:00:00"):
+            client.put_object(Bucket="bucket_", Key="test.txt", Body=b"test")
+            obj = client.get_object(Bucket="bucket_", Key="test.txt")
+            assert obj["LastModified"].replace(tzinfo=None) == datetime.now()
+            # If we get here, the LastModified date will have been successfully parsed
+            # Regardless of which weekday it is
+
+    for month in range(1, 13):
+        with freeze_time(f"2023-{month}-02 12:00:00"):
+            client.put_object(Bucket="bucket_", Key="test.txt", Body=b"test")
+            obj = client.get_object(Bucket="bucket_", Key="test.txt")
+            assert obj["LastModified"].replace(tzinfo=None) == datetime.now()
+            # If we get here, the LastModified date will have been successfully parsed
+            # Regardless of which month it is
diff --git a/tests/test_sagemaker/test_sagemaker_feature_groups.py b/tests/test_sagemaker/test_sagemaker_feature_groups.py
new file mode 100644
index 000000000..029b042c3
--- /dev/null
+++ b/tests/test_sagemaker/test_sagemaker_feature_groups.py
@@ -0,0 +1,117 @@
+"""Unit tests for sagemaker-supported APIs."""
+import re
+from datetime import datetime
+
+import boto3
+import pytest
+from botocore.exceptions import ClientError
+
+from moto import mock_sagemaker
+
+# See our Development Tips on writing tests for hints on how to write good tests:
+# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
+
+
+@mock_sagemaker
+def test_create_feature_group():
+    client = boto3.client("sagemaker", region_name="us-east-2")
+    resp = client.create_feature_group(
+        FeatureGroupName="some-feature-group-name",
+        RecordIdentifierFeatureName="some_record_identifier",
+        EventTimeFeatureName="EventTime",
+        FeatureDefinitions=[
+            {"FeatureName": "some_feature", "FeatureType": "String"},
+            {"FeatureName": "EventTime", "FeatureType": "Fractional"},
+            {"FeatureName": "some_record_identifier", "FeatureType": "String"},
+        ],
+        RoleArn="arn:aws:iam::123456789012:role/AWSFeatureStoreAccess",
+        OfflineStoreConfig={
+            "DisableGlueTableCreation": False,
+            "S3StorageConfig": {"S3Uri": "s3://mybucket"},
+        },
+    )
+
+    assert (
+        resp["FeatureGroupArn"]
+        == "arn:aws:sagemaker:us-east-2:123456789012:feature-group/some-feature-group-name"
+    )
+
+    with pytest.raises(ClientError) as raised_exception:
+        client.create_feature_group(
+            FeatureGroupName="some-feature-group-name",
+            RecordIdentifierFeatureName="some_record_identifier",
+            EventTimeFeatureName="EventTime",
+            FeatureDefinitions=[
+                {"FeatureName": "some_feature", "FeatureType": "String"},
+                {"FeatureName": "EventTime", "FeatureType": "Fractional"},
+                {"FeatureName": "some_record_identifier", "FeatureType": "String"},
+            ],
+            RoleArn="arn:aws:iam::123456789012:role/AWSFeatureStoreAccess",
+            OfflineStoreConfig={
+                "DisableGlueTableCreation": False,
+                "S3StorageConfig": {"S3Uri": "s3://mybucket"},
+            },
+        )
+
+    assert raised_exception.value.response["Error"]["Code"] == "ResourceInUse"
+    assert (
+        raised_exception.value.response["Error"]["Message"]
+        == "An error occurred (ResourceInUse) when calling the CreateFeatureGroup operation: Resource Already Exists: FeatureGroup with name some-feature-group-name already exists. Choose a different name.\nInfo: Feature Group 'some-feature-group-name' already exists."
+    )
+
+
+@mock_sagemaker
+def test_describe_feature_group():
+    client = boto3.client("sagemaker", region_name="us-east-2")
+    feature_group_name = "some-feature-group-name"
+    record_identifier_feature_name = "some_record_identifier"
+    event_time_feature_name = "EventTime"
+    role_arn = "arn:aws:iam::123456789012:role/AWSFeatureStoreAccess"
+    feature_definitions = [
+        {"FeatureName": "some_feature", "FeatureType": "String"},
+        {"FeatureName": event_time_feature_name, "FeatureType": "Fractional"},
+        {"FeatureName": record_identifier_feature_name, "FeatureType": "String"},
+    ]
+    client.create_feature_group(
+        FeatureGroupName=feature_group_name,
+        RecordIdentifierFeatureName=record_identifier_feature_name,
+        EventTimeFeatureName=event_time_feature_name,
+        FeatureDefinitions=feature_definitions,
+        RoleArn=role_arn,
+        OfflineStoreConfig={
+            "DisableGlueTableCreation": False,
+            "S3StorageConfig": {"S3Uri": "s3://mybucket/some-folder/some-subfolder"},
+        },
+    )
+    resp = client.describe_feature_group(FeatureGroupName=feature_group_name)
+
+    assert resp["FeatureGroupName"] == feature_group_name
+    assert (
+        resp["FeatureGroupArn"]
+        == "arn:aws:sagemaker:us-east-2:123456789012:feature-group/some-feature-group-name"
+    )
+    assert resp["RecordIdentifierFeatureName"] == record_identifier_feature_name
+    assert resp["EventTimeFeatureName"] == event_time_feature_name
+    assert resp["FeatureDefinitions"] == feature_definitions
+    assert resp["RoleArn"] == role_arn
+    assert re.match(
+        f"^{feature_group_name.replace('-', '_')}_[0-9]+$",
+        resp["OfflineStoreConfig"]["DataCatalogConfig"]["TableName"],
+    )
+    assert (
+        resp["OfflineStoreConfig"]["DataCatalogConfig"]["Catalog"] == "AwsDataCatalog"
+    )
+    assert (
+        resp["OfflineStoreConfig"]["DataCatalogConfig"]["Database"]
+        == "sagemaker_featurestore"
+    )
+    assert (
+        resp["OfflineStoreConfig"]["S3StorageConfig"]["S3Uri"]
+        == "s3://mybucket/some-folder/some-subfolder"
+    )
+    assert re.match(
+        f"^s3://mybucket/some-folder/some-subfolder/123456789012/us-east-2/offline-store/{feature_group_name}-[0-9]+/data$",
+        resp["OfflineStoreConfig"]["S3StorageConfig"]["ResolvedOutputS3Uri"],
+    )
+    assert isinstance(resp["CreationTime"], datetime)
+    assert resp["FeatureGroupStatus"] == "Created"
diff --git a/tests/test_sagemaker/test_sagemaker_model_package_groups.py b/tests/test_sagemaker/test_sagemaker_model_package_groups.py
index 15ba43a8a..d9d50a261 100644
--- a/tests/test_sagemaker/test_sagemaker_model_package_groups.py
+++ b/tests/test_sagemaker/test_sagemaker_model_package_groups.py
@@ -4,6 +4,8 @@ from datetime import datetime
 from unittest import SkipTest
 
 import boto3
+import pytest
+from botocore.exceptions import ClientError
 from dateutil.tz import tzutc  # type: ignore
 from freezegun import freeze_time
 
@@ -193,6 +195,21 @@ def test_describe_model_package_group():
     assert resp["CreationTime"] == datetime(2020, 1, 1, 0, 0, 0, tzinfo=tzutc())
 
 
+@mock_sagemaker
+def test_describe_model_package_group_not_exists():
+    if settings.TEST_SERVER_MODE:
+        raise SkipTest("Can't freeze time in ServerMode")
+    client = boto3.client("sagemaker", region_name="eu-west-1")
+
+    with pytest.raises(ClientError) as e:
+        client.describe_model_package_group(
+            ModelPackageGroupName="test-model-package-group"
+        )
+
+    assert e.value.response["Error"]["Code"] == "ValidationException"
+    assert "does not exist" in e.value.response["Error"]["Message"]
+
+
 @mock_sagemaker
 def test_list_tags_model_package_group():
     region_name = "eu-west-1"