Skip to content

Commit fc41131

Browse files
authored
Add Uniform Bucket-Level Access Support for GCS Buckets (#41)
1 parent 5e2ca80 commit fc41131

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

gcs/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The GCS client requires a JSON configuration file.
1818
"json_key": "<string> (required if credentials_source = 'static')",
1919
"storage_class": "<string> (optional - default: 'STANDARD', check for more options=https://docs.cloud.google.com/storage/docs/storage-classes)",
2020
"encryption_key": "<string> (optional)",
21+
"uniform_bucket_level_access": "<boolean> (optional)"
2122
}
2223
```
2324

@@ -26,6 +27,12 @@ The GCS client requires a JSON configuration file.
2627
* **"none":** specifies that credentials are explicitly empty and that the client should be restricted to a read-only scope.
2728
* **"static:"** specifies that a service account file included in json_key should be used for authentication.
2829

30+
### Bucket Creation
31+
The `ensure-storage-exists` command creates a bucket if it does not already exist. The `uniform_bucket_level_access` configuration option controls the access control model:
32+
* **`true`**: Creates a bucket with uniform bucket-level access (IAM-only, ACLs disabled)
33+
* **`false` or omitted (default)**: Creates a bucket with fine-grained access control (ACLs enabled)
34+
35+
2936
### Authentication Methods (`credentials_source`)
3037
* `static`: A [service account](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) key will be provided via the `json_key` field.
3138
* `none`: No credentials are provided. The client is reading from a public bucket.

gcs/client/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,10 @@ func (client *GCSBlobstore) EnsureStorageExists() error {
433433
battr.StorageClass = client.config.StorageClass
434434
}
435435

436+
if client.config.UniformBucketLevelAccess {
437+
battr.UniformBucketLevelAccess = storage.UniformBucketLevelAccess{Enabled: true}
438+
}
439+
436440
projectID, err := extractProjectID(ctx, client.config)
437441
if err != nil {
438442
return fmt.Errorf("extracting project ID: %w", err)

gcs/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ type GCSCli struct {
3939
// StorageClass is the type of storage used for objects added to the bucket
4040
// https://cloud.google.com/storage/docs/storage-classes
4141
StorageClass string `json:"storage_class"`
42+
// UniformBucketLevelAccess enables uniform bucket-level access control.
43+
// When true, disables ACLs and uses only IAM for permissions.
44+
// When false (default), buckets use fine-grained ACL-based access control.
45+
// https://cloud.google.com/storage/docs/uniform-bucket-level-access
46+
UniformBucketLevelAccess bool `json:"uniform_bucket_level_access"`
4247
// EncryptionKey is a Customer-Supplied encryption key used to
4348
// encrypt objects added to the bucket.
4449
// If left empty, no explicit encryption key will be used;

gcs/config/config_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,27 @@ var _ = Describe("BlobstoreClient configuration", func() {
146146
})
147147
})
148148

149+
Describe("when uniform_bucket_level_access is set to true", func() {
150+
dummyJSONBytes := []byte(`{"bucket_name": "some-bucket", "uniform_bucket_level_access":true}`)
151+
dummyJSONReader := bytes.NewReader(dummyJSONBytes)
152+
153+
It("it has value true", func() {
154+
c, err := NewFromReader(dummyJSONReader)
155+
Expect(err).To(BeNil())
156+
Expect(c.UniformBucketLevelAccess).To(BeTrue())
157+
158+
})
159+
})
160+
161+
Describe("when uniform_bucket_level_access is not set", func() {
162+
dummyJSONBytes := []byte(`{"bucket_name": "some-bucket"}`)
163+
dummyJSONReader := bytes.NewReader(dummyJSONBytes)
164+
165+
It("it has value false", func() {
166+
c, err := NewFromReader(dummyJSONReader)
167+
Expect(err).To(BeNil())
168+
Expect(c.UniformBucketLevelAccess).To(BeFalse())
169+
})
170+
})
171+
149172
})

0 commit comments

Comments
 (0)