github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/rules/kubernetes/policies/aquacommercial/configmap_with_sensitive.rego (about) 1 # METADATA 2 # title: "ConfigMap with sensitive content" 3 # description: "Storing sensitive content such as usernames and email addresses in configMaps is unsafe" 4 # scope: package 5 # schemas: 6 # - input: schema["kubernetes"] 7 # custom: 8 # id: AVD-KSV-01010 9 # avd_id: AVD-KSV-01010 10 # severity: HIGH 11 # short_code: configMap_with_sensitive 12 # recommended_action: "Remove sensitive content from configMap data value" 13 # input: 14 # selector: 15 # - type: kubernetes 16 17 package builtin.kubernetes.KSV01010 18 19 import data.lib.kubernetes 20 21 # More patterns can be added here, adding more patterns may lead to performance issue 22 # some patterns are taken from https://github.com/americanexpress/earlybird/blob/d0b63538c1acbb5ab0cacf0541df5ea088d45d70/config/content.json 23 patterns := [ 24 "(?i)(username\\s*(=|:))", 25 "(?i)(email\\s*(=|:))", 26 "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)", 27 "(?i)(key\\s*(=|:))", 28 "(?i)(phone\\s*(=|:))", 29 "[^\\.](?:\\b[A-Z]{2}\\d{2} ?\\d{4} ?\\d{4} ?\\d{4} ?\\d{4} ?[\\d]{0,2}\\b)", 30 "(?i)(SHA1)", 31 "(?i)(MD5)", 32 ] 33 34 patternsForKey := [ 35 "(?i)(username\\s*)", 36 "(?i)(email\\s*)", 37 "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)", 38 "(?i)(key\\s*)", 39 "(?i)(phone\\s*)", 40 "[^\\.](?:\\b[A-Z]{2}\\d{2} ?\\d{4} ?\\d{4} ?\\d{4} ?\\d{4} ?[\\d]{0,2}\\b)", 41 "(?i)(SHA1\\s*)", 42 "(?i)(MD5\\s*)", 43 ] 44 45 patternsForEmail := "([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)" 46 47 # ConfigMapWithSensitive gives secret key 48 # To reduce performance overhead, only matched patterns will be applied to each value for key 49 ConfigMapWithSensitive[sensitiveData] { 50 kubernetes.kind == "ConfigMap" 51 regex.match(patterns[p], kubernetes.object.data[d]) 52 53 values := split(kubernetes.object.data[d], "\n") 54 regex.match(patterns[p], values[v]) 55 sensitiveData = configMapValue(values[v]) 56 } 57 58 # configMapValue gives sensitive key, splitting either by '=' or ':' 59 configMapValue(value) = sensitiveValue { 60 sensitiveData := split(value, ":") 61 count(sensitiveData) > 1 62 sensitiveValue = sensitiveData[0] 63 } else = sensitiveValue { 64 sensitiveData := split(value, "=") 65 count(sensitiveData) > 1 66 sensitiveValue = sensitiveData[0] 67 } 68 69 #check if key has sensitive data 70 ConfigMapWithSensitive[sensitiveData] { 71 kubernetes.kind == "ConfigMap" 72 values = split(kubernetes.object.data[d], "\n") 73 regex.match(patternsForKey[p], d) 74 sensitiveData = d 75 } 76 77 ConfigMapWithSensitive[sensitiveData] { 78 kubernetes.kind == "ConfigMap" 79 values = split(kubernetes.object.data[d], "\n") 80 val = split(values[v], ":") 81 regex.match(patternsForEmail, val[v]) 82 sensitiveData = d 83 } 84 85 configMapSensitiveList := ConfigMapWithSensitive 86 87 deny[res] { 88 count(configMapSensitiveList) > 0 89 msg := kubernetes.format(sprintf("%s '%s' in '%s' namespace stores sensitive contents in key(s) or value(s) '%s'", [kubernetes.kind, kubernetes.name, kubernetes.namespace, configMapSensitiveList])) 90 res := result.new(msg, kubernetes.kind) 91 }