The OSS bucket used to store ActionTrail logs is not publicly accessible
Alibaba Cloud ActionTrail logs a record of every API call made in your account and stores these log files in an OSS bucket. It is recommended that the Access Control List (ACL) of the OSS bucket used by ActionTrail is set to private to prevent unauthorized public access to sensitive audit log data.
Risk
Allowing public access to the OSS bucket containing ActionTrail logs may expose sensitive information about your infrastructure, API usage patterns, and security configurations. An adversary could use this information to identify weaknesses in the affected account, leading to potential data breaches, privilege escalation, and compliance violations.
Run this check with Prowler
Run in Prowler Cloudprowler alibabacloud --checks actiontrail_oss_bucket_not_publicly_accessibleRecommendation
Set the ACL of the OSS bucket used to store ActionTrail logs to private to prevent unauthorized public access to sensitive audit log data.
Remediation
CLI
ossutil set-acl oss://<bucketName> private -bTerraform
resource "alicloud_oss_bucket_public_access_block" "actiontrail" {
bucket = alicloud_oss_bucket.actiontrail.bucket
block_public_access = true
}Other
Check Code
from prowler.lib.check.models import Check, CheckReportAlibabaCloud
from prowler.providers.alibabacloud.services.actiontrail.actiontrail_client import (
actiontrail_client,
)
from prowler.providers.alibabacloud.services.oss.oss_client import oss_client
def _is_policy_public(policy_document: dict) -> bool:
"""
Check if a bucket policy allows public access.
A policy is considered public if it has a statement with:
- Effect: "Allow"
- Principal: ["*"] (or contains "*")
- No Condition elements
Args:
policy_document: The parsed policy document as a dictionary.
Returns:
bool: True if policy allows public access, False otherwise.
"""
if not policy_document:
return False
statements = policy_document.get("Statement", [])
if not isinstance(statements, list):
statements = [statements]
for statement in statements:
effect = statement.get("Effect", "")
principal = statement.get("Principal", [])
condition = statement.get("Condition")
# If there's a condition, it's not truly public
if condition:
continue
if effect == "Allow":
# Check if Principal is "*" or contains "*"
if isinstance(principal, list):
if "*" in principal:
return True
elif principal == "*":
return True
return False
class actiontrail_oss_bucket_not_publicly_accessible(Check):
"""Check if the OSS bucket used to store ActionTrail logs is not publicly accessible."""
def execute(self) -> list[CheckReportAlibabaCloud]:
findings = []
# Get all ActionTrail trails
for trail in actiontrail_client.trails.values():
# Only check trails that have an OSS bucket configured
if not trail.oss_bucket_name:
continue
# Find the OSS bucket used by this trail
bucket = None
for oss_bucket in oss_client.buckets.values():
if oss_bucket.name == trail.oss_bucket_name:
bucket = oss_bucket
break
# Create report for this trail's OSS bucket
report = CheckReportAlibabaCloud(metadata=self.metadata(), resource=trail)
report.region = trail.home_region
report.resource_id = trail.oss_bucket_name
report.resource_arn = (
f"acs:oss::{actiontrail_client.audited_account}:{trail.oss_bucket_name}"
)
if not bucket:
# Bucket not found in OSS service (might not have permissions or bucket doesn't exist)
report.status = "MANUAL"
report.status_extended = (
f"ActionTrail trail {trail.name} uses OSS bucket {trail.oss_bucket_name}, "
"but the bucket could not be found or accessed. Please verify the bucket exists "
"and that you have permissions to access it."
)
findings.append(report)
continue
# Check bucket ACL
acl_public = False
if bucket.acl and bucket.acl != "private":
if bucket.acl in ["public-read", "public-read-write"]:
acl_public = True
# Check bucket policy
policy_public = _is_policy_public(bucket.policy)
# Determine status
if acl_public or policy_public:
report.status = "FAIL"
issues = []
if acl_public:
issues.append(f"Bucket ACL is set to {bucket.acl}")
if policy_public:
issues.append("Bucket policy allows public access (Principal: '*')")
report.status_extended = (
f"OSS bucket {trail.oss_bucket_name} used by ActionTrail trail {trail.name} "
f"is publicly accessible. {'; '.join(issues)}. "
"ActionTrail logs contain sensitive information and should not be publicly accessible."
)
else:
report.status = "PASS"
report.status_extended = (
f"OSS bucket {trail.oss_bucket_name} used by ActionTrail trail {trail.name} "
f"is not publicly accessible. ACL is {bucket.acl} and bucket policy does not allow public access."
)
findings.append(report)
return findings