Skip to content

Commit

Permalink
feat(lambda): add lambda checks for secrets in environment and URL Au…
Browse files Browse the repository at this point in the history
…thType
  • Loading branch information
oussamaca committed Feb 10, 2023
1 parent f8dcc44 commit 610606f
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 0 deletions.
20 changes: 20 additions & 0 deletions aws/lambda/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,23 @@ func GetLambdas(s aws.Config) []types.FunctionConfiguration {
}
return lambdas
}

func GetLambdaUrlConfigs(s aws.Config, lambdas []types.FunctionConfiguration) []LambdaUrlConfig {
svc := lambda.NewFromConfig(s)
lambdaUrlConfigs := []LambdaUrlConfig{}
for _, function := range lambdas {
input := &lambda.ListFunctionUrlConfigsInput{
FunctionName: function.FunctionName,
}
result, err := svc.ListFunctionUrlConfigs(context.TODO(), input)
if err != nil {
return nil
}
lambdaUrlConfigs = append(lambdaUrlConfigs, LambdaUrlConfig{
LambdaName: *function.FunctionName,
LambdaArn: *function.FunctionArn,
UrlConfigs: result.FunctionUrlConfigs,
})
}
return lambdaUrlConfigs
}
3 changes: 3 additions & 0 deletions aws/lambda/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ func RunChecks(wa *sync.WaitGroup, s aws.Config, c *commons.Config, queue chan [
checkConfig.Init(s, c)
var checks []commons.Check
lambdas := GetLambdas(s)
lambdaUrlConfigs := GetLambdaUrlConfigs(s, lambdas)

go commons.CheckTest(checkConfig.Wg, c, "AWS_LMD_001", CheckIfLambdaPrivate)(checkConfig, lambdas, "AWS_LMD_001")
go commons.CheckTest(checkConfig.Wg, c, "AWS_LMD_002", CheckIfLambdaInSecurityGroup)(checkConfig, lambdas, "AWS_LMD_002")
go commons.CheckTest(checkConfig.Wg, c, "AWS_LMD_003", CheckIfLambdaNoErrors)(checkConfig, lambdas, "AWS_LMD_003")
go commons.CheckTest(checkConfig.Wg, c, "AWS_LMD_004", CheckIfLambdaNoSecrets)(checkConfig, lambdas, "AWS_LMD_004")
go commons.CheckTest(checkConfig.Wg, c, "AWS_LMD_005", CheckIfLambdaUrlAuth)(checkConfig, lambdaUrlConfigs, "AWS_LMD_005")
go func() {
for t := range checkConfig.Queue {
t.EndCheck()
Expand Down
57 changes: 57 additions & 0 deletions aws/lambda/lambdaNoSecrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package lambda

import (
"fmt"

"github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/dlclark/regexp2"
"github.com/padok-team/yatas/plugins/commons"
)

var secrets_patterns = []*regexp2.Regexp{
// General
regexp2.MustCompile("^-----BEGIN (RSA|EC|DSA|GPP) PRIVATE KEY-----$", regexp2.RE2),
// AWS
regexp2.MustCompile("(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])", regexp2.RE2), // AWS secret access key
regexp2.MustCompile("(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}", regexp2.RE2), // AWS access key ID
regexp2.MustCompile("(\"|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)(\"|')?\\s*(:|=>|=)\\s*(\"|')?[A-Za-z0-9/\\+=]{40}(\"|')?", regexp2.RE2),
regexp2.MustCompile("(\"|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?(\"|')?\\s*(:|=>|=)\\s*(\"|')?[0-9]{4}\\-?[0-9]{4}\\-?[0-9]{4}(\"|')?", regexp2.RE2),
}

func string_has_secrets(value string) bool {
isSecret := false
for _, pattern := range secrets_patterns {
if res, _ := pattern.MatchString(value); res {
isSecret = true
break
}
}
return isSecret
}

func CheckIfLambdaNoSecrets(checkConfig commons.CheckConfig, lambdas []types.FunctionConfiguration, testName string) {
var check commons.Check
check.InitCheck("Lambdas has no hard-coded secrets in environment", "Check if all Lambdas has no secrets as environment variable", testName, []string{"Security", "Good Practice"})

for _, lambda := range lambdas {
envSecrets := []string{}
if lambda.Environment.Error == nil {
for key, value := range lambda.Environment.Variables {
if string_has_secrets(value) {
envSecrets = append(envSecrets, key)
}
}
}

if len(envSecrets) > 0 {
Message := "Lambda " + *lambda.FunctionName + " has secrets in environment: " + fmt.Sprint(envSecrets)
result := commons.Result{Status: "FAIL", Message: Message, ResourceID: *lambda.FunctionArn}
check.AddResult(result)
} else {
Message := "Lambda " + *lambda.FunctionName + " has no secrets in environment"
result := commons.Result{Status: "OK", Message: Message, ResourceID: *lambda.FunctionArn}
check.AddResult(result)
}
}
checkConfig.Queue <- check
}
117 changes: 117 additions & 0 deletions aws/lambda/lambdaNoSecrets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package lambda

import (
"sync"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/padok-team/yatas/plugins/commons"
)

func TestCheckIfLambdaNoSecrets(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
lambdas []types.FunctionConfiguration
testName string
}
tests := []struct {
name string
args args
}{
{
name: "TestCheckIfLambdaNoSecrets",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdas: []types.FunctionConfiguration{
{
FunctionName: aws.String("test"),
FunctionArn: aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
Environment: &types.EnvironmentResponse{
Variables: map[string]string{},
},
},
},
},
},
{
name: "TestCheckIfLambdaNoSecrets",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdas: []types.FunctionConfiguration{
{
FunctionName: aws.String("test"),
FunctionArn: aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
Environment: &types.EnvironmentResponse{
Variables: map[string]string{
"my_variable": "test",
},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfLambdaNoSecrets(tt.args.checkConfig, tt.args.lambdas, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "OK" {
t.Errorf("CheckIfLambdaNoSecrets() = %v, want %v", check.Status, "OK")
}
tt.args.checkConfig.Wg.Done()
}
}()
tt.args.checkConfig.Wg.Wait()
})
}
}

func TestCheckIfLambdaNoSecretsFail(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
lambdas []types.FunctionConfiguration
testName string
}
tests := []struct {
name string
args args
}{
{
name: "TestCheckIfLambdaNoSecrets",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdas: []types.FunctionConfiguration{
{
FunctionName: aws.String("test"),
FunctionArn: aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
Environment: &types.EnvironmentResponse{
Variables: map[string]string{
"aws_access_key": "ASIAS6VZTAEWPKBMXQOL",
},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfLambdaNoSecrets(tt.args.checkConfig, tt.args.lambdas, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "FAIL" {
t.Errorf("CheckIfLambdaNoSecrets() = %v, want %v", check.Status, "FAIL")
}
tt.args.checkConfig.Wg.Done()
}
}()
tt.args.checkConfig.Wg.Wait()
})
}
}
31 changes: 31 additions & 0 deletions aws/lambda/lambdaUrlAuth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lambda

import (
"github.com/padok-team/yatas/plugins/commons"
)

func CheckIfLambdaUrlAuth(checkConfig commons.CheckConfig, lambdaUrlConfigs []LambdaUrlConfig, testName string) {
var check commons.Check
check.InitCheck("Lambdas has no public URL access", "Check if all Lambdas has no URL AuthType set to None", testName, []string{"Security", "Good Practice"})

for _, lambda := range lambdaUrlConfigs {
AuthTypeIsNone := false
for _, urlConfig := range lambda.UrlConfigs {
if urlConfig.AuthType == "NONE" {
AuthTypeIsNone = true
break
}
}

if AuthTypeIsNone {
Message := "Lambda " + lambda.LambdaName + " has URL AuthType set to None"
result := commons.Result{Status: "FAIL", Message: Message, ResourceID: lambda.LambdaArn}
check.AddResult(result)
} else {
Message := "Lambda " + lambda.LambdaName + " has no URL AuthType set to None"
result := commons.Result{Status: "OK", Message: Message, ResourceID: lambda.LambdaArn}
check.AddResult(result)
}
}
checkConfig.Queue <- check
}
111 changes: 111 additions & 0 deletions aws/lambda/lambdaUrlAuth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package lambda

import (
"sync"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/padok-team/yatas/plugins/commons"
)

func TestCheckIfLambdaUrlAuth(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
lambdaUrlConfigs []LambdaUrlConfig
testName string
}
tests := []struct {
name string
args args
}{
{
name: "TestCheckIfLambdaUrlAuth",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdaUrlConfigs: []LambdaUrlConfig{
{
LambdaName: *aws.String("test"),
LambdaArn: *aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
UrlConfigs: []types.FunctionUrlConfig{},
},
},
},
},
{
name: "TestCheckIfLambdaUrlAuth",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdaUrlConfigs: []LambdaUrlConfig{
{
LambdaName: *aws.String("test"),
LambdaArn: *aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
UrlConfigs: []types.FunctionUrlConfig{
{AuthType: "AWS_IAM"},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfLambdaUrlAuth(tt.args.checkConfig, tt.args.lambdaUrlConfigs, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "OK" {
t.Errorf("CheckIfLambdaUrlAuth() = %v, want %v", check.Status, "OK")
}
tt.args.checkConfig.Wg.Done()
}
}()
tt.args.checkConfig.Wg.Wait()
})
}
}

func TestCheckIfLambdaUrlAuthFail(t *testing.T) {
type args struct {
checkConfig commons.CheckConfig
lambdaUrlConfigs []LambdaUrlConfig
testName string
}
tests := []struct {
name string
args args
}{
{
name: "TestCheckIfLambdaUrlAuth",
args: args{
checkConfig: commons.CheckConfig{Queue: make(chan commons.Check, 1), Wg: &sync.WaitGroup{}},
lambdaUrlConfigs: []LambdaUrlConfig{
{
LambdaName: *aws.String("test"),
LambdaArn: *aws.String("arn:aws:lambda:us-east-1:123456789012:function:test"),
UrlConfigs: []types.FunctionUrlConfig{
{AuthType: "NONE"},
},
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CheckIfLambdaUrlAuth(tt.args.checkConfig, tt.args.lambdaUrlConfigs, tt.args.testName)
tt.args.checkConfig.Wg.Add(1)
go func() {
for check := range tt.args.checkConfig.Queue {
if check.Status != "FAIL" {
t.Errorf("CheckIfLambdaUrlAuth() = %v, want %v", check.Status, "FAIL")
}
tt.args.checkConfig.Wg.Done()
}
}()
tt.args.checkConfig.Wg.Wait()
})
}
}
9 changes: 9 additions & 0 deletions aws/lambda/struct.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package lambda

import "github.com/aws/aws-sdk-go-v2/service/lambda/types"

type LambdaUrlConfig struct {
LambdaName string
LambdaArn string
UrlConfigs []types.FunctionUrlConfig
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/dlclark/regexp2 v1.8.0 // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-github/v35 v35.3.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.8.0 h1:rJD5HeGIT/2b5CDk63FVCwZA3qgYElfg+oQK7uH5pfE=
github.com/dlclark/regexp2 v1.8.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
Expand Down

0 comments on commit 610606f

Please sign in to comment.