github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/terraform/aws/iam/convert.go (about) 1 package iam 2 3 import ( 4 "strings" 5 6 "github.com/khulnasoft-lab/defsec/pkg/scan" 7 8 "github.com/khulnasoft-lab/defsec/pkg/terraform" 9 10 "github.com/khulnasoft-lab/defsec/pkg/providers/aws/iam" 11 12 "github.com/liamg/iamgo" 13 ) 14 15 type wrappedDocument struct { 16 Source scan.MetadataProvider 17 Document iamgo.Document 18 } 19 20 func ParsePolicyFromAttr(attr *terraform.Attribute, owner *terraform.Block, modules terraform.Modules) (*iam.Document, error) { 21 22 documents := findAllPolicies(modules, owner, attr) 23 if len(documents) > 0 { 24 return &iam.Document{ 25 Parsed: documents[0].Document, 26 Metadata: documents[0].Source.GetMetadata(), 27 IsOffset: true, 28 }, nil 29 } 30 31 if attr.IsString() { 32 33 dataBlock, err := modules.GetBlockById(attr.Value().AsString()) 34 if err != nil { 35 parsed, err := iamgo.Parse([]byte(unescapeVars(attr.Value().AsString()))) 36 if err != nil { 37 return nil, err 38 } 39 return &iam.Document{ 40 Parsed: *parsed, 41 Metadata: attr.GetMetadata(), 42 IsOffset: false, 43 HasRefs: len(attr.AllReferences()) > 0, 44 }, nil 45 } else if dataBlock.Type() == "data" && dataBlock.TypeLabel() == "aws_iam_policy_document" { 46 if doc, err := ConvertTerraformDocument(modules, dataBlock); err == nil { 47 return &iam.Document{ 48 Metadata: dataBlock.GetMetadata(), 49 Parsed: doc.Document, 50 IsOffset: true, 51 HasRefs: false, 52 }, nil 53 } 54 } 55 } 56 57 return &iam.Document{ 58 Metadata: owner.GetMetadata(), 59 }, nil 60 } 61 62 func unescapeVars(input string) string { 63 return strings.ReplaceAll(input, "&{", "${") 64 } 65 66 // ConvertTerraformDocument converts a terraform data policy into an iamgo policy https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document 67 func ConvertTerraformDocument(modules terraform.Modules, block *terraform.Block) (*wrappedDocument, error) { 68 69 builder := iamgo.NewPolicyBuilder() 70 71 if sourceAttr := block.GetAttribute("source_json"); sourceAttr.IsString() { 72 doc, err := iamgo.ParseString(sourceAttr.Value().AsString()) 73 if err != nil { 74 return nil, err 75 } 76 builder = iamgo.PolicyBuilderFromDocument(*doc) 77 } 78 79 if sourceDocumentsAttr := block.GetAttribute("source_policy_documents"); sourceDocumentsAttr.IsIterable() { 80 docs := findAllPolicies(modules, block, sourceDocumentsAttr) 81 for _, doc := range docs { 82 statements, _ := doc.Document.Statements() 83 for _, statement := range statements { 84 builder.WithStatement(statement) 85 } 86 } 87 } 88 89 if idAttr := block.GetAttribute("policy_id"); idAttr.IsString() { 90 r := idAttr.GetMetadata().Range() 91 builder.WithId(idAttr.Value().AsString(), r.GetStartLine(), r.GetEndLine()) 92 } 93 94 if versionAttr := block.GetAttribute("version"); versionAttr.IsString() { 95 r := versionAttr.GetMetadata().Range() 96 builder.WithVersion(versionAttr.Value().AsString(), r.GetStartLine(), r.GetEndLine()) 97 } 98 99 for _, statementBlock := range block.GetBlocks("statement") { 100 statement := parseStatement(statementBlock) 101 builder.WithStatement(statement, statement.Range().StartLine, statement.Range().EndLine) 102 } 103 104 if overrideDocumentsAttr := block.GetAttribute("override_policy_documents"); overrideDocumentsAttr.IsIterable() { 105 docs := findAllPolicies(modules, block, overrideDocumentsAttr) 106 for _, doc := range docs { 107 statements, _ := doc.Document.Statements() 108 for _, statement := range statements { 109 builder.WithStatement(statement, statement.Range().StartLine, statement.Range().EndLine) 110 } 111 } 112 } 113 114 return &wrappedDocument{Document: builder.Build(), Source: block}, nil 115 } 116 117 // nolint 118 func parseStatement(statementBlock *terraform.Block) iamgo.Statement { 119 120 metadata := statementBlock.GetMetadata() 121 122 builder := iamgo.NewStatementBuilder() 123 builder.WithRange(metadata.Range().GetStartLine(), metadata.Range().GetEndLine()) 124 125 if sidAttr := statementBlock.GetAttribute("sid"); sidAttr.IsString() { 126 r := sidAttr.GetMetadata().Range() 127 builder.WithSid(sidAttr.Value().AsString(), r.GetStartLine(), r.GetEndLine()) 128 } 129 if actionsAttr := statementBlock.GetAttribute("actions"); actionsAttr.IsIterable() { 130 r := actionsAttr.GetMetadata().Range() 131 values := actionsAttr.AsStringValues().AsStrings() 132 builder.WithActions(values, r.GetStartLine(), r.GetEndLine()) 133 } 134 if notActionsAttr := statementBlock.GetAttribute("not_actions"); notActionsAttr.IsIterable() { 135 r := notActionsAttr.GetMetadata().Range() 136 values := notActionsAttr.AsStringValues().AsStrings() 137 builder.WithNotActions(values, r.GetStartLine(), r.GetEndLine()) 138 } 139 if resourcesAttr := statementBlock.GetAttribute("resources"); resourcesAttr.IsIterable() { 140 r := resourcesAttr.GetMetadata().Range() 141 values := resourcesAttr.AsStringValues().AsStrings() 142 builder.WithResources(values, r.GetStartLine(), r.GetEndLine()) 143 } 144 if notResourcesAttr := statementBlock.GetAttribute("not_resources"); notResourcesAttr.IsIterable() { 145 r := notResourcesAttr.GetMetadata().Range() 146 values := notResourcesAttr.AsStringValues().AsStrings() 147 builder.WithNotResources(values, r.GetStartLine(), r.GetEndLine()) 148 } 149 if effectAttr := statementBlock.GetAttribute("effect"); effectAttr.IsString() { 150 r := effectAttr.GetMetadata().Range() 151 builder.WithEffect(effectAttr.Value().AsString(), r.GetStartLine(), r.GetEndLine()) 152 } else { 153 builder.WithEffect(iamgo.EffectAllow) 154 } 155 156 for _, principalBlock := range statementBlock.GetBlocks("principals") { 157 typeAttr := principalBlock.GetAttribute("type") 158 if !typeAttr.IsString() { 159 continue 160 } 161 identifiersAttr := principalBlock.GetAttribute("identifiers") 162 if !identifiersAttr.IsIterable() { 163 continue 164 } 165 r := principalBlock.GetMetadata().Range() 166 switch typeAttr.Value().AsString() { 167 case "*": 168 builder.WithAllPrincipals(true, r.GetStartLine(), r.GetEndLine()) 169 case "AWS": 170 values := identifiersAttr.AsStringValues().AsStrings() 171 builder.WithAWSPrincipals(values, r.GetStartLine(), r.GetEndLine()) 172 case "Federated": 173 values := identifiersAttr.AsStringValues().AsStrings() 174 builder.WithFederatedPrincipals(values, r.GetStartLine(), r.GetEndLine()) 175 case "Service": 176 values := identifiersAttr.AsStringValues().AsStrings() 177 builder.WithServicePrincipals(values, r.GetStartLine(), r.GetEndLine()) 178 case "CanonicalUser": 179 values := identifiersAttr.AsStringValues().AsStrings() 180 builder.WithCanonicalUsersPrincipals(values, r.GetStartLine(), r.GetEndLine()) 181 } 182 } 183 184 for _, conditionBlock := range statementBlock.GetBlocks("condition") { 185 testAttr := conditionBlock.GetAttribute("test") 186 if !testAttr.IsString() { 187 continue 188 } 189 variableAttr := conditionBlock.GetAttribute("variable") 190 if !variableAttr.IsString() { 191 continue 192 } 193 valuesAttr := conditionBlock.GetAttribute("values") 194 values := valuesAttr.AsStringValues().AsStrings() 195 if valuesAttr.IsNil() || len(values) == 0 { 196 continue 197 } 198 199 r := conditionBlock.GetMetadata().Range() 200 201 builder.WithCondition( 202 testAttr.Value().AsString(), 203 variableAttr.Value().AsString(), 204 values, 205 r.GetStartLine(), 206 r.GetEndLine(), 207 ) 208 209 } 210 return builder.Build() 211 } 212 213 func findAllPolicies(modules terraform.Modules, parentBlock *terraform.Block, attr *terraform.Attribute) []wrappedDocument { 214 var documents []wrappedDocument 215 for _, ref := range attr.AllReferences() { 216 for _, b := range modules.GetBlocks() { 217 if b.Type() != "data" || b.TypeLabel() != "aws_iam_policy_document" { 218 continue 219 } 220 if ref.RefersTo(b.Reference()) { 221 document, err := ConvertTerraformDocument(modules, b) 222 if err != nil { 223 continue 224 } 225 documents = append(documents, *document) 226 continue 227 } 228 kref := *ref 229 kref.SetKey(parentBlock.Reference().RawKey()) 230 if kref.RefersTo(b.Reference()) { 231 document, err := ConvertTerraformDocument(modules, b) 232 if err != nil { 233 continue 234 } 235 documents = append(documents, *document) 236 } 237 } 238 } 239 return documents 240 }