Feature: Guardduty (#4667)

This commit is contained in:
Bert Blommers 2021-12-07 11:10:43 -01:00 committed by GitHub
parent 0c5a3cc8ca
commit cd5357ca41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 359 additions and 2 deletions

View File

@ -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

View 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

View File

@ -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)

View File

@ -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")),

View 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
View 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()

View 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
View 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,
}

View File

View 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})

View 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")