Skip to content

Commit 7c1e968

Browse files
authored
feat: add remove conditional binding sample (#3107)
* feat: add remove conditional binding sample * fix iam test fixture * fix silly mistake of removing all bindings * fix ubla test * address feedback * revert changes to tests
1 parent 1037f47 commit 7c1e968

File tree

2 files changed

+98
-10
lines changed

2 files changed

+98
-10
lines changed

storage/cloud-client/iam_test.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,27 @@
2222
import storage_add_bucket_iam_member
2323
import storage_add_bucket_conditional_iam_binding
2424
import storage_view_bucket_iam_members
25+
import storage_remove_bucket_conditional_iam_binding
2526

2627
MEMBER = "group:[email protected]"
2728
ROLE = "roles/storage.legacyBucketReader"
2829

2930
CONDITION_TITLE = "match-prefix"
3031
CONDITION_DESCRIPTION = "Applies to objects matching a prefix"
31-
CONDITION_EXPRESSION = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
32+
CONDITION_EXPRESSION = (
33+
'resource.name.startsWith("projects/_/buckets/bucket-name/objects/prefix-a-")'
34+
)
3235

3336

3437
@pytest.fixture
3538
def bucket():
3639
bucket = None
3740
while bucket is None or bucket.exists():
41+
storage_client = storage.Client()
3842
bucket_name = "test-iam-{}".format(uuid.uuid4())
39-
bucket = storage.Client().bucket(bucket_name)
40-
bucket.create()
41-
bucket.iam_configuration.uniform_bucket_level_access_enabled = True
42-
bucket.patch()
43+
bucket = storage_client.bucket(bucket_name)
44+
bucket.iam_configuration.uniform_bucket_level_access_enabled = True
45+
storage_client.create_bucket(bucket)
4346
yield bucket
4447
time.sleep(3)
4548
bucket.delete(force=True)
@@ -66,16 +69,17 @@ def test_add_bucket_conditional_iam_binding(bucket):
6669
CONDITION_TITLE,
6770
CONDITION_DESCRIPTION,
6871
CONDITION_EXPRESSION,
69-
{MEMBER}
72+
{MEMBER},
7073
)
7174
policy = bucket.get_iam_policy(requested_policy_version=3)
7275
assert any(
73-
binding["role"] == ROLE and
74-
binding["members"] == {MEMBER} and
75-
binding["condition"] == {
76+
binding["role"] == ROLE
77+
and binding["members"] == {MEMBER}
78+
and binding["condition"]
79+
== {
7680
"title": CONDITION_TITLE,
7781
"description": CONDITION_DESCRIPTION,
78-
"expression": CONDITION_EXPRESSION
82+
"expression": CONDITION_EXPRESSION,
7983
}
8084
for binding in policy.bindings
8185
)
@@ -89,3 +93,20 @@ def test_remove_bucket_iam_member(bucket):
8993
binding["role"] == ROLE and MEMBER in binding["members"]
9094
for binding in policy.bindings
9195
)
96+
97+
98+
def test_remove_bucket_conditional_iam_binding(bucket):
99+
storage_remove_bucket_conditional_iam_binding.remove_bucket_conditional_iam_binding(
100+
bucket.name, ROLE, CONDITION_TITLE, CONDITION_DESCRIPTION, CONDITION_EXPRESSION
101+
)
102+
103+
policy = bucket.get_iam_policy(requested_policy_version=3)
104+
condition = {
105+
"title": CONDITION_TITLE,
106+
"description": CONDITION_DESCRIPTION,
107+
"expression": CONDITION_EXPRESSION,
108+
}
109+
assert not any(
110+
(binding["role"] == ROLE and binding.get("condition") == condition)
111+
for binding in policy.bindings
112+
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2020 Google LLC. All Rights Reserved
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the 'License');
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import sys
18+
19+
# [START storage_remove_bucket_conditional_iam_binding]
20+
from google.cloud import storage
21+
22+
23+
def remove_bucket_conditional_iam_binding(
24+
bucket_name, role, title, description, expression
25+
):
26+
"""Remove a conditional IAM binding from a bucket's IAM policy."""
27+
# bucket_name = "your-bucket-name"
28+
# role = "IAM role, e.g. roles/storage.objectViewer"
29+
# title = "Condition title."
30+
# description = "Condition description."
31+
# expression = "Condition expression."
32+
33+
storage_client = storage.Client()
34+
bucket = storage_client.bucket(bucket_name)
35+
36+
policy = bucket.get_iam_policy(requested_policy_version=3)
37+
38+
# Set the policy's version to 3 to use condition in bindings.
39+
policy.version = 3
40+
41+
condition = {
42+
"title": title,
43+
"description": description,
44+
"expression": expression,
45+
}
46+
policy.bindings = [
47+
binding
48+
for binding in policy.bindings
49+
if not (binding["role"] == role and binding.get("condition") == condition)
50+
]
51+
52+
bucket.set_iam_policy(policy)
53+
54+
print("Conditional Binding was removed.")
55+
56+
57+
# [END storage_remove_bucket_conditional_iam_binding]
58+
59+
60+
if __name__ == "__main__":
61+
remove_bucket_conditional_iam_binding(
62+
bucket_name=sys.argv[1],
63+
role=sys.argv[2],
64+
title=sys.argv[3],
65+
description=sys.argv[4],
66+
expression=sys.argv[5],
67+
)

0 commit comments

Comments
 (0)