1 | /* Vuls - Vulnerability Scanner |
||
2 | Copyright (C) 2016 Future Corporation , Japan. |
||
3 | |||
4 | This program is free software: you can redistribute it and/or modify |
||
5 | it under the terms of the GNU General Public License as published by |
||
6 | the Free Software Foundation, either version 3 of the License, or |
||
7 | (at your option) any later version. |
||
8 | |||
9 | This program is distributed in the hope that it will be useful, |
||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
12 | GNU General Public License for more details. |
||
13 | |||
14 | You should have received a copy of the GNU General Public License |
||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
16 | */ |
||
17 | |||
18 | package report |
||
19 | |||
20 | import ( |
||
21 | "bytes" |
||
22 | "encoding/json" |
||
23 | "fmt" |
||
24 | "io/ioutil" |
||
25 | "net/http" |
||
26 | "net/url" |
||
27 | "os" |
||
28 | "path" |
||
29 | "strings" |
||
30 | "time" |
||
31 | |||
32 | "github.com/aws/aws-sdk-go/aws" |
||
33 | "github.com/aws/aws-sdk-go/aws/credentials" |
||
34 | "github.com/aws/aws-sdk-go/aws/session" |
||
35 | "github.com/aws/aws-sdk-go/service/s3" |
||
36 | "github.com/aws/aws-sdk-go/service/sts" |
||
37 | c "github.com/future-architect/vuls/config" |
||
38 | "github.com/future-architect/vuls/models" |
||
39 | "github.com/future-architect/vuls/util" |
||
40 | "golang.org/x/xerrors" |
||
41 | ) |
||
42 | |||
43 | // SaasWriter writes results to SaaS |
||
44 | type SaasWriter struct{} |
||
45 | |||
46 | // TempCredential : TempCredential |
||
47 | type TempCredential struct { |
||
48 | Credential *sts.Credentials `json:"Credential"` |
||
49 | S3Bucket string `json:"S3Bucket"` |
||
50 | S3ResultsDir string `json:"S3ResultsDir"` |
||
51 | } |
||
52 | |||
53 | type payload struct { |
||
54 | GroupID int `json:"GroupID"` |
||
55 | Token string `json:"Token"` |
||
56 | ScannedBy string `json:"ScannedBy"` |
||
57 | ScannedIPv4s string `json:"ScannedIPv4s"` |
||
58 | ScannedIPv6s string `json:"ScannedIPv6s"` |
||
59 | } |
||
60 | |||
61 | // UploadSaas : UploadSaas |
||
62 | func (w SaasWriter) Write(rs ...models.ScanResult) (err error) { |
||
63 | // dir string, configPath string, config *c.Config |
||
64 | if len(rs) == 0 { |
||
65 | return nil |
||
66 | } |
||
67 | |||
68 | ipv4s, ipv6s, err := util.IP() |
||
69 | if err != nil { |
||
70 | util.Log.Errorf("Failed to fetch scannedIPs. err: %+v", err) |
||
71 | } |
||
72 | hostname, _ := os.Hostname() |
||
73 | |||
74 | payload := payload{ |
||
75 | GroupID: c.Conf.Saas.GroupID, |
||
76 | Token: c.Conf.Saas.Token, |
||
77 | ScannedBy: hostname, |
||
78 | ScannedIPv4s: strings.Join(ipv4s, ", "), |
||
79 | ScannedIPv6s: strings.Join(ipv6s, ", "), |
||
80 | } |
||
81 | |||
82 | var body []byte |
||
83 | if body, err = json.Marshal(payload); err != nil { |
||
84 | return xerrors.Errorf("Failed to Marshal to JSON: %w", err) |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
85 | } |
||
86 | |||
87 | var req *http.Request |
||
88 | if req, err = http.NewRequest("POST", c.Conf.Saas.URL, bytes.NewBuffer(body)); err != nil { |
||
89 | return err |
||
90 | } |
||
91 | req.Header.Set("Content-Type", "application/json") |
||
92 | req.Header.Set("Accept", "application/json") |
||
93 | |||
94 | proxy := c.Conf.HTTPProxy |
||
95 | var client http.Client |
||
96 | if proxy != "" { |
||
97 | proxyURL, _ := url.Parse(proxy) |
||
98 | client = http.Client{ |
||
99 | Transport: &http.Transport{ |
||
100 | Proxy: http.ProxyURL(proxyURL), |
||
101 | }, |
||
102 | } |
||
103 | } else { |
||
104 | client = http.Client{} |
||
105 | } |
||
106 | |||
107 | var resp *http.Response |
||
108 | if resp, err = client.Do(req); err != nil { |
||
109 | return err |
||
110 | } |
||
111 | defer resp.Body.Close() |
||
112 | if resp.StatusCode != 200 { |
||
113 | return xerrors.Errorf("Failed to get Credential. Request JSON : %s,", string(body)) |
||
114 | } |
||
115 | |||
116 | var t []byte |
||
117 | if t, err = ioutil.ReadAll(resp.Body); err != nil { |
||
118 | return err |
||
119 | } |
||
120 | |||
121 | var tempCredential TempCredential |
||
122 | if err = json.Unmarshal(t, &tempCredential); err != nil { |
||
123 | return xerrors.Errorf("Failed to unmarshal saas credential file. err : %s", err) |
||
124 | } |
||
125 | |||
126 | credential := credentials.NewStaticCredentialsFromCreds(credentials.Value{ |
||
127 | AccessKeyID: *tempCredential.Credential.AccessKeyId, |
||
128 | SecretAccessKey: *tempCredential.Credential.SecretAccessKey, |
||
129 | SessionToken: *tempCredential.Credential.SessionToken, |
||
130 | }) |
||
131 | |||
132 | var sess *session.Session |
||
133 | if sess, err = session.NewSession(&aws.Config{ |
||
134 | Credentials: credential, |
||
135 | Region: aws.String("ap-northeast-1"), |
||
136 | }); err != nil { |
||
137 | return xerrors.Errorf("Failed to new aws session. err: %w", err) |
||
0 ignored issues
–
show
|
|||
138 | } |
||
139 | |||
140 | svc := s3.New(sess) |
||
141 | for _, r := range rs { |
||
142 | s3Key := renameKeyNameUTC(r.ScannedAt, r.ServerUUID, r.Container) |
||
143 | var b []byte |
||
144 | if b, err = json.Marshal(r); err != nil { |
||
145 | return xerrors.Errorf("Failed to Marshal to JSON: %w", err) |
||
0 ignored issues
–
show
|
|||
146 | } |
||
147 | util.Log.Infof("Uploading...: ServerName: %s, ", r.ServerName) |
||
148 | putObjectInput := &s3.PutObjectInput{ |
||
149 | Bucket: aws.String(tempCredential.S3Bucket), |
||
150 | Key: aws.String(path.Join(tempCredential.S3ResultsDir, s3Key)), |
||
151 | Body: bytes.NewReader(b), |
||
152 | } |
||
153 | |||
154 | if _, err := svc.PutObject(putObjectInput); err != nil { |
||
155 | return xerrors.Errorf("Failed to upload data to %s/%s, err: %w", |
||
0 ignored issues
–
show
|
|||
156 | tempCredential.S3Bucket, s3Key, err) |
||
157 | } |
||
158 | } |
||
159 | return nil |
||
160 | } |
||
161 | |||
162 | func renameKeyNameUTC(scannedAt time.Time, uuid string, container models.Container) string { |
||
163 | timestr := scannedAt.UTC().Format(time.RFC3339) |
||
164 | if len(container.ContainerID) == 0 { |
||
165 | return fmt.Sprintf("%s/%s.json", timestr, uuid) |
||
166 | } |
||
167 | return fmt.Sprintf("%s/%s@%s.json", timestr, container.UUID, uuid) |
||
168 | } |
||
169 |