""" Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 """ from datetime import date from cfnlint.rules import CloudFormationLintRule, RuleMatch class PolicyVersion(CloudFormationLintRule): """Check if IAM Policy Version is correct""" id = "W2511" shortdesc = "Check IAM Resource Policies syntax" description = ( "See if the elements inside an IAM Resource policy are configured correctly." ) source_url = "https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html" tags = ["properties", "iam"] def __init__(self): """Init""" super().__init__() self.resources_and_keys = { "AWS::ECR::Repository": "RepositoryPolicyText", "AWS::Elasticsearch::Domain": "AccessPolicies", "AWS::OpenSearchService::Domain": "AccessPolicies", "AWS::KMS::Key": "KeyPolicy", "AWS::S3::BucketPolicy": "PolicyDocument", "AWS::SNS::TopicPolicy": "PolicyDocument", "AWS::SQS::QueuePolicy": "PolicyDocument", } self.idp_and_keys = { "AWS::IAM::Group": "Policies", "AWS::IAM::ManagedPolicy": "PolicyDocument", "AWS::IAM::Policy": "PolicyDocument", "AWS::IAM::Role": "Policies", "AWS::IAM::User": "Policies", } for resource_type in self.resources_and_keys: self.resource_property_types.append(resource_type) for resource_type in self.idp_and_keys: self.resource_property_types.append(resource_type) def check_policy_document(self, value, path): """Check policy document""" matches = [] if not isinstance(value, dict): return matches for e_v, e_p in value.items_safe(path[:]): for p_vs, p_p in e_v.items_safe(e_p[:]): version = p_vs.get("Version") if version: if version in ["2008-10-17", date(2008, 10, 17)]: message = ( "IAM Policy Version should be updated to '2012-10-17'." ) matches.append(RuleMatch(p_p + ["Version"], message)) return matches def match_resource_properties(self, properties, resourcetype, path, cfn): """Check CloudFormation Properties""" matches = [] key = None if resourcetype in self.resources_and_keys: key = self.resources_and_keys.get(resourcetype) else: key = self.idp_and_keys.get(resourcetype) if key == "Policies": for index, policy in enumerate(properties.get(key, [])): matches.extend( cfn.check_value( obj=policy, key="PolicyDocument", path=path[:] + ["Policies", index], check_value=self.check_policy_document, ) ) else: matches.extend( cfn.check_value( obj=properties, key=key, path=path[:], check_value=self.check_policy_document, ) ) return matches