Skip to content

Commit

Permalink
more operators
Browse files Browse the repository at this point in the history
  • Loading branch information
lhitchon committed Mar 16, 2018
1 parent cdb83c0 commit 26e8845
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 36 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,7 @@ Rules:

Lots to do. This is just a proof-of-concept.

* Embedded JSON for IAM policies should be parsed and made available for JMESPath query
* Add an optional YAML file for project settings, such as ignoring certain rules for certain resources
* Implement more of the operators from Cloud Custodian
* Figure out what other assertion types might be needed (if any)
* Finish implementing value_from to allow for dynamic data (again, see Cloud Custodian)
* Add ability to extend with a Lambda function
Expand Down
30 changes: 28 additions & 2 deletions assertion/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
)

func isMatch(searchResult string, op string, value string) bool {
// TODO see Cloud Custodian for ideas
// ADD gt, ge, lt, le, not-null, empty, intersect, glob
switch op {
case "eq":
if searchResult == value {
Expand All @@ -17,6 +15,22 @@ func isMatch(searchResult string, op string, value string) bool {
if searchResult != value {
return true
}
case "lt":
if searchResult < value {
return true
}
case "le":
if searchResult <= value {
return true
}
case "gt":
if searchResult > value {
return true
}
case "ge":
if searchResult >= value {
return true
}
case "in":
for _, v := range strings.Split(value, ",") {
if v == searchResult {
Expand All @@ -38,6 +52,18 @@ func isMatch(searchResult string, op string, value string) bool {
if isPresent(searchResult) {
return true
}
case "not-null":
if isNotNull(searchResult) {
return true
}
case "empty":
if isEmpty(searchResult) {
return true
}
case "intersect":
if jsonListsIntersect(searchResult, value) {
return true
}
case "contains":
if strings.Contains(searchResult, value) {
return true
Expand Down
15 changes: 15 additions & 0 deletions assertion/match_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ func TestIsMatch(t *testing.T) {
{SearchResult: "Foo", Op: "regex", Value: "o$", ExpectedResult: true},
{SearchResult: "Foo", Op: "regex", Value: "^F", ExpectedResult: true},
{SearchResult: "Foo", Op: "regex", Value: "^Bar$", ExpectedResult: false},
{SearchResult: "a", Op: "lt", Value: "b", ExpectedResult: true},
{SearchResult: "a", Op: "lt", Value: "a", ExpectedResult: false},
{SearchResult: "a", Op: "le", Value: "a", ExpectedResult: true},
{SearchResult: "b", Op: "le", Value: "a", ExpectedResult: false},
{SearchResult: "b", Op: "gt", Value: "a", ExpectedResult: true},
{SearchResult: "b", Op: "gt", Value: "b", ExpectedResult: false},
{SearchResult: "b", Op: "ge", Value: "b", ExpectedResult: true},
{SearchResult: "b", Op: "ge", Value: "c", ExpectedResult: false},
{SearchResult: "null", Op: "not-null", Value: "", ExpectedResult: false},
{SearchResult: "1", Op: "not-null", Value: "", ExpectedResult: true},
{SearchResult: "[]", Op: "empty", Value: "", ExpectedResult: true},
{SearchResult: "[100]", Op: "empty", Value: "", ExpectedResult: false},
{SearchResult: "null", Op: "empty", Value: "", ExpectedResult: true},
{SearchResult: "[\"one\",\"two\"]", Op: "intersect", Value: "[\"two\",\"three\"]", ExpectedResult: true},
{SearchResult: "[\"one\",\"two\"]", Op: "intersect", Value: "[\"three\",\"four\"]", ExpectedResult: false},
}
for _, tc := range testCases {
b := isMatch(tc.SearchResult, tc.Op, tc.Value)
Expand Down
23 changes: 23 additions & 0 deletions assertion/util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package assertion

import (
"encoding/json"
"path/filepath"
)

Expand All @@ -22,6 +23,14 @@ func isPresent(s string) bool {
return !isAbsent(s)
}

func isNotNull(s string) bool {
return s != "null"
}

func isEmpty(s string) bool {
return s == "null" || s == "[]"
}

func listsIntersect(list1 []string, list2 []string) bool {
for _, a := range list1 {
for _, b := range list2 {
Expand All @@ -33,6 +42,20 @@ func listsIntersect(list1 []string, list2 []string) bool {
return false
}

func jsonListsIntersect(s1 string, s2 string) bool {
var a1 []string
var a2 []string
err := json.Unmarshal([]byte(s1), &a1)
if err != nil {
return false
}
err = json.Unmarshal([]byte(s2), &a2)
if err != nil {
return false
}
return listsIntersect(a1, a2)
}

func ShouldIncludeFile(patterns []string, filename string) bool {
for _, pattern := range patterns {
_, file := filepath.Split(filename)
Expand Down
8 changes: 8 additions & 0 deletions assertion/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,11 @@ func TestIntersectFalse(t *testing.T) {
t.Errorf("listsIntersect should return false fails")
}
}

func TestJSONListsIntersectTrue(t *testing.T) {
s1 := "[ \"foo\", \"bar\" ]"
s2 := "[ \"baz\", \"bar\" ]"
if jsonListsIntersect(s1, s2) != true {
t.Errorf("JSONIntersect should return true")
}
}
20 changes: 11 additions & 9 deletions cli/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ type TerraformLinter struct {
Log assertion.LoggingFunction
}

func parsePolicy(resource assertion.Resource, attribute string) assertion.Resource {
func parsePolicy(resource assertion.Resource) assertion.Resource {
if resource.Properties != nil {
properties := resource.Properties.(map[string]interface{})
if policyAttribute, hasPolicyString := properties[attribute]; hasPolicyString {
if policyString, ok := policyAttribute.(string); ok {
var policy interface{}
err := json.Unmarshal([]byte(policyString), &policy)
if err != nil {
panic(err)
for _, attribute := range []string{"assume_role_policy", "policy"} {
if policyAttribute, hasPolicyString := properties[attribute]; hasPolicyString {
if policyString, isString := policyAttribute.(string); isString {
var policy interface{}
err := json.Unmarshal([]byte(policyString), &policy)
if err != nil {
panic(err)
}
properties[attribute] = policy
}
properties[attribute] = policy
}
}
}
Expand Down Expand Up @@ -78,7 +80,7 @@ func loadTerraformResources(filename string, log assertion.LoggingFunction) []as
Properties: resource.([]interface{})[0],
Filename: filename,
}
resources = append(resources, parsePolicy(tr, "assume_role_policy"))
resources = append(resources, parsePolicy(tr))
}
}
}
Expand Down
98 changes: 98 additions & 0 deletions example-files/config/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
resource "aws_iam_role" "iam_role_1" {
name = "iam_role_1"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_role" "role_with_invalid_policy" {
name = "role1"
assume_role_policy = [ "invalid" ]
}

resource "aws_iam_policy" "policy_1" {
name = "policy_1"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_group_policy" "group_policy_1" {
name = "group_policy_1"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_role_policy" "role_policy_1" {
name = "role_policy_1"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_user_policy" "user_policy_1" {
name = "user_policy_1"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
23 changes: 0 additions & 23 deletions example-files/config/roles.tf

This file was deleted.

0 comments on commit 26e8845

Please sign in to comment.