CloudTrail improvements (#4875)
This commit is contained in:
parent
876c783a24
commit
efb19b92f0
@ -632,9 +632,9 @@
|
|||||||
|
|
||||||
## cloudtrail
|
## cloudtrail
|
||||||
<details>
|
<details>
|
||||||
<summary>27% implemented</summary>
|
<summary>55% implemented</summary>
|
||||||
|
|
||||||
- [ ] add_tags
|
- [X] add_tags
|
||||||
- [ ] cancel_query
|
- [ ] cancel_query
|
||||||
- [ ] create_event_data_store
|
- [ ] create_event_data_store
|
||||||
- [X] create_trail
|
- [X] create_trail
|
||||||
@ -643,26 +643,26 @@
|
|||||||
- [ ] describe_query
|
- [ ] describe_query
|
||||||
- [X] describe_trails
|
- [X] describe_trails
|
||||||
- [ ] get_event_data_store
|
- [ ] get_event_data_store
|
||||||
- [ ] get_event_selectors
|
- [X] get_event_selectors
|
||||||
- [ ] get_insight_selectors
|
- [X] get_insight_selectors
|
||||||
- [ ] get_query_results
|
- [ ] get_query_results
|
||||||
- [X] get_trail
|
- [X] get_trail
|
||||||
- [X] get_trail_status
|
- [X] get_trail_status
|
||||||
- [ ] list_event_data_stores
|
- [ ] list_event_data_stores
|
||||||
- [ ] list_public_keys
|
- [ ] list_public_keys
|
||||||
- [ ] list_queries
|
- [ ] list_queries
|
||||||
- [ ] list_tags
|
- [X] list_tags
|
||||||
- [X] list_trails
|
- [X] list_trails
|
||||||
- [ ] lookup_events
|
- [ ] lookup_events
|
||||||
- [ ] put_event_selectors
|
- [X] put_event_selectors
|
||||||
- [ ] put_insight_selectors
|
- [X] put_insight_selectors
|
||||||
- [ ] remove_tags
|
- [X] remove_tags
|
||||||
- [ ] restore_event_data_store
|
- [ ] restore_event_data_store
|
||||||
- [X] start_logging
|
- [X] start_logging
|
||||||
- [ ] start_query
|
- [ ] start_query
|
||||||
- [X] stop_logging
|
- [X] stop_logging
|
||||||
- [ ] update_event_data_store
|
- [ ] update_event_data_store
|
||||||
- [ ] update_trail
|
- [X] update_trail
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## cloudwatch
|
## cloudwatch
|
||||||
|
@ -27,7 +27,7 @@ cloudtrail
|
|||||||
|
|
||||||
|start-h3| Implemented features for this service |end-h3|
|
|start-h3| Implemented features for this service |end-h3|
|
||||||
|
|
||||||
- [ ] add_tags
|
- [X] add_tags
|
||||||
- [ ] cancel_query
|
- [ ] cancel_query
|
||||||
- [ ] create_event_data_store
|
- [ ] create_event_data_store
|
||||||
- [X] create_trail
|
- [X] create_trail
|
||||||
@ -36,24 +36,28 @@ cloudtrail
|
|||||||
- [ ] describe_query
|
- [ ] describe_query
|
||||||
- [X] describe_trails
|
- [X] describe_trails
|
||||||
- [ ] get_event_data_store
|
- [ ] get_event_data_store
|
||||||
- [ ] get_event_selectors
|
- [X] get_event_selectors
|
||||||
- [ ] get_insight_selectors
|
- [X] get_insight_selectors
|
||||||
- [ ] get_query_results
|
- [ ] get_query_results
|
||||||
- [X] get_trail
|
- [X] get_trail
|
||||||
- [X] get_trail_status
|
- [X] get_trail_status
|
||||||
- [ ] list_event_data_stores
|
- [ ] list_event_data_stores
|
||||||
- [ ] list_public_keys
|
- [ ] list_public_keys
|
||||||
- [ ] list_queries
|
- [ ] list_queries
|
||||||
- [ ] list_tags
|
- [X] list_tags
|
||||||
|
|
||||||
|
Pagination is not yet implemented
|
||||||
|
|
||||||
|
|
||||||
- [X] list_trails
|
- [X] list_trails
|
||||||
- [ ] lookup_events
|
- [ ] lookup_events
|
||||||
- [ ] put_event_selectors
|
- [X] put_event_selectors
|
||||||
- [ ] put_insight_selectors
|
- [X] put_insight_selectors
|
||||||
- [ ] remove_tags
|
- [X] remove_tags
|
||||||
- [ ] restore_event_data_store
|
- [ ] restore_event_data_store
|
||||||
- [X] start_logging
|
- [X] start_logging
|
||||||
- [ ] start_query
|
- [ ] start_query
|
||||||
- [X] stop_logging
|
- [X] stop_logging
|
||||||
- [ ] update_event_data_store
|
- [ ] update_event_data_store
|
||||||
- [ ] update_trail
|
- [X] update_trail
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import time
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel
|
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel
|
||||||
from moto.core.utils import iso_8601_datetime_without_milliseconds, BackendDict
|
from moto.core.utils import iso_8601_datetime_without_milliseconds, BackendDict
|
||||||
|
from moto.utilities.tagging_service import TaggingService
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
S3BucketDoesNotExistException,
|
S3BucketDoesNotExistException,
|
||||||
InsufficientSnsTopicPolicyException,
|
InsufficientSnsTopicPolicyException,
|
||||||
@ -78,9 +79,13 @@ class Trail(BaseModel):
|
|||||||
bucket_name,
|
bucket_name,
|
||||||
s3_key_prefix,
|
s3_key_prefix,
|
||||||
sns_topic_name,
|
sns_topic_name,
|
||||||
|
is_global,
|
||||||
is_multi_region,
|
is_multi_region,
|
||||||
log_validation,
|
log_validation,
|
||||||
is_org_trail,
|
is_org_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
):
|
):
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.trail_name = trail_name
|
self.trail_name = trail_name
|
||||||
@ -90,10 +95,17 @@ class Trail(BaseModel):
|
|||||||
self.is_multi_region = is_multi_region
|
self.is_multi_region = is_multi_region
|
||||||
self.log_validation = log_validation
|
self.log_validation = log_validation
|
||||||
self.is_org_trail = is_org_trail
|
self.is_org_trail = is_org_trail
|
||||||
|
self.include_global_service_events = is_global
|
||||||
|
self.cw_log_group_arn = cw_log_group_arn
|
||||||
|
self.cw_role_arn = cw_role_arn
|
||||||
|
self.kms_key_id = kms_key_id
|
||||||
self.check_name()
|
self.check_name()
|
||||||
self.check_bucket_exists()
|
self.check_bucket_exists()
|
||||||
self.check_topic_exists()
|
self.check_topic_exists()
|
||||||
self.status = TrailStatus()
|
self.status = TrailStatus()
|
||||||
|
self.event_selectors = list()
|
||||||
|
self.advanced_event_selectors = list()
|
||||||
|
self.insight_selectors = list()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def arn(self):
|
def arn(self):
|
||||||
@ -145,6 +157,56 @@ class Trail(BaseModel):
|
|||||||
def stop_logging(self):
|
def stop_logging(self):
|
||||||
self.status.stop_logging()
|
self.status.stop_logging()
|
||||||
|
|
||||||
|
def put_event_selectors(self, event_selectors, advanced_event_selectors):
|
||||||
|
if event_selectors:
|
||||||
|
self.event_selectors = event_selectors
|
||||||
|
elif advanced_event_selectors:
|
||||||
|
self.event_selectors = []
|
||||||
|
self.advanced_event_selectors = advanced_event_selectors
|
||||||
|
|
||||||
|
def get_event_selectors(self):
|
||||||
|
return self.event_selectors, self.advanced_event_selectors
|
||||||
|
|
||||||
|
def put_insight_selectors(self, insight_selectors):
|
||||||
|
self.insight_selectors.extend(insight_selectors)
|
||||||
|
|
||||||
|
def get_insight_selectors(self):
|
||||||
|
return self.insight_selectors
|
||||||
|
|
||||||
|
def update(
|
||||||
|
self,
|
||||||
|
s3_bucket_name,
|
||||||
|
s3_key_prefix,
|
||||||
|
sns_topic_name,
|
||||||
|
include_global_service_events,
|
||||||
|
is_multi_region_trail,
|
||||||
|
enable_log_file_validation,
|
||||||
|
is_organization_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
|
):
|
||||||
|
if s3_bucket_name is not None:
|
||||||
|
self.bucket_name = s3_bucket_name
|
||||||
|
if s3_key_prefix is not None:
|
||||||
|
self.s3_key_prefix = s3_key_prefix
|
||||||
|
if sns_topic_name is not None:
|
||||||
|
self.sns_topic_name = sns_topic_name
|
||||||
|
if include_global_service_events is not None:
|
||||||
|
self.include_global_service_events = include_global_service_events
|
||||||
|
if is_multi_region_trail is not None:
|
||||||
|
self.is_multi_region = is_multi_region_trail
|
||||||
|
if enable_log_file_validation is not None:
|
||||||
|
self.log_validation = enable_log_file_validation
|
||||||
|
if is_organization_trail is not None:
|
||||||
|
self.is_org_trail = is_organization_trail
|
||||||
|
if cw_log_group_arn is not None:
|
||||||
|
self.cw_log_group_arn = cw_log_group_arn
|
||||||
|
if cw_role_arn is not None:
|
||||||
|
self.cw_role_arn = cw_role_arn
|
||||||
|
if kms_key_id is not None:
|
||||||
|
self.kms_key_id = kms_key_id
|
||||||
|
|
||||||
def short(self):
|
def short(self):
|
||||||
return {
|
return {
|
||||||
"Name": self.trail_name,
|
"Name": self.trail_name,
|
||||||
@ -156,13 +218,16 @@ class Trail(BaseModel):
|
|||||||
desc = {
|
desc = {
|
||||||
"Name": self.trail_name,
|
"Name": self.trail_name,
|
||||||
"S3BucketName": self.bucket_name,
|
"S3BucketName": self.bucket_name,
|
||||||
"IncludeGlobalServiceEvents": True,
|
"IncludeGlobalServiceEvents": self.include_global_service_events,
|
||||||
"IsMultiRegionTrail": self.is_multi_region,
|
"IsMultiRegionTrail": self.is_multi_region,
|
||||||
"TrailARN": self.arn,
|
"TrailARN": self.arn,
|
||||||
"LogFileValidationEnabled": self.log_validation,
|
"LogFileValidationEnabled": self.log_validation,
|
||||||
"IsOrganizationTrail": self.is_org_trail,
|
"IsOrganizationTrail": self.is_org_trail,
|
||||||
"HasCustomEventSelectors": False,
|
"HasCustomEventSelectors": False,
|
||||||
"HasInsightSelectors": False,
|
"HasInsightSelectors": False,
|
||||||
|
"CloudWatchLogsLogGroupArn": self.cw_log_group_arn,
|
||||||
|
"CloudWatchLogsRoleArn": self.cw_role_arn,
|
||||||
|
"KmsKeyId": self.kms_key_id,
|
||||||
}
|
}
|
||||||
if self.s3_key_prefix is not None:
|
if self.s3_key_prefix is not None:
|
||||||
desc["S3KeyPrefix"] = self.s3_key_prefix
|
desc["S3KeyPrefix"] = self.s3_key_prefix
|
||||||
@ -180,6 +245,7 @@ class CloudTrailBackend(BaseBackend):
|
|||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.trails = dict()
|
self.trails = dict()
|
||||||
|
self.tagging_service = TaggingService(tag_name="TagsList")
|
||||||
|
|
||||||
def create_trail(
|
def create_trail(
|
||||||
self,
|
self,
|
||||||
@ -187,9 +253,14 @@ class CloudTrailBackend(BaseBackend):
|
|||||||
bucket_name,
|
bucket_name,
|
||||||
s3_key_prefix,
|
s3_key_prefix,
|
||||||
sns_topic_name,
|
sns_topic_name,
|
||||||
|
is_global,
|
||||||
is_multi_region,
|
is_multi_region,
|
||||||
log_validation,
|
log_validation,
|
||||||
is_org_trail,
|
is_org_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
|
tags_list,
|
||||||
):
|
):
|
||||||
trail = Trail(
|
trail = Trail(
|
||||||
self.region_name,
|
self.region_name,
|
||||||
@ -197,19 +268,27 @@ class CloudTrailBackend(BaseBackend):
|
|||||||
bucket_name,
|
bucket_name,
|
||||||
s3_key_prefix,
|
s3_key_prefix,
|
||||||
sns_topic_name,
|
sns_topic_name,
|
||||||
|
is_global,
|
||||||
is_multi_region,
|
is_multi_region,
|
||||||
log_validation,
|
log_validation,
|
||||||
is_org_trail,
|
is_org_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
)
|
)
|
||||||
self.trails[name] = trail
|
self.trails[name] = trail
|
||||||
|
self.tagging_service.tag_resource(trail.arn, tags_list)
|
||||||
return trail
|
return trail
|
||||||
|
|
||||||
def get_trail(self, name):
|
def get_trail(self, name_or_arn):
|
||||||
if len(name) < 3:
|
if len(name_or_arn) < 3:
|
||||||
raise TrailNameTooShort(actual_length=len(name))
|
raise TrailNameTooShort(actual_length=len(name_or_arn))
|
||||||
if name not in self.trails:
|
if name_or_arn in self.trails:
|
||||||
raise TrailNotFoundException(name)
|
return self.trails[name_or_arn]
|
||||||
return self.trails[name]
|
for trail in self.trails.values():
|
||||||
|
if trail.arn == name_or_arn:
|
||||||
|
return trail
|
||||||
|
raise TrailNotFoundException(name_or_arn)
|
||||||
|
|
||||||
def get_trail_status(self, name):
|
def get_trail_status(self, name):
|
||||||
if len(name) < 3:
|
if len(name) < 3:
|
||||||
@ -253,11 +332,79 @@ class CloudTrailBackend(BaseBackend):
|
|||||||
if name in self.trails:
|
if name in self.trails:
|
||||||
del self.trails[name]
|
del self.trails[name]
|
||||||
|
|
||||||
|
def update_trail(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
s3_bucket_name,
|
||||||
|
s3_key_prefix,
|
||||||
|
sns_topic_name,
|
||||||
|
include_global_service_events,
|
||||||
|
is_multi_region_trail,
|
||||||
|
enable_log_file_validation,
|
||||||
|
is_organization_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
|
):
|
||||||
|
trail = self.get_trail(name_or_arn=name)
|
||||||
|
trail.update(
|
||||||
|
s3_bucket_name=s3_bucket_name,
|
||||||
|
s3_key_prefix=s3_key_prefix,
|
||||||
|
sns_topic_name=sns_topic_name,
|
||||||
|
include_global_service_events=include_global_service_events,
|
||||||
|
is_multi_region_trail=is_multi_region_trail,
|
||||||
|
enable_log_file_validation=enable_log_file_validation,
|
||||||
|
is_organization_trail=is_organization_trail,
|
||||||
|
cw_log_group_arn=cw_log_group_arn,
|
||||||
|
cw_role_arn=cw_role_arn,
|
||||||
|
kms_key_id=kms_key_id,
|
||||||
|
)
|
||||||
|
return trail
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Re-initialize all attributes for this instance."""
|
"""Re-initialize all attributes for this instance."""
|
||||||
region_name = self.region_name
|
region_name = self.region_name
|
||||||
self.__dict__ = {}
|
self.__dict__ = {}
|
||||||
self.__init__(region_name)
|
self.__init__(region_name)
|
||||||
|
|
||||||
|
def put_event_selectors(
|
||||||
|
self, trail_name, event_selectors, advanced_event_selectors
|
||||||
|
):
|
||||||
|
trail = self.get_trail(trail_name)
|
||||||
|
trail.put_event_selectors(event_selectors, advanced_event_selectors)
|
||||||
|
trail_arn = trail.arn
|
||||||
|
return trail_arn, event_selectors, advanced_event_selectors
|
||||||
|
|
||||||
|
def get_event_selectors(self, trail_name):
|
||||||
|
trail = self.get_trail(trail_name)
|
||||||
|
event_selectors, advanced_event_selectors = trail.get_event_selectors()
|
||||||
|
return trail.arn, event_selectors, advanced_event_selectors
|
||||||
|
|
||||||
|
def add_tags(self, resource_id, tags_list):
|
||||||
|
self.tagging_service.tag_resource(resource_id, tags_list)
|
||||||
|
|
||||||
|
def remove_tags(self, resource_id, tags_list):
|
||||||
|
self.tagging_service.untag_resource_using_tags(resource_id, tags_list)
|
||||||
|
|
||||||
|
def list_tags(self, resource_id_list):
|
||||||
|
"""
|
||||||
|
Pagination is not yet implemented
|
||||||
|
"""
|
||||||
|
resp = [{"ResourceId": r_id} for r_id in resource_id_list]
|
||||||
|
for item in resp:
|
||||||
|
item["TagsList"] = self.tagging_service.list_tags_for_resource(
|
||||||
|
item["ResourceId"]
|
||||||
|
)["TagsList"]
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def put_insight_selectors(self, trail_name, insight_selectors):
|
||||||
|
trail = self.get_trail(trail_name)
|
||||||
|
trail.put_insight_selectors(insight_selectors)
|
||||||
|
return trail.arn, insight_selectors
|
||||||
|
|
||||||
|
def get_insight_selectors(self, trail_name):
|
||||||
|
trail = self.get_trail(trail_name)
|
||||||
|
return trail.arn, trail.get_insight_selectors()
|
||||||
|
|
||||||
|
|
||||||
cloudtrail_backends = BackendDict(CloudTrailBackend, "cloudtrail")
|
cloudtrail_backends = BackendDict(CloudTrailBackend, "cloudtrail")
|
||||||
|
@ -17,7 +17,7 @@ class CloudTrailResponse(BaseResponse):
|
|||||||
def create_trail(self):
|
def create_trail(self):
|
||||||
name = self._get_param("Name")
|
name = self._get_param("Name")
|
||||||
bucket_name = self._get_param("S3BucketName")
|
bucket_name = self._get_param("S3BucketName")
|
||||||
is_global = self._get_bool_param("IncludeGlobalServiceEvents")
|
is_global = self._get_bool_param("IncludeGlobalServiceEvents", True)
|
||||||
is_multi_region = self._get_bool_param("IsMultiRegionTrail", False)
|
is_multi_region = self._get_bool_param("IsMultiRegionTrail", False)
|
||||||
if not is_global and is_multi_region:
|
if not is_global and is_multi_region:
|
||||||
raise InvalidParameterCombinationException(
|
raise InvalidParameterCombinationException(
|
||||||
@ -27,14 +27,23 @@ class CloudTrailResponse(BaseResponse):
|
|||||||
sns_topic_name = self._get_param("SnsTopicName")
|
sns_topic_name = self._get_param("SnsTopicName")
|
||||||
log_validation = self._get_bool_param("EnableLogFileValidation", False)
|
log_validation = self._get_bool_param("EnableLogFileValidation", False)
|
||||||
is_org_trail = self._get_bool_param("IsOrganizationTrail", False)
|
is_org_trail = self._get_bool_param("IsOrganizationTrail", False)
|
||||||
|
cw_log_group_arn = self._get_param("CloudWatchLogsLogGroupArn")
|
||||||
|
cw_role_arn = self._get_param("CloudWatchLogsRoleArn")
|
||||||
|
kms_key_id = self._get_param("KmsKeyId")
|
||||||
|
tags_list = self._get_param("TagsList", [])
|
||||||
trail = self.cloudtrail_backend.create_trail(
|
trail = self.cloudtrail_backend.create_trail(
|
||||||
name,
|
name,
|
||||||
bucket_name,
|
bucket_name,
|
||||||
s3_key_prefix,
|
s3_key_prefix,
|
||||||
sns_topic_name,
|
sns_topic_name,
|
||||||
|
is_global,
|
||||||
is_multi_region,
|
is_multi_region,
|
||||||
log_validation,
|
log_validation,
|
||||||
is_org_trail,
|
is_org_trail,
|
||||||
|
cw_log_group_arn,
|
||||||
|
cw_role_arn,
|
||||||
|
kms_key_id,
|
||||||
|
tags_list,
|
||||||
)
|
)
|
||||||
return json.dumps(trail.description())
|
return json.dumps(trail.description())
|
||||||
|
|
||||||
@ -73,3 +82,111 @@ class CloudTrailResponse(BaseResponse):
|
|||||||
name = self._get_param("Name")
|
name = self._get_param("Name")
|
||||||
self.cloudtrail_backend.delete_trail(name)
|
self.cloudtrail_backend.delete_trail(name)
|
||||||
return json.dumps({})
|
return json.dumps({})
|
||||||
|
|
||||||
|
def update_trail(self):
|
||||||
|
name = self._get_param("Name")
|
||||||
|
s3_bucket_name = self._get_param("S3BucketName")
|
||||||
|
s3_key_prefix = self._get_param("S3KeyPrefix")
|
||||||
|
sns_topic_name = self._get_param("SnsTopicName")
|
||||||
|
include_global_service_events = self._get_param("IncludeGlobalServiceEvents")
|
||||||
|
is_multi_region_trail = self._get_param("IsMultiRegionTrail")
|
||||||
|
enable_log_file_validation = self._get_param("EnableLogFileValidation")
|
||||||
|
is_organization_trail = self._get_param("IsOrganizationTrail")
|
||||||
|
cw_log_group_arn = self._get_param("CloudWatchLogsLogGroupArn")
|
||||||
|
cw_role_arn = self._get_param("CloudWatchLogsRoleArn")
|
||||||
|
kms_key_id = self._get_param("KmsKeyId")
|
||||||
|
trail = self.cloudtrail_backend.update_trail(
|
||||||
|
name=name,
|
||||||
|
s3_bucket_name=s3_bucket_name,
|
||||||
|
s3_key_prefix=s3_key_prefix,
|
||||||
|
sns_topic_name=sns_topic_name,
|
||||||
|
include_global_service_events=include_global_service_events,
|
||||||
|
is_multi_region_trail=is_multi_region_trail,
|
||||||
|
enable_log_file_validation=enable_log_file_validation,
|
||||||
|
is_organization_trail=is_organization_trail,
|
||||||
|
cw_log_group_arn=cw_log_group_arn,
|
||||||
|
cw_role_arn=cw_role_arn,
|
||||||
|
kms_key_id=kms_key_id,
|
||||||
|
)
|
||||||
|
return json.dumps(trail.description())
|
||||||
|
|
||||||
|
def put_event_selectors(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
trail_name = params.get("TrailName")
|
||||||
|
event_selectors = params.get("EventSelectors")
|
||||||
|
advanced_event_selectors = params.get("AdvancedEventSelectors")
|
||||||
|
(
|
||||||
|
trail_arn,
|
||||||
|
event_selectors,
|
||||||
|
advanced_event_selectors,
|
||||||
|
) = self.cloudtrail_backend.put_event_selectors(
|
||||||
|
trail_name=trail_name,
|
||||||
|
event_selectors=event_selectors,
|
||||||
|
advanced_event_selectors=advanced_event_selectors,
|
||||||
|
)
|
||||||
|
return json.dumps(
|
||||||
|
dict(
|
||||||
|
TrailARN=trail_arn,
|
||||||
|
EventSelectors=event_selectors,
|
||||||
|
AdvancedEventSelectors=advanced_event_selectors,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_event_selectors(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
trail_name = params.get("TrailName")
|
||||||
|
(
|
||||||
|
trail_arn,
|
||||||
|
event_selectors,
|
||||||
|
advanced_event_selectors,
|
||||||
|
) = self.cloudtrail_backend.get_event_selectors(trail_name=trail_name,)
|
||||||
|
return json.dumps(
|
||||||
|
dict(
|
||||||
|
TrailARN=trail_arn,
|
||||||
|
EventSelectors=event_selectors,
|
||||||
|
AdvancedEventSelectors=advanced_event_selectors,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_tags(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
resource_id = params.get("ResourceId")
|
||||||
|
tags_list = params.get("TagsList")
|
||||||
|
self.cloudtrail_backend.add_tags(
|
||||||
|
resource_id=resource_id, tags_list=tags_list,
|
||||||
|
)
|
||||||
|
return json.dumps(dict())
|
||||||
|
|
||||||
|
def remove_tags(self):
|
||||||
|
resource_id = self._get_param("ResourceId")
|
||||||
|
tags_list = self._get_param("TagsList")
|
||||||
|
self.cloudtrail_backend.remove_tags(
|
||||||
|
resource_id=resource_id, tags_list=tags_list,
|
||||||
|
)
|
||||||
|
return json.dumps(dict())
|
||||||
|
|
||||||
|
def list_tags(self):
|
||||||
|
params = json.loads(self.body)
|
||||||
|
resource_id_list = params.get("ResourceIdList")
|
||||||
|
resource_tag_list = self.cloudtrail_backend.list_tags(
|
||||||
|
resource_id_list=resource_id_list,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(ResourceTagList=resource_tag_list))
|
||||||
|
|
||||||
|
def put_insight_selectors(self):
|
||||||
|
trail_name = self._get_param("TrailName")
|
||||||
|
insight_selectors = self._get_param("InsightSelectors")
|
||||||
|
trail_arn, insight_selectors = self.cloudtrail_backend.put_insight_selectors(
|
||||||
|
trail_name=trail_name, insight_selectors=insight_selectors,
|
||||||
|
)
|
||||||
|
return json.dumps(dict(TrailARN=trail_arn, InsightSelectors=insight_selectors))
|
||||||
|
|
||||||
|
def get_insight_selectors(self):
|
||||||
|
trail_name = self._get_param("TrailName")
|
||||||
|
trail_arn, insight_selectors = self.cloudtrail_backend.get_insight_selectors(
|
||||||
|
trail_name=trail_name,
|
||||||
|
)
|
||||||
|
resp = {"TrailARN": trail_arn}
|
||||||
|
if insight_selectors:
|
||||||
|
resp["InsightSelectors"] = insight_selectors
|
||||||
|
return json.dumps(resp)
|
||||||
|
@ -30,7 +30,9 @@ class FakeOrganization(BaseModel):
|
|||||||
self.master_account_id = utils.MASTER_ACCOUNT_ID
|
self.master_account_id = utils.MASTER_ACCOUNT_ID
|
||||||
self.master_account_email = utils.MASTER_ACCOUNT_EMAIL
|
self.master_account_email = utils.MASTER_ACCOUNT_EMAIL
|
||||||
self.available_policy_types = [
|
self.available_policy_types = [
|
||||||
# TODO: verify if this should be enabled by default (breaks TF tests for CloudTrail)
|
# This policy is available, but not applied
|
||||||
|
# User should use enable_policy_type/disable_policy_type to do anything else
|
||||||
|
# This field is deprecated in AWS, but we'll return it for old time's sake
|
||||||
{"Type": "SERVICE_CONTROL_POLICY", "Status": "ENABLED"}
|
{"Type": "SERVICE_CONTROL_POLICY", "Status": "ENABLED"}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -140,10 +142,7 @@ class FakeRoot(FakeOrganizationalUnit):
|
|||||||
self.type = "ROOT"
|
self.type = "ROOT"
|
||||||
self.id = organization.root_id
|
self.id = organization.root_id
|
||||||
self.name = "Root"
|
self.name = "Root"
|
||||||
self.policy_types = [
|
self.policy_types = []
|
||||||
# TODO: verify if this should be enabled by default (breaks TF tests for CloudTrail)
|
|
||||||
{"Type": "SERVICE_CONTROL_POLICY", "Status": "ENABLED"}
|
|
||||||
]
|
|
||||||
self._arn_format = utils.ROOT_ARN_FORMAT
|
self._arn_format = utils.ROOT_ARN_FORMAT
|
||||||
self.attached_policies = []
|
self.attached_policies = []
|
||||||
self.tags = {tag["Key"]: tag["Value"] for tag in kwargs.get("Tags", [])}
|
self.tags = {tag["Key"]: tag["Value"] for tag in kwargs.get("Tags", [])}
|
||||||
|
@ -11,6 +11,7 @@ TestAccAWSAppsyncGraphqlApi
|
|||||||
TestAccAWSAvailabilityZones
|
TestAccAWSAvailabilityZones
|
||||||
TestAccAWSBillingServiceAccount
|
TestAccAWSBillingServiceAccount
|
||||||
TestAccAWSCallerIdentity
|
TestAccAWSCallerIdentity
|
||||||
|
TestAccAWSCloudTrail
|
||||||
TestAccAWSCloudTrailServiceAccount
|
TestAccAWSCloudTrailServiceAccount
|
||||||
TestAccAWSCloudWatchDashboard
|
TestAccAWSCloudWatchDashboard
|
||||||
TestAccAWSCloudWatchEventApiDestination
|
TestAccAWSCloudWatchEventApiDestination
|
||||||
|
@ -147,7 +147,9 @@ def test_create_trail_advanced():
|
|||||||
)
|
)
|
||||||
resp.should.have.key("LogFileValidationEnabled").equal(True)
|
resp.should.have.key("LogFileValidationEnabled").equal(True)
|
||||||
resp.should.have.key("IsOrganizationTrail").equal(True)
|
resp.should.have.key("IsOrganizationTrail").equal(True)
|
||||||
return resp
|
resp.should.have.key("CloudWatchLogsLogGroupArn").equals("cwllga")
|
||||||
|
resp.should.have.key("CloudWatchLogsRoleArn").equals("cwlra")
|
||||||
|
resp.should.have.key("KmsKeyId").equals("kki")
|
||||||
|
|
||||||
|
|
||||||
def create_trail_advanced(region_name="us-east-1"):
|
def create_trail_advanced(region_name="us-east-1"):
|
||||||
@ -168,6 +170,9 @@ def create_trail_advanced(region_name="us-east-1"):
|
|||||||
IsMultiRegionTrail=True,
|
IsMultiRegionTrail=True,
|
||||||
EnableLogFileValidation=True,
|
EnableLogFileValidation=True,
|
||||||
IsOrganizationTrail=True,
|
IsOrganizationTrail=True,
|
||||||
|
CloudWatchLogsLogGroupArn="cwllga",
|
||||||
|
CloudWatchLogsRoleArn="cwlra",
|
||||||
|
KmsKeyId="kki",
|
||||||
TagsList=[{"Key": "tk", "Value": "tv"}, {"Key": "tk2", "Value": "tv2"}],
|
TagsList=[{"Key": "tk", "Value": "tv"}, {"Key": "tk2", "Value": "tv2"}],
|
||||||
)
|
)
|
||||||
return bucket_name, resp, sns_topic_name, trail_name
|
return bucket_name, resp, sns_topic_name, trail_name
|
||||||
@ -461,3 +466,72 @@ def test_delete_trail():
|
|||||||
|
|
||||||
trails = client.describe_trails()["trailList"]
|
trails = client.describe_trails()["trailList"]
|
||||||
trails.should.have.length_of(0)
|
trails.should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_update_trail_simple():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-2")
|
||||||
|
bucket_name, trail, name = create_trail_simple(region_name="ap-southeast-2")
|
||||||
|
resp = client.update_trail(Name=name)
|
||||||
|
resp.should.have.key("Name").equal(name)
|
||||||
|
resp.should.have.key("S3BucketName").equal(bucket_name)
|
||||||
|
resp.should.have.key("IncludeGlobalServiceEvents").equal(True)
|
||||||
|
resp.should.have.key("IsMultiRegionTrail").equal(False)
|
||||||
|
resp.should.have.key("LogFileValidationEnabled").equal(False)
|
||||||
|
resp.should.have.key("IsOrganizationTrail").equal(False)
|
||||||
|
resp.shouldnt.have.key("S3KeyPrefix")
|
||||||
|
resp.shouldnt.have.key("SnsTopicName")
|
||||||
|
resp.shouldnt.have.key("SnsTopicARN")
|
||||||
|
|
||||||
|
trail = client.get_trail(Name=name)["Trail"]
|
||||||
|
trail.should.have.key("Name").equal(name)
|
||||||
|
trail.should.have.key("S3BucketName").equal(bucket_name)
|
||||||
|
trail.should.have.key("IncludeGlobalServiceEvents").equal(True)
|
||||||
|
trail.should.have.key("IsMultiRegionTrail").equal(False)
|
||||||
|
trail.should.have.key("LogFileValidationEnabled").equal(False)
|
||||||
|
trail.should.have.key("IsOrganizationTrail").equal(False)
|
||||||
|
trail.shouldnt.have.key("S3KeyPrefix")
|
||||||
|
trail.shouldnt.have.key("SnsTopicName")
|
||||||
|
trail.shouldnt.have.key("SnsTopicARN")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_update_trail_full():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-1")
|
||||||
|
_, trail, name = create_trail_simple(region_name="ap-southeast-1")
|
||||||
|
resp = client.update_trail(
|
||||||
|
Name=name,
|
||||||
|
S3BucketName="updated_bucket",
|
||||||
|
S3KeyPrefix="s3kp",
|
||||||
|
SnsTopicName="stn",
|
||||||
|
IncludeGlobalServiceEvents=False,
|
||||||
|
IsMultiRegionTrail=True,
|
||||||
|
EnableLogFileValidation=True,
|
||||||
|
CloudWatchLogsLogGroupArn="cwllga",
|
||||||
|
CloudWatchLogsRoleArn="cwlra",
|
||||||
|
KmsKeyId="kki",
|
||||||
|
IsOrganizationTrail=True,
|
||||||
|
)
|
||||||
|
resp.should.have.key("Name").equal(name)
|
||||||
|
resp.should.have.key("S3BucketName").equal("updated_bucket")
|
||||||
|
resp.should.have.key("S3KeyPrefix").equals("s3kp")
|
||||||
|
resp.should.have.key("SnsTopicName").equals("stn")
|
||||||
|
resp.should.have.key("IncludeGlobalServiceEvents").equal(False)
|
||||||
|
resp.should.have.key("IsMultiRegionTrail").equal(True)
|
||||||
|
resp.should.have.key("LogFileValidationEnabled").equal(True)
|
||||||
|
resp.should.have.key("IsOrganizationTrail").equal(True)
|
||||||
|
|
||||||
|
trail = client.get_trail(Name=name)["Trail"]
|
||||||
|
trail.should.have.key("Name").equal(name)
|
||||||
|
trail.should.have.key("S3BucketName").equal("updated_bucket")
|
||||||
|
trail.should.have.key("S3KeyPrefix").equals("s3kp")
|
||||||
|
trail.should.have.key("SnsTopicName").equals("stn")
|
||||||
|
trail.should.have.key("IncludeGlobalServiceEvents").equal(False)
|
||||||
|
trail.should.have.key("IsMultiRegionTrail").equal(True)
|
||||||
|
trail.should.have.key("LogFileValidationEnabled").equal(True)
|
||||||
|
trail.should.have.key("IsOrganizationTrail").equal(True)
|
||||||
|
trail.should.have.key("CloudWatchLogsLogGroupArn").equals("cwllga")
|
||||||
|
trail.should.have.key("CloudWatchLogsRoleArn").equals("cwlra")
|
||||||
|
trail.should.have.key("KmsKeyId").equals("kki")
|
||||||
|
208
tests/test_cloudtrail/test_cloudtrail_eventselectors.py
Normal file
208
tests/test_cloudtrail/test_cloudtrail_eventselectors.py
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
import boto3
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from moto import mock_cloudtrail, mock_s3
|
||||||
|
from moto.core import ACCOUNT_ID
|
||||||
|
|
||||||
|
from .test_cloudtrail import create_trail_simple
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_put_event_selectors():
|
||||||
|
client = boto3.client("cloudtrail", region_name="eu-west-1")
|
||||||
|
_, _, trail_name = create_trail_simple(region_name="eu-west-1")
|
||||||
|
|
||||||
|
resp = client.put_event_selectors(
|
||||||
|
TrailName=trail_name,
|
||||||
|
EventSelectors=[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": True,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
resp.should.have.key("EventSelectors").equals(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": True,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
resp.shouldnt.have.key("AdvancedEventSelectors")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_put_event_selectors_advanced():
|
||||||
|
client = boto3.client("cloudtrail", region_name="eu-west-1")
|
||||||
|
_, _, trail_name = create_trail_simple(region_name="eu-west-1")
|
||||||
|
|
||||||
|
resp = client.put_event_selectors(
|
||||||
|
TrailName=trail_name,
|
||||||
|
EventSelectors=[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": True,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
AdvancedEventSelectors=[
|
||||||
|
{"Name": "aes1", "FieldSelectors": [{"Field": "f", "Equals": ["fs1"]}]}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
resp.should.have.key("EventSelectors").equals(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": True,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
resp.should.have.key("AdvancedEventSelectors").equals(
|
||||||
|
[{"Name": "aes1", "FieldSelectors": [{"Field": "f", "Equals": ["fs1"]}]}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_get_event_selectors_empty():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-1")
|
||||||
|
_, _, trail_name = create_trail_simple(region_name="ap-southeast-1")
|
||||||
|
|
||||||
|
resp = client.get_event_selectors(TrailName=trail_name)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN").equals(
|
||||||
|
f"arn:aws:cloudtrail:ap-southeast-1:{ACCOUNT_ID}:trail/{trail_name}"
|
||||||
|
)
|
||||||
|
resp.should.have.key("EventSelectors").equals([])
|
||||||
|
resp.should.have.key("AdvancedEventSelectors").equals([])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_get_event_selectors():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-2")
|
||||||
|
_, _, trail_name = create_trail_simple(region_name="ap-southeast-2")
|
||||||
|
|
||||||
|
client.put_event_selectors(
|
||||||
|
TrailName=trail_name,
|
||||||
|
EventSelectors=[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": False,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.get_event_selectors(TrailName=trail_name)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN").equals(
|
||||||
|
f"arn:aws:cloudtrail:ap-southeast-2:{ACCOUNT_ID}:trail/{trail_name}"
|
||||||
|
)
|
||||||
|
resp.should.have.key("EventSelectors").equals(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": False,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_get_event_selectors_multiple():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-1")
|
||||||
|
_, _, trail_name = create_trail_simple(region_name="ap-southeast-1")
|
||||||
|
|
||||||
|
client.put_event_selectors(
|
||||||
|
TrailName=trail_name,
|
||||||
|
EventSelectors=[
|
||||||
|
{
|
||||||
|
"ReadWriteType": "All",
|
||||||
|
"IncludeManagementEvents": False,
|
||||||
|
"DataResources": [
|
||||||
|
{"Type": "AWS::S3::Object", "Values": ["arn:aws:s3:::*/*"]}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
client.put_event_selectors(
|
||||||
|
TrailName=trail_name,
|
||||||
|
AdvancedEventSelectors=[
|
||||||
|
{"Name": "aes1", "FieldSelectors": [{"Field": "f", "Equals": ["fs1"]}]}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.get_event_selectors(TrailName=trail_name)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
# Setting advanced selectors cancels any existing event selectors
|
||||||
|
resp.should.have.key("EventSelectors").equals([])
|
||||||
|
resp.should.have.key("AdvancedEventSelectors").length_of(1)
|
||||||
|
resp.should.have.key("AdvancedEventSelectors").equals(
|
||||||
|
[{"Name": "aes1", "FieldSelectors": [{"Field": "f", "Equals": ["fs1"]}]}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
@pytest.mark.parametrize("using_arn", [True, False])
|
||||||
|
def test_put_insight_selectors(using_arn):
|
||||||
|
client = boto3.client("cloudtrail", region_name="us-east-2")
|
||||||
|
_, resp, trail_name = create_trail_simple(region_name="us-east-2")
|
||||||
|
|
||||||
|
resp = client.put_insight_selectors(
|
||||||
|
TrailName=trail_name, InsightSelectors=[{"InsightType": "ApiCallRateInsight"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
resp.should.have.key("InsightSelectors").equals(
|
||||||
|
[{"InsightType": "ApiCallRateInsight"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
if using_arn:
|
||||||
|
trail_arn = resp["TrailARN"]
|
||||||
|
resp = client.get_insight_selectors(TrailName=trail_arn)
|
||||||
|
else:
|
||||||
|
resp = client.get_insight_selectors(TrailName=trail_name)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
resp.should.have.key("InsightSelectors").equals(
|
||||||
|
[{"InsightType": "ApiCallRateInsight"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_get_insight_selectors():
|
||||||
|
client = boto3.client("cloudtrail", region_name="eu-west-1")
|
||||||
|
_, resp, trail_name = create_trail_simple(region_name="eu-west-1")
|
||||||
|
resp = client.get_insight_selectors(TrailName=trail_name)
|
||||||
|
|
||||||
|
resp.should.have.key("TrailARN")
|
||||||
|
resp.shouldnt.have.key("InsightSelectors")
|
77
tests/test_cloudtrail/test_cloudtrail_tags.py
Normal file
77
tests/test_cloudtrail/test_cloudtrail_tags.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import boto3
|
||||||
|
|
||||||
|
from moto import mock_cloudtrail, mock_s3, mock_sns
|
||||||
|
|
||||||
|
from .test_cloudtrail import create_trail_simple, create_trail_advanced
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_add_tags():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-1")
|
||||||
|
_, resp, _ = create_trail_simple(region_name="ap-southeast-1")
|
||||||
|
trail_arn = resp["TrailARN"]
|
||||||
|
|
||||||
|
client.add_tags(ResourceId=trail_arn, TagsList=[{"Key": "k1", "Value": "v1"},])
|
||||||
|
|
||||||
|
resp = client.list_tags(ResourceIdList=[trail_arn])
|
||||||
|
resp.should.have.key("ResourceTagList").length_of(1)
|
||||||
|
resp["ResourceTagList"][0].should.equal(
|
||||||
|
{"ResourceId": trail_arn, "TagsList": [{"Key": "k1", "Value": "v1"},]}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
@mock_sns
|
||||||
|
def test_remove_tags():
|
||||||
|
client = boto3.client("cloudtrail", region_name="ap-southeast-1")
|
||||||
|
# Start with two tags
|
||||||
|
_, resp, _, _ = create_trail_advanced(region_name="ap-southeast-1")
|
||||||
|
trail_arn = resp["TrailARN"]
|
||||||
|
|
||||||
|
# Add a third tag
|
||||||
|
client.add_tags(ResourceId=trail_arn, TagsList=[{"Key": "tk3", "Value": "tv3"},])
|
||||||
|
|
||||||
|
# Remove the second tag
|
||||||
|
client.remove_tags(ResourceId=trail_arn, TagsList=[{"Key": "tk2", "Value": "tv2"}])
|
||||||
|
|
||||||
|
# Verify the first and third tag are still there
|
||||||
|
resp = client.list_tags(ResourceIdList=[trail_arn])
|
||||||
|
resp.should.have.key("ResourceTagList").length_of(1)
|
||||||
|
resp["ResourceTagList"][0].should.equal(
|
||||||
|
{
|
||||||
|
"ResourceId": trail_arn,
|
||||||
|
"TagsList": [{"Key": "tk", "Value": "tv"}, {"Key": "tk3", "Value": "tv3"}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
def test_create_trail_without_tags_and_list_tags():
|
||||||
|
client = boto3.client("cloudtrail", region_name="us-east-2")
|
||||||
|
_, resp, _ = create_trail_simple(region_name="us-east-2")
|
||||||
|
trail_arn = resp["TrailARN"]
|
||||||
|
|
||||||
|
resp = client.list_tags(ResourceIdList=[trail_arn])
|
||||||
|
resp.should.have.key("ResourceTagList").length_of(1)
|
||||||
|
resp["ResourceTagList"][0].should.equal({"ResourceId": trail_arn, "TagsList": []})
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudtrail
|
||||||
|
@mock_s3
|
||||||
|
@mock_sns
|
||||||
|
def test_create_trail_with_tags_and_list_tags():
|
||||||
|
client = boto3.client("cloudtrail", region_name="us-east-2")
|
||||||
|
_, resp, _, _ = create_trail_advanced(region_name="us-east-2")
|
||||||
|
trail_arn = resp["TrailARN"]
|
||||||
|
|
||||||
|
resp = client.list_tags(ResourceIdList=[trail_arn])
|
||||||
|
resp.should.have.key("ResourceTagList").length_of(1)
|
||||||
|
resp["ResourceTagList"][0].should.equal(
|
||||||
|
{
|
||||||
|
"ResourceId": trail_arn,
|
||||||
|
"TagsList": [{"Key": "tk", "Value": "tv"}, {"Key": "tk2", "Value": "tv2"}],
|
||||||
|
}
|
||||||
|
)
|
@ -70,11 +70,7 @@ def validate_roots(org, response):
|
|||||||
utils.ROOT_ARN_FORMAT.format(org["MasterAccountId"], org["Id"], root["Id"])
|
utils.ROOT_ARN_FORMAT.format(org["MasterAccountId"], org["Id"], root["Id"])
|
||||||
)
|
)
|
||||||
root.should.have.key("Name").should.be.a(str)
|
root.should.have.key("Name").should.be.a(str)
|
||||||
root.should.have.key("PolicyTypes").should.be.a(list)
|
root.should.have.key("PolicyTypes").should.equal([])
|
||||||
root["PolicyTypes"][0].should.have.key("Type").should.equal(
|
|
||||||
"SERVICE_CONTROL_POLICY"
|
|
||||||
)
|
|
||||||
root["PolicyTypes"][0].should.have.key("Status").should.equal("ENABLED")
|
|
||||||
|
|
||||||
|
|
||||||
def validate_organizational_unit(org, response):
|
def validate_organizational_unit(org, response):
|
||||||
|
@ -1812,10 +1812,7 @@ def test_enable_policy_type():
|
|||||||
)
|
)
|
||||||
root["Name"].should.equal("Root")
|
root["Name"].should.equal("Root")
|
||||||
sorted(root["PolicyTypes"], key=lambda x: x["Type"]).should.equal(
|
sorted(root["PolicyTypes"], key=lambda x: x["Type"]).should.equal(
|
||||||
[
|
[{"Type": "AISERVICES_OPT_OUT_POLICY", "Status": "ENABLED"}]
|
||||||
{"Type": "AISERVICES_OPT_OUT_POLICY", "Status": "ENABLED"},
|
|
||||||
{"Type": "SERVICE_CONTROL_POLICY", "Status": "ENABLED"},
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -1842,7 +1839,10 @@ def test_enable_policy_type_errors():
|
|||||||
"You specified a root that doesn't exist."
|
"You specified a root that doesn't exist."
|
||||||
)
|
)
|
||||||
|
|
||||||
# enable policy again ('SERVICE_CONTROL_POLICY' is enabled by default)
|
# enable policy again
|
||||||
|
# given
|
||||||
|
client.enable_policy_type(RootId=root_id, PolicyType="SERVICE_CONTROL_POLICY")
|
||||||
|
|
||||||
# when
|
# when
|
||||||
with pytest.raises(ClientError) as e:
|
with pytest.raises(ClientError) as e:
|
||||||
client.enable_policy_type(RootId=root_id, PolicyType="SERVICE_CONTROL_POLICY")
|
client.enable_policy_type(RootId=root_id, PolicyType="SERVICE_CONTROL_POLICY")
|
||||||
@ -1889,9 +1889,7 @@ def test_disable_policy_type():
|
|||||||
utils.ROOT_ARN_FORMAT.format(org["MasterAccountId"], org["Id"], root_id)
|
utils.ROOT_ARN_FORMAT.format(org["MasterAccountId"], org["Id"], root_id)
|
||||||
)
|
)
|
||||||
root["Name"].should.equal("Root")
|
root["Name"].should.equal("Root")
|
||||||
root["PolicyTypes"].should.equal(
|
root["PolicyTypes"].should.equal([])
|
||||||
[{"Type": "SERVICE_CONTROL_POLICY", "Status": "ENABLED"}]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@mock_organizations
|
@mock_organizations
|
||||||
|
Loading…
x
Reference in New Issue
Block a user