package policy import ( "fmt" "strings" ) type PolicyStatement struct { Sid string `json:"Sid,omitempty"` Effect string `json:"Effect"` Principal PolicyStatementPrincipal `json:"Principal,omitempty"` Action ListOrString `json:"Action"` NotAction ListOrString `json:"NotAction,omitempty"` Resource ListOrString `json:"Resource,omitempty"` NotResource ListOrString `json:"NotResource,omitempty"` Condition PolicyStatementCondition `json:"Condition,omitempty"` } func (ps *PolicyStatement) IsEmpty() bool { return ps.Sid == "" && ps.Effect == "" && ps.Principal.IsEmpty() && len(ps.Action) < 1 && len(ps.Resource) < 1 && ps.Condition.IsEmpty() } func (ps *PolicyStatement) IsAllow() bool { return strings.TrimSpace(strings.ToLower(ps.Effect)) == "allow" } func (ps *PolicyStatement) GetAllActionsAsString() string { actions := "" if len(ps.Action) < 3 { for _, action := range ps.Action { if ps.Effect == "Allow" { actions = fmt.Sprintf("%scan %s & ", actions, action) } else if ps.Effect == "Deny" { actions = fmt.Sprintf("%sis denied %s & ", actions, action) } } } else { if ps.Effect == "Allow" { actions = fmt.Sprintf("can perform %d actions", len(ps.Action)) } else if ps.Effect == "Deny" { actions = fmt.Sprintf("is denied %d actions", len(ps.Action)) } } actions = strings.TrimSuffix(actions, " & ") actions = actions + "\n" return actions } func (ps *PolicyStatement) GetAllPrincipalsAsString() string { principals := "" for _, principal := range ps.Principal.O.GetListOfPrincipals() { if len(ps.Principal.O.GetListOfPrincipals()) > 1 { principals = fmt.Sprintf("%s%s \n& ", principals, principal) } else { principals = fmt.Sprintf("%s%s", principals, principal) } } if principals == "" && ps.Principal.S == "*" { principals = "Everyone" } // replace " &\n--" in principals with just a newline principals = strings.TrimSuffix(principals, " \n& ") principals = principals + "\n" return principals } func (ps *PolicyStatement) GetConditionsInEnglish(caller string) string { conditionTextAll := "" for condition, kv := range ps.Condition { if condition == "StringEquals" || condition == "ArnEquals" { condition = "=" } else if condition == "StringLike" || condition == "ArnLike" { condition = "is like" } for k, v := range kv { for _, arn := range v { var conditionText string if (k == "AWS:SourceOwner" || k == "AWS:SourceAccount") && contains(v, caller) { conditionText = "Default resource policy: Not exploitable" } else { conditionText = fmt.Sprintf("-> Only when %s %s %s\n", k, condition, arn) } conditionTextAll = fmt.Sprintf("%s%s", conditionTextAll, conditionText) // trim the last newline character //conditionTextAll = strings.TrimSuffix(conditionTextAll, "\n") } } } return conditionTextAll } func (ps *PolicyStatement) GetStatementSummaryInEnglish(caller string) string { var statementSummary string actions := ps.GetAllActionsAsString() principals := ps.GetAllPrincipalsAsString() conditions := ps.GetConditionsInEnglish(caller) if conditions == "Default resource policy: Not exploitable" { statementSummary = "Default resource policy: Not exploitable\n" + "\n" } else if conditions != "\n" { statementSummary = fmt.Sprintf("%s %s %s", strings.TrimSuffix(principals, "\n"), actions, conditions) } else { statementSummary = fmt.Sprintf("%s %s\n", strings.TrimSuffix(principals, "\n"), actions) } // trim the last newline character //statementSummary = strings.TrimSuffix(statementSummary, "\n") return statementSummary } // GetResources as list of strings func (ps *PolicyStatement) GetResources() []string { return ps.Resource }