Trying to search an If statement for a value
Describe the issue A clear and concise description of what the issue is.
Trying to search the If statement of CloudFormation template to see if its contents match a regex expression.
Any examples Please supply:
- Example rules and template that you have tried
let aws_iam_entities_no_managed_policy = Resources.*[
Type in [ /AWS::IAM::User/,
/AWS::IAM::Role/,
/AWS::IAM::Group/ ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_ONLY_ALLOW_ManagedPolicies"
]
let INVALID_VALUES = [/(?i)policy\/AWS/, /(?i)\/VMImportExportRoleForAWSConnector/]
rule IAM_ONLY_ALLOW_ManagedPolicies when %aws_iam_entities_no_managed_policy !empty {
when %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns[*] !empty {
let sub_queries = %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns.*[ keys == "Fn::Sub" ]
let if_queries = %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns.*[ keys == "Fn::If" ]
when %sub_queries EXISTS {
%sub_queries not in %INVALID_VALUES
<<
Violation: AWS Managed Policies are not approved for use.
Fix: Use EDB-Manged Policies instead
>>
%if_queries not in %INVALID_VALUES
<<
Violation: AWS Managed Policies are not approved for use.
Fix: Use EDB-Manged Policies instead
>>
}
}
}
let aws_iam_entities_no_managed_policy = Resources.*[
Type in [ /AWS::IAM::User/,
/AWS::IAM::Role/,
/AWS::IAM::Group/ ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_ONLY_ALLOW_ManagedPolicies"
]
let INVALID_VALUES = [/(?i)\/AWS/, /(?i)\/VMImportExportRoleForAWSConnector/]
rule IAM_ONLY_ALLOW_ManagedPolicies when %aws_iam_entities_no_managed_policy !empty {
when %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns[*] !empty {
let sub_queries = %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns.*[ keys == "Fn::Sub" ]
let if_queries = %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns.*[ keys == "Fn::If" ].*[ keys == "Fn::Sub" ]
when %sub_queries EXISTS {
%sub_queries not in %INVALID_VALUES
<<
Violation: AWS Managed Policies are not approved for use.
Fix: Use EDB-Manged Policies instead
>>
%if_queries not in %INVALID_VALUES
<<
Violation: AWS Managed Policies are not approved for use.
Fix: Use EDB-Manged Policies instead
>>
}
}
}
- The commands you used to invoke the tool
OUTPUT=`RUST_BACKTRACE=1 ./cfn-guard-v3-ubuntu-latest/cfn-guard validate --show-summary pass,fail --data "$TEMPLATE_FILE" --rules .github/pr-automation/lib/cfn-guard/rules/ 2>&1`
- The output of a
-vlog level if it's not related to cfn-guard-lambda, or the relevant CloudWatch log messages if it is related to the cfn-guard-lambda
Everything passed for the first one
The second one gave me errors saying things did not equal Fn::Sub, this was resolved when I removed the .*[ keys == "Fn::Sub" ] from the if statement query.
Operating System: Ubuntu
OS Version Latest
Additional Information Here is an example block of code:
rAwsEdbFPDBUDeveloperRole:
Type: AWS::IAM::Role
# Condition: CreateDevORQaRole
Properties:
RoleName: !Sub aws_${pBusinessUsecase}_${pEnv}
PermissionsBoundary: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/Boundary'
MaxSessionDuration: 36000
AssumeRolePolicyDocument:
Version: '2012-10-17'
ManagedPolicyArns:
**- !Sub "arn:aws:iam::${AWS::AccountId}:policy/aws-kms-s3-rw"**
- !Sub "arn:aws:iam::${AWS::AccountId}:policy/kms-secrets-rw"
- !If [
CreateDevRole,
**!Sub "arn:aws:iam::${AWS::AccountId}:policy/aws-allowed-policies",**
!Ref "AWS::NoValue",
]
- !If [CreateDevRole, !Ref rFPDs3WritePolicy, !Ref "AWS::NoValue"]
- !Ref rFPDs3ReadPolicy
- !Ref rSecretsPolicy
- !If [CreateDevRole, !Ref rFPDRedshiftPolicy, !Ref "AWS::NoValue"]
I am wanting it to look at this chunk of code and flag anything !Sub that has aws after the "/" and anything !If that has aws after the "/", such as the bolded lines above. The !Sub search works well, but the !If statement keeps passing incorrectly even though I am searching only for \/aws.
Hey @Aaron-Garrett I think i was able to come up with a rule to help you with this specific use case. I think one issue with the logic in your original rule was to do with the way if intrinsic functions is mapped to their json equivalent..
In this case your first if function maps to this in json format
{
"Fn::If": [
"CreateDevRole",
{
"Fn::Sub": "arn:aws:iam::${AWS::AccountId}:policy/aws-allowed-policies"
},
{
"Ref": "AWS::NoValue"
}
]
}
It's important to note here when evaluating this mapped if function that youre comparing a value (in this case a list where some elements are strings, some elements are maps/structs) to an array of regex. This will always pass in this case due to the contents of the list.
Heres the rule, i have added some comments to help clear things up
let aws_iam_entities_no_managed_policy = Resources.*[
Type in [ /AWS::IAM::User/,
/AWS::IAM::Role/,
/AWS::IAM::Group/ ]
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "IAM_ONLY_ALLOW_ManagedPolicies"
]
let INVALID_VALUES = [/(?i)\/AWS/, /(?i)\/VMImportExportRoleForAWSConnector/]
rule IAM_ONLY_ALLOW_ManagedPolicies when %aws_iam_entities_no_managed_policy !empty {
let managed_policy_arns = %aws_iam_entities_no_managed_policy.Properties.ManagedPolicyArns
when %managed_policy_arns !empty {
check(%managed_policy_arns)
}
}
rule check(curr) {
# if is string, we can do direct comparison to the list of strings/regex
when %curr is_string {
%curr NOT IN %INVALID_VALUES
}
# if is_list or is_struct iterate and check each individual value
when %curr is_list OR %curr is_struct{
%curr.* {
check(this)
}
}
}
I hope this was helpful to you, please let me know if you have anymore questions.
Hey @Aaron-Garrett just checking in to see if the information I provided was enough to help you resolve your issue here.
Please let us know if you need anymore help on this issue