mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(AWS): New Storage Gateway FileShare KMS CMK Check (#4082)
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_service import (
|
||||
StorageGateway,
|
||||
)
|
||||
from prowler.providers.common.provider import Provider
|
||||
|
||||
storagegateway_client = StorageGateway(Provider.get_global_provider())
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "storagegateway_fileshare_encryption_enabled",
|
||||
"CheckTitle": "Check if AWS StorageGateway File Shares are encrypted with KMS CMK.",
|
||||
"CheckType": [
|
||||
"Security"
|
||||
],
|
||||
"ServiceName": "storagegateway",
|
||||
"SubServiceName": "filegateway",
|
||||
"ResourceIdTemplate": "arn:aws:storagegateway:region:account-id:share",
|
||||
"Severity": "low",
|
||||
"ResourceType": "AwsStorageGatewayFileShares",
|
||||
"Description": "Ensure that Amazon Storage Gateway service is using AWS KMS Customer Master Keys (CMKs) instead of AWS managed-keys (i.e. default keys) for file share data encryption, in order to have a fine-grained control over data-at-rest encryption/decryption process and meet compliance requirements. An AWS Storage Gateway file share is a file system mount point backed by Amazon S3 cloud storage.",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data by not having fine-grained control over data-at-rest encryption/decryption process and meet compliance requirements.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/filegateway/latest/files3/encrypt-objects-stored-by-file-gateway-in-amazon-s3.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws storagegateway update-nfs-file-share --region us-east-1 --file-share-arn arn:aws:storagegateway:us-east-1:123456789012:share/share-abcd1234 --kms-encrypted --kms-key arn:aws:kms:us-east-1:123456789012:key/abcdabcd-1234-1234-1234-abcdabcdabcd",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity-staging/knowledge-base/aws/StorageGateway/file-shares-encrypted-with-cmk.html#",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Ensure that Amazon Storage Gateway service is using AWS KMS Customer Master Keys (CMKs).",
|
||||
"Url": "https://docs.aws.amazon.com/filegateway/latest/files3/encrypt-objects-stored-by-file-gateway-in-amazon-s3.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_client import (
|
||||
storagegateway_client,
|
||||
)
|
||||
|
||||
|
||||
class storagegateway_fileshare_encryption_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for fileshare in storagegateway_client.fileshares:
|
||||
report = Check_Report_AWS(self.metadata())
|
||||
report.region = fileshare.region
|
||||
report.resource_id = fileshare.id
|
||||
report.resource_arn = fileshare.arn
|
||||
report.resource_tags = fileshare.tags
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"StorageGateway File Share {fileshare.id} is not using KMS CMK."
|
||||
)
|
||||
if fileshare.kms:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"StorageGateway File Share {fileshare.id} is using KMS CMK."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,96 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.lib.scan_filters.scan_filters import is_resource_filtered
|
||||
from prowler.providers.aws.lib.service.service import AWSService
|
||||
|
||||
|
||||
################################ StorageGateway
|
||||
class StorageGateway(AWSService):
|
||||
def __init__(self, provider):
|
||||
# Call AWSService's __init__
|
||||
super().__init__(__class__.__name__, provider)
|
||||
self.fileshares = []
|
||||
self.__threading_call__(self.__list_file_shares__)
|
||||
self.__threading_call__(self.__describe_nfs_file_shares__)
|
||||
self.__threading_call__(self.__describe_smb_file_shares__)
|
||||
|
||||
def __list_file_shares__(self, regional_client):
|
||||
try:
|
||||
list_file_share_paginator = regional_client.get_paginator(
|
||||
"list_file_shares"
|
||||
)
|
||||
for page in list_file_share_paginator.paginate():
|
||||
for fileshare in page["FileShareInfoList"]:
|
||||
if not self.audit_resources or (
|
||||
is_resource_filtered(
|
||||
fileshare["FileShareARN"], self.audit_resources
|
||||
)
|
||||
):
|
||||
self.fileshares.append(
|
||||
FileShare(
|
||||
id=fileshare["FileShareId"],
|
||||
arn=fileshare["FileShareARN"],
|
||||
gateway_arn=fileshare["GatewayARN"],
|
||||
region=regional_client.region,
|
||||
fs_type=fileshare["FileShareType"],
|
||||
status=fileshare["FileShareStatus"],
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_nfs_file_shares__(self, regional_client):
|
||||
logger.info("StorageGateway - Describe NFS FileShares...")
|
||||
try:
|
||||
for fileshare in self.fileshares:
|
||||
if fileshare.fs_type == "NFS":
|
||||
response = regional_client.describe_nfs_file_shares(
|
||||
FileShareARNList=[fileshare.arn]
|
||||
)
|
||||
fileshare.tags = response["NFSFileShareInfoList"][0].get("Tags", [])
|
||||
fileshare.kms = response["NFSFileShareInfoList"][0]["KMSEncrypted"]
|
||||
fileshare.kms_key = response["NFSFileShareInfoList"][0].get(
|
||||
"KMSKey", ""
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_smb_file_shares__(self, regional_client):
|
||||
logger.info("StorageGateway - Describe SMB FileShares...")
|
||||
try:
|
||||
for fileshare in self.fileshares:
|
||||
if fileshare.fs_type == "SMB":
|
||||
response = regional_client.describe_smb_file_shares(
|
||||
FileShareARNList=[fileshare.arn]
|
||||
)
|
||||
fileshare.tags = response["SMBFileShareInfoList"][0].get("Tags", [])
|
||||
fileshare.kms = response["SMBFileShareInfoList"][0]["KMSEncrypted"]
|
||||
fileshare.kms_key = response["SMBFileShareInfoList"][0].get(
|
||||
"KMSKey", ""
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
|
||||
class FileShare(BaseModel):
|
||||
id: str
|
||||
arn: str
|
||||
gateway_arn: str
|
||||
region: str
|
||||
fs_type: str
|
||||
status: str
|
||||
kms: Optional[bool]
|
||||
kms_key: Optional[str]
|
||||
tags: Optional[list] = []
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_service import (
|
||||
FileShare,
|
||||
)
|
||||
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_US_EAST_1
|
||||
|
||||
test_gateway = "sgw-12A3456B"
|
||||
test_gateway_arn = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:gateway/{test_gateway}"
|
||||
test_kms_key = f"arn:aws:kms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:key/b72aaa2a-2222-99tt-12345690qwe"
|
||||
test_share_nfs = "share-nfs2wwe"
|
||||
test_share_arn_nfs = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_nfs}"
|
||||
test_share_smb = "share-smb2wwe"
|
||||
test_share_arn_smb = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_smb}"
|
||||
|
||||
|
||||
class Test_storagegateway_fileshare_encryption_enabled:
|
||||
def test_no_storagegateway_fileshare(self):
|
||||
storagegateway_client = mock.MagicMock
|
||||
storagegateway_client.fileshares = []
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.storagegateway.storagegateway_service.StorageGateway",
|
||||
storagegateway_client,
|
||||
):
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_fileshare_encryption_enabled.storagegateway_fileshare_encryption_enabled import (
|
||||
storagegateway_fileshare_encryption_enabled,
|
||||
)
|
||||
|
||||
check = storagegateway_fileshare_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_nfs_fileshare_kms_encryption(self):
|
||||
storagegateway_client = mock.MagicMock
|
||||
storagegateway_client.fileshares = []
|
||||
storagegateway_client.fileshares.append(
|
||||
FileShare(
|
||||
id=test_share_nfs,
|
||||
arn=test_share_arn_nfs,
|
||||
gateway_arn=test_gateway_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
fs_type="NFS",
|
||||
status="AVAILABLE",
|
||||
kms=True,
|
||||
kms_key=test_kms_key,
|
||||
tags=[
|
||||
{"Key": "test", "Value": "test"},
|
||||
],
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.storagegateway.storagegateway_service.StorageGateway",
|
||||
storagegateway_client,
|
||||
):
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_fileshare_encryption_enabled.storagegateway_fileshare_encryption_enabled import (
|
||||
storagegateway_fileshare_encryption_enabled,
|
||||
)
|
||||
|
||||
check = storagegateway_fileshare_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"StorageGateway File Share {test_share_nfs} is using KMS CMK."
|
||||
)
|
||||
assert result[0].resource_id == f"{test_share_nfs}"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_nfs}"
|
||||
)
|
||||
assert result[0].resource_tags == [
|
||||
{"Key": "test", "Value": "test"},
|
||||
]
|
||||
|
||||
def test_nfs_fileshare_no_kms_encryption(self):
|
||||
storagegateway_client = mock.MagicMock
|
||||
storagegateway_client.fileshares = []
|
||||
storagegateway_client.fileshares.append(
|
||||
FileShare(
|
||||
id=test_share_nfs,
|
||||
arn=test_share_arn_nfs,
|
||||
gateway_arn=test_gateway_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
fs_type="NFS",
|
||||
status="AVAILABLE",
|
||||
kms=False,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.storagegateway.storagegateway_service.StorageGateway",
|
||||
storagegateway_client,
|
||||
):
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_fileshare_encryption_enabled.storagegateway_fileshare_encryption_enabled import (
|
||||
storagegateway_fileshare_encryption_enabled,
|
||||
)
|
||||
|
||||
check = storagegateway_fileshare_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"StorageGateway File Share {test_share_nfs} is not using KMS CMK."
|
||||
)
|
||||
assert result[0].resource_id == f"{test_share_nfs}"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_nfs}"
|
||||
)
|
||||
assert result[0].resource_tags == []
|
||||
|
||||
def test_smb_fileshare_kms_encryption(self):
|
||||
storagegateway_client = mock.MagicMock
|
||||
storagegateway_client.fileshares = []
|
||||
storagegateway_client.fileshares.append(
|
||||
FileShare(
|
||||
id=test_share_smb,
|
||||
arn=test_share_arn_smb,
|
||||
gateway_arn=test_gateway_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
fs_type="SMB",
|
||||
status="AVAILABLE",
|
||||
kms=True,
|
||||
kms_key=test_kms_key,
|
||||
tags=[
|
||||
{"Key": "test", "Value": "test"},
|
||||
],
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.storagegateway.storagegateway_service.StorageGateway",
|
||||
storagegateway_client,
|
||||
):
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_fileshare_encryption_enabled.storagegateway_fileshare_encryption_enabled import (
|
||||
storagegateway_fileshare_encryption_enabled,
|
||||
)
|
||||
|
||||
check = storagegateway_fileshare_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"StorageGateway File Share {test_share_smb} is using KMS CMK."
|
||||
)
|
||||
assert result[0].resource_id == f"{test_share_smb}"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_smb}"
|
||||
)
|
||||
assert result[0].resource_tags == [
|
||||
{"Key": "test", "Value": "test"},
|
||||
]
|
||||
|
||||
def test_smb_fileshare_no_kms_encryption(self):
|
||||
storagegateway_client = mock.MagicMock
|
||||
storagegateway_client.fileshares = []
|
||||
storagegateway_client.fileshares.append(
|
||||
FileShare(
|
||||
id=test_share_smb,
|
||||
arn=test_share_arn_smb,
|
||||
gateway_arn=test_gateway_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
fs_type="SMB",
|
||||
status="AVAILABLE",
|
||||
kms=False,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.storagegateway.storagegateway_service.StorageGateway",
|
||||
storagegateway_client,
|
||||
):
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_fileshare_encryption_enabled.storagegateway_fileshare_encryption_enabled import (
|
||||
storagegateway_fileshare_encryption_enabled,
|
||||
)
|
||||
|
||||
check = storagegateway_fileshare_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"StorageGateway File Share {test_share_smb} is not using KMS CMK."
|
||||
)
|
||||
assert result[0].resource_id == f"{test_share_smb}"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_smb}"
|
||||
)
|
||||
assert result[0].resource_tags == []
|
||||
@@ -0,0 +1,127 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
import botocore
|
||||
from moto import mock_aws
|
||||
|
||||
from prowler.providers.aws.services.storagegateway.storagegateway_service import (
|
||||
StorageGateway,
|
||||
)
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
test_gateway = "sgw-12A3456B"
|
||||
test_gateway_arn = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:gateway/{test_gateway}"
|
||||
test_iam_role = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:role/my-role"
|
||||
test_kms_key = f"arn:aws:kms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:key/b72aaa2a-2222-99tt-12345690qwe"
|
||||
test_share_nfs = "share-nfs2wwe"
|
||||
test_share_arn_nfs = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_nfs}"
|
||||
test_share_smb = "share-smb2wwe"
|
||||
test_share_arn_smb = f"arn:aws:storagegateway:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:share/{test_share_smb}"
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
|
||||
def mock_make_api_call(self, operation_name, kwarg):
|
||||
if operation_name == "CreateNFSFileShare":
|
||||
return {"FileShareARN": f"{test_share_arn_nfs}"}
|
||||
if operation_name == "CreateSMBFileShare":
|
||||
return {"FileShareARN": f"{test_share_arn_smb}"}
|
||||
if operation_name == "ListFileShares":
|
||||
return {
|
||||
"FileShareInfoList": [
|
||||
{
|
||||
"FileShareType": "NFS",
|
||||
"FileShareARN": f"{test_share_arn_nfs}",
|
||||
"FileShareId": f"{test_share_nfs}",
|
||||
"FileShareStatus": "AVAILABLE",
|
||||
"GatewayARN": f"{test_gateway_arn}",
|
||||
},
|
||||
{
|
||||
"FileShareType": "SMB",
|
||||
"FileShareARN": f"{test_share_arn_smb}",
|
||||
"FileShareId": f"{test_share_smb}",
|
||||
"FileShareStatus": "AVAILABLE",
|
||||
"GatewayARN": f"{test_gateway_arn}",
|
||||
},
|
||||
]
|
||||
}
|
||||
if operation_name == "DescribeNFSFileShares":
|
||||
return {
|
||||
"NFSFileShareInfoList": [
|
||||
{
|
||||
"FileShareType": "NFS",
|
||||
"FileShareARN": f"{test_share_arn_nfs}",
|
||||
"FileShareId": f"{test_share_nfs}",
|
||||
"FileShareStatus": "AVAILABLE",
|
||||
"GatewayARN": f"{test_gateway_arn}",
|
||||
"Tags": [
|
||||
{"Key": "test", "Value": "test"},
|
||||
],
|
||||
"KMSEncrypted": True,
|
||||
"KMSKey": f"{test_kms_key}",
|
||||
},
|
||||
]
|
||||
}
|
||||
if operation_name == "DescribeSMBFileShares":
|
||||
return {
|
||||
"SMBFileShareInfoList": [
|
||||
{
|
||||
"FileShareType": "SMB",
|
||||
"FileShareARN": f"{test_share_arn_smb}",
|
||||
"FileShareId": f"{test_share_smb}",
|
||||
"FileShareStatus": "AVAILABLE",
|
||||
"GatewayARN": f"{test_gateway_arn}",
|
||||
"KMSEncrypted": False,
|
||||
"KMSKey": "",
|
||||
},
|
||||
]
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
class Test_StorageGateway_Service:
|
||||
|
||||
# Test SGW Service
|
||||
@mock_aws
|
||||
def test_service(self):
|
||||
# SGW client for this test class
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
storagegateway = StorageGateway(aws_provider)
|
||||
assert storagegateway.service == "storagegateway"
|
||||
|
||||
# Test SGW Describe FileShares
|
||||
@mock_aws
|
||||
def test__describe_file_shares__(self):
|
||||
# StorageGateway client for this test class
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
sgw = StorageGateway(aws_provider)
|
||||
assert len(sgw.fileshares) == 2
|
||||
assert sgw.fileshares[0].id == "share-nfs2wwe"
|
||||
assert sgw.fileshares[0].fs_type == "NFS"
|
||||
assert sgw.fileshares[0].status == "AVAILABLE"
|
||||
assert (
|
||||
sgw.fileshares[0].gateway_arn
|
||||
== "arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12A3456B"
|
||||
)
|
||||
assert sgw.fileshares[0].kms
|
||||
assert (
|
||||
sgw.fileshares[0].kms_key
|
||||
== "arn:aws:kms:us-east-1:123456789012:key/b72aaa2a-2222-99tt-12345690qwe"
|
||||
)
|
||||
assert sgw.fileshares[0].tags == [
|
||||
{"Key": "test", "Value": "test"},
|
||||
]
|
||||
assert sgw.fileshares[1].id == "share-smb2wwe"
|
||||
assert sgw.fileshares[1].fs_type == "SMB"
|
||||
assert sgw.fileshares[1].status == "AVAILABLE"
|
||||
assert (
|
||||
sgw.fileshares[1].gateway_arn
|
||||
== "arn:aws:storagegateway:us-east-1:123456789012:gateway/sgw-12A3456B"
|
||||
)
|
||||
assert not sgw.fileshares[1].kms
|
||||
assert sgw.fileshares[1].kms_key == ""
|
||||
assert sgw.fileshares[1].tags == []
|
||||
Reference in New Issue
Block a user