Merge branch 'master' into PRWLR-5093-design-the-fixer-class

This commit is contained in:
Daniel Barranquero
2025-05-20 13:14:59 +02:00
75 changed files with 6097 additions and 2013 deletions
+1 -1
View File
@@ -86,7 +86,7 @@ prowler dashboard
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) |
|---|---|---|---|---|
| AWS | 564 | 82 | 33 | 10 |
| AWS | 564 | 82 | 34 | 10 |
| GCP | 79 | 13 | 7 | 3 |
| Azure | 140 | 18 | 8 | 3 |
| Kubernetes | 83 | 7 | 4 | 7 |
+3 -1
View File
@@ -2,12 +2,14 @@
All notable changes to the **Prowler API** are documented in this file.
## [v1.8.0] (Prowler UNRELEASED)
## [v1.8.0] (Prowler v5.7.0)
### Added
- Added huge improvements to `/findings/metadata` and resource related filters for findings [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added improvements to `/overviews` endpoints [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added new queue to perform backfill background tasks [(#7690)](https://github.com/prowler-cloud/prowler/pull/7690).
- Added new endpoints to retrieve latest findings and metadata [(#7743)](https://github.com/prowler-cloud/prowler/pull/7743).
- Added export support for Prowler ThreatScore in M365 [(7783)](https://github.com/prowler-cloud/prowler/pull/7783)
---
+134 -98
View File
@@ -81,6 +81,114 @@ class ChoiceInFilter(BaseInFilter, ChoiceFilter):
pass
class CommonFindingFilters(FilterSet):
# We filter providers from the scan in findings
provider = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in")
provider_uid__icontains = CharFilter(
field_name="scan__provider__uid", lookup_expr="icontains"
)
provider_alias = CharFilter(field_name="scan__provider__alias", lookup_expr="exact")
provider_alias__in = CharInFilter(
field_name="scan__provider__alias", lookup_expr="in"
)
provider_alias__icontains = CharFilter(
field_name="scan__provider__alias", lookup_expr="icontains"
)
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
uid = CharFilter(field_name="uid")
delta = ChoiceFilter(choices=Finding.DeltaChoices.choices)
status = ChoiceFilter(choices=StatusChoices.choices)
severity = ChoiceFilter(choices=SeverityChoices)
impact = ChoiceFilter(choices=SeverityChoices)
muted = BooleanFilter(
help_text="If this filter is not provided, muted and non-muted findings will be returned."
)
resources = UUIDInFilter(field_name="resource__id", lookup_expr="in")
region = CharFilter(method="filter_resource_region")
region__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap")
region__icontains = CharFilter(
field_name="resource_regions", lookup_expr="icontains"
)
service = CharFilter(method="filter_resource_service")
service__in = CharInFilter(field_name="resource_services", lookup_expr="overlap")
service__icontains = CharFilter(
field_name="resource_services", lookup_expr="icontains"
)
resource_uid = CharFilter(field_name="resources__uid")
resource_uid__in = CharInFilter(field_name="resources__uid", lookup_expr="in")
resource_uid__icontains = CharFilter(
field_name="resources__uid", lookup_expr="icontains"
)
resource_name = CharFilter(field_name="resources__name")
resource_name__in = CharInFilter(field_name="resources__name", lookup_expr="in")
resource_name__icontains = CharFilter(
field_name="resources__name", lookup_expr="icontains"
)
resource_type = CharFilter(method="filter_resource_type")
resource_type__in = CharInFilter(field_name="resource_types", lookup_expr="overlap")
resource_type__icontains = CharFilter(
field_name="resources__type", lookup_expr="icontains"
)
# Temporarily disabled until we implement tag filtering in the UI
# resource_tag_key = CharFilter(field_name="resources__tags__key")
# resource_tag_key__in = CharInFilter(
# field_name="resources__tags__key", lookup_expr="in"
# )
# resource_tag_key__icontains = CharFilter(
# field_name="resources__tags__key", lookup_expr="icontains"
# )
# resource_tag_value = CharFilter(field_name="resources__tags__value")
# resource_tag_value__in = CharInFilter(
# field_name="resources__tags__value", lookup_expr="in"
# )
# resource_tag_value__icontains = CharFilter(
# field_name="resources__tags__value", lookup_expr="icontains"
# )
# resource_tags = CharInFilter(
# method="filter_resource_tag",
# lookup_expr="in",
# help_text="Filter by resource tags `key:value` pairs.\nMultiple values may be "
# "separated by commas.",
# )
def filter_resource_service(self, queryset, name, value):
return queryset.filter(resource_services__contains=[value])
def filter_resource_region(self, queryset, name, value):
return queryset.filter(resource_regions__contains=[value])
def filter_resource_type(self, queryset, name, value):
return queryset.filter(resource_types__contains=[value])
def filter_resource_tag(self, queryset, name, value):
overall_query = Q()
for key_value_pair in value:
tag_key, tag_value = key_value_pair.split(":", 1)
overall_query |= Q(
resources__tags__key__icontains=tag_key,
resources__tags__value__icontains=tag_value,
)
return queryset.filter(overall_query).distinct()
class TenantFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
@@ -257,94 +365,7 @@ class ResourceFilter(ProviderRelationshipFilterSet):
return queryset.filter(tags__text_search=value)
class FindingFilter(FilterSet):
# We filter providers from the scan in findings
provider = UUIDFilter(field_name="scan__provider__id", lookup_expr="exact")
provider__in = UUIDInFilter(field_name="scan__provider__id", lookup_expr="in")
provider_type = ChoiceFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_type__in = ChoiceInFilter(
choices=Provider.ProviderChoices.choices, field_name="scan__provider__provider"
)
provider_uid = CharFilter(field_name="scan__provider__uid", lookup_expr="exact")
provider_uid__in = CharInFilter(field_name="scan__provider__uid", lookup_expr="in")
provider_uid__icontains = CharFilter(
field_name="scan__provider__uid", lookup_expr="icontains"
)
provider_alias = CharFilter(field_name="scan__provider__alias", lookup_expr="exact")
provider_alias__in = CharInFilter(
field_name="scan__provider__alias", lookup_expr="in"
)
provider_alias__icontains = CharFilter(
field_name="scan__provider__alias", lookup_expr="icontains"
)
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
uid = CharFilter(field_name="uid")
delta = ChoiceFilter(choices=Finding.DeltaChoices.choices)
status = ChoiceFilter(choices=StatusChoices.choices)
severity = ChoiceFilter(choices=SeverityChoices)
impact = ChoiceFilter(choices=SeverityChoices)
muted = BooleanFilter(
help_text="If this filter is not provided, muted and non-muted findings will be returned."
)
resources = UUIDInFilter(field_name="resource__id", lookup_expr="in")
region = CharFilter(method="filter_resource_region")
region__in = CharInFilter(field_name="resource_regions", lookup_expr="overlap")
region__icontains = CharFilter(
field_name="resource_regions", lookup_expr="icontains"
)
service = CharFilter(method="filter_resource_service")
service__in = CharInFilter(field_name="resource_services", lookup_expr="overlap")
service__icontains = CharFilter(
field_name="resource_services", lookup_expr="icontains"
)
resource_uid = CharFilter(field_name="resources__uid")
resource_uid__in = CharInFilter(field_name="resources__uid", lookup_expr="in")
resource_uid__icontains = CharFilter(
field_name="resources__uid", lookup_expr="icontains"
)
resource_name = CharFilter(field_name="resources__name")
resource_name__in = CharInFilter(field_name="resources__name", lookup_expr="in")
resource_name__icontains = CharFilter(
field_name="resources__name", lookup_expr="icontains"
)
resource_type = CharFilter(method="filter_resource_type")
resource_type__in = CharInFilter(field_name="resource_types", lookup_expr="overlap")
resource_type__icontains = CharFilter(
field_name="resources__type", lookup_expr="icontains"
)
# Temporarily disabled until we implement tag filtering in the UI
# resource_tag_key = CharFilter(field_name="resources__tags__key")
# resource_tag_key__in = CharInFilter(
# field_name="resources__tags__key", lookup_expr="in"
# )
# resource_tag_key__icontains = CharFilter(
# field_name="resources__tags__key", lookup_expr="icontains"
# )
# resource_tag_value = CharFilter(field_name="resources__tags__value")
# resource_tag_value__in = CharInFilter(
# field_name="resources__tags__value", lookup_expr="in"
# )
# resource_tag_value__icontains = CharFilter(
# field_name="resources__tags__value", lookup_expr="icontains"
# )
# resource_tags = CharInFilter(
# method="filter_resource_tag",
# lookup_expr="in",
# help_text="Filter by resource tags `key:value` pairs.\nMultiple values may be "
# "separated by commas.",
# )
class FindingFilter(CommonFindingFilters):
scan = UUIDFilter(method="filter_scan_id")
scan__in = UUIDInFilter(method="filter_scan_id_in")
@@ -512,16 +533,6 @@ class FindingFilter(FilterSet):
return queryset.filter(id__lt=end)
def filter_resource_tag(self, queryset, name, value):
overall_query = Q()
for key_value_pair in value:
tag_key, tag_value = key_value_pair.split(":", 1)
overall_query |= Q(
resources__tags__key__icontains=tag_key,
resources__tags__value__icontains=tag_value,
)
return queryset.filter(overall_query).distinct()
@staticmethod
def maybe_date_to_datetime(value):
dt = value
@@ -530,6 +541,31 @@ class FindingFilter(FilterSet):
return dt
class LatestFindingFilter(CommonFindingFilters):
class Meta:
model = Finding
fields = {
"id": ["exact", "in"],
"uid": ["exact", "in"],
"delta": ["exact", "in"],
"status": ["exact", "in"],
"severity": ["exact", "in"],
"impact": ["exact", "in"],
"check_id": ["exact", "in", "icontains"],
}
filter_overrides = {
FindingDeltaEnumField: {
"filter_class": CharFilter,
},
StatusEnumField: {
"filter_class": CharFilter,
},
SeverityEnumField: {
"filter_class": CharFilter,
},
}
class ProviderSecretFilter(FilterSet):
inserted_at = DateFilter(field_name="inserted_at", lookup_expr="date")
updated_at = DateFilter(field_name="updated_at", lookup_expr="date")
+7 -2
View File
@@ -218,9 +218,13 @@ class Provider(RowLevelSecurityProtectedModel):
@staticmethod
def validate_m365_uid(value):
if not re.match(r"^[a-zA-Z0-9-]+\.onmicrosoft\.com$", value):
if not re.match(
r"""^(?!-)[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.(?!-)[A-Za-z0-9]"""
r"""(?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*\.[A-Za-z]{2,}$""",
value,
):
raise ModelValidationError(
detail="M365 tenant ID must be a valid domain.",
detail="M365 domain ID must be a valid domain.",
code="m365-uid",
pointer="/data/attributes/uid",
)
@@ -426,6 +430,7 @@ class Scan(RowLevelSecurityProtectedModel):
PeriodicTask, on_delete=models.CASCADE, null=True, blank=True
)
output_location = models.CharField(blank=True, null=True, max_length=200)
# TODO: mutelist foreign key
class Meta(RowLevelSecurityProtectedModel.Meta):
+796
View File
@@ -1238,6 +1238,416 @@ paths:
schema:
$ref: '#/components/schemas/FindingDynamicFilterResponse'
description: ''
/api/v1/findings/latest:
get:
operationId: findings_latest_retrieve
description: Retrieve a list of the latest findings from the latest scans for
each provider with options for filtering by various criteria.
summary: List the latest findings
parameters:
- in: query
name: fields[findings]
schema:
type: array
items:
type: string
enum:
- uid
- delta
- status
- status_extended
- severity
- check_id
- check_metadata
- raw_result
- inserted_at
- updated_at
- first_seen_at
- muted
- url
- scan
- resources
description: endpoint return only specific fields in the response on a per-type
basis by including a fields[TYPE] query parameter.
explode: false
- in: query
name: filter[check_id]
schema:
type: string
- in: query
name: filter[check_id__icontains]
schema:
type: string
- in: query
name: filter[check_id__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[delta]
schema:
type: string
nullable: true
enum:
- changed
- new
description: |-
* `new` - New
* `changed` - Changed
- in: query
name: filter[delta__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[id]
schema:
type: string
format: uuid
- in: query
name: filter[id__in]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[impact]
schema:
type: string
enum:
- critical
- high
- informational
- low
- medium
description: |-
* `critical` - Critical
* `high` - High
* `medium` - Medium
* `low` - Low
* `informational` - Informational
- in: query
name: filter[impact__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[muted]
schema:
type: boolean
description: If this filter is not provided, muted and non-muted findings
will be returned.
- in: query
name: filter[provider]
schema:
type: string
format: uuid
- in: query
name: filter[provider__in]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[provider_alias]
schema:
type: string
- in: query
name: filter[provider_alias__icontains]
schema:
type: string
- in: query
name: filter[provider_alias__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[provider_type]
schema:
type: string
enum:
- aws
- azure
- gcp
- kubernetes
- m365
description: |-
* `aws` - AWS
* `azure` - Azure
* `gcp` - GCP
* `kubernetes` - Kubernetes
* `m365` - M365
- in: query
name: filter[provider_type__in]
schema:
type: array
items:
type: string
enum:
- aws
- azure
- gcp
- kubernetes
- m365
description: |-
Multiple values may be separated by commas.
* `aws` - AWS
* `azure` - Azure
* `gcp` - GCP
* `kubernetes` - Kubernetes
* `m365` - M365
explode: false
style: form
- in: query
name: filter[provider_uid]
schema:
type: string
- in: query
name: filter[provider_uid__icontains]
schema:
type: string
- in: query
name: filter[provider_uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[region]
schema:
type: string
- in: query
name: filter[region__icontains]
schema:
type: string
- in: query
name: filter[region__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_name]
schema:
type: string
- in: query
name: filter[resource_name__icontains]
schema:
type: string
- in: query
name: filter[resource_name__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_type]
schema:
type: string
- in: query
name: filter[resource_type__icontains]
schema:
type: string
- in: query
name: filter[resource_type__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_uid]
schema:
type: string
- in: query
name: filter[resource_uid__icontains]
schema:
type: string
- in: query
name: filter[resource_uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resources]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- name: filter[search]
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: filter[service]
schema:
type: string
- in: query
name: filter[service__icontains]
schema:
type: string
- in: query
name: filter[service__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[severity]
schema:
type: string
enum:
- critical
- high
- informational
- low
- medium
description: |-
* `critical` - Critical
* `high` - High
* `medium` - Medium
* `low` - Low
* `informational` - Informational
- in: query
name: filter[severity__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[status]
schema:
type: string
enum:
- FAIL
- MANUAL
- PASS
description: |-
* `FAIL` - Fail
* `PASS` - Pass
* `MANUAL` - Manual
- in: query
name: filter[status__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[uid]
schema:
type: string
- in: query
name: filter[uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[updated_at]
schema:
type: string
format: date
- in: query
name: include
schema:
type: array
items:
type: string
enum:
- scan
- resources
description: include query parameter to allow the client to customize which
related resources should be returned.
explode: false
- name: sort
required: false
in: query
description: '[list of fields to sort by](https://jsonapi.org/format/#fetching-sorting)'
schema:
type: array
items:
type: string
enum:
- status
- -status
- severity
- -severity
- check_id
- -check_id
- inserted_at
- -inserted_at
- updated_at
- -updated_at
explode: false
tags:
- Finding
security:
- jwtAuth: []
responses:
'200':
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/FindingResponse'
description: ''
/api/v1/findings/metadata:
get:
operationId: findings_metadata_retrieve
@@ -1674,6 +2084,392 @@ paths:
schema:
$ref: '#/components/schemas/FindingMetadataResponse'
description: ''
/api/v1/findings/metadata/latest:
get:
operationId: findings_metadata_latest_retrieve
description: Fetch unique metadata values from a set of findings from the latest
scans for each provider. This is useful for dynamic filtering.
summary: Retrieve metadata values from the latest findings
parameters:
- in: query
name: fields[findings-metadata]
schema:
type: array
items:
type: string
enum:
- services
- regions
- resource_types
description: endpoint return only specific fields in the response on a per-type
basis by including a fields[TYPE] query parameter.
explode: false
- in: query
name: filter[check_id]
schema:
type: string
- in: query
name: filter[check_id__icontains]
schema:
type: string
- in: query
name: filter[check_id__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[delta]
schema:
type: string
nullable: true
enum:
- changed
- new
description: |-
* `new` - New
* `changed` - Changed
- in: query
name: filter[delta__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[id]
schema:
type: string
format: uuid
- in: query
name: filter[id__in]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[impact]
schema:
type: string
enum:
- critical
- high
- informational
- low
- medium
description: |-
* `critical` - Critical
* `high` - High
* `medium` - Medium
* `low` - Low
* `informational` - Informational
- in: query
name: filter[impact__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[muted]
schema:
type: boolean
description: If this filter is not provided, muted and non-muted findings
will be returned.
- in: query
name: filter[provider]
schema:
type: string
format: uuid
- in: query
name: filter[provider__in]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[provider_alias]
schema:
type: string
- in: query
name: filter[provider_alias__icontains]
schema:
type: string
- in: query
name: filter[provider_alias__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[provider_type]
schema:
type: string
enum:
- aws
- azure
- gcp
- kubernetes
- m365
description: |-
* `aws` - AWS
* `azure` - Azure
* `gcp` - GCP
* `kubernetes` - Kubernetes
* `m365` - M365
- in: query
name: filter[provider_type__in]
schema:
type: array
items:
type: string
enum:
- aws
- azure
- gcp
- kubernetes
- m365
description: |-
Multiple values may be separated by commas.
* `aws` - AWS
* `azure` - Azure
* `gcp` - GCP
* `kubernetes` - Kubernetes
* `m365` - M365
explode: false
style: form
- in: query
name: filter[provider_uid]
schema:
type: string
- in: query
name: filter[provider_uid__icontains]
schema:
type: string
- in: query
name: filter[provider_uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[region]
schema:
type: string
- in: query
name: filter[region__icontains]
schema:
type: string
- in: query
name: filter[region__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_name]
schema:
type: string
- in: query
name: filter[resource_name__icontains]
schema:
type: string
- in: query
name: filter[resource_name__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_type]
schema:
type: string
- in: query
name: filter[resource_type__icontains]
schema:
type: string
- in: query
name: filter[resource_type__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resource_uid]
schema:
type: string
- in: query
name: filter[resource_uid__icontains]
schema:
type: string
- in: query
name: filter[resource_uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[resources]
schema:
type: array
items:
type: string
format: uuid
description: Multiple values may be separated by commas.
explode: false
style: form
- name: filter[search]
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: filter[service]
schema:
type: string
- in: query
name: filter[service__icontains]
schema:
type: string
- in: query
name: filter[service__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[severity]
schema:
type: string
enum:
- critical
- high
- informational
- low
- medium
description: |-
* `critical` - Critical
* `high` - High
* `medium` - Medium
* `low` - Low
* `informational` - Informational
- in: query
name: filter[severity__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[status]
schema:
type: string
enum:
- FAIL
- MANUAL
- PASS
description: |-
* `FAIL` - Fail
* `PASS` - Pass
* `MANUAL` - Manual
- in: query
name: filter[status__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[uid]
schema:
type: string
- in: query
name: filter[uid__in]
schema:
type: array
items:
type: string
description: Multiple values may be separated by commas.
explode: false
style: form
- in: query
name: filter[updated_at]
schema:
type: string
format: date
- name: sort
required: false
in: query
description: '[list of fields to sort by](https://jsonapi.org/format/#fetching-sorting)'
schema:
type: array
items:
type: string
enum:
- status
- -status
- severity
- -severity
- check_id
- -check_id
- inserted_at
- -inserted_at
- updated_at
- -updated_at
explode: false
tags:
- Finding
security:
- jwtAuth: []
responses:
'200':
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/FindingMetadataResponse'
description: ''
/api/v1/integrations:
get:
operationId: integrations_list
+88
View File
@@ -918,6 +918,26 @@ class TestProviderViewSet:
"uid": "8851db6b-42e5-4533-aa9e-30a32d67e875",
"alias": "test",
},
{
"provider": "m365",
"uid": "TestingPro.onMirosoft.com",
"alias": "test",
},
{
"provider": "m365",
"uid": "subdomain.domain.es",
"alias": "test",
},
{
"provider": "m365",
"uid": "microsoft.net",
"alias": "test",
},
{
"provider": "m365",
"uid": "subdomain1.subdomain2.subdomain3.subdomain4.domain.net",
"alias": "test",
},
]
),
)
@@ -986,6 +1006,51 @@ class TestProviderViewSet:
"invalid_choice",
"provider",
),
(
{
"provider": "m365",
"uid": "https://test.com",
"alias": "test",
},
"m365-uid",
"uid",
),
(
{
"provider": "m365",
"uid": "thisisnotadomain",
"alias": "test",
},
"m365-uid",
"uid",
),
(
{
"provider": "m365",
"uid": "http://test.com",
"alias": "test",
},
"m365-uid",
"uid",
),
(
{
"provider": "m365",
"uid": f"{'a' * 64}.domain.com",
"alias": "test",
},
"m365-uid",
"uid",
),
(
{
"provider": "m365",
"uid": f"subdomain.{'a' * 64}.com",
"alias": "test",
},
"m365-uid",
"uid",
),
]
),
)
@@ -3185,6 +3250,29 @@ class TestFindingViewSet:
]
}
def test_findings_latest(self, authenticated_client, latest_scan_finding):
response = authenticated_client.get(
reverse("finding-latest"),
)
assert response.status_code == status.HTTP_200_OK
# The latest scan only has one finding, in comparison with `GET /findings`
assert len(response.json()["data"]) == 1
assert (
response.json()["data"][0]["attributes"]["status"]
== latest_scan_finding.status
)
def test_findings_metadata_latest(self, authenticated_client, latest_scan_finding):
response = authenticated_client.get(
reverse("finding-metadata_latest"),
)
assert response.status_code == status.HTTP_200_OK
attributes = response.json()["data"]["attributes"]
assert attributes["services"] == latest_scan_finding.resource_services
assert attributes["regions"] == latest_scan_finding.resource_regions
assert attributes["resource_types"] == latest_scan_finding.resource_types
@pytest.mark.django_db
class TestJWTFields:
+33
View File
@@ -0,0 +1,33 @@
from rest_framework.response import Response
class PaginateByPkMixin:
"""
Mixin to paginate on a list of PKs (cheaper than heavy JOINs),
re-fetch the full objects with the desired select/prefetch,
re-sort them to preserve DB ordering, then serialize + return.
"""
def paginate_by_pk(
self,
request, # noqa: F841
base_queryset,
manager,
select_related: list[str] | None = None,
prefetch_related: list[str] | None = None,
) -> Response:
pk_list = base_queryset.values_list("id", flat=True)
page = self.paginate_queryset(pk_list)
if page is None:
return Response(self.get_serializer(base_queryset, many=True).data)
queryset = manager.filter(id__in=page)
if select_related:
queryset = queryset.select_related(*select_related)
if prefetch_related:
queryset = queryset.prefetch_related(*prefetch_related)
queryset = sorted(queryset, key=lambda obj: page.index(obj.id))
serialized = self.get_serializer(queryset, many=True).data
return self.get_paginated_response(serialized)
+132 -17
View File
@@ -65,6 +65,7 @@ from api.filters import (
FindingFilter,
IntegrationFilter,
InvitationFilter,
LatestFindingFilter,
MembershipFilter,
ProviderFilter,
ProviderGroupFilter,
@@ -110,6 +111,7 @@ from api.utils import (
validate_invitation,
)
from api.uuid_utils import datetime_to_uuid7, uuid7_start
from api.v1.mixins import PaginateByPkMixin
from api.v1.serializers import (
ComplianceOverviewFullSerializer,
ComplianceOverviewMetadataSerializer,
@@ -1671,10 +1673,24 @@ class ResourceViewSet(BaseRLSViewSet):
],
filters=True,
),
latest=extend_schema(
tags=["Finding"],
summary="List the latest findings",
description="Retrieve a list of the latest findings from the latest scans for each provider with options for "
"filtering by various criteria.",
filters=True,
),
metadata_latest=extend_schema(
tags=["Finding"],
summary="Retrieve metadata values from the latest findings",
description="Fetch unique metadata values from a set of findings from the latest scans for each provider. "
"This is useful for dynamic filtering.",
filters=True,
),
)
@method_decorator(CACHE_DECORATOR, name="list")
@method_decorator(CACHE_DECORATOR, name="retrieve")
class FindingViewSet(BaseRLSViewSet):
class FindingViewSet(PaginateByPkMixin, BaseRLSViewSet):
queryset = Finding.all_objects.all()
serializer_class = FindingSerializer
filterset_class = FindingFilter
@@ -1706,11 +1722,16 @@ class FindingViewSet(BaseRLSViewSet):
def get_serializer_class(self):
if self.action == "findings_services_regions":
return FindingDynamicFilterSerializer
elif self.action == "metadata":
elif self.action in ["metadata", "metadata_latest"]:
return FindingMetadataSerializer
return super().get_serializer_class()
def get_filterset_class(self):
if self.action in ["latest", "metadata_latest"]:
return LatestFindingFilter
return FindingFilter
def get_queryset(self):
tenant_id = self.request.tenant_id
user_roles = get_role(self.request.user)
@@ -1750,21 +1771,14 @@ class FindingViewSet(BaseRLSViewSet):
return super().filter_queryset(queryset)
def list(self, request, *args, **kwargs):
base_qs = self.filter_queryset(self.get_queryset())
paginated_ids = self.paginate_queryset(base_qs.values_list("id", flat=True))
if paginated_ids is not None:
ids = list(paginated_ids)
findings = (
Finding.all_objects.filter(tenant_id=self.request.tenant_id, id__in=ids)
.select_related("scan")
.prefetch_related("resources")
)
# Re-sort in Python to preserve ordering:
findings = sorted(findings, key=lambda x: ids.index(x.id))
serializer = self.get_serializer(findings, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(base_qs, many=True)
return Response(serializer.data)
filtered_queryset = self.filter_queryset(self.get_queryset())
return self.paginate_by_pk(
request,
filtered_queryset,
manager=Finding.all_objects,
select_related=["scan"],
prefetch_related=["resources"],
)
@action(detail=False, methods=["get"], url_name="findings_services_regions")
def findings_services_regions(self, request):
@@ -1897,6 +1911,107 @@ class FindingViewSet(BaseRLSViewSet):
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
@action(detail=False, methods=["get"], url_name="latest")
def latest(self, request):
tenant_id = request.tenant_id
filtered_queryset = self.filter_queryset(self.get_queryset())
latest_scan_ids = (
Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED)
.order_by("provider_id", "-inserted_at")
.distinct("provider_id")
.values_list("id", flat=True)
)
filtered_queryset = filtered_queryset.filter(
tenant_id=tenant_id, scan_id__in=latest_scan_ids
)
return self.paginate_by_pk(
request,
filtered_queryset,
manager=Finding.all_objects,
select_related=["scan"],
prefetch_related=["resources"],
)
@action(
detail=False,
methods=["get"],
url_name="metadata_latest",
url_path="metadata/latest",
)
def metadata_latest(self, request):
tenant_id = request.tenant_id
query_params = request.query_params
latest_scans_queryset = (
Scan.all_objects.filter(tenant_id=tenant_id, state=StateChoices.COMPLETED)
.order_by("provider_id", "-inserted_at")
.distinct("provider_id")
)
latest_scans_ids = list(latest_scans_queryset.values_list("id", flat=True))
queryset = ResourceScanSummary.objects.filter(
tenant_id=tenant_id,
scan_id__in=latest_scans_queryset.values_list("id", flat=True),
)
# ToRemove: Temporary fallback mechanism
present_ids = set(
ResourceScanSummary.objects.filter(
tenant_id=tenant_id, scan_id__in=latest_scans_ids
)
.values_list("scan_id", flat=True)
.distinct()
)
missing_scan_ids = [sid for sid in latest_scans_ids if sid not in present_ids]
if missing_scan_ids:
for scan_id in missing_scan_ids:
backfill_scan_resource_summaries_task.apply_async(
kwargs={"tenant_id": tenant_id, "scan_id": scan_id}
)
return Response(
get_findings_metadata_no_aggregations(
tenant_id, self.filter_queryset(self.get_queryset())
)
)
if service_filter := query_params.get("filter[service]") or query_params.get(
"filter[service__in]"
):
queryset = queryset.filter(service__in=service_filter.split(","))
if region_filter := query_params.get("filter[region]") or query_params.get(
"filter[region__in]"
):
queryset = queryset.filter(region__in=region_filter.split(","))
if resource_type_filter := query_params.get(
"filter[resource_type]"
) or query_params.get("filter[resource_type__in]"):
queryset = queryset.filter(
resource_type__in=resource_type_filter.split(",")
)
services = list(
queryset.values_list("service", flat=True).distinct().order_by("service")
)
regions = list(
queryset.values_list("region", flat=True).distinct().order_by("region")
)
resource_types = list(
queryset.values_list("resource_type", flat=True)
.distinct()
.order_by("resource_type")
)
result = {
"services": services,
"regions": regions,
"resource_types": resource_types,
}
serializer = self.get_serializer(data=result)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
@extend_schema_view(
list=extend_schema(
+41
View File
@@ -929,6 +929,47 @@ def backfill_scan_metadata_fixture(scans_fixture, findings_fixture):
backfill_resource_scan_summaries(tenant_id=tenant_id, scan_id=scan_id)
@pytest.fixture(scope="function")
def latest_scan_finding(authenticated_client, providers_fixture, resources_fixture):
provider = providers_fixture[0]
tenant_id = str(providers_fixture[0].tenant_id)
resource = resources_fixture[0]
scan = Scan.objects.create(
name="latest completed scan",
provider=provider,
trigger=Scan.TriggerChoices.MANUAL,
state=StateChoices.COMPLETED,
tenant_id=tenant_id,
)
finding = Finding.objects.create(
tenant_id=tenant_id,
uid="test_finding_uid_1",
scan=scan,
delta="new",
status=Status.FAIL,
status_extended="test status extended ",
impact=Severity.critical,
impact_extended="test impact extended one",
severity=Severity.critical,
raw_result={
"status": Status.FAIL,
"impact": Severity.critical,
"severity": Severity.critical,
},
tags={"test": "dev-qa"},
check_id="test_check_id",
check_metadata={
"CheckId": "test_check_id",
"Description": "test description apple sauce",
},
first_seen_at="2024-01-02T00:00:00Z",
)
finding.add_resources([resource])
backfill_resource_scan_summaries(tenant_id, str(scan.id))
return finding
def get_authorization_header(access_token: str) -> dict:
return {"Authorization": f"Bearer {access_token}"}
+4
View File
@@ -45,6 +45,9 @@ from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_azur
from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_gcp import (
ProwlerThreatScoreGCP,
)
from prowler.lib.outputs.compliance.prowler_threatscore.prowler_threatscore_m365 import (
ProwlerThreatScoreM365,
)
from prowler.lib.outputs.csv.csv import CSV
from prowler.lib.outputs.html.html import HTML
from prowler.lib.outputs.ocsf.ocsf import OCSF
@@ -85,6 +88,7 @@ COMPLIANCE_CLASS_MAP = {
],
"m365": [
(lambda name: name.startswith("cis_"), M365CIS),
(lambda name: name == "prowler_threatscore_m365", ProwlerThreatScoreM365),
],
}
+24
View File
@@ -0,0 +1,24 @@
import warnings
from dashboard.common_methods import get_section_containers_cis
warnings.filterwarnings("ignore")
def get_table(data):
aux = data[
[
"REQUIREMENTS_ID",
"REQUIREMENTS_DESCRIPTION",
"REQUIREMENTS_ATTRIBUTES_SECTION",
"CHECKID",
"STATUS",
"REGION",
"ACCOUNTID",
"RESOURCEID",
]
].copy()
return get_section_containers_cis(
aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION"
)
+2 -2
View File
@@ -38,11 +38,11 @@ prowler <provider> --list-checks
```
- Execute specific check(s):
```console
prowler <provider> -c/--checks s3_bucket_public_access
prowler <provider> -c/--checks s3_bucket_public_access iam_root_mfa_enabled
```
- Exclude specific check(s):
```console
prowler <provider> -e/--excluded-checks ec2 rds
prowler <provider> -e/--excluded-checks s3_bucket_public_access iam_root_mfa_enabled
```
- Execute checks that appears in a json file:
```json
+8
View File
@@ -14,11 +14,19 @@ All notable changes to the **Prowler SDK** are documented in this file.
- Add `repository_default_branch_requires_linear_history` check for GitHub provider. [(#6162)](https://github.com/prowler-cloud/prowler/pull/6162)
- Add `repository_default_branch_disallows_force_push` check for GitHub provider. [(#6197)](https://github.com/prowler-cloud/prowler/pull/6197)
- Add `repository_default_branch_deletion_disabled` check for GitHub provider. [(#6200)](https://github.com/prowler-cloud/prowler/pull/6200)
- Add `repository_default_branch_status_checks_required` check for GitHub provider. [(#6204)](https://github.com/prowler-cloud/prowler/pull/6204)
- Add `repository_default_branch_protection_applies_to_admins` check for GitHub provider. [(#6205)](https://github.com/prowler-cloud/prowler/pull/6205)
- Add `repository_branch_delete_on_merge_enabled` check for GitHub provider. [(#6209)](https://github.com/prowler-cloud/prowler/pull/6209)
- Add `repository_default_branch_requires_conversation_resolution` check for GitHub provider. [(#6208)](https://github.com/prowler-cloud/prowler/pull/6208)
- Add `organization_members_mfa_required` check for GitHub provider. [(#6304)](https://github.com/prowler-cloud/prowler/pull/6304)
- Add GitHub provider documentation and CIS v1.0.0 compliance. [(#6116)](https://github.com/prowler-cloud/prowler/pull/6116)
- Add CIS 5.0 compliance framework for AWS. [(7766)](https://github.com/prowler-cloud/prowler/pull/7766)
### Fixed
- Update CIS 4.0 for M365 provider. [(#7699)](https://github.com/prowler-cloud/prowler/pull/7699)
- Update and upgrade CIS for all the providers [(#7738)](https://github.com/prowler-cloud/prowler/pull/7738)
- Cover policies with conditions with SNS endpoint in `sns_topics_not_publicly_accessible`. [(#7750)](https://github.com/prowler-cloud/prowler/pull/7750)
- Change severity logic for `ec2_securitygroup_allow_ingress_from_internet_to_all_ports` check. [(#7764)](https://github.com/prowler-cloud/prowler/pull/7764)
---
+64 -64
View File
@@ -12,7 +12,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
@@ -33,7 +33,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
@@ -54,7 +54,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
@@ -76,7 +76,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
@@ -97,7 +97,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
@@ -118,7 +118,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
@@ -139,7 +139,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.",
@@ -161,7 +161,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
@@ -182,7 +182,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
@@ -203,7 +203,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
@@ -224,7 +224,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
@@ -245,7 +245,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
@@ -266,7 +266,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
@@ -287,7 +287,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
@@ -308,7 +308,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
@@ -329,7 +329,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
@@ -350,7 +350,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
@@ -371,7 +371,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
@@ -392,7 +392,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
@@ -413,7 +413,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
@@ -434,7 +434,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
@@ -455,8 +455,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
@@ -477,8 +477,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -499,8 +499,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -521,8 +521,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -544,8 +544,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -566,7 +566,7 @@
],
"Attributes": [
{
"Section": "2. Storage",
"Section": "2 Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
@@ -589,8 +589,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -611,7 +611,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
@@ -632,7 +632,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -653,7 +653,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -674,7 +674,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
@@ -695,7 +695,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
@@ -716,7 +716,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
@@ -737,7 +737,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
@@ -758,7 +758,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
@@ -779,7 +779,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
@@ -800,7 +800,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
@@ -821,7 +821,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
@@ -842,7 +842,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
@@ -863,7 +863,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
@@ -884,7 +884,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
@@ -905,7 +905,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
@@ -926,7 +926,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
@@ -947,7 +947,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
@@ -968,7 +968,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
@@ -989,7 +989,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
@@ -1010,7 +1010,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
@@ -1031,7 +1031,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
@@ -1052,7 +1052,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1073,7 +1073,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
@@ -1094,7 +1094,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
@@ -1115,7 +1115,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
@@ -1136,7 +1136,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1159,7 +1159,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1182,7 +1182,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1203,7 +1203,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
@@ -1224,7 +1224,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
+72 -72
View File
@@ -12,7 +12,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
@@ -33,7 +33,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
@@ -54,7 +54,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
@@ -76,7 +76,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
@@ -97,7 +97,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
@@ -118,7 +118,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
@@ -139,7 +139,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.",
@@ -161,7 +161,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
@@ -182,7 +182,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
@@ -203,7 +203,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
@@ -224,7 +224,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
@@ -245,7 +245,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
@@ -266,7 +266,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
@@ -287,7 +287,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
@@ -308,7 +308,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
@@ -329,7 +329,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
@@ -350,7 +350,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
@@ -371,7 +371,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
@@ -392,7 +392,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
@@ -413,7 +413,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
@@ -434,7 +434,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
@@ -455,8 +455,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides a variety of no, or low, cost encryption options to protect data at rest.",
@@ -477,8 +477,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -499,8 +499,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -521,8 +521,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -544,8 +544,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -566,8 +566,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2 Storage",
"SubSection": "2.2 Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -589,8 +589,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -611,8 +611,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -633,8 +633,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
@@ -655,7 +655,7 @@
],
"Attributes": [
{
"Section": "2. Storage",
"Section": "2 Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
@@ -677,7 +677,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
@@ -698,7 +698,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -719,7 +719,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -740,7 +740,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
@@ -761,7 +761,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
@@ -782,7 +782,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
@@ -803,7 +803,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
@@ -824,7 +824,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
@@ -845,7 +845,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
@@ -866,7 +866,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
@@ -887,7 +887,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
@@ -908,7 +908,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
@@ -929,7 +929,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
@@ -950,7 +950,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
@@ -971,7 +971,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
@@ -992,7 +992,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
@@ -1013,7 +1013,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
@@ -1034,7 +1034,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
@@ -1055,7 +1055,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
@@ -1076,7 +1076,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
@@ -1097,7 +1097,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
@@ -1118,7 +1118,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
@@ -1139,7 +1139,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1160,7 +1160,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
@@ -1181,7 +1181,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
@@ -1202,7 +1202,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
@@ -1223,7 +1223,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1246,7 +1246,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1269,7 +1269,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1292,7 +1292,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1313,7 +1313,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
@@ -1334,7 +1334,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
+71 -71
View File
@@ -12,7 +12,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
@@ -33,7 +33,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
@@ -54,7 +54,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
@@ -76,7 +76,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
@@ -97,7 +97,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
@@ -118,7 +118,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
@@ -139,7 +139,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.",
@@ -161,7 +161,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
@@ -182,7 +182,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
@@ -203,7 +203,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
@@ -224,7 +224,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
@@ -245,7 +245,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
@@ -266,7 +266,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
@@ -287,7 +287,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
@@ -308,7 +308,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers.",
@@ -329,7 +329,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
@@ -350,7 +350,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
@@ -371,7 +371,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
@@ -392,7 +392,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
@@ -413,7 +413,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
@@ -434,7 +434,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
@@ -455,7 +455,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
@@ -476,7 +476,7 @@
],
"Attributes": [
{
"Section": "2. Storage",
"Section": "2 Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
@@ -499,8 +499,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -521,8 +521,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -544,8 +544,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -566,8 +566,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2 Storage",
"SubSection": "2.2 Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -589,8 +589,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -611,8 +611,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -633,8 +633,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to any publicly accessible RDS database instance, you must disable the database Publicly Accessible flag and update the VPC security group associated with the instance.",
@@ -655,7 +655,7 @@
],
"Attributes": [
{
"Section": "2. Storage",
"Section": "2 Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
@@ -677,7 +677,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
@@ -698,7 +698,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -719,7 +719,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -740,7 +740,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
@@ -761,7 +761,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "CloudTrail logs a record of every API call made in your AWS account. These logs file are stored in an S3 bucket. It is recommended that the bucket policy or access control list (ACL) applied to the S3 bucket that CloudTrail logs to prevent public access to the CloudTrail logs.",
@@ -782,7 +782,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls made in a given AWS account. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail uses Amazon S3 for log file storage and delivery, so log files are stored durably. In addition to capturing CloudTrail logs within a specified S3 bucket for long term analysis, realtime analysis can be performed by configuring CloudTrail to send logs to CloudWatch Logs. For a trail that is enabled in all regions in an account, CloudTrail sends log files from all those regions to a CloudWatch Logs log group. It is recommended that CloudTrail logs be sent to CloudWatch Logs. Note: The intent of this recommendation is to ensure AWS account activity is being captured, monitored, and appropriately alarmed on. CloudWatch Logs is a native way to accomplish this using AWS services but does not preclude the use of an alternate solution.",
@@ -803,7 +803,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
@@ -824,7 +824,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
@@ -845,7 +845,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
@@ -866,7 +866,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
@@ -887,7 +887,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
@@ -908,7 +908,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
@@ -929,7 +929,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
@@ -950,7 +950,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
@@ -971,7 +971,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
@@ -992,7 +992,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
@@ -1013,7 +1013,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
@@ -1034,7 +1034,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
@@ -1055,7 +1055,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
@@ -1076,7 +1076,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
@@ -1097,7 +1097,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
@@ -1118,7 +1118,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
@@ -1139,7 +1139,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1160,7 +1160,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
@@ -1181,7 +1181,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
@@ -1202,7 +1202,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
@@ -1223,7 +1223,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1246,7 +1246,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1269,7 +1269,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1292,7 +1292,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1313,7 +1313,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
@@ -1334,7 +1334,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
@@ -1356,7 +1356,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
+70 -70
View File
@@ -12,7 +12,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization. An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of Acceptable Use Policy or indicative of likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
@@ -33,7 +33,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
@@ -54,7 +54,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When cerating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
@@ -76,7 +76,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed.",
@@ -97,7 +97,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
@@ -118,7 +118,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be regularly rotated.",
@@ -139,7 +139,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM users are granted access to services, functions, and data through IAM policies. There are three ways to define policies for a user: 1) Edit the user policy directly, aka an inline, or user, policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy. Only the third implementation is recommended.",
@@ -161,7 +161,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered a standard security advice to grant _least privilege_ -that is, granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform _only_ those tasks, instead of allowing full administrative privileges.",
@@ -182,7 +182,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role to allow authorized users to manage incidents with AWS Support.",
@@ -203,7 +203,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. \"AWS Access\" means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
@@ -224,7 +224,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use ACM or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
@@ -245,7 +245,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
@@ -266,7 +266,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable IAM Access analyzer for IAM policies about all resources in each region. IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. So the results allow you to determine if an unintended user is allowed, making it easier for administrators to monitor least privileges access. Access Analyzer analyzes only policies that are applied to resources in the same AWS Region.",
@@ -287,7 +287,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
@@ -306,7 +306,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment a user has sudo permissions, and can access the internet. So it is feasible to install file transfer software (for example) and move data from CloudShell to external internet servers.",
@@ -327,7 +327,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
@@ -348,7 +348,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be removed.",
@@ -369,7 +369,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device. **Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is managed to be kept charged and secured independent of any individual personal devices. (\"non-personal virtual MFA\") This lessens the risks of losing access to the MFA due to device loss, device trade-in or if the individual owning the device is no longer employed at the company.",
@@ -390,7 +390,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
@@ -411,7 +411,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
@@ -432,7 +432,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure password are at least a given length. It is recommended that the password policy require a minimum password length 14.",
@@ -453,7 +453,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
@@ -474,8 +474,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "At the Amazon S3 bucket level, you can configure permissions through a bucket policy making the objects accessible only through HTTPS.",
@@ -496,8 +496,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
@@ -518,8 +518,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Amazon S3 buckets can contain sensitive data, that for security purposes should be discovered, monitored, classified and protected. Macie along with other 3rd party tools can automatically provide an inventory of Amazon S3 buckets.",
@@ -541,8 +541,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.1. Simple Storage Service (S3)",
"Section": "2 Storage",
"SubSection": "2.1 Simple Storage Service (S3)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon S3 provides `Block public access (bucket settings)` and `Block public access (account settings)` to help you manage public access to Amazon S3 resources. By default, S3 buckets and objects are created with public access disabled. However, an IAM principal with sufficient S3 permissions can enable public access at the bucket and/or object level. While enabled, `Block public access (bucket settings)` prevents an individual bucket, and its contained objects, from becoming publicly accessible. Similarly, `Block public access (account settings)` prevents all buckets, and contained objects, from becoming publicly accessible across the entire account.",
@@ -563,8 +563,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.2. Elastic Compute Cloud (EC2)",
"Section": "2 Storage",
"SubSection": "2.2 Elastic Compute Cloud (EC2)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.",
@@ -585,8 +585,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Amazon RDS encrypted DB instances use the industry standard AES-256 encryption algorithm to encrypt your data on the server that hosts your Amazon RDS DB instances. After your data is encrypted, Amazon RDS handles authentication of access and decryption of your data transparently with a minimal impact on performance.",
@@ -607,8 +607,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure that RDS database instances have the Auto Minor Version Upgrade flag enabled in order to receive automatically minor engine upgrades during the specified maintenance window. So, RDS instances can get the new features, bug fixes, and security patches for their database engines.",
@@ -629,8 +629,8 @@
],
"Attributes": [
{
"Section": "2. Storage",
"SubSection": "2.3. Relational Database Service (RDS)",
"Section": "2 Storage",
"SubSection": "2.3 Relational Database Service (RDS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure and verify that RDS database instances provisioned in your AWS account do restrict unauthorized access in order to minimize security risks. To restrict access to anypublicly accessible RDS database instance, you must disable the database PubliclyAccessible flag and update the VPC security group associated with the instance",
@@ -651,7 +651,7 @@
],
"Attributes": [
{
"Section": "2. Storage",
"Section": "2 Storage",
"SubSection": "2.4 Elastic File System (EFS)",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
@@ -673,7 +673,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
@@ -694,7 +694,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -715,7 +715,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations such as GetObject, DeleteObject, and PutObject are called data events. By default, CloudTrail trails don't log data events and so it is recommended to enable Object-level logging for S3 buckets.",
@@ -736,7 +736,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled on all CloudTrails.",
@@ -757,7 +757,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.",
@@ -778,7 +778,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "S3 Bucket Access Logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that bucket access logging be enabled on the CloudTrail S3 bucket.",
@@ -799,7 +799,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
@@ -820,7 +820,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation can not be enabled for any asymmetric CMK.",
@@ -841,7 +841,7 @@
],
"Attributes": [
{
"Section": "3. Logging",
"Section": "3 Logging",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.",
@@ -862,7 +862,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
@@ -883,7 +883,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Security Groups are a stateful packet filter that controls ingress and egress traffic within a VPC. It is recommended that a metric filter and alarm be established for detecting changes to Security Groups.",
@@ -904,7 +904,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for changes made to NACLs.",
@@ -925,7 +925,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
@@ -946,7 +946,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways. It is recommended that a metric filter and alarm be established for changes to route tables.",
@@ -967,7 +967,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is possible to have more than 1 VPC within an account, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs. It is recommended that a metric filter and alarm be established for changes made to VPCs.",
@@ -988,7 +988,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for AWS Organizations changes made in the master AWS Account.",
@@ -1009,7 +1009,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Security Hub collects security data from across AWS accounts, services, and supported third-party partner products and helps you analyze your security trends and identify the highest priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
@@ -1030,7 +1030,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
@@ -1051,7 +1051,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts.",
@@ -1072,7 +1072,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established changes made to Identity and Access Management (IAM) policies.",
@@ -1093,7 +1093,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1114,7 +1114,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
@@ -1135,7 +1135,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer created CMKs which have changed state to disabled or scheduled deletion.",
@@ -1156,7 +1156,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
@@ -1177,7 +1177,7 @@
],
"Attributes": [
{
"Section": "4. Monitoring",
"Section": "4 Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to CloudTrail's configurations.",
@@ -1200,7 +1200,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The Network Access Control List (NACL) function provide stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1223,7 +1223,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1246,7 +1246,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH to port `22` and RDP to port `3389`.",
@@ -1267,7 +1267,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If you don't specify a security group when you launch an instance, the instance is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic. The default VPC in every region should have its default security group updated to comply. Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation. **NOTE:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly because it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering - discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
@@ -1288,7 +1288,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Once a VPC peering connection is established, routing tables must be updated to establish any connections between the peered VPCs. These routes can be as specific as desired - even peering a VPC to only a single host on the other side of the connection.",
@@ -1309,7 +1309,7 @@
],
"Attributes": [
{
"Section": "5. Networking",
"Section": "5 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
-53
View File
@@ -13,7 +13,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Ensure contact email and telephone details for AWS accounts are current and map to more than one individual in your organization.An AWS account supports a number of contact details, and AWS will use these to contact the account owner if activity judged to be in breach of the Acceptable Use Policy or indicative of a likely security compromise is observed by the AWS Abuse team. Contact details should not be for a single individual, as circumstances may arise where that individual is unavailable. Email contact details should point to a mail alias which forwards email to multiple individuals within the organization; where feasible, phone contact details should point to a PABX hunt group or other call-forwarding system.",
@@ -36,7 +35,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS provides customers with the option of specifying the contact information for account's security team. It is recommended that this information be provided.",
@@ -59,7 +57,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "The AWS support portal allows account owners to establish security questions that can be used to authenticate individuals calling AWS customer service for support. It is recommended that security questions be established.",
@@ -82,7 +79,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. AWS Access Keys provide programmatic access to a given AWS account. It is recommended that all access keys associated with the 'root' user account be deleted.",
@@ -105,7 +101,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The 'root' user account is the most privileged user in an AWS account. Multi-factor Authentication (MFA) adds an extra layer of protection on top of a username and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their username and password as well as for an authentication code from their AWS MFA device.**Note:** When virtual MFA is used for 'root' accounts, it is recommended that the device used is NOT a personal device, but rather a dedicated mobile device (tablet or phone) that is kept charged and secured, independent of any individual personal devices (non-personal virtual MFA). This lessens the risks of losing access to the MFA due to device loss, device trade-in, or if the individual owning the device is no longer employed at the company.",
@@ -128,7 +123,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "The 'root' user account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the 'root' user account be protected with a hardware MFA.",
@@ -151,7 +145,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "With the creation of an AWS account, a 'root user' is created that cannot be disabled or deleted. That user has unrestricted access to and control over all resources in the AWS account. It is highly recommended that the use of this account be avoided for everyday tasks.",
@@ -174,7 +167,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Password policies are, in part, used to enforce password complexity requirements. IAM password policies can be used to ensure passwords are at least a given length. It is recommended that the password policy require a minimum password length 14.",
@@ -197,7 +189,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM password policies can prevent the reuse of a given password by the same user. It is recommended that the password policy prevent the reuse of passwords.",
@@ -220,7 +211,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Multi-Factor Authentication (MFA) adds an extra layer of authentication assurance beyond traditional credentials. With MFA enabled, when a user signs in to the AWS Console, they will be prompted for their user name and password as well as for an authentication code from their physical or virtual MFA token. It is recommended that MFA be enabled for all accounts that have a console password.",
@@ -243,7 +233,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS console defaults to no check boxes selected when creating a new IAM user. When creating the IAM User credentials you have to determine what type of access they require. Programmatic access: The IAM user might need to make API calls, use the AWS CLI, or use the Tools for Windows PowerShell. In that case, create an access key (access key ID and a secret access key) for that user. AWS Management Console access: If the user needs to access the AWS Management Console, create a password for the user.",
@@ -267,7 +256,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS IAM users can access AWS resources using different types of credentials, such as passwords or access keys. It is recommended that all credentials that have been unused for 45 days or more be deactivated or removed.",
@@ -290,7 +278,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys are long-term credentials for an IAM user or the AWS account 'root' user. You can use access keys to sign programmatic requests to the AWS CLI or AWS API (directly or using the AWS SDK)",
@@ -313,7 +300,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Access keys consist of an access key ID and secret access key, which are used to sign programmatic requests that you make to AWS. AWS users need their own access keys to make programmatic calls to AWS from the AWS Command Line Interface (AWS CLI), Tools for Windows PowerShell, the AWS SDKs, or direct HTTP calls using the APIs for individual AWS services. It is recommended that all access keys be rotated regularly.",
@@ -336,7 +322,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM users are granted access to services, functions, and data through IAM policies. There are four ways to define policies for a user: 1) Edit the user policy directly, also known as an inline or user policy; 2) attach a policy directly to a user; 3) add the user to an IAM group that has an attached policy; 4) add the user to an IAM group that has an inline policy.Only the third implementation is recommended.",
@@ -360,7 +345,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "IAM policies are the means by which privileges are granted to users, groups, or roles. It is recommended and considered standard security advice to grant least privilege—that is, granting only the permissions required to perform a task. Determine what users need to do, and then craft policies for them that allow the users to perform only those tasks, instead of granting full administrative privileges.",
@@ -383,7 +367,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS provides a support center that can be used for incident notification and response, as well as technical support and customer services. Create an IAM Role, with the appropriate policy assigned, to allow authorized users to manage incidents with AWS Support.",
@@ -406,7 +389,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS access from within AWS instances can be done by either encoding AWS keys into AWS API calls or by assigning the instance to a role which has an appropriate permissions policy for the required access. AWS Access means accessing the APIs of AWS in order to access AWS resources or manage AWS account resources.",
@@ -429,7 +411,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To enable HTTPS connections to your website or application in AWS, you need an SSL/TLS server certificate. You can use AWS Certificate Manager (ACM) or IAM to store and deploy server certificates. Use IAM as a certificate manager only when you must support HTTPS connections in a region that is not supported by ACM. IAM securely encrypts your private keys and stores the encrypted version in IAM SSL certificate storage. IAM supports deploying server certificates in all regions, but you must obtain your certificate from an external provider for use with AWS. You cannot upload an ACM certificate to IAM. Additionally, you cannot manage your certificates from the IAM Console.",
@@ -452,7 +433,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enable the IAM Access Analyzer for IAM policies regarding all resources in each active AWS region.IAM Access Analyzer is a technology introduced at AWS reinvent 2019. After the Analyzer is enabled in IAM, scan results are displayed on the console showing the accessible resources. Scans show resources that other accounts and federated users can access, such as KMS keys and IAM roles. The results allow you to determine whether an unintended user is permitted, making it easier for administrators to monitor least privilege access. Access Analyzer analyzes only the policies that are applied to resources in the same AWS Region.",
@@ -475,7 +455,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In multi-account environments, IAM user centralization facilitates greater user control. User access beyond the initial account is then provided via role assumption. Centralization of users can be accomplished through federation with an external identity provider or through the use of AWS Organizations.",
@@ -498,7 +477,6 @@
"Attributes": [
{
"Section": "1 Identity and Access Management",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "AWS CloudShell is a convenient way of running CLI commands against AWS services; a managed IAM policy ('AWSCloudShellFullAccess') provides full access to CloudShell, which allows file upload and download capability between a user's local system and the CloudShell environment. Within the CloudShell environment, a user has sudo permissions and can access the internet. Therefore, it is feasible to install file transfer software, for example, and move data from CloudShell to external internet servers.",
@@ -730,7 +708,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for your account and delivers log files to you. The recorded information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the AWS service. CloudTrail provides a history of AWS API calls for an account, including API calls made via the Management Console, SDKs, command line tools, and higher-level AWS services (such as CloudFormation).",
@@ -753,7 +730,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "CloudTrail log file validation creates a digitally signed digest file containing a hash of each log that CloudTrail writes to S3. These digest files can be used to determine whether a log file was changed, deleted, or remained unchanged after CloudTrail delivered the log. It is recommended that file validation be enabled for all CloudTrails.",
@@ -776,7 +752,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration items (AWS resources), relationships between configuration items (AWS resources), and any configuration changes between resources. It is recommended that AWS Config be enabled in all regions.",
@@ -799,7 +774,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Server access logging generates a log that contains access records for each request made to your S3 bucket. An access log record contains details about the request, such as the request type, the resources specified in the request worked, and the time and date the request was processed. It is recommended that server access logging be enabled on the CloudTrail S3 bucket.",
@@ -822,7 +796,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS CloudTrail is a web service that records AWS API calls for an account and makes those logs available to users and resources in accordance with IAM policies. AWS Key Management Service (KMS) is a managed service that helps create and control the encryption keys used to encrypt account data, and uses Hardware Security Modules (HSMs) to protect the security of encryption keys. CloudTrail logs can be configured to leverage server side encryption (SSE) and KMS customer-created master keys (CMK) to further protect CloudTrail logs. It is recommended that CloudTrail be configured to use SSE-KMS.",
@@ -845,7 +818,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "AWS Key Management Service (KMS) allows customers to rotate the backing key, which is key material stored within the KMS that is tied to the key ID of the customer-created customer master key (CMK). The backing key is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can occur transparently. It is recommended that CMK key rotation be enabled for symmetric keys. Key rotation cannot be enabled for any asymmetric CMK.",
@@ -868,7 +840,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet Rejects for VPCs.",
@@ -891,7 +862,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
@@ -914,7 +884,6 @@
"Attributes": [
{
"Section": "3 Logging",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "S3 object-level API operations, such as GetObject, DeleteObject, and PutObject, are referred to as data events. By default, CloudTrail trails do not log data events, so it is recommended to enable object-level logging for S3 buckets.",
@@ -937,7 +906,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for unauthorized API calls.",
@@ -960,7 +928,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for console logins that are not protected by multi-factor authentication (MFA).",
@@ -983,7 +950,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for 'root' login attempts to detect unauthorized use or attempts to use the root account.",
@@ -1006,7 +972,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms.It is recommended that a metric filter and alarm be established for changes made to Identity and Access Management (IAM) policies.",
@@ -1029,7 +994,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be used to detect changes to CloudTrail's configurations.",
@@ -1052,7 +1016,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for failed console authentication attempts.",
@@ -1075,7 +1038,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for customer-created CMKs that have changed state to disabled or are scheduled for deletion.",
@@ -1098,7 +1060,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes to S3 bucket policies.",
@@ -1121,7 +1082,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for detecting changes to AWS Config's configurations.",
@@ -1144,7 +1104,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Security groups are stateful packet filters that control ingress and egress traffic within a VPC.It is recommended that a metric filter and alarm be established to detect changes to security groups.",
@@ -1167,7 +1126,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. NACLs are used as a stateless packet filter to control ingress and egress traffic for subnets within a VPC. It is recommended that a metric filter and alarm be established for any changes made to NACLs.",
@@ -1190,7 +1148,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Network gateways are required to send and receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.",
@@ -1213,7 +1170,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. Routing tables are used to route network traffic between subnets and to network gateways.It is recommended that a metric filter and alarm be established for changes to route tables.",
@@ -1236,7 +1192,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is possible to have more than one VPC within an account; additionally, it is also possible to create a peer connection between two VPCs, enabling network traffic to route between them.It is recommended that a metric filter and alarm be established for changes made to VPCs.",
@@ -1259,7 +1214,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs or an external Security Information and Event Management (SIEM) environment, and establishing corresponding metric filters and alarms. It is recommended that a metric filter and alarm be established for changes made to AWS Organizations in the master AWS account.",
@@ -1282,7 +1236,6 @@
"Attributes": [
{
"Section": "4 Monitoring",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Security Hub collects security data from various AWS accounts, services, and supported third-party partner products, helping you analyze your security trends and identify the highest-priority security issues. When you enable Security Hub, it begins to consume, aggregate, organize, and prioritize findings from the AWS services that you have enabled, such as Amazon GuardDuty, Amazon Inspector, and Amazon Macie. You can also enable integrations with AWS partner security products.",
@@ -1307,7 +1260,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The Network Access Control List (NACL) function provides stateless filtering of ingress and egress network traffic to AWS resources. It is recommended that no NACL allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
@@ -1332,7 +1284,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`, using either the TCP (6), UDP (17), or ALL (-1) protocols.",
@@ -1357,7 +1308,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Security groups provide stateful filtering of ingress and egress network traffic to AWS resources. It is recommended that no security group allows unrestricted ingress access to remote server administration ports, such as SSH on port `22` and RDP on port `3389`.",
@@ -1380,7 +1330,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "A VPC comes with a default security group whose initial settings deny all inbound traffic, allow all outbound traffic, and allow all traffic between instances assigned to the security group. If a security group is not specified when an instance is launched, it is automatically assigned to this default security group. Security groups provide stateful filtering of ingress/egress network traffic to AWS resources. It is recommended that the default security group restrict all traffic, both inbound and outbound.The default VPC in every region should have its default security group updated to comply with the following: - No inbound rules. - No outbound rules.Any newly created VPCs will automatically contain a default security group that will need remediation to comply with this recommendation.**Note:** When implementing this recommendation, VPC flow logging is invaluable in determining the least privilege port access required by systems to work properly, as it can log all packet acceptances and rejections occurring under the current security groups. This dramatically reduces the primary barrier to least privilege engineering by discovering the minimum ports required by systems in the environment. Even if the VPC flow logging recommendation in this benchmark is not adopted as a permanent security measure, it should be used during any period of discovery and engineering for least privileged security groups.",
@@ -1403,7 +1352,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Once a VPC peering connection is established, routing tables must be updated to enable any connections between the peered VPCs. These routes can be as specific as desired, even allowing for the peering of a VPC to only a single host on the other side of the connection.",
@@ -1426,7 +1374,6 @@
"Attributes": [
{
"Section": "5 Networking",
"SubSection": "",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "When enabling the Metadata Service on AWS EC2 instances, users have the option of using either Instance Metadata Service Version 1 (IMDSv1; a request/response method) or Instance Metadata Service Version 2 (IMDSv2; a session-oriented method).",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+103 -103
View File
@@ -10,7 +10,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Use corporate login credentials instead of personal accounts, such as Gmail accounts.",
@@ -29,7 +29,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Setup multi-factor authentication for Google Cloud Platform accounts.",
@@ -48,7 +48,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Setup Security Key Enforcement for Google Cloud Platform admin accounts.",
@@ -69,7 +69,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. API keys are always at risk because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API keys to use (call) only APIs required by an application.",
@@ -90,7 +90,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. If they are in use it is recommended to rotate API keys every 90 days.",
@@ -111,7 +111,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. Unused keys with their permissions in tact may still exist within a project. Keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to use standard authentication flow instead.",
@@ -132,7 +132,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that Essential Contacts is configured to designate email addresses for Google Cloud services to notify of important technical or security information.",
@@ -153,7 +153,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Google Cloud Key Management Service stores cryptographic keys in a hierarchical structure designed for useful and elegant access control management. The format for the rotation schedule depends on the client library that is used. For the gcloud command-line tool, the next rotation time must be in `ISO` or `RFC3339` format, and the rotation period must be in the form `INTEGERUNIT`, where units can be one of seconds (s), minutes (m), hours (h) or days (d).",
@@ -174,7 +174,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the IAM policy on Cloud KMS `cryptokeys` should restrict anonymous and/or public access.",
@@ -195,7 +195,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "When you use Dataproc, cluster and job data is stored on Persistent Disks (PDs) associated with the Compute Engine VMs in your cluster and in a Cloud Storage staging bucket. This PD and bucket data is encrypted using a Google-generated data encryption key (DEK) and key encryption key (KEK). The CMEK feature allows you to create, use, and revoke the key encryption key (KEK). Google still controls the data encryption key (DEK).",
@@ -216,7 +216,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to assign the `Service Account User (iam.serviceAccountUser)` and `Service Account Token Creator (iam.serviceAccountTokenCreator)` roles to a user for a specific service account rather than assigning the role to a user at project level.",
@@ -237,7 +237,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning KMS related roles to users.",
@@ -256,7 +256,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. In this case, unrestricted keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API key usage to trusted hosts, HTTP referrers and apps. It is recommended to use the more secure standard authentication flow instead.",
@@ -277,7 +277,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning service-account related roles to users.",
@@ -298,7 +298,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "A service account is a special Google account that belongs to an application or a VM, instead of to an individual end-user. The application uses the service account to call the service's Google API so that users aren't directly involved. It's recommended not to use admin access for ServiceAccount.",
@@ -319,7 +319,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "User managed service accounts should not have user-managed keys.",
@@ -340,7 +340,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Service Account keys consist of a key ID (Private_key_Id) and Private key, which are used to sign programmatic requests users make to Google cloud services accessible to that particular service account. It is recommended that all Service Account keys are regularly rotated.",
@@ -359,7 +359,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Google Cloud Functions allow you to host serverless code that is executed when an event is triggered, without the requiring the management a host operating system. These functions can also store environment variables to be used by the code that may contain authentication or other information that needs to remain confidential.",
@@ -380,7 +380,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP Access Approval enables you to require your organizations' explicit approval whenever Google support try to access your projects. You can then select users within your organization who can approve these requests through giving them a security role in IAM. All access requests display which Google Employee requested them in an email or Pub/Sub message that you can choose to Approve. This adds an additional control and logging of who in your organization approved/denied these requests.",
@@ -401,7 +401,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.",
@@ -422,7 +422,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "In order to prevent unnecessary project ownership assignments to users/service-accounts and further misuses of projects and resources, all `roles/Owner` assignments should be monitored. Members (users/Service-Accounts) with a role assignment to primitive role `roles/Owner` are project owners. The project owner has all the privileges on the project the role belongs to. These are summarized below: - All viewer permissions on all GCP Services within the project - Permissions for actions that modify the state of all GCP services within the project - Manage roles and permissions for a project and all resources within the project - Set up billing for a project Granting the owner role to a member (user/Service-Account) will allow that member to modify the Identity and Access Management (IAM) policy. Therefore, grant the owner role only if the member has a legitimate purpose to manage the IAM policy. This is because the project IAM policy contains sensitive access control data. Having a minimal set of users allowed to manage IAM policy will simplify any auditing that may be necessary.",
@@ -443,7 +443,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Logging enabled on a HTTPS Load Balancer will show all network traffic and its destination.",
@@ -464,7 +464,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that Cloud Audit Logging is configured to track all admin activities and read, write access to user data.",
@@ -485,7 +485,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Cloud DNS logging records the queries from the name servers within your VPC to Stackdriver. Logged queries can come from Compute Engine VMs, GKE containers, or other GCP resources provisioned within the VPC.",
@@ -506,7 +506,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enabling retention policies on log buckets will protect logs stored in cloud storage buckets from being overwritten or accidentally deleted. It is recommended to set up retention policies and configure Bucket Lock on all storage buckets that are used as log sinks.",
@@ -527,7 +527,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to create a sink that will export copies of all the log entries. This can help aggregate logs from multiple projects and export them to a Security Information and Event Management (SIEM).",
@@ -548,7 +548,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Google Cloud Platform (GCP) services write audit log entries to the Admin Activity and Data Access logs to help answer the questions of, \"who did what, where, and when?\" within GCP projects. Cloud audit logging records information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by GCP services. Cloud audit logging provides a history of GCP API calls for an account, including API calls made via the console, SDKs, command-line tools, and other GCP services.",
@@ -569,7 +569,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Cloud Storage Bucket IAM changes.",
@@ -590,7 +590,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for changes to Identity and Access Management (IAM) role creation, deletion and updating activities.",
@@ -611,7 +611,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for SQL instance configuration changes.",
@@ -632,7 +632,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network changes.",
@@ -651,7 +651,7 @@
"Checks": [],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "GCP Access Transparency provides audit logs for all actions that Google personnel take in your Google Cloud resources.",
@@ -672,7 +672,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) Network Firewall rule changes.",
@@ -693,7 +693,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network route changes.",
@@ -714,7 +714,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "In order to prevent use of legacy networks, a project should not have a legacy network configured. As of now, Legacy Networks are gradually being phased out, and you can no longer create projects with them. This recommendation is to check older projects to ensure that they are not using Legacy Networks.",
@@ -735,7 +735,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Cloud Domain Name System (DNS) is a fast, reliable and cost-effective domain name system that powers millions of domains on the internet. Domain Name System Security Extensions (DNSSEC) in Cloud DNS enables domain owners to take easy steps to protect their domains against DNS hijacking and man-in-the-middle and other attacks.",
@@ -756,7 +756,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow users to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances. Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the Internet to a VPC or VM instance using `RDP` on `Port 3389` can be avoided.",
@@ -777,7 +777,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract. DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
@@ -798,7 +798,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract. DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
@@ -819,7 +819,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow the user to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances. Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, only an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the internet to VPC or VM instance using `SSH` on `Port 22` can be avoided.",
@@ -840,7 +840,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "To prevent use of `default` network, a project should not have a `default` network.",
@@ -861,7 +861,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Flow Logs is a feature that enables users to capture information about the IP traffic going to and from network interfaces in the organization's VPC Subnets. Once a flow log is created, the user can view and retrieve its data in Stackdriver Logging. It is recommended that Flow Logs be enabled for every business-critical VPC subnet.",
@@ -880,7 +880,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Secure Sockets Layer (SSL) policies determine what port Transport Layer Security (TLS) features clients are permitted to use when connecting to load balancers. To prevent usage of insecure features, SSL policies should use (a) at least TLS 1.2 with the MODERN profile; or (b) the RESTRICTED profile, because it effectively requires clients to use TLS 1.2 regardless of the chosen minimum TLS version; or (3) a CUSTOM profile that does not support any of the following features: ``` TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA ```",
@@ -899,7 +899,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "IAP authenticates the user requests to your apps via a Google single sign in. You can then manage these users with permissions to control access. It is recommended to use both IAP permissions and firewalls to restrict this access to your apps with sensitive information.",
@@ -920,7 +920,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Interacting with a serial port is often referred to as the serial console, which is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support. If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. Therefore interactive serial console support should be disabled.",
@@ -941,7 +941,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to use Instance specific SSH key(s) instead of using common/shared project-wide SSH key(s) to access Instances.",
@@ -962,7 +962,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "To defend against advanced threats and ensure that the boot loader and firmware on your VMs are signed and untampered, it is recommended that Compute instances are launched with Shielded VM enabled.",
@@ -983,7 +983,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling OS login binds SSH certificates to IAM users and facilitates effective SSH certificate management.",
@@ -1004,7 +1004,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Compute instances should not be configured to have external IP addresses.",
@@ -1025,7 +1025,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Google Cloud encrypts data at-rest and in-transit, but customer data must be decrypted for processing. Confidential Computing is a breakthrough technology which encrypts data in-use—while it is being processed. Confidential Computing environments keep data encrypted in memory and elsewhere outside the central processing unit (CPU). Confidential VMs leverage the Secure Encrypted Virtualization (SEV) feature of AMD EPYC™ CPUs. Customer data will stay encrypted while it is used, indexed, queried, or trained on. Encryption keys are generated in hardware, per VM, and not exportable. Thanks to built-in hardware optimizations of both performance and security, there is no significant performance penalty to Confidential Computing workloads.",
@@ -1046,7 +1046,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to configure your instance to not use the default Compute Engine service account because it has the Editor role on the project.",
@@ -1067,7 +1067,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account `Compute Engine default service account` with Scope `Allow full access to all Cloud APIs`.",
@@ -1088,7 +1088,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets. Forwarding of data packets should be disabled to prevent data loss or information disclosure.",
@@ -1107,7 +1107,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In order to maintain the highest level of security all connections to an application should be secure by default.",
@@ -1128,7 +1128,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Customer-Supplied Encryption Keys (CSEK) are a feature in Google Cloud Storage and Google Compute Engine. If you supply your own encryption keys, Google uses your key to protect the Google-generated keys used to encrypt and decrypt your data. By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.",
@@ -1147,7 +1147,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Google Cloud Virtual Machines have the ability via an OS Config agent API to periodically (about every 10 minutes) report OS inventory data. A patch compliance API periodically reads this data, and cross references metadata to determine if the latest updates are installed. This is not the only Patch Management solution available to your organization and you should weigh your needs before committing to using this method.",
@@ -1168,7 +1168,7 @@
],
"Attributes": [
{
"Section": "5. Storage",
"Section": "5 Storage",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that IAM policy on Cloud Storage bucket does not allows anonymous or public access.",
@@ -1189,7 +1189,7 @@
],
"Attributes": [
{
"Section": "5. Storage",
"Section": "5 Storage",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that uniform bucket-level access is enabled on Cloud Storage buckets.",
@@ -1210,7 +1210,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to have all SQL database instances set to enable automated backups.",
@@ -1231,7 +1231,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended to configure Second Generation Sql instance to use private IPs instead of public IPs.",
@@ -1252,7 +1252,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from public IP addresses.",
@@ -1273,7 +1273,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to enforce all incoming connections to SQL database instance to use SSL.",
@@ -1292,8 +1292,8 @@
"Checks": [],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "It is recommended to set a password for the administrative user (`root` by default) to prevent unauthorized access to the SQL database instances. This recommendation is applicable only for MySQL Instances. PostgreSQL does not offer any setting for No Password from the cloud console.",
@@ -1314,8 +1314,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `skip_show_database` database flag for Cloud SQL Mysql instance to `on`",
@@ -1336,8 +1336,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set the `local_infile` database flag for a Cloud SQL MySQL instance to `off`.",
@@ -1358,8 +1358,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The `log_error_verbosity` flag controls the verbosity/details of messages logged. Valid values are: - `TERSE` - `DEFAULT` - `VERBOSE` `TERSE` excludes the logging of `DETAIL`, `HINT`, `QUERY`, and `CONTEXT` error information. `VERBOSE` output includes the `SQLSTATE` error code, source code file name, function name, and line number that generated the error. Ensure an appropriate value is set to 'DEFAULT' or stricter.",
@@ -1380,8 +1380,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_error_statement` flag defines the minimum message severity level that are considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. Ensure a value of `ERROR` or stricter is set.",
@@ -1402,8 +1402,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The value of `log_statement` flag determined the SQL statements that are logged. Valid values are: - `none` - `ddl` - `mod` - `all` The value `ddl` logs all data definition statements. The value `mod` logs all ddl statements, plus data-modifying statements. The statements are logged after a basic parsing is done and statement type is determined, thus this does not logs statements with errors. When using extended query protocol, logging occurs after an Execute message is received and values of the Bind parameters are included. A value of 'ddl' is recommended unless otherwise directed by your organization's logging policy.",
@@ -1424,8 +1424,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Instance addresses can be public IP or private IP. Public IP means that the instance is accessible through the public internet. In contrast, instances using only private IP are not accessible through the public internet, but are accessible through a Virtual Private Cloud (VPC). Limiting network access to your database will limit potential attacks.",
@@ -1446,8 +1446,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure `cloudsql.enable_pgaudit` database flag for Cloud SQL PostgreSQL instance is set to `on` to allow for centralized logging.",
@@ -1468,8 +1468,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_connections` setting causes each attempted connection to the server to be logged, along with successful completion of client authentication. This parameter cannot be changed after the session starts.",
@@ -1490,8 +1490,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_disconnections` setting logs the end of each session, including the session duration.",
@@ -1512,8 +1512,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_duration_statement` flag defines the minimum amount of execution time of a statement in milliseconds where the total duration of the statement is logged. Ensure that `log_min_duration_statement` is disabled, i.e., a value of `-1` is set.",
@@ -1534,8 +1534,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_messages` flag defines the minimum message severity level that is considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`. Each severity level includes the subsequent levels mentioned above. ERROR is considered the best practice setting. Changes should only be made in accordance with the organization's logging policy.",
@@ -1556,8 +1556,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `3625 (trace flag)` database flag for Cloud SQL SQL Server instance to `on`.",
@@ -1578,8 +1578,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `external scripts enabled` database flag for Cloud SQL SQL Server instance to `off`",
@@ -1600,8 +1600,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `remote access` database flag for Cloud SQL SQL Server instance to `off`.",
@@ -1622,8 +1622,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to check the `user connections` for a Cloud SQL SQL Server instance to ensure that it is not artificially limiting connections.",
@@ -1644,8 +1644,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that, `user options` database flag for Cloud SQL SQL Server instance should not be configured.",
@@ -1666,8 +1666,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `contained database authentication` database flag for Cloud SQL on the SQL Server instance to `off`.",
@@ -1688,8 +1688,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `cross db ownership chaining` database flag for Cloud SQL SQL Server instance to `off`.",
@@ -1710,7 +1710,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets.",
@@ -1731,7 +1731,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets. If CMEK is used, the CMEK is used to encrypt the data encryption keys instead of using google-managed encryption keys.",
@@ -1752,7 +1752,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the IAM policy on BigQuery datasets does not allow anonymous and/or public access.",
+103 -103
View File
@@ -10,7 +10,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Use corporate login credentials instead of consumer accounts, such as Gmail accounts.",
@@ -30,7 +30,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Setup multi-factor authentication for Google Cloud Platform accounts.",
@@ -50,7 +50,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Setup Security Key Enforcement for Google Cloud Platform admin accounts.",
@@ -72,7 +72,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "User-managed service accounts should not have user-managed keys.",
@@ -94,7 +94,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "A service account is a special Google account that belongs to an application or a VM, instead of to an individual end-user. The application uses the service account to call the service's Google API so that users aren't directly involved. It's recommended not to use admin access for ServiceAccount.",
@@ -116,7 +116,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to assign the `Service Account User (iam.serviceAccountUser)` and `Service Account Token Creator (iam.serviceAccountTokenCreator)` roles to a user for a specific service account rather than assigning the role to a user at project level.",
@@ -138,7 +138,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Service Account keys consist of a key ID (Private_key_Id) and Private key, which are used to sign programmatic requests users make to Google cloud services accessible to that particular service account. It is recommended that all Service Account keys are regularly rotated.",
@@ -160,7 +160,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning service-account related roles to users.",
@@ -182,7 +182,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the IAM policy on Cloud KMS `cryptokeys` should restrict anonymous and/or public access.",
@@ -204,7 +204,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Google Cloud Key Management Service stores cryptographic keys in a hierarchical structure designed for useful and elegant access control management. The format for the rotation schedule depends on the client library that is used. For the gcloud command-line tool, the next rotation time must be in `ISO` or `RFC3339` format, and the rotation period must be in the form `INTEGER[UNIT]`, where units can be one of seconds (s), minutes (m), hours (h) or days (d).",
@@ -226,7 +226,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the principle of 'Separation of Duties' is enforced while assigning KMS related roles to users.",
@@ -248,7 +248,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. Unused keys with their permissions in tact may still exist within a project. Keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to use standard authentication flow instead.",
@@ -268,7 +268,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. In this case, unrestricted keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API key usage to trusted hosts, HTTP referrers and apps. It is recommended to use the more secure standard authentication flow instead.",
@@ -290,7 +290,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. API keys are always at risk because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API keys to use (call) only APIs required by an application.",
@@ -312,7 +312,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "API Keys should only be used for services in cases where other authentication methods are unavailable. If they are in use it is recommended to rotate API keys every 90 days.",
@@ -334,7 +334,7 @@
],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that Essential Contacts is configured to designate email addresses for Google Cloud services to notify of important technical or security information.",
@@ -354,7 +354,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Identity and Access Management",
"Section": "1 Identity and Access Management",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Google Cloud Functions allow you to host serverless code that is executed when an event is triggered, without the requiring the management a host operating system. These functions can also store environment variables to be used by the code that may contain authentication or other information that needs to remain confidential.",
@@ -376,7 +376,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that Cloud Audit Logging is configured to track all admin activities and read, write access to user data.",
@@ -398,7 +398,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to create a sink that will export copies of all the log entries. This can help aggregate logs from multiple projects and export them to a Security Information and Event Management (SIEM).",
@@ -420,7 +420,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Enabling retention policies on log buckets will protect logs stored in cloud storage buckets from being overwritten or accidentally deleted. It is recommended to set up retention policies and configure Bucket Lock on all storage buckets that are used as log sinks.",
@@ -442,7 +442,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "In order to prevent unnecessary project ownership assignments to users/service-accounts and further misuses of projects and resources, all `roles/Owner` assignments should be monitored.Members (users/Service-Accounts) with a role assignment to primitive role `roles/Owner` are project owners.The project owner has all the privileges on the project the role belongs to. These are summarized below:- All viewer permissions on all GCP Services within the project- Permissions for actions that modify the state of all GCP services within the project- Manage roles and permissions for a project and all resources within the project- Set up billing for a projectGranting the owner role to a member (user/Service-Account) will allow that member to modify the Identity and Access Management (IAM) policy. Therefore, grant the owner role only if the member has a legitimate purpose to manage the IAM policy. This is because the project IAM policy contains sensitive access control data. Having a minimal set of users allowed to manage IAM policy will simplify any auditing that may be necessary.",
@@ -464,7 +464,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Google Cloud Platform (GCP) services write audit log entries to the Admin Activity and Data Access logs to help answer the questions of, \"who did what, where, and when?\" within GCP projects.Cloud audit logging records information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by GCP services. Cloud audit logging provides a history of GCP API calls for an account, including API calls made via the console, SDKs, command-line tools, and other GCP services.",
@@ -486,7 +486,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for changes to Identity and Access Management (IAM) role creation, deletion and updating activities.",
@@ -508,7 +508,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) Network Firewall rule changes.",
@@ -530,7 +530,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network route changes.",
@@ -552,7 +552,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Virtual Private Cloud (VPC) network changes.",
@@ -574,7 +574,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for Cloud Storage Bucket IAM changes.",
@@ -596,7 +596,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that a metric filter and alarm be established for SQL instance configuration changes.",
@@ -616,7 +616,7 @@
"Checks": [],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Cloud DNS logging records the queries from the name servers within your VPC to Stackdriver. Logged queries can come from Compute Engine VMs, GKE containers, or other GCP resources provisioned within the VPC.",
@@ -638,7 +638,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "GCP Cloud Asset Inventory is services that provides a historical view of GCP resources and IAM policies through a time-series database. The information recorded includes metadata on Google Cloud resources, metadata on policies set on Google Cloud projects or resources, and runtime information gathered within a Google Cloud resource.Cloud Asset Inventory Service (CAIS) API enablement is not required for operation of the service, but rather enables the mechanism for searching/exporting CAIS asset data directly.",
@@ -658,7 +658,7 @@
"Checks": [],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "GCP Access Transparency provides audit logs for all actions that Google personnel take in your Google Cloud resources.",
@@ -680,7 +680,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP Access Approval enables you to require your organizations' explicit approval whenever Google support try to access your projects. You can then select users within your organization who can approve these requests through giving them a security role in IAM. All access requests display which Google Employee requested them in an email or Pub/Sub message that you can choose to Approve. This adds an additional control and logging of who in your organization approved/denied these requests.",
@@ -702,7 +702,7 @@
],
"Attributes": [
{
"Section": "2. Logging and Monitoring",
"Section": "2 Logging and Monitoring",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Logging enabled on a HTTPS Load Balancer will show all network traffic and its destination.",
@@ -724,7 +724,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "To prevent use of `default` network, a project should not have a `default` network.",
@@ -746,7 +746,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "In order to prevent use of legacy networks, a project should not have a legacy network configured. As of now, Legacy Networks are gradually being phased out, and you can no longer create projects with them. This recommendation is to check older projects to ensure that they are not using Legacy Networks.",
@@ -768,7 +768,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Cloud Domain Name System (DNS) is a fast, reliable and cost-effective domain name system that powers millions of domains on the internet. Domain Name System Security Extensions (DNSSEC) in Cloud DNS enables domain owners to take easy steps to protect their domains against DNS hijacking and man-in-the-middle and other attacks.",
@@ -790,7 +790,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
@@ -812,7 +812,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "NOTE: Currently, the SHA1 algorithm has been removed from general use by Google, and, if being used, needs to be whitelisted on a project basis by Google and will also, therefore, require a Google Cloud support contract.DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be a recommended one and it should be strong.",
@@ -834,7 +834,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow the user to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, only an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the internet to VPC or VM instance using `SSH` on `Port 22` can be avoided.",
@@ -856,7 +856,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "GCP `Firewall Rules` are specific to a `VPC Network`. Each rule either `allows` or `denies` traffic when its conditions are met. Its conditions allow users to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances.Firewall rules are defined at the VPC network level and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, an `IPv4` address or `IPv4 block in CIDR` notation can be used. Generic `(0.0.0.0/0)` incoming traffic from the Internet to a VPC or VM instance using `RDP` on `Port 3389` can be avoided.",
@@ -878,7 +878,7 @@
],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Flow Logs is a feature that enables users to capture information about the IP traffic going to and from network interfaces in the organization's VPC Subnets. Once a flow log is created, the user can view and retrieve its data in Stackdriver Logging. It is recommended that Flow Logs be enabled for every business-critical VPC subnet.",
@@ -898,7 +898,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "Secure Sockets Layer (SSL) policies determine what port Transport Layer Security (TLS) features clients are permitted to use when connecting to load balancers. To prevent usage of insecure features, SSL policies should use (a) at least TLS 1.2 with the MODERN profile; or (b) the RESTRICTED profile, because it effectively requires clients to use TLS 1.2 regardless of the chosen minimum TLS version; or (3) a CUSTOM profile that does not support any of the following features: ```TLS_RSA_WITH_AES_128_GCM_SHA256TLS_RSA_WITH_AES_256_GCM_SHA384TLS_RSA_WITH_AES_128_CBC_SHATLS_RSA_WITH_AES_256_CBC_SHATLS_RSA_WITH_3DES_EDE_CBC_SHA```",
@@ -918,7 +918,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Networking",
"Section": "3 Networking",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "IAP authenticates the user requests to your apps via a Google single sign in. You can then manage these users with permissions to control access. It is recommended to use both IAP permissions and firewalls to restrict this access to your apps with sensitive information.",
@@ -940,7 +940,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to configure your instance to not use the default Compute Engine service account because it has the Editor role on the project.",
@@ -962,7 +962,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account `Compute Engine default service account` with Scope `Allow full access to all Cloud APIs`.",
@@ -984,7 +984,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to use Instance specific SSH key(s) instead of using common/shared project-wide SSH key(s) to access Instances.",
@@ -1006,7 +1006,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling OS login binds SSH certificates to IAM users and facilitates effective SSH certificate management.",
@@ -1028,7 +1028,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Interacting with a serial port is often referred to as the serial console, which is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support.If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. Therefore interactive serial console support should be disabled.",
@@ -1050,7 +1050,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets.Forwarding of data packets should be disabled to prevent data loss or information disclosure.",
@@ -1072,7 +1072,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Customer-Supplied Encryption Keys (CSEK) are a feature in Google Cloud Storage and Google Compute Engine. If you supply your own encryption keys, Google uses your key to protect the Google-generated keys used to encrypt and decrypt your data. By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.",
@@ -1094,7 +1094,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "To defend against advanced threats and ensure that the boot loader and firmware on your VMs are signed and untampered, it is recommended that Compute instances are launched with Shielded VM enabled.",
@@ -1116,7 +1116,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Compute instances should not be configured to have external IP addresses.",
@@ -1136,7 +1136,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "In order to maintain the highest level of security all connections to an application should be secure by default.",
@@ -1158,7 +1158,7 @@
],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "Google Cloud encrypts data at-rest and in-transit, but customer data must be decrypted for processing. Confidential Computing is a breakthrough technology which encrypts data in-use—while it is being processed. Confidential Computing environments keep data encrypted in memory and elsewhere outside the central processing unit (CPU). Confidential VMs leverage the Secure Encrypted Virtualization (SEV) feature of AMD EPYC™ CPUs. Customer data will stay encrypted while it is used, indexed, queried, or trained on. Encryption keys are generated in hardware, per VM, and not exportable. Thanks to built-in hardware optimizations of both performance and security, there is no significant performance penalty to Confidential Computing workloads.",
@@ -1178,7 +1178,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Virtual Machines",
"Section": "4 Virtual Machines",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "Google Cloud Virtual Machines have the ability via an OS Config agent API to periodically (about every 10 minutes) report OS inventory data. A patch compliance API periodically reads this data, and cross references metadata to determine if the latest updates are installed.This is not the only Patch Management solution available to your organization and you should weigh your needs before committing to using this method.",
@@ -1200,7 +1200,7 @@
],
"Attributes": [
{
"Section": "5. Storage",
"Section": "5 Storage",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that IAM policy on Cloud Storage bucket does not allows anonymous or public access.",
@@ -1222,7 +1222,7 @@
],
"Attributes": [
{
"Section": "5. Storage",
"Section": "5 Storage",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended that uniform bucket-level access is enabled on Cloud Storage buckets.",
@@ -1244,7 +1244,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to enforce all incoming connections to SQL database instance to use SSL.",
@@ -1266,7 +1266,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from public IP addresses.",
@@ -1288,7 +1288,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "It is recommended to configure Second Generation Sql instance to use private IPs instead of public IPs.",
@@ -1310,7 +1310,7 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"Section": "6 Cloud SQL Database Services",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to have all SQL database instances set to enable automated backups.",
@@ -1330,8 +1330,8 @@
"Checks": [],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Manual",
"Description": "It is recommended to set a password for the administrative user (`root` by default) to prevent unauthorized access to the SQL database instances.This recommendation is applicable only for MySQL Instances. PostgreSQL does not offer any setting for No Password from the cloud console.",
@@ -1353,8 +1353,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `skip_show_database` database flag for Cloud SQL Mysql instance to `on`",
@@ -1376,8 +1376,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.1. MySQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.1 MySQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set the `local_infile` database flag for a Cloud SQL MySQL instance to `off`.",
@@ -1399,8 +1399,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The `log_error_verbosity` flag controls the verbosity/details of messages logged. Valid values are:- `TERSE`- `DEFAULT`- `VERBOSE``TERSE` excludes the logging of `DETAIL`, `HINT`, `QUERY`, and `CONTEXT` error information.`VERBOSE` output includes the `SQLSTATE` error code, source code file name, function name, and line number that generated the error.Ensure an appropriate value is set to 'DEFAULT' or stricter.",
@@ -1422,8 +1422,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_connections` setting causes each attempted connection to the server to be logged, along with successful completion of client authentication. This parameter cannot be changed after the session starts.",
@@ -1445,8 +1445,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Enabling the `log_disconnections` setting logs the end of each session, including the session duration.",
@@ -1468,8 +1468,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "The value of `log_statement` flag determined the SQL statements that are logged. Valid values are:- `none`- `ddl`- `mod`- `all`The value `ddl` logs all data definition statements.The value `mod` logs all ddl statements, plus data-modifying statements.The statements are logged after a basic parsing is done and statement type is determined, thus this does not logs statements with errors. When using extended query protocol, logging occurs after an Execute message is received and values of the Bind parameters are included.A value of 'ddl' is recommended unless otherwise directed by your organization's logging policy.",
@@ -1491,8 +1491,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_messages` flag defines the minimum message severity level that is considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include (from lowest to highest severity) `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`.Each severity level includes the subsequent levels mentioned above. ERROR is considered the best practice setting. Changes should only be made in accordance with the organization's logging policy.",
@@ -1514,8 +1514,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_error_statement` flag defines the minimum message severity level that are considered as an error statement. Messages for error statements are logged with the SQL statement. Valid values include (from lowest to highest severity) `DEBUG5`, `DEBUG4`, `DEBUG3`, `DEBUG2`, `DEBUG1`, `INFO`, `NOTICE`, `WARNING`, `ERROR`, `LOG`, `FATAL`, and `PANIC`.Each severity level includes the subsequent levels mentioned above. Ensure a value of `ERROR` or stricter is set.",
@@ -1537,8 +1537,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "The `log_min_duration_statement` flag defines the minimum amount of execution time of a statement in milliseconds where the total duration of the statement is logged. Ensure that `log_min_duration_statement` is disabled, i.e., a value of `-1` is set.",
@@ -1560,8 +1560,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.2. PostgreSQL Database",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.2 PostgreSQL Database",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "Ensure `cloudsql.enable_pgaudit` database flag for Cloud SQL PostgreSQL instance is set to `on` to allow for centralized logging.",
@@ -1583,8 +1583,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `external scripts enabled` database flag for Cloud SQL SQL Server instance to `off`",
@@ -1606,8 +1606,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `cross db ownership chaining` database flag for Cloud SQL SQL Server instance to `off`.This flag is deprecated for all SQL Server versions in CGP. Going forward, you can't set its value to on. However, if you have this flag enabled, we strongly recommend that you either remove the flag from your database or set it to off. For cross-database access, use the [Microsoft tutorial for signing stored procedures with a certificate](https://learn.microsoft.com/en-us/sql/relational-databases/tutorial-signing-stored-procedures-with-a-certificate?view=sql-server-ver16).",
@@ -1629,8 +1629,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to check the `user connections` for a Cloud SQL SQL Server instance to ensure that it is not artificially limiting connections.",
@@ -1652,8 +1652,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that, `user options` database flag for Cloud SQL SQL Server instance should not be configured.",
@@ -1675,8 +1675,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `remote access` database flag for Cloud SQL SQL Server instance to `off`.",
@@ -1694,12 +1694,12 @@
"Id": "6.3.6",
"Description": "Ensure '3625 (trace flag)' database flag for all Cloud SQL Server instances is set to 'on'",
"Checks": [
"cloudsql_instance_sqlserver_trace_flag\""
"cloudsql_instance_sqlserver_trace_flag"
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended to set `3625 (trace flag)` database flag for Cloud SQL SQL Server instance to `on`.",
@@ -1721,8 +1721,8 @@
],
"Attributes": [
{
"Section": "6. Cloud SQL Database Services",
"SubSection": "6.3. SQL Server",
"Section": "6 Cloud SQL Database Services",
"SubSection": "6.3 SQL Server",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended not to set `contained database authentication` database flag for Cloud SQL on the SQL Server instance to `on`.",
@@ -1744,7 +1744,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 1",
"AssessmentStatus": "Automated",
"Description": "It is recommended that the IAM policy on BigQuery datasets does not allow anonymous and/or public access.",
@@ -1766,7 +1766,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets. If CMEK is used, the CMEK is used to encrypt the data encryption keys instead of using google-managed encryption keys.",
@@ -1788,7 +1788,7 @@
],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "BigQuery by default encrypts the data as rest by employing `Envelope Encryption` using Google managed cryptographic keys. The data is encrypted using the `data encryption keys` and data encryption keys themselves are further encrypted using `key encryption keys`. This is seamless and do not require any additional input from the user. However, if you want to have greater control, Customer-managed encryption keys (CMEK) can be used as encryption key management solution for BigQuery Data Sets.",
@@ -1808,7 +1808,7 @@
"Checks": [],
"Attributes": [
{
"Section": "7. BigQuery",
"Section": "7 BigQuery",
"Profile": "Level 2",
"AssessmentStatus": "Manual",
"Description": "BigQuery tables can contain sensitive data that for security purposes should be discovered, monitored, classified, and protected. Google Cloud's Sensitive Data Protection tools can automatically provide data classification of all BigQuery data across an organization.",
@@ -1830,7 +1830,7 @@
],
"Attributes": [
{
"Section": "8. Dataproc",
"Section": "8 Dataproc",
"Profile": "Level 2",
"AssessmentStatus": "Automated",
"Description": "When you use Dataproc, cluster and job data is stored on Persistent Disks (PDs) associated with the Compute Engine VMs in your cluster and in a Cloud Storage staging bucket. This PD and bucket data is encrypted using a Google-generated data encryption key (DEK) and key encryption key (KEK). The CMEK feature allows you to create, use, and revoke the key encryption key (KEK). Google still controls the data encryption key (DEK).",
File diff suppressed because it is too large Load Diff
@@ -10,7 +10,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -31,7 +31,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -52,7 +52,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -73,7 +73,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -94,7 +94,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -115,7 +115,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -136,7 +136,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -157,7 +157,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -178,7 +178,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -199,7 +199,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -220,7 +220,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -241,7 +241,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -262,7 +262,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -283,7 +283,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -304,7 +304,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -325,7 +325,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -346,7 +346,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -367,7 +367,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -388,7 +388,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -409,7 +409,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -430,7 +430,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.1 Control Plane Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -453,7 +453,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -476,7 +476,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -499,7 +499,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -522,7 +522,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -545,7 +545,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -568,7 +568,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -591,7 +591,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -614,7 +614,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -637,7 +637,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -660,7 +660,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -683,7 +683,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -706,7 +706,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -729,7 +729,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Automated",
@@ -752,7 +752,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Automated",
@@ -775,7 +775,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Automated",
@@ -798,7 +798,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -821,7 +821,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -844,7 +844,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -867,7 +867,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -890,7 +890,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -913,7 +913,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -936,7 +936,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -959,7 +959,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -982,7 +982,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1005,7 +1005,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1028,7 +1028,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1051,7 +1051,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1074,7 +1074,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1095,7 +1095,7 @@
"Checks": [],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1118,7 +1118,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.2 API Server",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1141,7 +1141,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1164,7 +1164,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1187,7 +1187,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1210,7 +1210,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1233,7 +1233,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1256,7 +1256,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1279,7 +1279,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.3 Controller Manager",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1302,7 +1302,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.4 Scheduler",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1325,7 +1325,7 @@
],
"Attributes": [
{
"Section": "1. Control Plane Components",
"Section": "1 Control Plane Components",
"SubSection": "1.4 Scheduler",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1500,7 +1500,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Control Plane Configuration",
"Section": "3 Control Plane Configuration",
"SubSection": "3.1 Authentication and Authorization",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1521,7 +1521,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Control Plane Configuration",
"Section": "3 Control Plane Configuration",
"SubSection": "3.1 Authentication and Authorization",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1542,7 +1542,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Control Plane Configuration",
"Section": "3 Control Plane Configuration",
"SubSection": "3.1 Authentication and Authorization",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1563,7 +1563,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Control Plane Configuration",
"Section": "3 Control Plane Configuration",
"SubSection": "3.2 Logging",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -1584,7 +1584,7 @@
"Checks": [],
"Attributes": [
{
"Section": "3. Control Plane Configuration",
"Section": "3 Control Plane Configuration",
"SubSection": "3.2 Logging",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -1607,7 +1607,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -1630,7 +1630,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1651,7 +1651,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1672,7 +1672,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1695,7 +1695,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1718,7 +1718,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1739,7 +1739,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1760,7 +1760,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1783,7 +1783,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1806,7 +1806,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.1 Worker Node Configuration Files",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1829,7 +1829,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1852,7 +1852,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1875,7 +1875,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1898,7 +1898,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1921,7 +1921,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1944,7 +1944,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -1965,7 +1965,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -1988,7 +1988,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 2 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2011,7 +2011,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2034,7 +2034,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Automated",
@@ -2055,7 +2055,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2078,7 +2078,7 @@
],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2099,7 +2099,7 @@
"Checks": [],
"Attributes": [
{
"Section": "4. Worker Nodes",
"Section": "4 Worker Nodes",
"SubSection": "4.2 Kubelet",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2122,7 +2122,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2145,7 +2145,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2168,7 +2168,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Worker Node",
"AssessmentStatus": "Manual",
@@ -2191,7 +2191,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2212,7 +2212,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2233,7 +2233,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2254,7 +2254,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2275,7 +2275,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2298,7 +2298,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2321,7 +2321,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2344,7 +2344,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2367,7 +2367,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2390,7 +2390,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.1 RBAC and Service Accounts",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2411,7 +2411,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2434,7 +2434,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2457,7 +2457,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2480,7 +2480,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2503,7 +2503,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2526,7 +2526,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2549,7 +2549,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Automated",
@@ -2572,7 +2572,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2595,7 +2595,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Automated",
@@ -2618,7 +2618,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2641,7 +2641,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2662,7 +2662,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2685,7 +2685,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.2 Pod Security Standards",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2706,7 +2706,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.3 Network Policies and CNI",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2727,7 +2727,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.3 Network Policies and CNI",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2750,7 +2750,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.4 Secrets Management",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2771,7 +2771,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.4 Secrets Management",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2792,7 +2792,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.4 Secrets Management",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2813,7 +2813,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.7 General Policies",
"Profile": "Level 1 - Master Node",
"AssessmentStatus": "Manual",
@@ -2836,7 +2836,7 @@
],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.7 General Policies",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2857,7 +2857,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.7 General Policies",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
@@ -2878,7 +2878,7 @@
"Checks": [],
"Attributes": [
{
"Section": "5. Policies",
"Section": "5 Policies",
"SubSection": "5.7 General Policies",
"Profile": "Level 2 - Master Node",
"AssessmentStatus": "Manual",
File diff suppressed because it is too large Load Diff
@@ -48,6 +48,7 @@ class M365CIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -79,6 +80,7 @@ class M365CIS(ComplianceOutput):
Requirements_Id=requirement.Id,
Requirements_Description=requirement.Description,
Requirements_Attributes_Section=attribute.Section,
Requirements_Attributes_SubSection=attribute.SubSection,
Requirements_Attributes_Profile=attribute.Profile,
Requirements_Attributes_AssessmentStatus=attribute.AssessmentStatus,
Requirements_Attributes_Description=attribute.Description,
@@ -82,6 +82,7 @@ class M365CISModel(BaseModel):
Requirements_Id: str
Requirements_Description: str
Requirements_Attributes_Section: str
Requirements_Attributes_SubSection: Optional[str]
Requirements_Attributes_Profile: str
Requirements_Attributes_AssessmentStatus: str
Requirements_Attributes_Description: str
@@ -8,7 +8,7 @@
"ServiceName": "ec2",
"SubServiceName": "securitygroup",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "high",
"Severity": "critical",
"ResourceType": "AwsEc2SecurityGroup",
"Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to all ports.",
"Risk": "If Security groups are not properly configured the attack surface is increased. An attacker could exploit this misconfiguration to gain unauthorized access to resources.",
@@ -1,4 +1,4 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.lib.check.models import Check, Check_Report_AWS, Severity
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
from prowler.providers.aws.services.vpc.vpc_client import vpc_client
@@ -9,14 +9,17 @@ class ec2_securitygroup_allow_ingress_from_internet_to_all_ports(Check):
findings = []
for security_group_arn, security_group in ec2_client.security_groups.items():
# Check if ignoring flag is set and if the VPC and the SG is in use
if ec2_client.provider.scan_unused_services or (
sg_in_use = (
security_group.vpc_id in vpc_client.vpcs
and vpc_client.vpcs[security_group.vpc_id].in_use
and len(security_group.network_interfaces) > 0
):
)
if ec2_client.provider.scan_unused_services or sg_in_use:
report = Check_Report_AWS(
metadata=self.metadata(), resource=security_group
)
if not sg_in_use:
report.check_metadata.Severity = Severity.high
report.resource_details = security_group.name
report.status = "PASS"
report.status_extended = f"Security group {security_group.name} ({security_group.id}) does not have all ports open to the Internet."
@@ -1,4 +1,5 @@
from ipaddress import ip_address, ip_network
import re
from prowler.lib.logger import logger
from prowler.providers.aws.aws_provider import read_aws_regions_file
@@ -415,6 +416,55 @@ def is_condition_block_restrictive_organization(
return is_condition_valid
def is_condition_block_restrictive_sns_endpoint(
condition_statement: dict,
):
"""
is_condition_block_restrictive_sns_endpoint parses the IAM Condition policy block and returns True if the condition_statement is restrictive for an endpoint, False if not.
@param condition_statement: dict with an IAM Condition block, e.g.:
{
"StringLike": {
"SNS:Endpoint": "https://events.pagerduty.com/integration/<api-key>/enqueue"
}
}
"""
is_condition_valid = False
# The conditions must be defined in lowercase since the context key names are not case-sensitive.
# For example, including the aws:PrincipalOrgID context key is equivalent to testing for AWS:PrincipalOrgID
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html
valid_condition_options = {
"StringEquals": [
"sns:endpoint",
],
"StringLike": [
"sns:endpoint",
],
}
for condition_operator, condition_operator_key in valid_condition_options.items():
if condition_operator in condition_statement:
# https://docs.aws.amazon.com/sns/latest/dg/sns-using-identity-based-policies.html#sns-policy-keys
# sns:endpoint - The URL, email address, or ARN from a Subscribe request or a previously confirmed subscription.
pattern = re.compile(r".+@[^*]+|^https:\/\/[^*]+|^arn:aws:sns:[^*]+")
for value in condition_operator_key:
# We need to transform the condition_statement into lowercase
condition_statement[condition_operator] = {
k.lower(): v
for k, v in condition_statement[condition_operator].items()
}
if value in condition_statement[condition_operator]:
if pattern.fullmatch(
condition_statement[condition_operator][value]
):
is_condition_valid = True
return is_condition_valid
def process_actions(effect, actions, target_set):
"""
process_actions processes the actions in the policy.
@@ -2,6 +2,7 @@ from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.iam.lib.policy import (
is_condition_block_restrictive,
is_condition_block_restrictive_organization,
is_condition_block_restrictive_sns_endpoint,
)
from prowler.providers.aws.services.sns.sns_client import sns_client
@@ -32,6 +33,7 @@ class sns_topics_not_publicly_accessible(Check):
):
condition_account = False
condition_org = False
condition_endpoint = False
if (
"Condition" in statement
and is_condition_block_restrictive(
@@ -47,6 +49,13 @@ class sns_topics_not_publicly_accessible(Check):
)
):
condition_org = True
if (
"Condition" in statement
and is_condition_block_restrictive_sns_endpoint(
statement["Condition"],
)
):
condition_endpoint = True
if condition_account and condition_org:
report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from the account {sns_client.audited_account} and an organization."
@@ -54,6 +63,8 @@ class sns_topics_not_publicly_accessible(Check):
report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from the account {sns_client.audited_account}."
elif condition_org:
report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from an organization."
elif condition_endpoint:
report.status_extended = f"SNS topic {topic.name} is not public because its policy only allows access from an endpoint."
else:
report.status = "FAIL"
report.status_extended = f"SNS topic {topic.name} is public because its policy allows public access."
+1 -1
View File
@@ -247,7 +247,7 @@ class GithubProvider(Provider):
if not session_token:
# OAUTH
logger.info(
"Looking for GITHUB_OAUTH_TOKEN environment variable as user has not provided any token...."
"Looking for GITHUB_OAUTH_APP_TOKEN environment variable as user has not provided any token...."
)
session_token = environ.get("GITHUB_OAUTH_APP_TOKEN", "")
if session_token:
@@ -0,0 +1,30 @@
{
"Provider": "github",
"CheckID": "repository_branch_delete_on_merge_enabled",
"CheckTitle": "Check if a repository deletes the branch after merging",
"CheckType": [],
"ServiceName": "repository",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "GitHubRepository",
"Description": "Ensure that the repository deletes the branch after merging.",
"Risk": "Inactive branches pose a security risk as they can accumulate outdated code, dependencies, and potential vulnerabilities over time. Malicious actors may exploit these branches, and they can clutter the repository, making it harder to manage and track the active code. Additionally, stale branches may unintentionally be accessed or used inappropriately, leading to potential security breaches.",
"RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Regularly review and remove inactive branches from your repositories. This helps reduce the risk of malicious code injection, sensitive data leaks, and unnecessary clutter in the repository. By keeping branches active and up to date, you ensure that your codebase remains secure and manageable.",
"Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,41 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGithub
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_branch_delete_on_merge_enabled(Check):
"""Check if a repository deletes branches on merge
This class verifies whether each repository deletes branches on merge.
"""
def execute(self) -> List[CheckReportGithub]:
"""Execute the Github Repository Deletes Branch On Merge check
Iterates over all repositories and checks if they delete branches on merge.
Returns:
List[CheckReportGithub]: A list of reports for each repository
"""
findings = []
for repo in repository_client.repositories.values():
report = CheckReportGithub(
metadata=self.metadata(), resource=repo, repository=repo.name
)
report.status = "FAIL"
report.status_extended = (
f"Repository {repo.name} does not delete branches on merge."
)
if repo.delete_branch_on_merge:
report.status = "PASS"
report.status_extended = (
f"Repository {repo.name} does delete branches on merge."
)
findings.append(report)
return findings
@@ -0,0 +1,30 @@
{
"Provider": "github",
"CheckID": "repository_default_branch_protection_applies_to_admins",
"CheckTitle": "Check if repository enforces admin branch protection",
"CheckType": [],
"ServiceName": "repository",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "GithubRepository",
"Description": "Ensure that the repository enforces branch protection rules for administrators.",
"Risk": "Excluding administrators from branch protection rules introduces a significant risk of unauthorized or unreviewed changes being pushed to protected branches. This can lead to vulnerabilities, including the potential insertion of malicious code, especially if an administrator account is compromised.",
"RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#do-not-allow-bypassing-the-above-settings",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enforce branch protection rules for administrators to ensure they adhere to the same security and quality standards as other users. This mitigates the risk of unreviewed or untrusted code being introduced, enhancing the overall integrity of the codebase.",
"Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,38 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGithub
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_default_branch_protection_applies_to_admins(Check):
"""Check if a repository enforces administrators to be subject to the same branch protection rules as other users
This class verifies whether each repository enforces administrators to be subject to the same branch protection rules as other users.
"""
def execute(self) -> List[CheckReportGithub]:
"""Execute the Github Repository Enforces Admin Branch Protection check
Iterates over all repositories and checks if they enforce administrators to be subject to the same branch protection rules as other users.
Returns:
List[CheckReportGithub]: A list of reports for each repository.
"""
findings = []
for repo in repository_client.repositories.values():
if repo.enforce_admins is not None:
report = CheckReportGithub(
metadata=self.metadata(), resource=repo, repository=repo.name
)
report.status = "FAIL"
report.status_extended = f"Repository {repo.name} does not enforce administrators to be subject to the same branch protection rules as other users."
if repo.enforce_admins:
report.status = "PASS"
report.status_extended = f"Repository {repo.name} does enforce administrators to be subject to the same branch protection rules as other users."
findings.append(report)
return findings
@@ -0,0 +1,30 @@
{
"Provider": "github",
"CheckID": "repository_default_branch_requires_conversation_resolution",
"CheckTitle": "Check if repository requires conversation resolution before merging",
"CheckType": [],
"ServiceName": "repository",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "GitHubRepository",
"Description": "Ensure that the repository requires conversation resolution before merging.",
"Risk": "Leaving comments unresolved before merging code can lead to overlooked issues, including potential bugs or security vulnerabilities, that might affect the quality and security of the codebase. Unaddressed concerns could result in a lower quality of code, increasing the risk of production failures or breaches.",
"RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-conversation-resolution-before-merging",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure that all comments in a code change proposal are resolved before merging. This guarantees that every reviewers concern is addressed, improving code quality and security by preventing issues from being ignored or overlooked.",
"Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,42 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGithub
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_default_branch_requires_conversation_resolution(Check):
"""Check if a repository requires conversation resolution
This class verifies whether each repository requires conversation resolution.
"""
def execute(self) -> List[CheckReportGithub]:
"""Execute the Github Repository Merging Requires Conversation Resolution check
Iterates over all repositories and checks if they require conversation resolution.
Returns:
List[CheckReportGithub]: A list of reports for each repository
"""
findings = []
for repo in repository_client.repositories.values():
if repo.conversation_resolution is not None:
report = CheckReportGithub(
metadata=self.metadata(), resource=repo, repository=repo.name
)
report.status = "FAIL"
report.status_extended = (
f"Repository {repo.name} does not require conversation resolution."
)
if repo.conversation_resolution:
report.status = "PASS"
report.status_extended = (
f"Repository {repo.name} does require conversation resolution."
)
findings.append(report)
return findings
@@ -0,0 +1,30 @@
{
"Provider": "github",
"CheckID": "repository_default_branch_status_checks_required",
"CheckTitle": "Check if repository enforces status checks to pass",
"CheckType": [],
"ServiceName": "repository",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "GithubRepository",
"Description": "Ensure that the repository enforces status checks to pass before merging code into the main branch.",
"Risk": "Merging code without requiring all checks to pass increases the risk of introducing bugs, vulnerabilities, or unstable changes into the codebase. This can compromise the quality, security, and functionality of the application.",
"RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Require all predefined status checks to pass successfully before allowing code changes to be merged. This ensures that all quality, stability, and security conditions are met, reducing the likelihood of errors or vulnerabilities being introduced into the project.",
"Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,42 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportGithub
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_default_branch_status_checks_required(Check):
"""Check if a repository enforces status checks.
This class verifies whether each repository enforces status checks.
"""
def execute(self) -> List[CheckReportGithub]:
"""Execute the Github Repository
Iterates over all repositories and checks if they enforce status checks.
Returns:
List[CheckReportGithub]: A list of reports for each repository.
"""
findings = []
for repo in repository_client.repositories.values():
if repo.status_checks is not None:
report = CheckReportGithub(
self.metadata(), resource=repo, repository=repo.name
)
report.status = "FAIL"
report.status_extended = (
f"Repository {repo.name} does not enforce status checks."
)
if repo.status_checks:
report.status = "PASS"
report.status_extended = (
f"Repository {repo.name} does enforce status checks."
)
findings.append(report)
return findings
@@ -18,6 +18,11 @@ class Repository(GithubService):
for client in self.clients:
for repo in client.get_user().get_repos():
default_branch = repo.default_branch
delete_branch_on_merge = (
repo.delete_branch_on_merge
if repo.delete_branch_on_merge is not None
else False
)
securitymd_exists = False
try:
securitymd_exists = repo.get_contents("SECURITY.md") is not None
@@ -36,6 +41,9 @@ class Repository(GithubService):
required_linear_history = False
allow_force_pushes = True
branch_deletion = True
status_checks = False
enforce_admins = False
conversation_resolution = False
try:
branch = repo.get_branch(default_branch)
if branch.protected:
@@ -54,6 +62,13 @@ class Repository(GithubService):
)
allow_force_pushes = protection.allow_force_pushes
branch_deletion = protection.allow_deletions
status_checks = (
protection.required_status_checks is not None
)
enforce_admins = protection.enforce_admins
conversation_resolution = (
protection.required_conversation_resolution
)
branch_protection = True
except Exception as error:
# If the branch is not found, it is not protected
@@ -69,6 +84,9 @@ class Repository(GithubService):
required_linear_history = None
allow_force_pushes = None
branch_deletion = None
status_checks = None
enforce_admins = None
conversation_resolution = None
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@@ -85,7 +103,11 @@ class Repository(GithubService):
required_linear_history=required_linear_history,
allow_force_pushes=allow_force_pushes,
default_branch_deletion=branch_deletion,
status_checks=status_checks,
enforce_admins=enforce_admins,
conversation_resolution=conversation_resolution,
default_branch_protection=branch_protection,
delete_branch_on_merge=delete_branch_on_merge,
)
except Exception as error:
@@ -109,4 +131,8 @@ class Repo(BaseModel):
required_linear_history: Optional[bool]
allow_force_pushes: Optional[bool]
default_branch_deletion: Optional[bool]
status_checks: Optional[bool]
enforce_admins: Optional[bool]
approval_count: Optional[int]
delete_branch_on_merge: Optional[bool]
conversation_resolution: Optional[bool]
@@ -7,7 +7,7 @@ from prowler.lib.powershell.powershell import PowerShellSession
from prowler.providers.m365.exceptions.exceptions import (
M365UserNotBelongingToTenantError,
)
from prowler.providers.m365.models import M365Credentials
from prowler.providers.m365.models import M365Credentials, M365IdentityInfo
class M365PowerShell(PowerShellSession):
@@ -34,7 +34,7 @@ class M365PowerShell(PowerShellSession):
to be installed and available in the PowerShell environment.
"""
def __init__(self, credentials: M365Credentials):
def __init__(self, credentials: M365Credentials, identity: M365IdentityInfo):
"""
Initialize a Microsoft 365 PowerShell session.
@@ -46,6 +46,7 @@ class M365PowerShell(PowerShellSession):
for authentication.
"""
super().__init__()
self.tenant_identity = identity
self.init_credential(credentials)
def init_credential(self, credentials: M365Credentials) -> None:
@@ -95,12 +96,24 @@ class M365PowerShell(PowerShellSession):
'Write-Output "$($credential.GetNetworkCredential().Password)"'
)
# Validate user belongs to tenant
user_domain = credentials.user.split("@")[1]
if not any(
user_domain.endswith(domain)
for domain in self.tenant_identity.tenant_domains
):
raise M365UserNotBelongingToTenantError(
file=os.path.basename(__file__),
message=f"The user domain {user_domain} does not match any of the tenant domains: {', '.join(self.tenant_identity.tenant_domains)}",
)
app = msal.ConfidentialClientApplication(
client_id=credentials.client_id,
client_credential=credentials.client_secret,
authority=f"https://login.microsoftonline.com/{credentials.tenant_id}",
)
# Validate credentials
result = app.acquire_token_by_username_password(
username=credentials.user,
password=decrypted_password, # Needs to be in plain text
@@ -113,14 +126,6 @@ class M365PowerShell(PowerShellSession):
if "access_token" not in result:
return False
# Validate user credentials belong to tenant
user_domain = credentials.user.split("@")[1]
if not credentials.provider_id.endswith(user_domain):
raise M365UserNotBelongingToTenantError(
file=os.path.basename(__file__),
message="The provided M365 User does not belong to the specified tenant.",
)
return True
def connect_microsoft_teams(self) -> dict:
@@ -15,5 +15,7 @@ class M365Service:
# Initialize PowerShell client only if credentials are available
self.powershell = (
M365PowerShell(provider.credentials) if provider.credentials else None
M365PowerShell(provider.credentials, provider.identity)
if provider.credentials and provider.identity
else None
)
+90 -86
View File
@@ -194,20 +194,17 @@ class M365Provider(Provider):
# Set up the identity
self._identity = self.setup_identity(
az_cli_auth,
sp_env_auth,
env_auth,
browser_auth,
client_id,
self._session,
)
# Set up PowerShell session credentials
self._credentials = self.setup_powershell(
env_auth=env_auth,
m365_credentials=m365_credentials,
provider_id=self.identity.tenant_domain,
init_modules=init_modules,
identity=self.identity,
init_modules=init_modules,
)
# Audit Config
@@ -381,9 +378,8 @@ class M365Provider(Provider):
def setup_powershell(
env_auth: bool = False,
m365_credentials: dict = {},
provider_id: str = None,
init_modules: bool = False,
identity: M365IdentityInfo = None,
init_modules: bool = False,
) -> M365Credentials:
"""Gets the M365 credentials.
@@ -404,7 +400,7 @@ class M365Provider(Provider):
client_id=m365_credentials.get("client_id", ""),
client_secret=m365_credentials.get("client_secret", ""),
tenant_id=m365_credentials.get("tenant_id", ""),
provider_id=provider_id,
tenant_domains=identity.tenant_domains,
)
elif env_auth:
m365_user = getenv("M365_USER")
@@ -422,19 +418,18 @@ class M365Provider(Provider):
message="Missing M365_USER or M365_ENCRYPTED_PASSWORD environment variables required for credentials authentication.",
)
credentials = M365Credentials(
user=m365_user,
passwd=m365_password,
client_id=client_id,
client_secret=client_secret,
tenant_id=tenant_id,
provider_id=provider_id,
tenant_domains=identity.tenant_domains,
user=m365_user,
passwd=m365_password,
)
if credentials:
if identity:
identity.identity_type = "Service Principal and User Credentials"
identity.user = credentials.user
test_session = M365PowerShell(credentials)
test_session = M365PowerShell(credentials, identity)
try:
if test_session.test_credentials(credentials):
if init_modules:
@@ -704,7 +699,7 @@ class M365Provider(Provider):
)
# Set up the M365 session
credentials = M365Provider.setup_session(
session = M365Provider.setup_session(
az_cli_auth,
sp_env_auth,
env_auth,
@@ -714,16 +709,35 @@ class M365Provider(Provider):
region_config,
)
GraphServiceClient(credentials=credentials)
GraphServiceClient(credentials=session)
logger.info("M365 provider: Connection to MSGraph successful")
# Set up Identity
identity = M365Provider.setup_identity(
sp_env_auth,
env_auth,
session,
)
if not identity:
raise M365GetTokenIdentityError(
file=os.path.basename(__file__),
message="Failed to retrieve M365 identity",
)
if provider_id not in identity.tenant_domains:
raise M365InvalidProviderIdError(
file=os.path.basename(__file__),
message=f"The provider ID {provider_id} does not match any of the service principal tenant domains: {', '.join(identity.tenant_domains)}",
)
# Set up PowerShell credentials
if user and encrypted_password:
M365Provider.setup_powershell(
env_auth,
m365_credentials,
provider_id,
identity,
)
else:
logger.info(
@@ -732,15 +746,6 @@ class M365Provider(Provider):
logger.info("M365 provider: Connection to PowerShell successful")
# Check that user domain, provider_id and Graph client tenant_domain are the same
if user and encrypted_password:
user_domain = user.split("@")[1]
if provider_id and user_domain != provider_id:
raise M365InvalidProviderIdError(
file=os.path.basename(__file__),
message=f"Provider ID {provider_id} does not match Application tenant domain {user_domain}",
)
return Connection(is_connected=True)
# Exceptions from setup_region_config
@@ -867,13 +872,11 @@ class M365Provider(Provider):
message=f"Missing environment variable {env_var} required to authenticate.",
)
@staticmethod
def setup_identity(
self,
az_cli_auth,
sp_env_auth,
env_auth,
browser_auth,
client_id,
session,
):
"""
Sets up the identity for the M365 provider.
@@ -888,7 +891,7 @@ class M365Provider(Provider):
Returns:
M365IdentityInfo: An instance of M365IdentityInfo containing the identity information.
"""
credentials = self.session
logger.info("M365 provider: Setting up identity ...")
# TODO: fill this object with real values not default and set to none
identity = M365IdentityInfo()
@@ -896,74 +899,75 @@ class M365Provider(Provider):
# the identity can access AAD and retrieve the tenant domain name.
# With cli also should be possible but right now it does not work, m365 python package issue is coming
# At the time of writting this with az cli creds is not working, despite that is included
if env_auth or az_cli_auth or sp_env_auth or browser_auth or client_id:
async def get_m365_identity():
# Trying to recover tenant domain info
async def get_m365_identity(identity):
# Trying to recover tenant domain info
try:
logger.info(
"Trying to retrieve tenant domain from AAD to populate identity structure ..."
)
client = GraphServiceClient(credentials=session)
domain_result = await client.domains.get()
if getattr(domain_result, "value"):
if getattr(domain_result.value[0], "id"):
identity.tenant_domain = domain_result.value[0].id
for domain in domain_result.value:
identity.tenant_domains.append(domain.id)
except HttpResponseError as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
raise M365HTTPResponseError(
file=os.path.basename(__file__),
original_exception=error,
)
except ClientAuthenticationError as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
raise M365GetTokenIdentityError(
file=os.path.basename(__file__),
original_exception=error,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
# since that exception is not considered as critical, we keep filling another identity fields
identity.identity_id = (
getenv("AZURE_CLIENT_ID") or "Unknown user id (Missing AAD permissions)"
)
if sp_env_auth:
identity.identity_type = "Service Principal"
elif env_auth:
identity.identity_type = "Service Principal and User Credentials"
else:
identity.identity_type = "User"
try:
logger.info(
"Trying to retrieve tenant domain from AAD to populate identity structure ..."
"Trying to retrieve user information from AAD to populate identity structure ..."
)
client = GraphServiceClient(credentials=credentials)
client = GraphServiceClient(credentials=session)
domain_result = await client.domains.get()
if getattr(domain_result, "value"):
if getattr(domain_result.value[0], "id"):
identity.tenant_domain = domain_result.value[0].id
me = await client.me.get()
if me:
if getattr(me, "user_principal_name"):
identity.identity_id = me.user_principal_name
except HttpResponseError as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
raise M365HTTPResponseError(
file=os.path.basename(__file__),
original_exception=error,
)
except ClientAuthenticationError as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
raise M365GetTokenIdentityError(
file=os.path.basename(__file__),
original_exception=error,
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
# since that exception is not considered as critical, we keep filling another identity fields
if sp_env_auth or env_auth or client_id:
# The id of the sp can be retrieved from environment variables
identity.identity_id = getenv("AZURE_CLIENT_ID")
identity.identity_type = "Service Principal"
# Same here, if user can access AAD, some fields are retrieved if not, default value, for az cli
# should work but it doesn't, pending issue
else:
identity.identity_id = "Unknown user id (Missing AAD permissions)"
identity.identity_type = "User"
try:
logger.info(
"Trying to retrieve user information from AAD to populate identity structure ..."
)
client = GraphServiceClient(credentials=credentials)
me = await client.me.get()
if me:
if getattr(me, "user_principal_name"):
identity.identity_id = me.user_principal_name
# Retrieve tenant id from the client
client = GraphServiceClient(credentials=session)
organization_info = await client.organization.get()
identity.tenant_id = organization_info.value[0].id
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
# Retrieve tenant id from the client
client = GraphServiceClient(credentials=credentials)
organization_info = await client.organization.get()
identity.tenant_id = organization_info.value[0].id
asyncio.get_event_loop().run_until_complete(get_m365_identity())
return identity
asyncio.get_event_loop().run_until_complete(get_m365_identity(identity))
return identity
@staticmethod
def validate_static_credentials(
+5 -4
View File
@@ -8,7 +8,8 @@ class M365IdentityInfo(BaseModel):
identity_id: str = ""
identity_type: str = ""
tenant_id: str = ""
tenant_domain: str = "Unknown tenant domain (missing AAD permissions)"
tenant_domain: str = "Unknown tenant domain (missing Entra permissions)"
tenant_domains: list[str] = []
location: str = ""
user: str = None
@@ -21,12 +22,12 @@ class M365RegionConfig(BaseModel):
class M365Credentials(BaseModel):
user: str = ""
passwd: str = ""
client_id: str = ""
client_secret: str = ""
tenant_id: str = ""
provider_id: str = ""
tenant_domains: list[str] = []
user: str = ""
passwd: str = ""
class M365OutputOptions(ProviderOutputOptions):
@@ -0,0 +1,182 @@
from datetime import datetime
from io import StringIO
from freezegun import freeze_time
from mock import patch
from prowler.lib.outputs.compliance.cis.cis_m365 import M365CIS
from prowler.lib.outputs.compliance.cis.models import M365CISModel
from tests.lib.outputs.compliance.fixtures import CIS_4_0_M365
from tests.lib.outputs.fixtures.fixtures import generate_finding_output
from tests.providers.m365.m365_fixtures import DOMAIN, LOCATION, TENANT_ID
class TestM365CIS:
def test_output_transform(self):
findings = [
generate_finding_output(
provider="m365",
compliance={"CIS-4.0": "2.1.3"},
account_name=DOMAIN,
account_uid=TENANT_ID,
region=LOCATION,
)
]
# Clear the data from CSV class
output = M365CIS(findings, CIS_4_0_M365)
output_data = output.data[0]
assert isinstance(output_data, M365CISModel)
assert output_data.Provider == "m365"
assert output_data.TenantId == TENANT_ID
assert output_data.Location == LOCATION
assert output_data.Description == CIS_4_0_M365.Description
assert output_data.Requirements_Id == CIS_4_0_M365.Requirements[0].Id
assert (
output_data.Requirements_Description
== CIS_4_0_M365.Requirements[0].Description
)
assert (
output_data.Requirements_Attributes_Section
== CIS_4_0_M365.Requirements[0].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_SubSection
== CIS_4_0_M365.Requirements[0].Attributes[0].SubSection
)
assert (
output_data.Requirements_Attributes_Profile
== CIS_4_0_M365.Requirements[0].Attributes[0].Profile
)
assert (
output_data.Requirements_Attributes_AssessmentStatus
== CIS_4_0_M365.Requirements[0].Attributes[0].AssessmentStatus
)
assert (
output_data.Requirements_Attributes_Description
== CIS_4_0_M365.Requirements[0].Attributes[0].Description
)
assert (
output_data.Requirements_Attributes_RationaleStatement
== CIS_4_0_M365.Requirements[0].Attributes[0].RationaleStatement
)
assert (
output_data.Requirements_Attributes_ImpactStatement
== CIS_4_0_M365.Requirements[0].Attributes[0].ImpactStatement
)
assert (
output_data.Requirements_Attributes_RemediationProcedure
== CIS_4_0_M365.Requirements[0].Attributes[0].RemediationProcedure
)
assert (
output_data.Requirements_Attributes_AuditProcedure
== CIS_4_0_M365.Requirements[0].Attributes[0].AuditProcedure
)
assert (
output_data.Requirements_Attributes_AdditionalInformation
== CIS_4_0_M365.Requirements[0].Attributes[0].AdditionalInformation
)
assert (
output_data.Requirements_Attributes_References
== CIS_4_0_M365.Requirements[0].Attributes[0].References
)
assert (
output_data.Requirements_Attributes_DefaultValue
== CIS_4_0_M365.Requirements[0].Attributes[0].DefaultValue
)
assert output_data.Status == "PASS"
assert output_data.StatusExtended == ""
assert output_data.ResourceId == ""
assert output_data.ResourceName == ""
assert output_data.CheckId == "test-check-id"
assert output_data.Muted is False
# Test manual check
output_data_manual = output.data[1]
assert output_data_manual.Provider == "m365"
assert output_data_manual.TenantId == TENANT_ID
assert output_data_manual.Location == LOCATION
assert output_data_manual.Description == CIS_4_0_M365.Description
assert output_data_manual.Requirements_Id == CIS_4_0_M365.Requirements[1].Id
assert (
output_data_manual.Requirements_Description
== CIS_4_0_M365.Requirements[1].Description
)
assert (
output_data_manual.Requirements_Attributes_Section
== CIS_4_0_M365.Requirements[1].Attributes[0].Section
)
assert (
output_data.Requirements_Attributes_SubSection
== CIS_4_0_M365.Requirements[0].Attributes[0].SubSection
)
assert (
output_data_manual.Requirements_Attributes_Profile
== CIS_4_0_M365.Requirements[1].Attributes[0].Profile
)
assert (
output_data_manual.Requirements_Attributes_AssessmentStatus
== CIS_4_0_M365.Requirements[1].Attributes[0].AssessmentStatus
)
assert (
output_data_manual.Requirements_Attributes_Description
== CIS_4_0_M365.Requirements[1].Attributes[0].Description
)
assert (
output_data_manual.Requirements_Attributes_RationaleStatement
== CIS_4_0_M365.Requirements[1].Attributes[0].RationaleStatement
)
assert (
output_data_manual.Requirements_Attributes_ImpactStatement
== CIS_4_0_M365.Requirements[1].Attributes[0].ImpactStatement
)
assert (
output_data_manual.Requirements_Attributes_RemediationProcedure
== CIS_4_0_M365.Requirements[1].Attributes[0].RemediationProcedure
)
assert (
output_data_manual.Requirements_Attributes_AuditProcedure
== CIS_4_0_M365.Requirements[1].Attributes[0].AuditProcedure
)
assert (
output_data_manual.Requirements_Attributes_AdditionalInformation
== CIS_4_0_M365.Requirements[1].Attributes[0].AdditionalInformation
)
assert (
output_data_manual.Requirements_Attributes_References
== CIS_4_0_M365.Requirements[1].Attributes[0].References
)
assert (
output_data_manual.Requirements_Attributes_DefaultValue
== CIS_4_0_M365.Requirements[1].Attributes[0].DefaultValue
)
assert output_data_manual.Status == "MANUAL"
assert output_data_manual.StatusExtended == "Manual check"
assert output_data_manual.ResourceId == "manual_check"
assert output_data_manual.ResourceName == "Manual check"
assert output_data_manual.CheckId == "manual"
assert output_data_manual.Muted is False
@freeze_time(datetime.now())
def test_batch_write_data_to_file(self):
mock_file = StringIO()
findings = [
generate_finding_output(
provider="m365",
compliance={"CIS-4.0": "2.1.3"},
account_name=DOMAIN,
account_uid=TENANT_ID,
region=LOCATION,
)
]
# Clear the data from CSV class
output = M365CIS(findings, CIS_4_0_M365)
output._file_descriptor = mock_file
with patch.object(mock_file, "close", return_value=None):
output.batch_write_data_to_file()
mock_file.seek(0)
content = mock_file.read()
expected_csv = f"PROVIDER;DESCRIPTION;TENANTID;LOCATION;ASSESSMENTDATE;REQUIREMENTS_ID;REQUIREMENTS_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_SECTION;REQUIREMENTS_ATTRIBUTES_SUBSECTION;REQUIREMENTS_ATTRIBUTES_PROFILE;REQUIREMENTS_ATTRIBUTES_ASSESSMENTSTATUS;REQUIREMENTS_ATTRIBUTES_DESCRIPTION;REQUIREMENTS_ATTRIBUTES_RATIONALESTATEMENT;REQUIREMENTS_ATTRIBUTES_IMPACTSTATEMENT;REQUIREMENTS_ATTRIBUTES_REMEDIATIONPROCEDURE;REQUIREMENTS_ATTRIBUTES_AUDITPROCEDURE;REQUIREMENTS_ATTRIBUTES_ADDITIONALINFORMATION;REQUIREMENTS_ATTRIBUTES_DEFAULTVALUE;REQUIREMENTS_ATTRIBUTES_REFERENCES;STATUS;STATUSEXTENDED;RESOURCEID;RESOURCENAME;CHECKID;MUTED\r\nm365;The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.;00000000-0000-0000-0000-000000000000;global;{datetime.now()};2.1.3;Ensure MFA Delete is enabled on S3 buckets;2.1. Simple Storage Service (S3);;Level 1;Automated;Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.;Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.;;Perform the steps below to enable MFA delete on an S3 bucket.Note:-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.-You must use your 'root' account to enable MFA Delete on S3 buckets.**From Command line:**1. Run the s3api put-bucket-versioning command aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode;Perform the steps below to confirm MFA delete is configured on an S3 Bucket**From Console:**1. Login to the S3 console at `https://console.aws.amazon.com/s3/`2. Click the `Check` box next to the Bucket name you want to confirm3. In the window under `Properties`4. Confirm that Versioning is `Enabled`5. Confirm that MFA Delete is `Enabled`**From Command Line:**1. Run the `get-bucket-versioning aws s3api get-bucket-versioning --bucket my-bucket Output example: <VersioningConfiguration xmlns=`http://s3.amazonaws.com/doc/2006-03-01/`> <Status>Enabled</Status> <MfaDelete>Enabled</MfaDelete></VersioningConfiguration>\ If the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.;;By default, MFA Delete is not enabled on S3 buckets.;https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html;PASS;;;;test-check-id;False\r\nm365;The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.;00000000-0000-0000-0000-000000000000;global;{datetime.now()};2.1.4;Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive;1.1 Control Plane Node Configuration Files;;Level 1 - Master Node;Automated;Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.;The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.;;Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```;Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the permissions are `600` or more restrictive.;;By default, the `kube-controller-manager.yaml` file has permissions of `640`.;https://kubernetes.io/docs/admin/kube-apiserver/;MANUAL;Manual check;manual_check;Manual check;manual;False\r\n"
assert content == expected_csv
+52
View File
@@ -243,6 +243,58 @@ CIS_1_5_AWS = Compliance(
],
)
CIS_4_0_M365_NAME = "cis_4.0_m365"
CIS_4_0_M365 = Compliance(
Framework="CIS",
Provider="M365",
Version="4.0",
Description="The CIS Microsoft 365 Foundations Benchmark provides prescriptive guidance for configuring security options for Microsoft 365 with an emphasis on foundational, testable, and architecture agnostic settings.",
Requirements=[
Compliance_Requirement(
Checks=[
"mfa_delete_enabled",
],
Id="2.1.3",
Description="Ensure MFA Delete is enabled on S3 buckets",
Attributes=[
CIS_Requirement_Attribute(
Section="2.1. Simple Storage Service (S3)",
Profile="Level 1",
AssessmentStatus="Automated",
Description="Once MFA Delete is enabled on your sensitive and classified S3 bucket it requires the user to have two forms of authentication.",
RationaleStatement="Adding MFA delete to an S3 bucket, requires additional authentication when you change the version state of your bucket or you delete and object version adding another layer of security in the event your security credentials are compromised or unauthorized access is granted.",
ImpactStatement="",
RemediationProcedure="Perform the steps below to enable MFA delete on an S3 bucket.Note:-You cannot enable MFA Delete using the AWS Management Console. You must use the AWS CLI or API.-You must use your 'root' account to enable MFA Delete on S3 buckets.**From Command line:**1. Run the s3api put-bucket-versioning command aws s3api put-bucket-versioning --profile my-root-profile --bucket Bucket_Name --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa arn:aws:iam::aws_account_id:mfa/root-account-mfa-device passcode",
AuditProcedure="Perform the steps below to confirm MFA delete is configured on an S3 Bucket**From Console:**1. Login to the S3 console at `https://console.aws.amazon.com/s3/`2. Click the `Check` box next to the Bucket name you want to confirm3. In the window under `Properties`4. Confirm that Versioning is `Enabled`5. Confirm that MFA Delete is `Enabled`**From Command Line:**1. Run the `get-bucket-versioning aws s3api get-bucket-versioning --bucket my-bucket Output example: <VersioningConfiguration xmlns=`http://s3.amazonaws.com/doc/2006-03-01/`> <Status>Enabled</Status> <MfaDelete>Enabled</MfaDelete></VersioningConfiguration>\ If the Console or the CLI output does not show Versioning and MFA Delete `enabled` refer to the remediation below.",
AdditionalInformation="",
References="https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete:https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html:https://aws.amazon.com/blogs/security/securing-access-to-aws-using-mfa-part-3/:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa_lost-or-broken.html",
DefaultValue="By default, MFA Delete is not enabled on S3 buckets.",
)
],
),
Compliance_Requirement(
Checks=[],
Id="2.1.4",
Description="Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive",
Attributes=[
CIS_Requirement_Attribute(
Section="1.1 Control Plane Node Configuration Files",
Profile="Level 1 - Master Node",
AssessmentStatus="Automated",
Description="Ensure that the controller manager pod specification file has permissions of `600` or more restrictive.",
RationaleStatement="The controller manager pod specification file controls various parameters that set the behavior of the Controller Manager on the master node. You should restrict its file permissions to maintain the integrity of the file. The file should be writable by only the administrators on the system.",
ImpactStatement="",
RemediationProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` chmod 600 /etc/kubernetes/manifests/kube-controller-manager.yaml ```",
AuditProcedure="Run the below command (based on the file location on your system) on the Control Plane node. For example, ``` stat -c %a /etc/kubernetes/manifests/kube-controller-manager.yaml ``` Verify that the permissions are `600` or more restrictive.",
AdditionalInformation="",
References="https://kubernetes.io/docs/admin/kube-apiserver/",
DefaultValue="By default, the `kube-controller-manager.yaml` file has permissions of `640`.",
)
],
),
],
)
MITRE_ATTACK_AWS_NAME = "mitre_attack_aws"
MITRE_ATTACK_AWS = Compliance(
Framework="MITRE-ATTACK",
@@ -269,6 +269,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports:
== f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:security-group/{default_sg_id}"
)
assert sg.resource_details == default_sg_name
assert sg.check_metadata.Severity == "high"
assert sg.resource_tags == []
@mock_aws
@@ -361,6 +362,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports:
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].check_metadata.Severity == "critical"
@mock_aws
def test_set_failed_check_called_correctly(self):
@@ -409,7 +411,6 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_all_ports:
"prowler.providers.aws.lib.service.service.AWSService.set_failed_check"
) as mock_set_failed_check,
):
from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_all_ports.ec2_securitygroup_allow_ingress_from_internet_to_all_ports import (
ec2_securitygroup_allow_ingress_from_internet_to_all_ports,
)
@@ -3,9 +3,11 @@ from prowler.providers.aws.services.iam.lib.policy import (
check_full_service_access,
is_condition_block_restrictive,
is_condition_block_restrictive_organization,
is_condition_block_restrictive_sns_endpoint,
is_condition_restricting_from_private_ip,
is_policy_public,
)
import pytest
TRUSTED_AWS_ACCOUNT_NUMBER = "123456789012"
NON_TRUSTED_AWS_ACCOUNT_NUMBER = "111222333444"
@@ -1442,6 +1444,39 @@ class Test_Policy:
condition_statement = {"StringEquals": {"aws:PrincipalOrgID": ALL_ORGS}}
assert not is_condition_block_restrictive_organization(condition_statement)
@pytest.mark.parametrize(
"condition_value,expected",
[
("*@example.com", True),
("https://events.pagerduty.com/integration/<api-key>/enqueue", True),
(
"arn:aws:sns:eu-west-2:123456789012:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7",
True,
),
("*@*.com", False),
("*@*", False),
("*@example.*", False),
("https://events.pagerduty.com/integration/*/enqueue", False),
("arn:aws:sns:eu-west-2:123456789012:example-topic:*", False),
(
"arn:aws:sns:eu-west-2:*:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7",
False,
),
],
)
def test_condition_parser_string_equals_sns_endpoint_str(
self, condition_value: str, expected: bool
):
condition_statement = {"StringEquals": {"SNS:Endpoint": condition_value}}
assert (
is_condition_block_restrictive_sns_endpoint(condition_statement) == expected
)
condition_statement = {"StringLike": {"SNS:Endpoint": condition_value}}
assert (
is_condition_block_restrictive_sns_endpoint(condition_statement) == expected
)
def test_policy_allows_cross_account_access_with_root_and_wildcard_principal(self):
policy_allow_root_and_wildcard_principal = {
"Statement": [
@@ -1,8 +1,10 @@
from typing import Any, Dict
from unittest import mock
from uuid import uuid4
from prowler.providers.aws.services.sns.sns_service import Topic
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1
import pytest
kms_key_id = str(uuid4())
topic_name = "test-topic"
@@ -97,6 +99,20 @@ test_policy_restricted_principal_account_organization = {
}
def generate_policy_restricted_on_sns_endpoint(endpoint: str) -> Dict[str, Any]:
return {
"Statement": [
{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": ["sns:Publish"],
"Resource": f"arn:aws:sns:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:{topic_name}",
"Condition": {"StringEquals": {"SNS:Endpoint": endpoint}},
}
]
}
class Test_sns_topics_not_publicly_accessible:
def test_no_topics(self):
sns_client = mock.MagicMock
@@ -379,3 +395,94 @@ class Test_sns_topics_not_publicly_accessible:
assert result[0].resource_arn == topic_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == []
@pytest.mark.parametrize(
"endpoint",
[
("*@example.com"),
("user@example.com"),
("https://events.pagerduty.com/integration/987654321/enqueue"),
(
"arn:aws:sns:eu-west-2:123456789012:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7"
),
],
)
def test_topic_public_with_sns_endpoint(self, endpoint: str):
sns_client = mock.MagicMock
sns_client.audited_account = AWS_ACCOUNT_NUMBER
sns_client.topics = []
sns_client.topics.append(
Topic(
arn=topic_arn,
name=topic_name,
policy=generate_policy_restricted_on_sns_endpoint(endpoint=endpoint),
region=AWS_REGION_EU_WEST_1,
)
)
sns_client.provider = mock.MagicMock()
sns_client.provider.organizations_metadata = mock.MagicMock()
sns_client.provider.organizations_metadata.organization_id = org_id
with mock.patch(
"prowler.providers.aws.services.sns.sns_service.SNS",
sns_client,
):
from prowler.providers.aws.services.sns.sns_topics_not_publicly_accessible.sns_topics_not_publicly_accessible import (
sns_topics_not_publicly_accessible,
)
check = sns_topics_not_publicly_accessible()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"SNS topic {topic_name} is not public because its policy only allows access from an endpoint."
)
assert result[0].resource_id == topic_name
assert result[0].resource_arn == topic_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == []
@pytest.mark.parametrize(
"endpoint",
[
("*@*"),
("https://events.pagerduty.com/integration/*/enqueue"),
("arn:aws:sns:eu-west-2:*:example-topic:*"),
],
)
def test_topic_public_with_unrestricted_sns_endpoint(self, endpoint: str):
sns_client = mock.MagicMock
sns_client.audited_account = AWS_ACCOUNT_NUMBER
sns_client.topics = []
sns_client.topics.append(
Topic(
arn=topic_arn,
name=topic_name,
policy=generate_policy_restricted_on_sns_endpoint(endpoint=endpoint),
region=AWS_REGION_EU_WEST_1,
)
)
sns_client.provider = mock.MagicMock()
sns_client.provider.organizations_metadata = mock.MagicMock()
sns_client.provider.organizations_metadata.organization_id = org_id
with mock.patch(
"prowler.providers.aws.services.sns.sns_service.SNS",
sns_client,
):
from prowler.providers.aws.services.sns.sns_topics_not_publicly_accessible.sns_topics_not_publicly_accessible import (
sns_topics_not_publicly_accessible,
)
check = sns_topics_not_publicly_accessible()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"SNS topic {topic_name} is public because its policy allows public access."
)
assert result[0].resource_id == topic_name
assert result[0].resource_arn == topic_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == []
@@ -0,0 +1,108 @@
from unittest import mock
from prowler.providers.github.services.repository.repository_service import Repo
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_repository_branch_delete_on_merge_enabled_test:
def test_no_repositories(self):
repository_client = mock.MagicMock
repository_client.repositories = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import (
repository_branch_delete_on_merge_enabled,
)
check = repository_branch_delete_on_merge_enabled()
result = check.execute()
assert len(result) == 0
def test_branch_deletion_disabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
default_branch="main",
private=False,
securitymd=False,
delete_branch_on_merge=False,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import (
repository_branch_delete_on_merge_enabled,
)
check = repository_branch_delete_on_merge_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Repository {repo_name} does not delete branches on merge."
)
def test_branch_deletion_enabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
default_branch="main",
private=False,
securitymd=True,
delete_branch_on_merge=True,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_branch_delete_on_merge_enabled.repository_branch_delete_on_merge_enabled import (
repository_branch_delete_on_merge_enabled,
)
check = repository_branch_delete_on_merge_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Repository {repo_name} does delete branches on merge."
)
@@ -0,0 +1,110 @@
from unittest import mock
from prowler.providers.github.services.repository.repository_service import Repo
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_repository_default_branch_protection_applies_to_admins_test:
def test_no_repositories(self):
repository_client = mock.MagicMock
repository_client.repositories = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import (
repository_default_branch_protection_applies_to_admins,
)
check = repository_default_branch_protection_applies_to_admins()
result = check.execute()
assert len(result) == 0
def test_enforce_status_checks_disabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
default_branch=default_branch,
private=False,
securitymd=False,
enforce_admins=False,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import (
repository_default_branch_protection_applies_to_admins,
)
check = repository_default_branch_protection_applies_to_admins()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Repository {repo_name} does not enforce administrators to be subject to the same branch protection rules as other users."
)
def test_enforce_status_checks_enabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
private=False,
default_branch=default_branch,
enforce_admins=True,
securitymd=True,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_protection_applies_to_admins.repository_default_branch_protection_applies_to_admins import (
repository_default_branch_protection_applies_to_admins,
)
check = repository_default_branch_protection_applies_to_admins()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Repository {repo_name} does enforce administrators to be subject to the same branch protection rules as other users."
)
@@ -0,0 +1,110 @@
from unittest import mock
from prowler.providers.github.services.repository.repository_service import Repo
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_repository_default_branch_requires_conversation_resolution_test:
def test_no_repositories(self):
repository_client = mock.MagicMock
repository_client.repositories = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import (
repository_default_branch_requires_conversation_resolution,
)
check = repository_default_branch_requires_conversation_resolution()
result = check.execute()
assert len(result) == 0
def test_conversation_resolution_disabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
default_branch=default_branch,
conversation_resolution=False,
private=False,
securitymd=False,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import (
repository_default_branch_requires_conversation_resolution,
)
check = repository_default_branch_requires_conversation_resolution()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Repository {repo_name} does not require conversation resolution."
)
def test_conversation_resolution_enabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
private=False,
default_branch=default_branch,
conversation_resolution=True,
securitymd=True,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_requires_conversation_resolution.repository_default_branch_requires_conversation_resolution import (
repository_default_branch_requires_conversation_resolution,
)
check = repository_default_branch_requires_conversation_resolution()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Repository {repo_name} does require conversation resolution."
)
@@ -0,0 +1,110 @@
from unittest import mock
from prowler.providers.github.services.repository.repository_service import Repo
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_repository_default_branch_status_checks_required_test:
def test_no_repositories(self):
repository_client = mock.MagicMock
repository_client.repositories = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import (
repository_default_branch_status_checks_required,
)
check = repository_default_branch_status_checks_required()
result = check.execute()
assert len(result) == 0
def test_enforce_status_checks_disabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
default_branch=default_branch,
status_checks=False,
private=False,
securitymd=False,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import (
repository_default_branch_status_checks_required,
)
check = repository_default_branch_status_checks_required()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Repository {repo_name} does not enforce status checks."
)
def test_enforce_status_checks_enabled(self):
repository_client = mock.MagicMock
repo_name = "repo1"
default_branch = "main"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
private=False,
default_branch=default_branch,
status_checks=True,
securitymd=True,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required.repository_client",
new=repository_client,
),
):
from prowler.providers.github.services.repository.repository_default_branch_status_checks_required.repository_default_branch_status_checks_required import (
repository_default_branch_status_checks_required,
)
check = repository_default_branch_status_checks_required()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Repository {repo_name} does enforce status checks."
)
@@ -21,7 +21,11 @@ def mock_list_repositories(_):
required_linear_history=True,
allow_force_pushes=True,
default_branch_deletion=True,
status_checks=True,
approval_count=2,
enforce_admins=True,
delete_branch_on_merge=True,
conversation_resolution=True,
),
}
@@ -51,4 +55,8 @@ class Test_Repository_Service:
assert repository_service.repositories[1].require_pull_request
assert repository_service.repositories[1].allow_force_pushes
assert repository_service.repositories[1].default_branch_deletion
assert repository_service.repositories[1].status_checks
assert repository_service.repositories[1].enforce_admins
assert repository_service.repositories[1].delete_branch_on_merge
assert repository_service.repositories[1].conversation_resolution
assert repository_service.repositories[1].approval_count == 2
@@ -7,7 +7,7 @@ from prowler.providers.m365.exceptions.exceptions import (
M365UserNotBelongingToTenantError,
)
from prowler.providers.m365.lib.powershell.m365_powershell import M365PowerShell
from prowler.providers.m365.models import M365Credentials
from prowler.providers.m365.models import M365Credentials, M365IdentityInfo
class Testm365PowerShell:
@@ -16,9 +16,17 @@ class Testm365PowerShell:
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
with patch.object(M365PowerShell, "init_credential") as mock_init_credential:
session = M365PowerShell(credentials)
session = M365PowerShell(credentials, identity)
mock_popen.assert_called_once()
mock_init_credential.assert_called_once_with(credentials)
@@ -29,7 +37,15 @@ class Testm365PowerShell:
@patch("subprocess.Popen")
def test_sanitize(self, _):
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
test_cases = [
("test@example.com", "test@example.com"),
@@ -63,7 +79,15 @@ class Testm365PowerShell:
client_secret="test_client_secret",
tenant_id="test_tenant_id",
)
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
session.execute = MagicMock()
@@ -95,9 +119,16 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="contoso.onmicrosoft.com",
tenant_domains=["contoso.onmicrosoft.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
# Mock read_output to return the decrypted password
session.read_output = MagicMock(return_value="decrypted_password")
@@ -150,9 +181,16 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="contoso.onmicrosoft.com",
tenant_domains=["contoso.onmicrosoft.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
# Mock the execute method to return the decrypted password
def mock_execute(command, *args, **kwargs):
@@ -168,20 +206,15 @@ class Testm365PowerShell:
session.test_credentials(credentials)
assert exception.type == M365UserNotBelongingToTenantError
assert "The provided M365 User does not belong to the specified tenant." in str(
exception.value
assert (
"The user domain otherdomain.com does not match any of the tenant domains: contoso.onmicrosoft.com"
in str(exception.value)
)
mock_msal.assert_called_once_with(
client_id="test_client_id",
client_credential="test_client_secret",
authority="https://login.microsoftonline.com/test_tenant_id",
)
mock_msal_instance.acquire_token_by_username_password.assert_called_once_with(
username="user@otherdomain.com",
password="decrypted_password",
scopes=["https://graph.microsoft.com/.default"],
)
# Verify MSAL was not called since domain validation failed first
mock_msal.assert_not_called()
mock_msal_instance.acquire_token_by_username_password.assert_not_called()
session.close()
@patch("subprocess.Popen")
@@ -199,9 +232,16 @@ class Testm365PowerShell:
client_id="test_client_id",
client_secret="test_client_secret",
tenant_id="test_tenant_id",
provider_id="contoso.onmicrosoft.com",
)
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="contoso.onmicrosoft.com",
tenant_domains=["contoso.onmicrosoft.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
# Mock the execute method to return the decrypted password
def mock_execute(command, *args, **kwargs):
@@ -231,7 +271,15 @@ class Testm365PowerShell:
@patch("subprocess.Popen")
def test_remove_ansi(self, mock_popen):
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
test_cases = [
("\x1b[32mSuccess\x1b[0m", "Success"),
@@ -250,7 +298,15 @@ class Testm365PowerShell:
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
command = "Get-Command"
expected_output = {"Name": "Get-Command"}
@@ -261,18 +317,19 @@ class Testm365PowerShell:
@patch("subprocess.Popen")
def test_read_output(self, mock_popen):
"""Test the read_output method with various scenarios:
- Normal stdout output
- Error in stderr
- Timeout in stdout
- Empty output
- Empty queue handling
"""
# Setup
"""Test the read_output method with various scenarios"""
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
# Test 1: Normal stdout output
mock_process.stdout.readline.side_effect = [
@@ -304,95 +361,6 @@ class Testm365PowerShell:
result = session.read_output(timeout=0.1, default="timeout")
assert result == "timeout"
# Test 4: Empty output
mock_process.stdout.readline.side_effect = [f"{session.END}\n"]
mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n"
result = session.read_output()
assert result == ""
# Test 5: Empty queue handling
mock_process.stdout.readline.side_effect = [] # No output at all
mock_process.stderr.readline.return_value = f"Write-Error: {session.END}\n"
result = session.read_output(timeout=0.1, default="empty_queue")
assert result == "empty_queue"
# Test 6: Empty error queue handling
mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"]
mock_process.stderr.readline.side_effect = [] # No error output
with patch("prowler.lib.logger.logger.error") as mock_error:
result = session.read_output()
assert result == "test output"
mock_error.assert_not_called()
# Test 7: Both queues empty
mock_process.stdout.readline.side_effect = [] # No output
mock_process.stderr.readline.side_effect = [] # No error output
result = session.read_output(timeout=0.1, default="both_empty")
assert result == "both_empty"
session.close()
@patch("subprocess.Popen")
def test_read_output_queue_empty(self, mock_popen):
"""Test read_output when both queues are empty"""
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
# Mock process to return empty queues
mock_process.stdout.readline.side_effect = [] # No output
mock_process.stderr.readline.side_effect = [] # No error output
# Test with default value
result = session.read_output(timeout=0.1, default="empty_queue")
assert result == "empty_queue"
# Test without default value
result = session.read_output(timeout=0.1)
assert result == ""
session.close()
@patch("subprocess.Popen")
def test_read_output_error_queue_empty(self, mock_popen):
"""Test read_output when error queue is empty but stdout has content"""
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
# Mock process to return content in stdout but empty stderr
mock_process.stdout.readline.side_effect = ["test output\n", f"{session.END}\n"]
mock_process.stderr.readline.side_effect = [] # No error output
with patch("prowler.lib.logger.logger.error") as mock_error:
result = session.read_output()
assert result == "test output"
mock_error.assert_not_called()
session.close()
@patch("subprocess.Popen")
def test_read_output_result_queue_empty(self, mock_popen):
"""Test read_output when result queue is empty but stderr has content"""
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
# Mock process to return empty stdout but content in stderr
mock_process.stdout.readline.side_effect = [] # No output
mock_process.stderr.readline.side_effect = [
"Error message\n",
f"Write-Error: {session.END}\n",
]
with patch("prowler.lib.logger.logger.error") as mock_error:
result = session.read_output(timeout=0.1, default="default")
assert result == "default"
mock_error.assert_called_once_with("PowerShell error output: Error message")
session.close()
@patch("subprocess.Popen")
@@ -400,7 +368,15 @@ class Testm365PowerShell:
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
test_cases = [
('{"key": "value"}', {"key": "value"}),
@@ -425,7 +401,15 @@ class Testm365PowerShell:
mock_process = MagicMock()
mock_popen.return_value = mock_process
credentials = M365Credentials(user="test@example.com", passwd="test_password")
session = M365PowerShell(credentials)
identity = M365IdentityInfo(
identity_id="test_id",
identity_type="User",
tenant_id="test_tenant",
tenant_domain="example.com",
tenant_domains=["example.com"],
location="test_location",
)
session = M365PowerShell(credentials, identity)
session.close()
+117 -7
View File
@@ -286,6 +286,17 @@ class TestM365Provider:
patch(
"prowler.providers.m365.m365_provider.GraphServiceClient"
) as mock_graph_client,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity",
return_value=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
),
):
# Mock the return value of DefaultAzureCredential
mock_credentials = MagicMock()
@@ -298,7 +309,7 @@ class TestM365Provider:
mock_session = MagicMock()
mock_setup_session.return_value = mock_session
# Mock GraphServiceClient to avoid real API calls
# Mock GraphServiceClient
mock_client = MagicMock()
mock_graph_client.return_value = mock_client
@@ -307,6 +318,7 @@ class TestM365Provider:
tenant_id=str(uuid4()),
region="M365Global",
raise_on_exception=False,
provider_id="test.onmicrosoft.com",
)
assert isinstance(test_connection, Connection)
@@ -321,6 +333,17 @@ class TestM365Provider:
patch(
"prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
) as mock_validate_static_credentials,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity",
return_value=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
),
):
# Mock setup_session to return a mocked session object
mock_session = MagicMock()
@@ -335,6 +358,7 @@ class TestM365Provider:
raise_on_exception=False,
client_id=str(uuid4()),
client_secret=str(uuid4()),
provider_id="test.onmicrosoft.com",
)
assert isinstance(test_connection, Connection)
@@ -458,9 +482,15 @@ class TestM365Provider:
result = M365Provider.setup_powershell(
env_auth=False,
m365_credentials=credentials_dict,
provider_id="test_provider_id",
identity=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
)
assert result.user == credentials_dict["user"]
assert result.passwd == credentials_dict["encrypted_password"]
@@ -595,6 +625,17 @@ class TestM365Provider:
patch(
"prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
) as mock_validate_static_credentials,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity",
return_value=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain="contoso.com",
tenant_domains=["contoso.com"],
location=LOCATION,
),
),
):
# Mock setup_session to return a mocked session object
mock_session = MagicMock()
@@ -620,7 +661,7 @@ class TestM365Provider:
assert exception.type == M365InvalidProviderIdError
assert (
f"Provider ID {provider_id} does not match Application tenant domain {user_domain}"
f"The provider ID {provider_id} does not match any of the service principal tenant domains: {user_domain}"
in str(exception.value)
)
@@ -646,7 +687,14 @@ class TestM365Provider:
M365Provider.setup_powershell(
env_auth=False,
m365_credentials=credentials_dict,
provider_id="test_provider_id",
identity=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
init_modules=False,
)
mock_init_modules.assert_not_called()
@@ -673,7 +721,14 @@ class TestM365Provider:
M365Provider.setup_powershell(
env_auth=False,
m365_credentials=credentials_dict,
provider_id="test_provider_id",
identity=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
init_modules=True,
)
mock_init_modules.assert_called_once()
@@ -702,8 +757,63 @@ class TestM365Provider:
M365Provider.setup_powershell(
env_auth=False,
m365_credentials=credentials_dict,
provider_id="test_provider_id",
identity=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain=DOMAIN,
tenant_domains=["test.onmicrosoft.com"],
location=LOCATION,
),
init_modules=True,
)
assert str(exc_info.value) == "Module initialization failed"
def test_test_connection_provider_id_not_in_tenant_domains(self):
"""Test that an exception is raised when provider_id is not in tenant_domains"""
with (
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_session"
) as mock_setup_session,
patch(
"prowler.providers.m365.m365_provider.M365Provider.validate_static_credentials"
) as mock_validate_static_credentials,
patch(
"prowler.providers.m365.m365_provider.M365Provider.setup_identity",
return_value=M365IdentityInfo(
identity_id=IDENTITY_ID,
identity_type="User",
tenant_id=TENANT_ID,
tenant_domain="contoso.onmicrosoft.com",
tenant_domains=["contoso.onmicrosoft.com", "contoso.com"],
location=LOCATION,
),
),
):
# Mock setup_session to return a mocked session object
mock_session = MagicMock()
mock_setup_session.return_value = mock_session
# Mock ValidateStaticCredentials to avoid real API calls
mock_validate_static_credentials.return_value = None
provider_id = "test.onmicrosoft.com"
with pytest.raises(M365InvalidProviderIdError) as exception:
M365Provider.test_connection(
tenant_id=str(uuid4()),
region="M365Global",
raise_on_exception=True,
client_id=str(uuid4()),
client_secret=str(uuid4()),
user="user@contoso.onmicrosoft.com",
encrypted_password="test_password",
provider_id=provider_id,
)
assert exception.type == M365InvalidProviderIdError
assert (
f"The provider ID {provider_id} does not match any of the service principal tenant domains: contoso.onmicrosoft.com, contoso.com"
in str(exception.value)
)
+6 -1
View File
@@ -2,7 +2,10 @@
All notable changes to the **Prowler UI** are documented in this file.
## [v1.7.0] (Prowler v5.7.0) Not released
## [v1.8.0] (Prowler v5.8.0) Not released
---
## [v1.7.0] (Prowler v5.7.0)
### 🚀 Added
@@ -10,12 +13,14 @@ All notable changes to the **Prowler UI** are documented in this file.
- Added `Accordion` component. [(#7700)](https://github.com/prowler-cloud/prowler/pull/7700)
- Improve `Provider UID` filter by adding more context and enhancing the UI/UX. [(#7741)](https://github.com/prowler-cloud/prowler/pull/7741)
- Added an AWS CloudFormation Quick Link to the IAM Role credentials step [(#7735)](https://github.com/prowler-cloud/prowler/pull/7735)
Use `getLatestFindings` on findings page when no scan or date filters are applied. [(#7756)](https://github.com/prowler-cloud/prowler/pull/7756)
### 🐞 Fixes
- Fix form validation in launch scan workflow. [(#7693)](https://github.com/prowler-cloud/prowler/pull/7693)
- Moved ProviderType to a shared types file and replaced all occurrences across the codebase. [(#7710)](https://github.com/prowler-cloud/prowler/pull/7710)
- Added filter to retrieve only connected providers on the scan page. [(#7723)](https://github.com/prowler-cloud/prowler/pull/7723)
- Removed the alias if not added from findings detail page. [(#7751)](https://github.com/prowler-cloud/prowler/pull/7751)
---
+83
View File
@@ -44,6 +44,47 @@ export const getFindings = async ({
}
};
export const getLatestFindings = async ({
page = 1,
pageSize = 10,
query = "",
sort = "",
filters = {},
}) => {
const headers = await getAuthHeaders({ contentType: false });
if (isNaN(Number(page)) || page < 1)
redirect("findings?include=resources,scan.provider");
const url = new URL(
`${apiBaseUrl}/findings/latest?include=resources,scan.provider`,
);
if (page) url.searchParams.append("page[number]", page.toString());
if (pageSize) url.searchParams.append("page[size]", pageSize.toString());
if (query) url.searchParams.append("filter[search]", query);
if (sort) url.searchParams.append("sort", sort);
Object.entries(filters).forEach(([key, value]) => {
url.searchParams.append(key, String(value));
});
try {
const findings = await fetch(url.toString(), {
headers,
});
const data = await findings.json();
const parsedData = parseStringify(data);
revalidatePath("/findings");
return parsedData;
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error fetching findings:", error);
return undefined;
}
};
export const getMetadataInfo = async ({
query = "",
sort = "",
@@ -85,3 +126,45 @@ export const getMetadataInfo = async ({
return undefined;
}
};
export const getLatestMetadataInfo = async ({
query = "",
sort = "",
filters = {},
}) => {
const headers = await getAuthHeaders({ contentType: false });
const url = new URL(`${apiBaseUrl}/findings/metadata/latest`);
if (query) url.searchParams.append("filter[search]", query);
if (sort) url.searchParams.append("sort", sort);
Object.entries(filters).forEach(([key, value]) => {
// Define filters to exclude
const excludedFilters = ["region__in", "service__in", "resource_type__in"];
if (
key !== "filter[search]" &&
!excludedFilters.some((filter) => key.includes(filter))
) {
url.searchParams.append(key, String(value));
}
});
try {
const response = await fetch(url.toString(), {
headers,
});
if (!response.ok) {
throw new Error(`Failed to fetch metadata info: ${response.statusText}`);
}
const parsedData = parseStringify(await response.json());
return parsedData;
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error fetching metadata info:", error);
return undefined;
}
};
+24 -61
View File
@@ -1,8 +1,12 @@
import { Spacer } from "@nextui-org/react";
import { format, subDays } from "date-fns";
import React, { Suspense } from "react";
import { getFindings, getMetadataInfo } from "@/actions/findings";
import {
getFindings,
getLatestFindings,
getLatestMetadataInfo,
getMetadataInfo,
} from "@/actions/findings";
import { getProviders } from "@/actions/providers";
import { getScans } from "@/actions/scans";
import { filterFindings } from "@/components/filters/data-filters";
@@ -13,7 +17,12 @@ import {
} from "@/components/findings/table";
import { ContentLayout } from "@/components/ui";
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
import { createDict } from "@/lib";
import {
createDict,
extractFiltersAndQuery,
extractSortAndKey,
hasDateOrScanFilter,
} from "@/lib";
import { ProviderAccountProps, ProviderProps } from "@/types";
import { FindingProps, ScanProps, SearchParamsProps } from "@/types/components";
@@ -22,41 +31,14 @@ export default async function Findings({
}: {
searchParams: SearchParamsProps;
}) {
const searchParamsKey = JSON.stringify(searchParams || {});
const sort = searchParams.sort?.toString();
// Make sure the sort is correctly encoded
const encodedSort = sort?.replace(/^\+/, "");
const twoDaysAgo = format(subDays(new Date(), 2), "yyyy-MM-dd");
const { searchParamsKey, encodedSort } = extractSortAndKey(searchParams);
const { filters, query } = extractFiltersAndQuery(searchParams);
// Check if the searchParams contain any date or scan filter
const hasDateOrScanFilter = Object.keys(searchParams).some(
(key) => key.includes("inserted_at") || key.includes("scan__in"),
);
// Default filters for getMetadataInfo
const defaultFilters: Record<string, string> = hasDateOrScanFilter
? {} // Do not apply default filters if there are date or scan filters
: { "filter[inserted_at__gte]": twoDaysAgo };
// Extract all filter parameters and combine with default filters
const filters: Record<string, string> = {
...defaultFilters,
...Object.fromEntries(
Object.entries(searchParams)
.filter(([key]) => key.startsWith("filter["))
.map(([key, value]) => [
key,
Array.isArray(value) ? value.join(",") : value?.toString() || "",
]),
),
};
const query = filters["filter[search]"] || "";
const hasDateOrScan = hasDateOrScanFilter(searchParams);
const [metadataInfoData, providersData, scansData] = await Promise.all([
getMetadataInfo({
(hasDateOrScan ? getMetadataInfo : getLatestMetadataInfo)({
query,
sort: encodedSort,
filters,
@@ -163,38 +145,19 @@ const SSRDataTable = async ({
const page = parseInt(searchParams.page?.toString() || "1", 10);
const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10);
const defaultSort = "severity,status,-inserted_at";
const sort = searchParams.sort?.toString() || defaultSort;
// Make sure the sort is correctly encoded
const encodedSort = sort.replace(/^\+/, "");
const twoDaysAgo = format(subDays(new Date(), 2), "yyyy-MM-dd");
const { encodedSort } = extractSortAndKey({
...searchParams,
sort: searchParams.sort ?? defaultSort,
});
const { filters, query } = extractFiltersAndQuery(searchParams);
// Check if the searchParams contain any date or scan filter
const hasDateOrScanFilter = Object.keys(searchParams).some(
(key) => key.includes("inserted_at") || key.includes("scan__in"),
);
const hasDateOrScan = hasDateOrScanFilter(searchParams);
// Default filters for getFindings
const defaultFilters: Record<string, string> = hasDateOrScanFilter
? {} // Do not apply default filters if there are date or scan filters
: { "filter[inserted_at__gte]": twoDaysAgo };
const fetchFindings = hasDateOrScan ? getFindings : getLatestFindings;
const filters: Record<string, string> = {
...defaultFilters,
...Object.fromEntries(
Object.entries(searchParams)
.filter(([key]) => key.startsWith("filter["))
.map(([key, value]) => [
key,
Array.isArray(value) ? value.join(",") : value?.toString() || "",
]),
),
};
const query = filters["filter[search]"] || "";
const findingsData = await getFindings({
const findingsData = await fetchFindings({
query,
page,
sort: encodedSort,
@@ -307,7 +307,9 @@ export const FindingDetail = ({
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<InfoField label="Alias">{provider.alias}</InfoField>
{provider.alias && (
<InfoField label="Alias">{provider.alias}</InfoField>
)}
<InfoField label="Connection Status">
<span
className={`${provider.connection.connected ? "text-green-500" : "text-red-500"}`}
+47 -8
View File
@@ -995,13 +995,17 @@ export const AzureIcon: React.FC<IconSvgProps> = ({
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
viewBox="0 0 16 16"
width={size || width}
height={size || height}
fill="currentColor"
{...props}
>
<path d="M11.001 5h-6v6h6zm2 0v6h6V5zm6 8h-6v6h6zm-8 6v-6h-6v6zm-8-16h18v18h-18z" />
<path
fill-rule="evenodd"
d="m15.37 13.68l-4-12a1 1 0 0 0-1-.68H5.63a1 1 0 0 0-.95.68l-4.05 12a1 1 0 0 0 1 1.32h2.93a1 1 0 0 0 .94-.68l.61-1.78l3 2.27a1 1 0 0 0 .6.19h4.68a1 1 0 0 0 .98-1.32m-5.62.66a.32.32 0 0 1-.2-.07L3.9 10.08l-.09-.07h3l.08-.21l1-2.53l2.24 6.63a.34.34 0 0 1-.38.44m4.67 0H10.7a1 1 0 0 0 0-.66l-4.05-12h3.72a.34.34 0 0 1 .32.23l4.05 12a.34.34 0 0 1-.32.43"
clip-rule="evenodd"
/>
</svg>
);
};
@@ -1010,6 +1014,7 @@ export const M365Icon: React.FC<IconSvgProps> = ({
size = 24,
width,
height,
strokeWidth = 2,
...props
}) => {
return (
@@ -1017,16 +1022,27 @@ export const M365Icon: React.FC<IconSvgProps> = ({
xmlns="http://www.w3.org/2000/svg"
width={size || width}
height={size || height}
viewBox="0 0 24 24"
viewBox="0 0 48 48"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M17.5 21H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z" />
<path d="M22 10a3 3 0 0 0-3-3h-2.207a5.502 5.502 0 0 0-10.702.5" />
<path
strokeLinejoin="round"
d="M20.507 3.241L8.443 9.74a8.6 8.6 0 0 0-4.508 7.563V30.7a8.6 8.6 0 0 0 4.508 7.564m15.668-5.597l-2.826-1.557a8.6 8.6 0 0 1-4.45-7.532v-4.072"
strokeWidth={strokeWidth}
></path>
<path
strokeLinejoin="round"
d="M31.166 19.275v4.45a8.6 8.6 0 0 1-4.508 7.564l-11.466 6.202a8.6 8.6 0 0 1-7.435.358q.33.222.687.414l11.465 6.202a8.6 8.6 0 0 0 8.182 0l11.465-6.202a8.6 8.6 0 0 0 4.508-7.563"
strokeWidth={strokeWidth}
></path>
<path
strokeLinejoin="round"
d="M39.557 9.739L28.092 3.536a8.6 8.6 0 0 0-7.585-.295a8.6 8.6 0 0 0-3.673 7.048v8.986l3.288-1.661a8.6 8.6 0 0 1 7.756 0l11.465 5.793a8.6 8.6 0 0 1 4.72 7.484l.001-.191V17.302a8.6 8.6 0 0 0-4.507-7.563"
strokeWidth={strokeWidth}
></path>
</svg>
);
};
@@ -1046,7 +1062,7 @@ export const GCPIcon: React.FC<IconSvgProps> = ({
fill="currentColor"
{...props}
>
<path d="M12 11h8.533q.066.578.067 1.184c0 2.734-.98 5.036-2.678 6.6c-1.485 1.371-3.518 2.175-5.942 2.175A8.976 8.976 0 0 1 3 11.98A8.976 8.976 0 0 1 11.98 3c2.42 0 4.453.89 6.008 2.339L16.526 6.8C15.368 5.681 13.803 5 12 5a7 7 0 0 0 0 14c3.527 0 6.144-2.608 6.577-6H12z" />
<path d="M12.19 2.38a9.344 9.344 0 0 0-9.234 6.893c.053-.02-.055.013 0 0c-3.875 2.551-3.922 8.11-.247 10.941l.006-.007l-.007.03a6.7 6.7 0 0 0 4.077 1.356h5.173l.03.03h5.192c6.687.053 9.376-8.605 3.835-12.35a9.37 9.37 0 0 0-2.821-4.552l-.043.043l.006-.05A9.34 9.34 0 0 0 12.19 2.38m-.358 4.146c1.244-.04 2.518.368 3.486 1.15a5.19 5.19 0 0 1 1.862 4.078v.518c3.53-.07 3.53 5.262 0 5.193h-5.193l-.008.009v-.04H6.785a2.6 2.6 0 0 1-1.067-.23h.001a2.597 2.597 0 1 1 3.437-3.437l3.013-3.012A6.75 6.75 0 0 0 8.11 8.24c.018-.01.04-.026.054-.023a5.2 5.2 0 0 1 3.67-1.69z" />
</svg>
);
};
@@ -1078,3 +1094,26 @@ export const MutedIcon: React.FC<IconSvgProps> = ({
</svg>
);
};
export const KubernetesIcon: React.FC<IconSvgProps> = ({
size = 24,
width,
height,
...props
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
width={size || width}
height={size || height}
fill="currentColor"
{...props}
>
<path
fill="currentColor"
d="m29.223 17.964l-3.304-.754a9.78 9.78 0 0 0-1.525-6.624l2.54-2.026l-1.247-1.564l-2.539 2.024A9.97 9.97 0 0 0 17 6.05V3h-2v3.05a9.97 9.97 0 0 0-6.148 2.97l-2.54-2.024L5.066 8.56l2.54 2.025a9.78 9.78 0 0 0-1.524 6.625l-3.304.754l.446 1.95l3.297-.753a10.04 10.04 0 0 0 4.269 5.358l-1.33 2.763l1.802.867l1.329-2.76a9.8 9.8 0 0 0 6.82 0l1.33 2.76l1.802-.868l-1.33-2.762a10.04 10.04 0 0 0 4.269-5.358l3.297.752ZM24 16q-.002.385-.039.763l-5-1.142a3 3 0 0 0-.137-.594l3.996-3.187A7.94 7.94 0 0 1 24 16m-9 0a1 1 0 1 1 1 1a1 1 0 0 1-1-1m6.576-5.726l-3.996 3.187a3 3 0 0 0-.58-.277V8.07a7.98 7.98 0 0 1 4.576 2.205M15 8.07v5.115a3 3 0 0 0-.58.277l-3.996-3.187A7.98 7.98 0 0 1 15 8.07M8 16a7.94 7.94 0 0 1 1.18-4.16l3.996 3.187a3 3 0 0 0-.137.594l-5 1.141A8 8 0 0 1 8 16m.484 2.712l4.975-1.136a3 3 0 0 0 .414.537L11.66 22.71a8.03 8.03 0 0 1-3.176-3.998M16 24a8 8 0 0 1-2.54-.42l2.22-4.612A3 3 0 0 0 16 19a3 3 0 0 0 .319-.032l2.221 4.612A8 8 0 0 1 16 24m4.34-1.29l-2.213-4.598a3 3 0 0 0 .414-.536l4.976 1.136a8.03 8.03 0 0 1-3.176 3.998"
/>
</svg>
);
};
+46
View File
@@ -0,0 +1,46 @@
/**
* Extracts normalized filters and search query from the URL search params.
* Used Server Side Rendering (SSR). There is a hook (useUrlFilters) for client side.
*/
export const extractFiltersAndQuery = (
searchParams: Record<string, unknown>,
) => {
const filters: Record<string, string> = {
...Object.fromEntries(
Object.entries(searchParams)
.filter(([key]) => key.startsWith("filter["))
.map(([key, value]) => [
key,
Array.isArray(value) ? value.join(",") : value?.toString() || "",
]),
),
};
const query = filters["filter[search]"] || "";
return { filters, query };
};
/**
* Returns true if there are any scan or inserted_at filters in the search params.
* Used to determine whether to call the full findings endpoint.
*/
export const hasDateOrScanFilter = (searchParams: Record<string, unknown>) =>
Object.keys(searchParams).some(
(key) => key.includes("inserted_at") || key.includes("scan__in"),
);
/**
* Encodes sort strings by removing leading "+" symbols.
*/
export const encodeSort = (sort?: string) => sort?.replace(/^\+/, "") || "";
/**
* Extracts the sort string and the stable key to use in Suspense boundaries.
*/
export const extractSortAndKey = (searchParams: Record<string, unknown>) => {
const searchParamsKey = JSON.stringify(searchParams || {});
const rawSort = searchParams.sort?.toString();
const encodedSort = encodeSort(rawSort);
return { searchParamsKey, rawSort, encodedSort };
};
+1
View File
@@ -1,4 +1,5 @@
export * from "./external-urls";
export * from "./helper";
export * from "./helper-filters";
export * from "./menu-list";
export * from "./utils";
+2 -2
View File
@@ -3,7 +3,6 @@
import {
AlertCircle,
Bookmark,
Boxes,
CloudCog,
Group,
LayoutGrid,
@@ -26,6 +25,7 @@ import {
CircleHelpIcon,
DocIcon,
GCPIcon,
KubernetesIcon,
M365Icon,
SupportIcon,
} from "@/components/icons/Icons";
@@ -108,7 +108,7 @@ export const getMenuList = (pathname: string): GroupProps[] => {
{
href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=kubernetes&sort=severity,-inserted_at",
label: "Kubernetes",
icon: Boxes,
icon: KubernetesIcon,
},
],
defaultOpen: false,