-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(elasticache): add check elasticache_redis_cluster_auth_enabled
#4830
feat(elasticache): add check elasticache_redis_cluster_auth_enabled
#4830
Conversation
I used the |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4830 +/- ##
==========================================
+ Coverage 89.00% 89.12% +0.12%
==========================================
Files 965 974 +9
Lines 29526 29852 +326
==========================================
+ Hits 26279 26607 +328
+ Misses 3247 3245 -2 ☔ View full report in Codecov by Sentry. |
@@ -0,0 +1,32 @@ | |||
{ | |||
"Provider": "aws", | |||
"CheckID": "elasticache_redis_cluster_below_v6_auth_enabled", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"CheckID": "elasticache_redis_cluster_below_v6_auth_enabled", | |
"CheckID": "elasticache_redis_cluster_auth_enabled", |
{ | ||
"Provider": "aws", | ||
"CheckID": "elasticache_redis_cluster_below_v6_auth_enabled", | ||
"CheckTitle": "Ensure Elasticache Elasticache Redis replication groups under version 6.0 have Redis OSS AUTH Enabled.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, don't hardcore versions in the metadata, it could change in the future.
"CheckTitle": "Ensure Elasticache Elasticache Redis replication groups under version 6.0 have Redis OSS AUTH Enabled.", | |
"CheckTitle": "Ensure Elasticache Elasticache Redis replication groups of earlier versions should have Redis OSS AUTH enabled.", |
"CheckType": [ | ||
"AWS Foundational Security Best Practices v1.0.0" | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, use the types from https://docs.aws.amazon.com/securityhub/latest/userguide/asff-required-attributes.html#Types
for cluster in elasticache_client.clusters.values(): | ||
if ( | ||
cluster.engine == "redis" and int(cluster.engine_version[0]) < 6 | ||
): # major.minor.patch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the comment for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was thought to clarify the string format of the version stored in engine_version
. If it is unclear or unnecessary we can remove it.
@@ -41,6 +41,10 @@ def _describe_cache_clusters(self, regional_client): | |||
auto_minor_version_upgrade=cache_cluster.get( | |||
"AutoMinorVersionUpgrade", False | |||
), | |||
engine_version=cache_cluster.get("EngineVersion", None), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The None value would raise an error in the check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, add another MANUAL finding for clusters of later versions saying to implement Redis ACL(Role bases access control) in the cluster.
class elasticache_redis_cluster_below_v6_auth_enabled(Check): | ||
def execute(self): | ||
findings = [] | ||
for cluster in elasticache_client.clusters.values(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, use the replication_groups
since we have to check it at that level and update the metadata.
elasticache_redis_cluster_auth_enabled
"SubServiceName": "", | ||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", | ||
"Severity": "medium", | ||
"ResourceType": "AWSElastiCacheClusters", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this ResourceType is not supported by AWS, please refer to the docs
@@ -0,0 +1,32 @@ | |||
{ | |||
"Provider": "aws", | |||
"CheckID": "elasticache_redis_cluster_auth_enabled", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why names redis_cluster
if you are giving findings about replication groups
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I handled it this way because all replication group checks were done that way. Making these corrections should imply renaming the checkID and outputs of all other replication group checks as well.
report.resource_tags = repl_group.tags | ||
|
||
cluster = repl_group.member_clusters[0] | ||
report.status = "PASS" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
report.status = "PASS" | |
report.status = "MANUAL" |
report.resource_arn = repl_group.arn | ||
report.resource_tags = repl_group.tags | ||
|
||
cluster = repl_group.member_clusters[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no other way to get the version of the replication cluster? It's weird to get it from the first cluster, it's a bit arbitrary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I´ll update this in a better way. I thought MemberClusters
returned primary node in first position, but I think that´s incorrect. I´ll take the primary node now (whose version is replicated in replica nodes) to make this non arbitrary at all.
@@ -41,6 +41,10 @@ def _describe_cache_clusters(self, regional_client): | |||
auto_minor_version_upgrade=cache_cluster.get( | |||
"AutoMinorVersionUpgrade", False | |||
), | |||
engine_version=cache_cluster.get("EngineVersion", "None"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 things here:
- If the default value "None" reach to the check it will be:
int("None")
which is a problem, - Why not store this values as a floating point instead a str?
@@ -90,6 +94,16 @@ def _describe_replication_groups(self, regional_client): | |||
if not self.audit_resources or ( | |||
is_resource_filtered(replication_arn, self.audit_resources) | |||
): | |||
member_clusters = repl_group.get("MemberClusters", []) | |||
cluster_list = [] | |||
if member_clusters: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if member_clusters: |
primary_id = primary_node["CacheClusterId"] | ||
break | ||
|
||
except Exception as error: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, could you manage the specific Exception instead just generic one
...eplication_group_auth_enabled/elasticache_redis_replication_group_auth_enabled.metadata.json
Outdated
Show resolved
Hide resolved
…ion-groups-of-earlier-redis-versions-should-have-redis-auth-enabled
version = cache_cluster.get("EngineVersion", "0.0") | ||
version = float(version[:3]) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
version = cache_cluster.get("EngineVersion", "0.0") | |
version = float(version[:3]) | |
version = version.parse(cache_cluster.get("EngineVersion", "0.0")) |
Please, use version function from the packaging library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from packaging import version
report.status = "MANUAL" | ||
report.status_extended = f"Elasticache Redis replication group {repl_group.id}(v{repl_group.engine_version}) does not have to use AUTH, but it should have Redis ACL configured." | ||
|
||
if repl_group.engine_version < 6.0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if repl_group.engine_version < 6.0: | |
if repl_group.engine_version < version.parse("6.0"): |
# Get primary cluster | ||
try: | ||
for node_group in repl_group["NodeGroups"][0]: | ||
primary_node = next( | ||
( | ||
node | ||
for node in node_group["NodeGroupMembers"] | ||
if node["CurrentRole"] == "primary" | ||
), | ||
None, | ||
) | ||
if primary_node: | ||
primary_id = primary_node["CacheClusterId"] | ||
break | ||
|
||
except Exception as error: | ||
primary_node = repl_group["NodeGroups"][0][ | ||
"NodeGroupMembers" | ||
][0] | ||
primary_id = primary_node["CacheClusterId"] | ||
logger.error( | ||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, get the nodes from MemberClusters
, and verify within the check if those members have the compliant configuration.
engine_version=version, | ||
auth_token_enabled=repl_group.get( | ||
"AuthTokenEnabled", False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, only store the member_clusters
attribute.
report.resource_arn = repl_group.arn | ||
report.resource_tags = repl_group.tags | ||
|
||
for cluster in repl_group.member_clusters: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, can you show in the status extended the member clusters that are not compliant (if any).
|
||
else: | ||
report.status = "PASS" | ||
report.status_extended = f"Elasticache Redis replication group {repl_group.id}(v{cluster.engine_version}) does have AUTH enabled." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
report.status_extended = f"Elasticache Redis replication group {repl_group.id}(v{cluster.engine_version}) does have AUTH enabled." | |
report.status_extended = f"Elasticache Redis replication group {repl_group.id}(v{cluster.engine_version}) has all member clusters with AUTH enabled." |
report.status = "PASS" | ||
report.status_extended = f"Elasticache Redis replication group {repl_group.id}(v{cluster.engine_version}) does have AUTH enabled." | ||
else: | ||
report.status = "MANUAL" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can member cluster have different versions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If not, leave it as it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I'm concerned, every node must have the exact same version inside a replication group.
…ion-groups-of-earlier-redis-versions-should-have-redis-auth-enabled
# Get first cluster version as they all have the same unless an upgrade is being made | ||
member_clusters = repl_group.get("MemberClusters", []) | ||
if member_clusters: | ||
cluster_arn = f"arn:aws:s3:::{member_clusters[0]}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, verify this ARN and add a test for this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
Context
Redis AUTH is essential for securing access to Redis clusters by requiring a password for client commands, especially since Role-Based Access Control (RBAC) is not available in versions prior to 6.0. The control will fail if Redis AUTH is not enabled for these earlier versions, helping to enforce best practices for data security in environments where older Redis versions are still in use. For Redis versions 6.0 and later, RBAC is recommended, but this check specifically targets the need for AUTH in versions below 6.0.
Description
I have implemented a new check called
elasticache_redis_cluster_auth_enabled
to address a security concern in Amazon ElastiCache for Redis. This check ensures that replication groups running Redis versions earlier than 6.0 have Redis AUTH enabled.Checklist
License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.