Feature: Guardduty (#4667)
This commit is contained in:
parent
0c5a3cc8ca
commit
cd5357ca41
@ -2481,6 +2481,70 @@
|
||||
- [ ] update_workflow
|
||||
</details>
|
||||
|
||||
## guardduty
|
||||
<details>
|
||||
<summary>3% implemented</summary>
|
||||
|
||||
- [ ] accept_invitation
|
||||
- [ ] archive_findings
|
||||
- [X] create_detector
|
||||
- [ ] create_filter
|
||||
- [ ] create_ip_set
|
||||
- [ ] create_members
|
||||
- [ ] create_publishing_destination
|
||||
- [ ] create_sample_findings
|
||||
- [ ] create_threat_intel_set
|
||||
- [ ] decline_invitations
|
||||
- [ ] delete_detector
|
||||
- [ ] delete_filter
|
||||
- [ ] delete_invitations
|
||||
- [ ] delete_ip_set
|
||||
- [ ] delete_members
|
||||
- [ ] delete_publishing_destination
|
||||
- [ ] delete_threat_intel_set
|
||||
- [ ] describe_organization_configuration
|
||||
- [ ] describe_publishing_destination
|
||||
- [ ] disable_organization_admin_account
|
||||
- [ ] disassociate_from_master_account
|
||||
- [ ] disassociate_members
|
||||
- [ ] enable_organization_admin_account
|
||||
- [ ] get_detector
|
||||
- [ ] get_filter
|
||||
- [ ] get_findings
|
||||
- [ ] get_findings_statistics
|
||||
- [ ] get_invitations_count
|
||||
- [ ] get_ip_set
|
||||
- [ ] get_master_account
|
||||
- [ ] get_member_detectors
|
||||
- [ ] get_members
|
||||
- [ ] get_threat_intel_set
|
||||
- [ ] get_usage_statistics
|
||||
- [ ] invite_members
|
||||
- [X] list_detectors
|
||||
- [ ] list_filters
|
||||
- [ ] list_findings
|
||||
- [ ] list_invitations
|
||||
- [ ] list_ip_sets
|
||||
- [ ] list_members
|
||||
- [ ] list_organization_admin_accounts
|
||||
- [ ] list_publishing_destinations
|
||||
- [ ] list_tags_for_resource
|
||||
- [ ] list_threat_intel_sets
|
||||
- [ ] start_monitoring_members
|
||||
- [ ] stop_monitoring_members
|
||||
- [ ] tag_resource
|
||||
- [ ] unarchive_findings
|
||||
- [ ] untag_resource
|
||||
- [ ] update_detector
|
||||
- [ ] update_filter
|
||||
- [ ] update_findings_feedback
|
||||
- [ ] update_ip_set
|
||||
- [ ] update_member_detectors
|
||||
- [ ] update_organization_configuration
|
||||
- [ ] update_publishing_destination
|
||||
- [ ] update_threat_intel_set
|
||||
</details>
|
||||
|
||||
## iam
|
||||
<details>
|
||||
<summary>67% implemented</summary>
|
||||
@ -4945,7 +5009,6 @@
|
||||
- greengrass
|
||||
- greengrassv2
|
||||
- groundstation
|
||||
- guardduty
|
||||
- health
|
||||
- healthlake
|
||||
- honeycode
|
||||
|
90
docs/docs/services/guardduty.rst
Normal file
90
docs/docs/services/guardduty.rst
Normal file
@ -0,0 +1,90 @@
|
||||
.. _implementedservice_guardduty:
|
||||
|
||||
.. |start-h3| raw:: html
|
||||
|
||||
<h3>
|
||||
|
||||
.. |end-h3| raw:: html
|
||||
|
||||
</h3>
|
||||
|
||||
=========
|
||||
guardduty
|
||||
=========
|
||||
|
||||
|start-h3| Example usage |end-h3|
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
@mock_guardduty
|
||||
def test_guardduty_behaviour:
|
||||
boto3.client("guardduty")
|
||||
...
|
||||
|
||||
|
||||
|
||||
|start-h3| Implemented features for this service |end-h3|
|
||||
|
||||
- [ ] accept_invitation
|
||||
- [ ] archive_findings
|
||||
- [X] create_detector
|
||||
- [ ] create_filter
|
||||
- [ ] create_ip_set
|
||||
- [ ] create_members
|
||||
- [ ] create_publishing_destination
|
||||
- [ ] create_sample_findings
|
||||
- [ ] create_threat_intel_set
|
||||
- [ ] decline_invitations
|
||||
- [ ] delete_detector
|
||||
- [ ] delete_filter
|
||||
- [ ] delete_invitations
|
||||
- [ ] delete_ip_set
|
||||
- [ ] delete_members
|
||||
- [ ] delete_publishing_destination
|
||||
- [ ] delete_threat_intel_set
|
||||
- [ ] describe_organization_configuration
|
||||
- [ ] describe_publishing_destination
|
||||
- [ ] disable_organization_admin_account
|
||||
- [ ] disassociate_from_master_account
|
||||
- [ ] disassociate_members
|
||||
- [ ] enable_organization_admin_account
|
||||
- [ ] get_detector
|
||||
- [ ] get_filter
|
||||
- [ ] get_findings
|
||||
- [ ] get_findings_statistics
|
||||
- [ ] get_invitations_count
|
||||
- [ ] get_ip_set
|
||||
- [ ] get_master_account
|
||||
- [ ] get_member_detectors
|
||||
- [ ] get_members
|
||||
- [ ] get_threat_intel_set
|
||||
- [ ] get_usage_statistics
|
||||
- [ ] invite_members
|
||||
- [X] list_detectors
|
||||
|
||||
The MaxResults and NextToken-parameter have not yet been implemented.
|
||||
|
||||
|
||||
- [ ] list_filters
|
||||
- [ ] list_findings
|
||||
- [ ] list_invitations
|
||||
- [ ] list_ip_sets
|
||||
- [ ] list_members
|
||||
- [ ] list_organization_admin_accounts
|
||||
- [ ] list_publishing_destinations
|
||||
- [ ] list_tags_for_resource
|
||||
- [ ] list_threat_intel_sets
|
||||
- [ ] start_monitoring_members
|
||||
- [ ] stop_monitoring_members
|
||||
- [ ] tag_resource
|
||||
- [ ] unarchive_findings
|
||||
- [ ] untag_resource
|
||||
- [ ] update_detector
|
||||
- [ ] update_filter
|
||||
- [ ] update_findings_feedback
|
||||
- [ ] update_ip_set
|
||||
- [ ] update_member_detectors
|
||||
- [ ] update_organization_configuration
|
||||
- [ ] update_publishing_destination
|
||||
- [ ] update_threat_intel_set
|
||||
|
@ -95,6 +95,7 @@ mock_forecast = lazy_load(".forecast", "mock_forecast")
|
||||
mock_glacier = lazy_load(".glacier", "mock_glacier")
|
||||
mock_glacier_deprecated = lazy_load(".glacier", "mock_glacier_deprecated")
|
||||
mock_glue = lazy_load(".glue", "mock_glue")
|
||||
mock_guardduty = lazy_load(".guardduty", "mock_guardduty")
|
||||
mock_iam = lazy_load(".iam", "mock_iam")
|
||||
mock_iam_deprecated = lazy_load(".iam", "mock_iam_deprecated")
|
||||
mock_iot = lazy_load(".iot", "mock_iot")
|
||||
@ -198,7 +199,6 @@ class MockAll(ContextDecorator):
|
||||
|
||||
mock_all = MockAll
|
||||
|
||||
|
||||
# import logging
|
||||
# logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
@ -66,6 +66,7 @@ backend_url_patterns = [
|
||||
("forecast", re.compile("https?://forecast\\.(.+)\\.amazonaws\\.com")),
|
||||
("glacier", re.compile("https?://glacier\\.(.+)\\.amazonaws.com")),
|
||||
("glue", re.compile("https?://glue\\.(.+)\\.amazonaws\\.com")),
|
||||
("guardduty", re.compile("https?://guardduty\\.(.+)\\.amazonaws\\.com")),
|
||||
("iam", re.compile("https?://iam\\.(.*\\.)?amazonaws\\.com")),
|
||||
("iot", re.compile("https?://iot\\.(.+)\\.amazonaws\\.com")),
|
||||
("iot-data", re.compile("https?://data\\.iot\\.(.+)\\.amazonaws.com")),
|
||||
|
7
moto/guardduty/__init__.py
Normal file
7
moto/guardduty/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .models import guardduty_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
guardduty_backend = guardduty_backends["us-east-1"]
|
||||
mock_guardduty = base_decorator(guardduty_backends)
|
79
moto/guardduty/models.py
Normal file
79
moto/guardduty/models.py
Normal file
@ -0,0 +1,79 @@
|
||||
from __future__ import unicode_literals
|
||||
from boto3 import Session
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
class GuardDutyBackend(BaseBackend):
|
||||
def __init__(self, region_name=None):
|
||||
super(GuardDutyBackend, self).__init__()
|
||||
self.region_name = region_name
|
||||
self.detectors = {}
|
||||
|
||||
def reset(self):
|
||||
region_name = self.region_name
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
def create_detector(
|
||||
self, enable, client_token, finding_publishing_frequency, data_sources, tags
|
||||
):
|
||||
if finding_publishing_frequency not in [
|
||||
"FIFTEEN_MINUTES",
|
||||
"ONE_HOUR",
|
||||
"SIX_HOURS",
|
||||
]:
|
||||
finding_publishing_frequency = "SIX_HOURS"
|
||||
|
||||
service_role = "AWSServiceRoleForAmazonGuardDuty"
|
||||
detector = Detector(
|
||||
self,
|
||||
datetime.now,
|
||||
finding_publishing_frequency,
|
||||
service_role,
|
||||
enable,
|
||||
data_sources,
|
||||
tags,
|
||||
)
|
||||
self.detectors[detector.id] = detector
|
||||
return detector.id
|
||||
|
||||
def list_detectors(self):
|
||||
"""
|
||||
The MaxResults and NextToken-parameter have not yet been implemented.
|
||||
"""
|
||||
detectorids = []
|
||||
for detector in self.detectors:
|
||||
detectorids.append(self.detectors[detector].id)
|
||||
return detectorids
|
||||
|
||||
|
||||
class Detector(BaseModel):
|
||||
def __init__(
|
||||
self,
|
||||
created_at,
|
||||
finding_publish_freq,
|
||||
service_role,
|
||||
status,
|
||||
updated_at,
|
||||
datasources,
|
||||
tags,
|
||||
):
|
||||
self.id = str(uuid4())
|
||||
self.created_at = created_at
|
||||
self.finding_publish_freq = finding_publish_freq
|
||||
self.service_role = service_role
|
||||
self.status = status
|
||||
self.updated_at = updated_at
|
||||
self.datasources = datasources
|
||||
self.tags = tags
|
||||
|
||||
|
||||
guardduty_backends = {}
|
||||
for region in Session().get_available_regions("guardduty"):
|
||||
guardduty_backends[region] = GuardDutyBackend()
|
||||
for region in Session().get_available_regions("guardduty", partition_name="aws-us-gov"):
|
||||
guardduty_backends[region] = GuardDutyBackend()
|
||||
for region in Session().get_available_regions("guardduty", partition_name="aws-cn"):
|
||||
guardduty_backends[region] = GuardDutyBackend()
|
39
moto/guardduty/responses.py
Normal file
39
moto/guardduty/responses.py
Normal file
@ -0,0 +1,39 @@
|
||||
from __future__ import unicode_literals
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import guardduty_backends
|
||||
import json
|
||||
|
||||
|
||||
class GuardDutyResponse(BaseResponse):
|
||||
SERVICE_NAME = "guardduty"
|
||||
|
||||
@property
|
||||
def guardduty_backend(self):
|
||||
return guardduty_backends[self.region]
|
||||
|
||||
def detector(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
if request.method == "POST":
|
||||
return self.create_detector()
|
||||
elif request.method == "GET":
|
||||
return self.list_detectors()
|
||||
else:
|
||||
return 404, {}, ""
|
||||
|
||||
def create_detector(self):
|
||||
enable = self._get_param("enable")
|
||||
client_token = self._get_param("clientToken")
|
||||
finding_publishing_frequency = self._get_param("findingPublishingFrequency")
|
||||
data_sources = self._get_param("dataSources")
|
||||
tags = self._get_param("tags")
|
||||
|
||||
detector_id = self.guardduty_backend.create_detector(
|
||||
enable, client_token, finding_publishing_frequency, data_sources, tags
|
||||
)
|
||||
|
||||
return 200, {}, json.dumps(dict(detectorId=detector_id))
|
||||
|
||||
def list_detectors(self):
|
||||
detector_ids = self.guardduty_backend.list_detectors()
|
||||
|
||||
return 200, {}, json.dumps({"detectorIds": detector_ids})
|
13
moto/guardduty/urls.py
Normal file
13
moto/guardduty/urls.py
Normal file
@ -0,0 +1,13 @@
|
||||
from __future__ import unicode_literals
|
||||
from .responses import GuardDutyResponse
|
||||
|
||||
response = GuardDutyResponse()
|
||||
|
||||
url_bases = [
|
||||
"https?://guardduty\\.(.+)\\.amazonaws\\.com",
|
||||
]
|
||||
|
||||
|
||||
url_paths = {
|
||||
"{0}/detector$": response.detector,
|
||||
}
|
0
tests/test_guardduty/__init__.py
Normal file
0
tests/test_guardduty/__init__.py
Normal file
51
tests/test_guardduty/test_guardduty.py
Normal file
51
tests/test_guardduty/test_guardduty.py
Normal file
@ -0,0 +1,51 @@
|
||||
import boto3
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
|
||||
from moto import mock_guardduty
|
||||
|
||||
|
||||
@mock_guardduty
|
||||
def test_create_detector():
|
||||
client = boto3.client("guardduty", region_name="us-east-1")
|
||||
response = client.create_detector(
|
||||
Enable=True,
|
||||
ClientToken="745645734574758463758",
|
||||
FindingPublishingFrequency="ONE_HOUR",
|
||||
DataSources={"S3Logs": {"Enable": True}},
|
||||
Tags={},
|
||||
)
|
||||
response.should.have.key("DetectorId")
|
||||
response["DetectorId"].shouldnt.equal(None)
|
||||
|
||||
|
||||
@mock_guardduty
|
||||
def test_create_detector_with_minimal_params():
|
||||
client = boto3.client("guardduty", region_name="us-east-1")
|
||||
response = client.create_detector(Enable=True)
|
||||
response.should.have.key("DetectorId")
|
||||
response["DetectorId"].shouldnt.equal(None)
|
||||
|
||||
|
||||
@mock_guardduty
|
||||
def test_list_detectors_initial():
|
||||
client = boto3.client("guardduty", region_name="us-east-1")
|
||||
|
||||
response = client.list_detectors()
|
||||
response.should.have.key("DetectorIds").equals([])
|
||||
|
||||
|
||||
@mock_guardduty
|
||||
def test_list_detectors():
|
||||
client = boto3.client("guardduty", region_name="us-east-1")
|
||||
d1 = client.create_detector(
|
||||
Enable=True,
|
||||
ClientToken="745645734574758463758",
|
||||
FindingPublishingFrequency="ONE_HOUR",
|
||||
DataSources={"S3Logs": {"Enable": True}},
|
||||
Tags={},
|
||||
)["DetectorId"]
|
||||
d2 = client.create_detector(Enable=False,)["DetectorId"]
|
||||
|
||||
response = client.list_detectors()
|
||||
response.should.have.key("DetectorIds")
|
||||
set(response["DetectorIds"]).should.equal({d1, d2})
|
14
tests/test_guardduty/test_server.py
Normal file
14
tests/test_guardduty/test_server.py
Normal file
@ -0,0 +1,14 @@
|
||||
import json
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
|
||||
import moto.server as server
|
||||
|
||||
|
||||
def test_create_without_enable_option():
|
||||
backend = server.create_backend_app("guardduty")
|
||||
test_client = backend.test_client()
|
||||
|
||||
body = {"enable": "True"}
|
||||
response = test_client.post("/detector", data=json.dumps(body))
|
||||
response.status_code.should.equal(200)
|
||||
json.loads(response.data).should.have.key("detectorId")
|
Loading…
Reference in New Issue
Block a user