-
Notifications
You must be signed in to change notification settings - Fork 12
/
nuke_leaked_aws_keys.go
141 lines (107 loc) · 4.12 KB
/
nuke_leaked_aws_keys.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements;
// and to You under the Apache License, Version 2.0. See LICENSE in project root for full license + copyright.
package keynuker
import (
"strings"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/pkg/errors"
)
// . Connect to AWS
// . For each leaked key
// .. Delete the key
// . Return doc with nuked keys and validated github event checkpoints
func NukeLeakedAwsKeys(params ParamsNukeLeakedAwsKeys) (doc DocumentNukeLeakedAwsKeys, err error) {
for _, leakedKeyEvent := range params.LeakedKeyEvents {
// Don't nuke the key that keynuker itself is using!
if leakedKeyEvent.LeakedKeyIsMonitorKey() {
return doc, errors.Errorf("Cannot nuke the key being used to monitor. LeakedKeyEvent: %+v", leakedKeyEvent)
}
// Find which target AWS account this leaked key is associated with
targetAwsAccount, err := FindAwsAccount(params.TargetAwsAccounts, leakedKeyEvent.AccessKeyMetadata.MonitorAwsAccessKeyId)
if err != nil {
return doc, err
}
// Create AWS session on target AWS account
sess, err := session.NewSession(&aws.Config{
Credentials: credentials.NewCredentials(
&credentials.StaticProvider{Value: credentials.Value{
AccessKeyID: targetAwsAccount.AwsAccessKeyId,
SecretAccessKey: targetAwsAccount.AwsSecretAccessKey,
}},
),
})
if err != nil {
return doc, err
}
// Create IAM client with the session.
svc := iam.New(sess)
// Nuke the key from AWS
deleteAccessKeyInput := &iam.DeleteAccessKeyInput{
AccessKeyId: leakedKeyEvent.AccessKeyMetadata.AccessKeyId,
UserName: leakedKeyEvent.AccessKeyMetadata.UserName,
}
log.Printf("Nuking key: %v", *leakedKeyEvent.AccessKeyMetadata.AccessKeyId)
deleteAccessKeyOutput, errDelKey := svc.DeleteAccessKey(deleteAccessKeyInput)
// Only consider it an error if it's not a "KeyNotFound error", which means the key was already nuked
if errDelKey != nil && !IsKeyNotFoundError(errDelKey) {
return doc, errDelKey
}
nukedKeyEvent := NukedKeyEvent{
LeakedKeyEvent: leakedKeyEvent,
DeleteAccessKeyOutput: deleteAccessKeyOutput,
}
doc.NukedKeyEvents = append(doc.NukedKeyEvents, nukedKeyEvent)
}
// Validate and propagate github checkpoints
doc.GithubEventCheckpoints = params.GithubEventCheckpoints
return doc, nil
}
func IsKeyNotFoundError(err error) bool {
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "NoSuchEntity" {
return true
}
}
if err == nil {
return false
}
// Otherwise resort to a string search
if strings.Contains(err.Error(), "NoSuchEntity") && strings.Contains(err.Error(), "cannot be found") {
return true
}
return false
}
type ParamsNukeLeakedAwsKeys struct {
// The list of AWS accounts in scope
TargetAwsAccounts []TargetAwsAccount
// This is the name of the KeyNuker "org/tenant". Defaults to "default", but allows to be extended multi-tenant.
KeyNukerOrg string
// The leaked keys to nuke
LeakedKeyEvents []LeakedKeyEvent
// The keep per-user checkpoints which will be validated/propagated after keys are successfully nuked
GithubEventCheckpoints GithubEventCheckpoints
}
type DocumentNukeLeakedAwsKeys struct {
Id string `json:"_id"`
NukedKeyEvents []NukedKeyEvent
GithubEventCheckpoints GithubEventCheckpoints
}
func (p ParamsNukeLeakedAwsKeys) Validate() error {
return nil
}
func FindAwsAccount(targetAwsAccounts []TargetAwsAccount, monitorAwsAccessKeyId string) (TargetAwsAccount, error) {
if ArtificialErrorInjection() {
return FindAwsAccountArtificialError(targetAwsAccounts, monitorAwsAccessKeyId)
}
for _, targetAwsAccount := range targetAwsAccounts {
if strings.TrimSpace(targetAwsAccount.AwsAccessKeyId) == strings.TrimSpace(monitorAwsAccessKeyId) {
return targetAwsAccount, nil
}
}
return TargetAwsAccount{}, errors.Errorf("Could not find TargetAwsAccount with monitorAwsAccessKeyId: |%v| in %+v", monitorAwsAccessKeyId, targetAwsAccounts)
}