Jelajahi Sumber

refactor(kubernetes-secret): collapse rules and update regex (#1462)

Richard Gomez 1 tahun lalu
induk
melakukan
3698060a2b

+ 1 - 2
cmd/generate/config/main.go

@@ -113,8 +113,7 @@ func main() {
 		rules.JWT(),
 		rules.JWTBase64(),
 		rules.KrakenAccessToken(),
-		rules.KubernetesSecretWithDataAfter(),
-		rules.KubernetesSecretWithDataBefore(),
+		rules.KubernetesSecret(),
 		rules.KucoinAccessToken(),
 		rules.KucoinSecretKey(),
 		rules.LaunchDarklyAccessToken(),

+ 1 - 1
cmd/generate/config/rules/config.tmpl

@@ -51,7 +51,7 @@ tags = [
 regexTarget = "{{ . }}"{{ end -}}
 {{- with $rule.Allowlist.Regexes }}
 regexes = [
-    {{ range $j, $regex := . }}"{{ $regex }}",{{ end }}
+    {{ range $j, $regex := . }}'''{{ $regex }}''',{{ end }}
 ]{{ end }}
 {{- with $rule.Allowlist.Paths }}paths = [
     {{ range $j, $path := . }}"{{ $path }}",{{ end }}

+ 388 - 43
cmd/generate/config/rules/kubernetes.go

@@ -1,69 +1,414 @@
 package rules
 
 import (
-	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/utils"
+	"fmt"
 	"regexp"
 
+	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/utils"
 	"github.com/zricethezav/gitleaks/v8/config"
 )
 
-// The kubernetes rules are split into two functions to make the complex proximity matching of the data-key and the kind-identifier more readable and testable
+// KubernetesSecret validates if we detected a kubernetes secret which contains data!
+func KubernetesSecret() *config.Rule {
+	// Only match basic variations of `kind: secret`, we don't want things like `kind: ExternalSecret`.
+	//language=regexp
+	kindPat := `\bkind:[ \t]*["']?secret["']?`
+	// Only matches values (`key: value`) under `data:` that are:
+	// - valid base64 characters
+	// - longer than 10 characters (no "YmFyCg==")
+	//language=regexp
+	dataPat := `\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9]{10,}={0,3}["']?|\{\{[ \t\w.-]+}}|""|''))`
+	//dataPat := `\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*["']?[a-z0-9]{10,}={0,3})["']?`
 
-// KubernetesSecretWithDataBefore validates if we detected a kubernetes secret which contains data, before the resource identifier!
-func KubernetesSecretWithDataBefore() *config.Rule {
 	// define rule
 	r := config.Rule{
-		RuleID:      "kubernetes-secret-with-data-before",
+		RuleID:      "kubernetes-secret-yaml",
 		Description: "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments",
-		// We try to match secrets by looking if we have the keyword
-		Regex: utils.GenerateUniqueTokenRegex(`(?i)(?:\b(?:data:))(\W+(?:\w+\W+){0,200}?)\bkind:.{0,10}Secret\b`, true),
-
+		Regex: regexp.MustCompile(fmt.Sprintf(
+			//language=regexp
+			`(?i)(?:%s(?:.|\s){0,200}?%s|%s(?:.|\s){0,200}?%s)`, kindPat, dataPat, dataPat, kindPat)),
 		Keywords: []string{
-			"Secret",
+			"secret",
 		},
-		// Kubernetes secrets are always yaml files, we limit to common yaml-endings to make this rule more safe!
+		// Kubernetes secrets are usually yaml files.
 		Path: regexp.MustCompile(`(?i)\.ya?ml$`),
+		Allowlist: config.Allowlist{
+			Regexes: []*regexp.Regexp{
+				// Ignore empty or placeholder values.
+				// variable: {{ .Values.Example }}
+				// variable: ""
+				// variable: ''
+				regexp.MustCompile(`[\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:\{\{[ \t\w.-]+}}|""|'')`),
+			},
+		},
 	}
 
 	// validate
 	tps := map[string]string{
+		"comment.yaml": `
+apiVersion: v1
+kind: Secret
+metadata:
+  name: heketi-secret
+  namespace: default
+data:
+  # base64 encoded password. E.g.: echo -n "mypassword" | base64
+  key: bXlwYXNzd29yZA==`,
+		// The "data"-key is before the identifier "kind: Secret"
+		"before-kubernetes.yaml": `apiVersion: v1
+ data:
+ 	extra: YWRtaW46cGFzc3dvcmQ=
+ kind: secret
+ metadata:
+	 name: secret-sa-sample
+	 annotations:
+	 	kubernetes.io/service-account.name: 'sa-name'`,
+		"before-kubernetes.yml": `apiVersion: v1
+data:
+	password: UyFCXCpkJHpEc2I9
+	username: YWRtaW4=
+kind: Secret
+metadata:
+	creationTimestamp: '2022-06-28T17:44:13Z'
+	name: db-user-pass
+	namespace: default
+type: Opaque`,
+		"before-comment.yml": `apiVersion: v1
+data:
+	# the data is abbreviated in this example
+	password: UyFCXCpkJHpEc2I9
+	username: YWRtaW4=
+kind: Secret
+metadata:
+	creationTimestamp: '2022-06-28T17:44:13Z'
+	name: db-user-pass
+	namespace: default
+type: Opaque`,
+		"before-quoted-1.yaml": `apiVersion: 'v1'
+data:
+	extra: 'YWRtaW46cGFzc3dvcmQ='
+kind: 'Secret'
+metadata:
+	name: 'secret-sa-sample'
+	annotations:
+		kubernetes.io/service-account.name: 'sa-name'`,
+		"before-quoted-2.yaml": `apiVersion: "v1"
+data:
+	extra: "YWRtaW46cGFzc3dvcmQ="
+kind: "secret"
+metadata:
+	name: "secret-sa-sample"
+	annotations:
+		kubernetes.io/service-account.name: "sa-name"`,
+		"before-multiline-literal.yaml": `apiVersion: v1
+data:
+  .dockercfg: |
+    eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=
+metadata:
+  name: secret-dockercfg
+type: kubernetes.io/dockercfg
+kind: Secret
+`,
+		"before-multiline-folded.yaml": `apiVersion: v1
+data:
+  .dockercfg: >
+    eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=
+metadata:
+  name: secret-dockercfg
+type: kubernetes.io/dockercfg
+kind: Secret`,
 		// Sample Kubernetes Secret from https://kubernetes.io/docs/concepts/configuration/secret/
-		// These secrets contain the "data"-key before the actual identifier "kind: Secret"
-		"kubernetes.yaml": "apiVersion: v1'\n' data:'\n' extra: YmFyCg=='\n' kind: secret'\n' metadata:'\n' name: secret-sa-sample'\n' annotations:'\n' kubernetes.io/service-account.name: 'sa-name'",                                                  // gitleaks:allow
-		"kubernetes.yml":  "apiVersion: v1'\n' data:'\n' password: UyFCXCpkJHpEc2I9'\n' username: YWRtaW4='\n' kind: Secret'\n' metadata:'\n' creationTimestamp: '2022-06-28T17:44:13Z''\n' name: db-user-pass'\n' namespace: default'\n' type: Opaque", // gitleaks:allow
-		// Quoted Test Cases
-		"kubernetes-quoted-1.yaml": "apiVersion: v1'\n' data:'\n' extra: YmFyCg=='\n' kind: 'Secret''\n' metadata:'\n' name: 'secret-sa-sample''\n' annotations:'\n' kubernetes.io/service-account.name: 'sa-name'", // gitleaks:allow
-		"kubernetes-quoted-2.yaml": "apiVersion: v1'\n' data:'\n' extra: YmFyCg=='\n' kind: 'secret''\n' metadata:'\n' name: 'secret-sa-sample''\n' annotations:'\n' kubernetes.io/service-account.name: 'sa-name'", // gitleaks:allow
+		// The "data"-key is after the identifier "kind: Secret"
+		"after-kubernetes.yaml": `apiVersion: v1
+kind: secret
+data:
+	extra: YWRtaW46cGFzc3dvcmQ=
+metadata:
+	name: secret-sa-sample
+	annotations:
+		kubernetes.io/service-account.name: 'sa-name'`,
+		"after-kubernetes.yml": `apiVersion: v1
+kind: Secret
+metadata:
+  name: ca-secret
+type: Opaque
+data:
+  ca.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR4RENDQXF5Z0F3SUJBZ0lVV3pqUDl5RUk0eHlRSnBzVHVERU4yV2ROaUFzd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2FERUxNQWtHQTFVRUJoTUNWVk14RHpBTkJnTlZCQWdUQms5eVpXZHZiakVSTUE4R0ExVUVCeE1JVUc5eQpkR3hoYm1ReEV6QVJCZ05WQkFvVENrdDFZbVZ5Ym1WMFpYTXhDekFKQmdOVkJBc1RBa05CTVJNd0VRWURWUVFECkV3cExkV0psY201bGRHVnpNQjRYRFRFMk1EZ3hNVEUyTkRnd01Gb1hEVEl4TURneE1ERTJORGd3TUZvd2FERUwKTUFrR0ExVUVCaE1DVlZNeER6QU5CZ05WQkFnVEJrOXlaV2R2YmpFUk1BOEdBMVVFQnhNSVVHOXlkR3hoYm1ReApFekFSQmdOVkJBb1RDa3QxWW1WeWJtVjBaWE14Q3pBSkJnTlZCQXNUQWtOQk1STXdFUVlEVlFRREV3cExkV0psCmNtNWxkR1Z6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3QkhNOGN6anc0Q1cKK05wbklhV012RzZlcVhtelNZT20vbHdaNUhOMnVLck9xaTNHYUUyTjFKd2tzcGRmMXNOUGFZMHdPR2xkbURIZgoxSnlyTW8rUFdLVUVjWko1WGE4Vm02d2I0MlpjczN3MEp5dlEzWFJjaDQyMFJRWGRKayszcmMybWRvSVRkL0lmCnZjWms0N0RzQTMrQU5QSUlSTzdWRmZpS1JNRFpTUDR1OThnVjI2eW1zbjc0TzFVKzNVUHR1TEFTVTFLck9FTk4KR01FWG0ydTJpdmVvbTJrbjFlZTZuM1hCR1o2bU52cUNPdWUxRXdza0gvWkhoUVh1UDgyV1U5dVk0aGVORnoyQwpBNmR0Q0Q0c3Z6eHc3ZFQ2cVhsV0ZIWUYrc3VLVDhXNkczd3NkOWxzV0ZVY0ZWL0lwaTVobEVaTWprNFNoY3RqCjdpYnlrRURKM1FJREFRQUJvMll3WkRBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIKL3dJQkFqQWRCZ05WSFE0RUZnUVVOdnhRZ3o5ZTNXS2VscU1KTmZXNE1KUHYzc0V3SHdZRFZSMGpCQmd3Rm9BVQpOdnhRZ3o5ZTNXS2VscU1KTmZXNE1KUHYzc0V3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUp1TUhYUms1TEVyCmxET1p4Mm9aRUNQZ29reXMzSGJsM05oempXd2pncXdxNVN6a011V3QrUnVkdnRTK0FUQjFtTjRjYTN0eSt2bWcKT09heTkvaDZoditmSE5jZHpYdWR5dFZYZW1KN3F4ZFoxd25DUUcwdnpqOWRZY0xFSGpJWi94dU1jNlY3dnJ4YwpSc0preGp5aE01UXBmRHd0eVZKeGpkUmVBZ0huSyswTkNieHdtQ3cyRGIvOXpudm9LWGk4TEQwbkQzOFQxY3R3CmhmdGxwTmRoZXFNRlpEZXBuTUYwY2g2cHo5TFV5Mkh1cnhrV2dkWVNjY2VNU0hPTzBMcG4xeVVBMWczOTJhUjUKWk81Zm5KMW95Vm1LVWFCeDJCMndsSVlUSXlES1ZiMnY1UXNHbnYvRHVTMDZhcmVLTmsvTGpHRTRlMXlHOHJkcwpacnZHMzNvUmtEbz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+`,
+		"after-comment.yml": `apiVersion: v1
+kind: Secret
+metadata:
+	creationTimestamp: '2022-06-28T17:44:13Z'
+	name: db-user-pass
+	namespace: default
+type: Opaque
+data:
+	# the data is abbreviated in this example
+	password: UyFCXCpkJHpEc2I9
+	username: YWRtaW4=
+`,
+		"after-quoted-1.yaml": `apiVersion: 'v1'
+kind: 'Secret'
+data:
+	password: 'UyFCXCpkJHpEc2I9'
+	username: 'YWRtaW4='
+metadata:
+	name: 'db-user-pass'
+	namespace: 'default'
+type: 'Opaque'`,
+		"after-quoted-2.yaml": `apiVersion: "v1"
+kind: "Secret"
+data:
+	password: "UyFCXCpkJHpEc2I9"
+	username: "YWRtaW4="
+metadata:
+	name: "db-user-pass"
+	namespace: "default"
+type: "Opaque"`,
+		"after-multiline-literal.yaml": `apiVersion: v1
+kind: Secret
+metadata:
+  name: secret-dockercfg
+type: kubernetes.io/dockercfg
+data:
+  .dockercfg: |
+    eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=
+`,
+		"after-multiline-folded.yaml": `apiVersion: v1
+kind: Secret
+metadata:
+  name: secret-dockercfg
+type: kubernetes.io/dockercfg
+data:
+  .dockercfg: >
+    eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=`,
 	}
-	return utils.ValidateWithPaths(r, tps, nil)
-}
+	fps := map[string]string{
+		"empty-quotes1.yml": `apiVersion: v1            
+kind: Secret              
+metadata:                 
+  name: registry-auth-data
+type: Opaque              
+data:                     
+  htpasswd: ''
+`,
+		"empty-quotes2.yml": `apiVersion: v1            
+kind: Secret              
+metadata:                 
+  name: registry-auth-data
+type: Opaque              
+data:                     
+  htpasswd: ""
+`,
+		"overly-permissive1.yaml": `apiVersion: v1            
+kind: Secret              
+metadata:                 
+  name: registry-auth-data
+type: Opaque              
+data:                     
+  htpasswd: {{ htpasswd }}
+---                       
+apiVersion: v1            
+                          kind: ReplicationController`,
+		"overly-permissive2.yaml": `apiVersion: v1
+kind: Secret
+metadata:
+  labels:
+    k8s-app: kubernetes-dashboard
+    addonmanager.kubernetes.io/mode: EnsureExists
+  name: kubernetes-dashboard-csrf
+  namespace: kubernetes-dashboard
+type: Opaque
+data:
+  csrf: ""
 
-// KubernetesSecretWithDataAfter validates if we detected a kubernetes secret which contains data, after the resource identifier!
-func KubernetesSecretWithDataAfter() *config.Rule {
-	// define rule
-	r := config.Rule{
-		RuleID:      "kubernetes-secret-with-data-after",
-		Description: "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments",
-		// We try to match secrets by looking if we have the keyword
-		Regex: utils.GenerateUniqueTokenRegex(`(?i)(?:\bkind:.{0,10}Secret\b)(?:.|\s){0,200}?\b(?:data:)\s*(.+)`, true),
+---
 
-		Keywords: []string{
-			"Secret",
-		},
-		// Kubernetes secrets are always yaml files, we limit to common yaml-endings to make this rule more safe!
-		Path: regexp.MustCompile(`(?i)\.ya?ml$`),
-	}
+apiVersion: v1
+kind: Secret
+metadata:
+  labels:
+    k8s-app: kubernetes-dashboard
+    addonmanager.kubernetes.io/mode: EnsureExists
+  name: kubernetes-dashboard-key-holder
+  namespace: kubernetes-dashboard
+type: Opaque
+`,
+		"sopssecret.yaml": `apiVersion: isindir.github.com/v1alpha3
+kind: SopsSecret
+metadata:
+    name: app1-sopssecret
+    namespace: test
+spec:
+    suspend: false
+    secretTemplates:
+    -   name: ENC[AES256_GCM,data:W3PiZ6lD6bpfAdI=,iv:2qF98ZkchgfWF4tZo8fok6zY0ZLNRV3wFpl8n2iyC7I=,tag:FzoL+CZHkLEqfWKniRApBA==,type:str]
+        labels:
+            app: ENC[AES256_GCM,data:t9ujIQ==,iv:slZBpmKF+DOg/wVBWmq5iTqkRBZUMao0a3MdoxzJs3s=,tag:xJyhdJ4rn/cB/4mxHzmGig==,type:str]
+        stringData:
+            db-password: ENC[AES256_GCM,data:O+5l4g==,iv:c/dS4BCBMbnKsXYuzBuCuVQt8RV9bOv5HgdpL+iwmns=,tag:KkQfh6OymvCt4uC13p318g==,type:str]
+sops:
+    kms: []
+    gcp_kms: []
+    azure_kv: []
+    hc_vault: []
+    lastmodified: '2021-10-21T10:56:37Z'
+    mac: ENC[AES256_GCM,data:Tl1V1PuI5tZ0Hu3qxxzpDNeKQkuW0g/x/Mlp1yM6HaBqDr+r2FukLdYSYqjjJ3A8g+YkpvMib50M7j0V7zoX9sgCvMKEg86pRsWtThv8n/L+bsjClVTqnhJ9nfYlaPOMlvggbiMOE5hXPIuVz8WXYoVYJ2cVNCd/GfwOraUmj7I=,iv:n7HVI13okfbW3FS/ZsJ2GNmibudxc/TlkLa3umQQ+vc=,tag:R4ikep1wlxlDWlODJqFHHw==,type:str]
+    pgp:
+    -   created_at: '2021-10-21T10:56:37Z'
+        enc: |
+            -----BEGIN PGP MESSAGE-----
 
-	// validate
-	tps := map[string]string{
-		// Sample Kubernetes Secret from https://kubernetes.io/docs/concepts/configuration/secret/
-		// These secrets contain the data after the  actual identifier "kind: Secret"
-		"kubernetes.yaml": "apiVersion: v1'\n' kind: secret'\n' data:'\n' extra: YmFyCg=='\n' metadata:'\n' name: secret-sa-sample'\n' annotations:'\n' kubernetes.io/service-account.name: 'sa-name'",                                                  // gitleaks:allow
-		"kubernetes.yml":  "apiVersion: v1'\n' kind: Secret'\n' data:'\n' password: UyFCXCpkJHpEc2I9'\n' username: YWRtaW4='\n' metadata:'\n' creationTimestamp: '2022-06-28T17:44:13Z''\n' name: db-user-pass'\n' namespace: default'\n' type: Opaque", // gitleaks:allow
-		// Quoted Test Cases
-		"kubernetes-quoted-1.yaml": "apiVersion: v1'\n' kind: 'Secret''\n' data:'\n' password: UyFCXCpkJHpEc2I9'\n' username: YWRtaW4='\n' metadata:'\n' name: db-user-pass'\n' namespace: default'\n' type: Opaque", // gitleaks:allow
-		"kubernetes-quoted-2.yaml": "apiVersion: v1'\n' kind: 'secret''\n' data:'\n' password: UyFCXCpkJHpEc2I9'\n' username: YWRtaW4='\n' metadata:'\n' name: db-user-pass'\n' namespace: default'\n' type: Opaque", // gitleaks:allow
+            hQGMA3muqimBu2IIAQwAkhR19/6roLq06oaD12vqDMes3/8FweAHxa6TLKg+LRjp
+            2/ntiRJHPBP9DYYFZbkTo8lAmIdVF7KfGIqWgPm5JiNhqfVRhyGPCRgBE7+I8qH6
+            EML9Vo/76kJLHtIjs5rOg7OXgwwitaibs1q6uyVY8TuaGXYIOO1iwL9xVtbayIry
+            NMQd1tFcNb6Vb86Plqm+T1VnSOJMUvryxrLelx89UNM0ctepyVu6YY9jpBjV0QLJ
+            NqNkKAGIMv3RNa9bZHTwveo9T0oXtFnk5H33BxH0ky/DGpD+5Ch1YgbzbqVnr+Bm
+            RX0R/GRhS9IDInd+eiyVX6y3LR5di0fc8TuK43+96wTG+2+ck+lbMrkHYsL2UJNv
+            bAjlOWmIcL4UwGlEOj4EzwcEx+xP3dq57pJ+DasfNwVqps2Kk+ofodR7d6gx7ELH
+            UQmLypCtkRic9v8fVSA2vEL8hAlg9bT8tpHLhHMOwe228cL5dTzFD60RoP+ovRar
+            jIU59Pnu1bnM4pXWEVA20l4BzJ8Fd6gj3TfAg/7Mat+dnTaUwnPgRSybFn0ZZHMW
+            RJDBPkMGFfSGRDfLeD37d61mI31360/w/61LaVp1sdDYodBJCRZFA1YzbqZcxnDl
+            YRjRmpcVRnO+o72CnU/P
+            =V4l4
+            -----END PGP MESSAGE-----
+        fp: 73019E949C1D3C3D1BE8B718C7CD51A565AB592C
+    encrypted_suffix: Templates
+    version: 3.6.1`, // https://github.com/luca-iachini/argocd-test/blob/af0c8eaba270bc918108c8bc3b909f26a4fe995d/kustomize/base/app1/secrets.enc.yaml#L4
+		// The "data"-key is before the identifier "kind: Secret"
+		"before-min-length.yaml": `apiVersion: v1
+data:
+	extra: YmFyCg==
+kind: secret
+metadata:
+	name: secret-sa-sample
+	annotations:
+		kubernetes.io/service-account.name: 'sa-name'`,
+		"before-template.yaml": `apiVersion: v1
+ data:
+ 	password: {{ .Values.Password }}
+ kind: secret
+ metadata:
+ 	name: secret-sa-sample
+ 	annotations:
+ 		kubernetes.io/service-account.name: 'sa-name'`,
+		"before-externalsecret1.yml": `apiVersion: 'kubernetes-client.io/v1'
+metadata:
+  name: actions-exporter
+  namespace: github-actions-exporter
+spec:
+  backendType: secretsManager
+  data:
+    - key: MySecretManagerKey
+      name: github_token
+      property: github_token
+kind: ExternalSecret
+`,
+		"before-externalsecret2.yml": `apiVersion: external-secrets.io/v1beta1
+spec:
+  secretStoreRef:
+    kind: ClusterSecretStore
+    name: aws-secretsmanager
+  refreshInterval: 1h
+  target:
+    creationPolicy: Owner
+  data:
+    - secretKey: api-key
+      remoteRef:
+        key: my-secrets-manager-secret
+metadata:
+  name: api-key
+  namespace: my-namespace
+kind: ExternalSecret
+`,
+		"before-sopssecret.yml": `apiVersion: isindir.github.com/v1alpha3
+spec:
+  secretTemplates:
+    - name: my-secret-name-1
+      labels:
+        label1: value1
+      annotations:
+        key1: value1
+      data:
+        data-name1: ZGF0YS12YWx1ZTE=
+        data-nameM: ZGF0YS12YWx1ZU0=
+kind: SopsSecret
+metadata:
+  name: sopssecret-sample
+`, // https://github.com/isindir/sops-secrets-operator/blob/8aaf8bb368dc841a2d57f251bd839f08216a9328/config/samples/isindir_v1alpha3_sopssecret.yaml#L4
+		// The "data"-key is after the identifier "kind: Secret"
+		"after-min-length.yaml": `apiVersion: v1
+kind: secret
+data:
+	extra: YmFyCg==
+metadata:
+	name: secret-sa-sample
+	annotations:
+		kubernetes.io/service-account.name: 'sa-name'`,
+		"after-externalsecret1.yml": `apiVersion: 'kubernetes-client.io/v1'
+kind: ExternalSecret
+metadata:
+  name: actions-exporter
+  namespace: github-actions-exporter
+spec:
+  backendType: secretsManager
+  data:
+    - key: MySecretManagerKey
+      name: github_token
+      property: github_token
+    - key: MySecretManagerKey`,
+		"after-externalsecret2.yml": `apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+  name: api-key
+  namespace: my-namespace
+spec:
+  secretStoreRef:
+    kind: ClusterSecretStore
+    name: aws-secretsmanager
+  refreshInterval: 1h
+  target:
+    creationPolicy: Owner
+  data:
+    - secretKey: api-key
+      remoteRef:
+        key: my-secrets-manager-secret`,
+		"after-sopssecret.yml": `apiVersion: isindir.github.com/v1alpha3
+kind: SopsSecret
+metadata:
+  name: sopssecret-sample
+spec:
+  secretTemplates:
+    - name: my-secret-name-0
+      labels:
+        label0: value0
+        labelK: valueK
+      annotations:
+        key0: value0
+        keyN: valueN
+      stringData:
+        data-name0: data-value0
+        data-nameL: data-valueL
+    - name: my-secret-name-1
+      labels:
+        label1: value1
+      annotations:
+        key1: value1
+      data:
+        data-name1: ZGF0YS12YWx1ZTE=
+        data-nameM: ZGF0YS12YWx1ZU0=`,
+		"after-empty-data.yaml": `apiVersion: v1
+kind: Secret
+metadata:
+  labels:
+    k8s-app: kubernetes-dashboard
+    addonmanager.kubernetes.io/mode: EnsureExists
+  name: kubernetes-dashboard-csrf
+  namespace: kubernetes-dashboard
+type: Opaque
+data:
+  csrf: ""
+`,
 	}
-
-	return utils.ValidateWithPaths(r, tps, nil)
+	return utils.ValidateWithPaths(r, tps, fps)
 }

+ 7 - 10
config/gitleaks.toml

@@ -2220,21 +2220,18 @@ keywords = [
 ]
 
 [[rules]]
-id = "kubernetes-secret-with-data-after"
+id = "kubernetes-secret-yaml"
 description = "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments"
-regex = '''(?i)\b((?i)(?:\bkind:.{0,10}Secret\b)(?:.|\s){0,200}?\b(?:data:)\s*(.+))(?:['|\"|\n|\r|\s|\x60|;]|$)'''
+regex = '''(?i)(?:\bkind:[ \t]*["']?secret["']?(?:.|\s){0,200}?\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9]{10,}={0,3}["']?|\{\{[ \t\w.-]+}}|""|''))|\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9]{10,}={0,3}["']?|\{\{[ \t\w.-]+}}|""|''))(?:.|\s){0,200}?\bkind:[ \t]*["']?secret["']?)'''
 path = '''(?i)\.ya?ml$'''
 keywords = [
     "secret",
 ]
 
-[[rules]]
-id = "kubernetes-secret-with-data-before"
-description = "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments"
-regex = '''(?i)\b((?i)(?:\b(?:data:))(\W+(?:\w+\W+){0,200}?)\bkind:.{0,10}Secret\b)(?:['|\"|\n|\r|\s|\x60|;]|$)'''
-path = '''(?i)\.ya?ml$'''
-keywords = [
-    "secret",
+[rules.allowlist]
+
+regexes = [
+    '''[\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:\{\{[ \t\w.-]+}}|""|'')''',
 ]
 
 [[rules]]
@@ -2797,7 +2794,7 @@ keywords = [
 
 regexTarget = "line"
 regexes = [
-    "sumOf",
+    '''sumOf''',
 ]
 
 [[rules]]