/
cloud.go
133 lines (121 loc) · 3.62 KB
/
cloud.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
package falcon
import (
"context"
"fmt"
"strings"
"github.com/crowdstrike/gofalcon/falcon/client"
"github.com/crowdstrike/gofalcon/falcon/client/oauth2"
"github.com/go-openapi/strfmt"
)
// CloudType represents type of CrowdStrike Falcon cloud region.
type CloudType int
const (
CloudAutoDiscover = iota
CloudUs1
CloudUs2
CloudEu1
CloudUsGov1
)
// Cloud parses cloud string (example: us-1, us-2, eu-1, us-gov-1, etc). If a string is not recognized CloudUs1 is returned.
func Cloud(cloudString string) CloudType {
c, _ := CloudValidate(cloudString)
return c
}
// CloudValidate parses cloud string (example: us-1, us-2, eu-1, us-gov-1, etc.). Error is returned when string cannot be recognized.
func CloudValidate(cloudString string) (CloudType, error) {
trimmed := strings.TrimSpace(cloudString)
lower := strings.ToLower(trimmed)
switch lower {
case "":
fallthrough
case "autodiscover":
return CloudAutoDiscover, nil
case "us-1":
return CloudUs1, nil
case "us-2":
return CloudUs2, nil
case "eu-1":
return CloudEu1, nil
case "us-gov-1":
return CloudUsGov1, nil
}
return CloudUs1, fmt.Errorf("unrecognized CrowdStrike Falcon Cloud: %s", lower)
}
// Host returns default hostname for given cloud.
func (c CloudType) Host() string {
switch c {
default:
fallthrough
case CloudUs1:
return "api.crowdstrike.com"
case CloudUs2:
return "api.us-2.crowdstrike.com"
case CloudEu1:
return "api.eu-1.crowdstrike.com"
case CloudUsGov1:
return "api.laggar.gcw.crowdstrike.com"
}
}
func (c CloudType) String() string {
switch c {
case CloudAutoDiscover:
return "autodiscover"
case CloudUs1:
return "us-1"
case CloudUs2:
return "us-2"
case CloudEu1:
return "eu-1"
case CloudUsGov1:
return "us-gov-1"
default:
return "UNKNOWN FALCON CLOUD REGION"
}
}
func (c *CloudType) Autodiscover(ctx context.Context, clientId, clientSecret string) error {
if *c != CloudAutoDiscover {
return nil
}
// (1) Request our cloud-region information from us-1 cloud-region
cli := client.NewHTTPClient(strfmt.Default)
token, err := cli.Oauth2.Oauth2AccessToken(&oauth2.Oauth2AccessTokenParams{
Context: ctx,
ClientID: clientId,
ClientSecret: clientSecret,
})
if err != nil {
switch e := err.(type) {
case *oauth2.Oauth2AccessTokenForbidden:
if e.Payload != nil && len(e.Payload.Errors) == 1 && e.Payload.Errors[0] != nil && e.Payload.Errors[0].Message != nil && *e.Payload.Errors[0].Message == "access denied, authorization failed" {
return fmt.Errorf("Please check the settings of IP-based allowlisting in CrowdStrike Falcon Console. %s", e)
}
return fmt.Errorf("Insufficient CrowdStrike privileges, please grant [Falcon Images Download: Read] to CrowdStrike API Key. Error was: %s", err)
}
return fmt.Errorf("Could not autodiscover Falcon cloud region: %v", err)
}
// (2) Parse & save the cloud-region information
cld, err := CloudValidate(token.XCSRegion)
if err != nil {
return fmt.Errorf("Could not validate Falcon cloud region '%s' during autodiscover: %v", token.XCSRegion, err)
}
(*c) = cld
// (3) Revoke the API token we have got from us-1 region
if (*c) != CloudUs1 {
// (4) Revocation needs to be done in our *local* region
transportConfig := client.DefaultTransportConfig().WithHost(c.Host())
cli = client.NewHTTPClientWithConfig(strfmt.Default, transportConfig)
}
revocation, err := cli.Oauth2.Oauth2RevokeToken(&oauth2.Oauth2RevokeTokenParams{
Context: ctx,
Token: token.Payload.AccessToken,
},
oauth2.AuthenticateRevocation(clientId, clientSecret),
)
if err != nil {
return nil
}
if err = AssertNoError(revocation.Payload.Errors); err != nil {
return err
}
return nil
}