-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathtable_gcp_storage_bucket.go
377 lines (344 loc) · 13.2 KB
/
table_gcp_storage_bucket.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
package gcp
import (
"context"
"strings"
"github.com/turbot/steampipe-plugin-sdk/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/plugin"
"github.com/turbot/steampipe-plugin-sdk/plugin/transform"
"google.golang.org/api/googleapi"
"google.golang.org/api/storage/v1"
)
func tableGcpStorageBucket(_ context.Context) *plugin.Table {
return &plugin.Table{
Name: "gcp_storage_bucket",
Description: "GCP Storage Bucket",
Get: &plugin.GetConfig{
KeyColumns: plugin.SingleColumn("name"),
Hydrate: getGcpStorageBucket,
},
List: &plugin.ListConfig{
Hydrate: listGcpStorageBuckets,
},
Columns: []*plugin.Column{
{
Name: "name",
Description: "The name of the bucket.",
Type: proto.ColumnType_STRING,
},
{
Name: "id",
Description: "The ID of the bucket. For buckets, the id and name properties are the same.",
Type: proto.ColumnType_STRING,
},
{
Name: "kind",
Description: "The kind of item this is. For buckets, this is always storage#bucket.",
Type: proto.ColumnType_STRING,
},
{
Name: "time_created",
Description: "The creation time of the bucket in RFC 3339 format.",
Type: proto.ColumnType_TIMESTAMP,
},
{
Name: "location_type",
Description: "The type of the bucket location.",
Type: proto.ColumnType_STRING,
},
{
Name: "storage_class",
Description: "The bucket's default storage class, used whenever no storageClass is specified for a newly-created object. This defines how objects in the bucket are stored and determines the SLA and the cost of storage. Values include MULTI_REGIONAL, REGIONAL, STANDARD, NEARLINE, COLDLINE, ARCHIVE, and DURABLE_REDUCED_AVAILABILITY. If this value is not specified when the bucket is created, it will default to STANDARD.",
Type: proto.ColumnType_STRING,
},
{
Name: "billing_requester_pays",
Description: "When set to true, Requester Pays is enabled for this bucket.",
Default: false,
Type: proto.ColumnType_BOOL,
Transform: transform.FromField("Billing.RequesterPays"),
},
{
Name: "default_event_based_hold",
Description: "The default value for event-based hold on newly created objects in this bucket. Event-based hold is a way to retain objects indefinitely until an event occurs, signified by the hold's release. After being released, such objects will be subject to bucket-level retention (if any).",
Type: proto.ColumnType_BOOL,
},
{
Name: "default_kms_key_name",
Description: "A Cloud KMS key that will be used to encrypt objects inserted into this bucket, if no encryption method is specified.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Encryption.DefaultKmsKeyName"),
},
{
Name: "etag",
Description: "HTTP 1.1 Entity tag for the bucket.",
Type: proto.ColumnType_STRING,
},
{
Name: "iam_configuration_bucket_policy_only_enabled",
Description: "The bucket's uniform bucket-level access configuration. The feature was formerly known as Bucket Policy Only. For backward compatibility, this field will be populated with identical information as the uniformBucketLevelAccess field.",
Type: proto.ColumnType_BOOL,
Default: false,
Transform: transform.FromField("IamConfiguration.BucketPolicyOnly.Enabled"),
},
{
Name: "iam_configuration_public_access_prevention",
Description: "The bucket's Public Access Prevention configuration. Currently, 'unspecified' and 'enforced' are supported.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("IamConfiguration.PublicAccessPrevention"),
},
{
Name: "iam_configuration_uniform_bucket_level_access_enabled",
Description: "The bucket's uniform bucket-level access configuration.",
Type: proto.ColumnType_BOOL,
Default: false,
Transform: transform.FromField("IamConfiguration.UniformBucketLevelAccess.Enabled"),
},
{
Name: "labels",
Description: "Labels that apply to this bucket.",
Type: proto.ColumnType_JSON,
},
{
Name: "log_bucket",
Description: "The destination bucket where the current bucket's logs should be placed.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Logging.LogBucket"),
},
{
Name: "log_object_prefix",
Description: "A prefix for log object names.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Logging.LogObjectPrefix"),
},
{
Name: "metageneration",
Description: "The metadata generation of this bucket.",
Type: proto.ColumnType_INT,
},
{
Name: "owner_entity",
Description: "The entity, in the form project-owner-projectId. This is always the project team's owner group.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Owner.Entity"),
},
{
Name: "owner_entity_id",
Description: "The ID for the entity.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Owner.EntityId"),
},
{
Name: "project_number",
Description: "The project number of the project the bucket belongs to.",
Type: proto.ColumnType_DOUBLE,
},
{
Name: "versioning_enabled",
Description: "While set to true, versioning is fully enabled for this bucket.",
Type: proto.ColumnType_BOOL,
Default: false,
Transform: transform.FromField("Versioning.Enabled"),
},
{
Name: "website_main_page_suffix",
Description: "If the requested object path is missing, the service will ensure the path has a trailing '/', append this suffix, and attempt to retrieve the resulting object. This allows the creation of index.html objects to represent directory pages.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Website.MainPageSuffix"),
},
{
Name: "website_not_found_page",
Description: "If the requested object path is missing, and any mainPageSuffix object is missing, if applicable, the service will return the named object from this bucket as the content for a 404 Not Found result.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Website.NotFoundPage"),
},
{
Name: "self_link",
Description: "The URI of this bucket.",
Type: proto.ColumnType_STRING,
},
{
Name: "updated",
Description: "The modification time of the bucket.",
Type: proto.ColumnType_TIMESTAMP,
},
{
Name: "acl",
Description: "An access-control list",
Type: proto.ColumnType_JSON,
Hydrate: getGcpStorageBucketACLs,
Transform: transform.FromValue(),
},
{
Name: "default_object_acl",
Description: "Lists of object access control entries",
Type: proto.ColumnType_JSON,
Hydrate: getGcpStorageBucketDefaultACLs,
Transform: transform.FromValue(),
},
{
Name: "cors",
Description: "The bucket's Cross-Origin Resource Sharing (CORS) configuration.",
Type: proto.ColumnType_JSON,
},
{
Name: "iam_policy",
Description: "An Identity and Access Management (IAM) policy, which specifies access controls for Google Cloud resources. A `Policy` is a collection of `bindings`. A `binding` binds one or more `members` to a single `role`. Members can be user accounts, service accounts, Google groups, and domains (such as G Suite). A `role` is a named list of permissions; each `role` can be an IAM predefined role or a user-created custom role. For some types of Google Cloud resources, a `binding` can also specify a `condition`, which is a logical expression that allows access to a resource only if the expression evaluates to `true`.",
Type: proto.ColumnType_JSON,
Hydrate: getGcpStorageBucketIAMPolicy,
Transform: transform.FromValue(),
},
{
Name: "lifecycle_rules",
Description: "The bucket's lifecycle configuration. See lifecycle management for more information.",
Type: proto.ColumnType_JSON,
Transform: transform.FromField("Lifecycle.Rule"),
},
{
Name: "retention_policy",
Description: "The bucket's retention policy. The retention policy enforces a minimum retention time for all objects contained in the bucket, based on their creation time. Any attempt to overwrite or delete objects younger than the retention period will result in a PERMISSION_DENIED error.",
Type: proto.ColumnType_JSON,
},
// standard steampipe columns
{
Name: "tags",
Description: ColumnDescriptionTags,
Type: proto.ColumnType_JSON,
Transform: transform.FromField("Labels"),
},
{
Name: "title",
Description: ColumnDescriptionTitle,
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Name"),
},
{
Name: "akas",
Description: ColumnDescriptionAkas,
Type: proto.ColumnType_JSON,
Hydrate: getBucketAka,
Transform: transform.FromValue(),
},
// standard gcp columns
{
Name: "location",
Description: ColumnDescriptionLocation,
Type: proto.ColumnType_STRING,
},
{
Name: "project",
Description: ColumnDescriptionProject,
Type: proto.ColumnType_STRING,
Hydrate: getProject,
Transform: transform.FromValue(),
},
},
}
}
//// LIST FUNCTION
func listGcpStorageBuckets(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
projectData, err := activeProject(ctx, d)
if err != nil {
return nil, err
}
project := projectData.Project
// Create Service Connection
service, err := StorageService(ctx, d)
if err != nil {
return nil, err
}
resp := service.Buckets.List(project)
if err := resp.Pages(ctx, func(page *storage.Buckets) error {
for _, bucket := range page.Items {
d.StreamListItem(ctx, bucket)
}
return nil
}); err != nil {
return nil, err
}
return nil, err
}
func getGcpStorageBucket(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
// project := projectName
name := d.KeyColumnQuals["name"].GetStringValue()
// Create Service Connection
service, err := StorageService(ctx, d)
if err != nil {
return nil, err
}
req, err := service.Buckets.Get(name).Do()
if err != nil {
plugin.Logger(ctx).Trace("getGcpStorageBucket", "Error", err)
return nil, err
}
return req, nil
}
//// HYDRATE FUNCTIONS
func getGcpStorageBucketIAMPolicy(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
plugin.Logger(ctx).Trace("getGcpStorageBucketIAMPolicy")
bucket := h.Item.(*storage.Bucket)
// Create Session
// Create Service Connection
service, err := StorageService(ctx, d)
if err != nil {
return nil, err
}
resp, err := service.Buckets.GetIamPolicy(bucket.Name).Do()
if err != nil {
return nil, err
}
return resp, nil
}
func getGcpStorageBucketACLs(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
plugin.Logger(ctx).Trace("getGcpStorageBucketACLs")
bucket := h.Item.(*storage.Bucket)
// Create Session
// Create Service Connection
service, err := StorageService(ctx, d)
if err != nil {
return nil, err
}
resp, err := service.BucketAccessControls.List(bucket.Name).Do()
if err != nil {
gerr, _ := err.(*googleapi.Error)
// It should not error out if the bucket has uniform bucket-level accesss
// googleapi: Error 400: Cannot get legacy ACL for a bucket that has uniform bucket-level access.
// Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access, invalid
if gerr.Code == 400 && strings.HasPrefix(gerr.Message, "Cannot get legacy ACL for a bucket that has uniform bucket-level access") {
return nil, nil
}
return nil, err
}
return resp, nil
}
func getGcpStorageBucketDefaultACLs(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
plugin.Logger(ctx).Trace("getGcpStorageBucketDefaultACLs")
bucket := h.Item.(*storage.Bucket)
// Create Session
// Create Service Connection
service, err := StorageService(ctx, d)
if err != nil {
return nil, err
}
resp, err := service.DefaultObjectAccessControls.List(bucket.Name).Do()
if err != nil {
gerr, _ := err.(*googleapi.Error)
// It should not error out if the bucket has uniform bucket-level accesss
// googleapi: Error 400: Cannot get legacy ACL for a bucket that has uniform bucket-level access.
// Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access, invalid
if gerr.Code == 400 && strings.HasPrefix(gerr.Message, "Cannot get legacy ACL for a bucket that has uniform bucket-level access") {
return nil, nil
}
return nil, err
}
return resp, nil
}
func getBucketAka(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
bucket := h.Item.(*storage.Bucket)
projectData, err := activeProject(ctx, d)
if err != nil {
return nil, err
}
project := projectData.Project
akas := []string{"gcp://storage.googleapis.com/projects/" + project + "/buckets/" + bucket.Name}
return akas, nil
}