-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: validate pairs of secrets (#210)
After adding the simple validation process on #206, I'm now adding a validation process for cases where both _access key_ and _secret key_ are needed together. For these cases, the engine will collect those secrets and after the scan is finished, it will validate all the pairs.
- Loading branch information
Baruch Odem (Rothkoff)
authored
Feb 21, 2024
1 parent
099e21b
commit 0c6fcaa
Showing
9 changed files
with
330 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package secrets | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha1" | ||
"encoding/base64" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
// https://www.alibabacloud.com/help/en/sdk/alibaba-cloud-api-overview | ||
// https://www.alibabacloud.com/help/en/sdk/product-overview/rpc-mechanism#sectiondiv-y9b-x9s-wvp | ||
|
||
func validateAlibaba(secrets pairsByRuleId) { | ||
|
||
accessKeys := secrets["alibaba-access-key-id"] | ||
secretKeys := secrets["alibaba-secret-key"] | ||
|
||
for _, accessKey := range accessKeys { | ||
accessKey.ValidationStatus = Unknown | ||
|
||
for _, secretKey := range secretKeys { | ||
status, err := alibabaRequest(accessKey.Value, secretKey.Value) | ||
if err != nil { | ||
log.Warn().Err(err).Str("service", "alibaba").Msg("Failed to validate secret") | ||
} | ||
|
||
secretKey.ValidationStatus = status | ||
if accessKey.ValidationStatus.CompareTo(status) == second { | ||
accessKey.ValidationStatus = status | ||
} | ||
} | ||
} | ||
} | ||
|
||
func alibabaRequest(accessKey, secretKey string) (validationResult, error) { | ||
req, err := http.NewRequest("GET", "https://ecs.aliyuncs.com/", nil) | ||
if err != nil { | ||
return Unknown, err | ||
} | ||
|
||
// Workaround for gitleaks returns the key ends with " | ||
// https://github.com/gitleaks/gitleaks/pull/1350 | ||
accessKey = strings.TrimSuffix(accessKey, "\"") | ||
secretKey = strings.TrimSuffix(secretKey, "\"") | ||
|
||
params := req.URL.Query() | ||
params.Add("AccessKeyId", accessKey) | ||
params.Add("Action", "DescribeRegions") | ||
params.Add("SignatureMethod", "HMAC-SHA1") | ||
params.Add("SignatureNonce", strconv.FormatInt(time.Now().UnixNano(), 10)) | ||
params.Add("SignatureVersion", "1.0") | ||
params.Add("Timestamp", time.Now().UTC().Format(time.RFC3339)) | ||
params.Add("Version", "2014-05-26") | ||
|
||
stringToSign := "GET&%2F&" + url.QueryEscape(params.Encode()) | ||
hmac := hmac.New(sha1.New, []byte(secretKey+"&")) | ||
hmac.Write([]byte(stringToSign)) | ||
signature := base64.StdEncoding.EncodeToString(hmac.Sum(nil)) | ||
|
||
params.Add("Signature", signature) | ||
req.URL.RawQuery = params.Encode() | ||
|
||
client := &http.Client{} | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
return Unknown, err | ||
} | ||
log.Debug().Str("service", "alibaba").Int("status_code", resp.StatusCode) | ||
|
||
// If the access key is invalid, the response will be 404 | ||
// If the secret key is invalid, the response will be 400 along with other signautre Errors | ||
if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusBadRequest { | ||
return Revoked, nil | ||
} | ||
|
||
if resp.StatusCode == http.StatusOK { | ||
return Valid, nil | ||
} | ||
|
||
err = fmt.Errorf("unexpected status code: %d", resp.StatusCode) | ||
return Unknown, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package secrets | ||
|
||
import ( | ||
"sync" | ||
) | ||
|
||
type pairsByRuleId map[string][]*Secret | ||
type pairsBySource map[string]pairsByRuleId | ||
type pairsByGeneralKey map[string]pairsBySource | ||
|
||
type pairsCollector struct { | ||
pairs pairsByGeneralKey | ||
} | ||
|
||
func newPairsCollector() *pairsCollector { | ||
return &pairsCollector{pairs: make(pairsByGeneralKey)} | ||
} | ||
|
||
func (p *pairsCollector) addIfNeeded(secret *Secret) bool { | ||
generalKey, ok := ruleToGeneralKey[secret.RuleID] | ||
if !ok { | ||
return false | ||
} | ||
|
||
if _, ok := p.pairs[generalKey]; !ok { | ||
p.pairs[generalKey] = make(pairsBySource) | ||
} | ||
if _, ok := p.pairs[generalKey][secret.Source]; !ok { | ||
p.pairs[generalKey][secret.Source] = make(pairsByRuleId) | ||
} | ||
if _, ok := p.pairs[generalKey][secret.Source][secret.RuleID]; !ok { | ||
p.pairs[generalKey][secret.Source][secret.RuleID] = make([]*Secret, 0) | ||
} | ||
|
||
p.pairs[generalKey][secret.Source][secret.RuleID] = append(p.pairs[generalKey][secret.Source][secret.RuleID], secret) | ||
return true | ||
} | ||
|
||
func (p *pairsCollector) validate(generalKey string, rulesById pairsByRuleId, wg *sync.WaitGroup) { | ||
defer wg.Done() | ||
generalKeyToValidation[generalKey](rulesById) | ||
} | ||
|
||
type pairsValidationFunc func(pairsByRuleId) | ||
|
||
var generalKeyToValidation = map[string]pairsValidationFunc{ | ||
"alibaba": validateAlibaba, | ||
} | ||
|
||
var generalKeyToRules = map[string][]string{ | ||
"alibaba": {"alibaba-access-key-id", "alibaba-secret-key"}, | ||
} | ||
|
||
func generateRuleToGeneralKey() map[string]string { | ||
ruleToGeneralKey := make(map[string]string) | ||
for key, rules := range generalKeyToRules { | ||
for _, rule := range rules { | ||
ruleToGeneralKey[rule] = key | ||
} | ||
} | ||
return ruleToGeneralKey | ||
} | ||
|
||
var ruleToGeneralKey = generateRuleToGeneralKey() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.