From edc4134283187577327cd7e00efd67e06b7db8f2 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 30 Jun 2022 23:19:51 +0530 Subject: [PATCH 01/18] docs(samples): init add deny samples and tests --- samples/snippets/deny_policies.py | 122 +++++++++++++++++++++++++ samples/snippets/test_deny_policies.py | 50 ++++++++++ 2 files changed, 172 insertions(+) create mode 100644 samples/snippets/deny_policies.py create mode 100644 samples/snippets/test_deny_policies.py diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py new file mode 100644 index 0000000..0431a30 --- /dev/null +++ b/samples/snippets/deny_policies.py @@ -0,0 +1,122 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from google.type import expr_pb2 + +from google.cloud import iam_v2beta + + +def create_deny_policy(project_id: str, policy_name: str): + policies_client = iam_v2beta.PoliciesClient() + + expr = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'test')" + ) + + deny_rule = iam_v2beta.DenyRule() + deny_rule.denied_principals = ["principalSet://goog/public:all"] + deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] + deny_rule.denial_condition = expr + + policy_rule = iam_v2beta.PolicyRule() + policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" + policy_rule.deny_rule = deny_rule + + policy = iam_v2beta.Policy() + policy.name = policy_name + policy.display_name = "Restrict xyz access for a member abc" + policy.rules = [policy_rule] + + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = iam_v2beta.CreatePolicyRequest() + request.parent = f"policies/{attachment_point}/denypolicies" + request.policy = policy + request.policy_id = f"deny-{uuid.uuid4()}" + + response = policies_client.create_policy(request=request) + print(f"Created the deny policy: {response.result()}") + + +def list_deny_policy(project_id: str): + policies_client = iam_v2beta.PoliciesClient() + + request = iam_v2beta.ListPoliciesRequest() + + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + request.parent = f"policies/{attachment_point}/denypolicies" + + policies = policies_client.list_policies(request=request) + + for policy in policies: + print(policy) + print("Listed all deny policies") + + +def get_deny_policy(project_id: str, policy_name: str): + policies_client = iam_v2beta.PoliciesClient() + + request = iam_v2beta.GetPolicyRequest() + + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_name}" + + policy = policies_client.get_policy(request=request) + print(f"Retrieved the deny policy: {policy}") + + +def update_deny_policy(project_id: str, policy_name: str): + policies_client = iam_v2beta.PoliciesClient() + + expr = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'prod')" + ) + + deny_rule = iam_v2beta.DenyRule() + deny_rule.denied_principals = ["principalSet://goog/public:all"] + deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] + deny_rule.denial_condition = expr + + policy_rule = iam_v2beta.PolicyRule() + policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" + policy_rule.deny_rule = deny_rule + + policy = iam_v2beta.Policy() + policy.name = policy_name + policy.display_name = "Restrict xyz access for a member abc" + policy.rules = policy_rule + + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = iam_v2beta.UpdatePolicyRequest() + request.parent = f"policies/{attachment_point}/denypolicies" + request.policy = policy + + response = policies_client.update_policy(request=request) + print(f"Updated the deny policy : {response}") + + +def delete_deny_policy(project_id: str, policy_name: str): + policies_client = iam_v2beta.PoliciesClient() + + request = iam_v2beta.DeletePolicyRequest() + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_name}" + + operation = policies_client.delete_policy(request=request) + print(f"Deleted the deny policy: {operation}") diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py new file mode 100644 index 0000000..d0d0ecd --- /dev/null +++ b/samples/snippets/test_deny_policies.py @@ -0,0 +1,50 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re + +import pytest +from _pytest.capture import CaptureFixture + +from samples.snippets.deny_policies import create_deny_policy, delete_deny_policy, get_deny_policy, list_deny_policy, \ + update_deny_policy + +PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] +GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] + + +@pytest.fixture +def deny_policy(): + policy_name = "limit-project-deletion" + + create_deny_policy(PROJECT_ID, policy_name) + + yield policy_name + + delete_deny_policy(PROJECT_ID, policy_name) + + +def test_retrieve_and_update_policy(capsys: CaptureFixture, deny_policy): + get_deny_policy(PROJECT_ID, deny_policy) + out, _ = capsys.readouterr() + assert re.search("Retrieved the deny policy", out) + + list_deny_policy(PROJECT_ID) + out, _ = capsys.readouterr() + assert re.search("Listed all deny policies", out) + + update_deny_policy(PROJECT_ID, deny_policy) + out, _ = capsys.readouterr() + assert re.search("Updated the deny policy", out) From a21d50ead3caa82f75107042d8b171fdf716d23c Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 30 Jun 2022 23:27:07 +0530 Subject: [PATCH 02/18] docs(samples): added requirements.txt --- samples/snippets/requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 samples/snippets/requirements.txt diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt new file mode 100644 index 0000000..654da51 --- /dev/null +++ b/samples/snippets/requirements.txt @@ -0,0 +1 @@ +google-cloud-iam==2.7.0 \ No newline at end of file From 7170f3bf74f4a858da89a44f2ff3f9b963c27c34 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Fri, 1 Jul 2022 17:27:56 +0530 Subject: [PATCH 03/18] docs(samples): minor update and refactoring --- samples/snippets/deny_policies.py | 86 +++++++++++++++----------- samples/snippets/test_deny_policies.py | 29 ++++++--- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index 0431a30..f1c9fb0 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -17,45 +17,46 @@ from google.type import expr_pb2 from google.cloud import iam_v2beta +from google.cloud.iam_v2beta import types, Policy -def create_deny_policy(project_id: str, policy_name: str): +def create_deny_policy(project_id: str, policy_id: str) -> None: policies_client = iam_v2beta.PoliciesClient() expr = expr_pb2.Expr( expression="!resource.matchTag('12345678/env', 'test')" ) - deny_rule = iam_v2beta.DenyRule() + deny_rule = types.DenyRule() deny_rule.denied_principals = ["principalSet://goog/public:all"] - deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] deny_rule.denial_condition = expr - policy_rule = iam_v2beta.PolicyRule() + policy_rule = types.PolicyRule() policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" policy_rule.deny_rule = deny_rule - policy = iam_v2beta.Policy() - policy.name = policy_name + policy = types.Policy() + policy.name = "Restrict access to test env project deletion" policy.display_name = "Restrict xyz access for a member abc" policy.rules = [policy_rule] attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - request = iam_v2beta.CreatePolicyRequest() + request = types.CreatePolicyRequest() request.parent = f"policies/{attachment_point}/denypolicies" request.policy = policy - request.policy_id = f"deny-{uuid.uuid4()}" + request.policy_id = policy_id - response = policies_client.create_policy(request=request) - print(f"Created the deny policy: {response.result()}") + policies_client.create_policy(request=request) + print(f"Created the deny policy: {policy_id}") -def list_deny_policy(project_id: str): +def list_deny_policy(project_id: str) -> None: policies_client = iam_v2beta.PoliciesClient() - request = iam_v2beta.ListPoliciesRequest() + request = types.ListPoliciesRequest() attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request.parent = f"policies/{attachment_point}/denypolicies" @@ -63,60 +64,75 @@ def list_deny_policy(project_id: str): policies = policies_client.list_policies(request=request) for policy in policies: - print(policy) + print(policy.name) print("Listed all deny policies") -def get_deny_policy(project_id: str, policy_name: str): +def get_deny_policy(project_id: str, policy_id: str) -> Policy: policies_client = iam_v2beta.PoliciesClient() - request = iam_v2beta.GetPolicyRequest() + request = types.GetPolicyRequest() attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - request.name = f"policies/{attachment_point}/denypolicies/{policy_name}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" policy = policies_client.get_policy(request=request) - print(f"Retrieved the deny policy: {policy}") + print(f"Retrieved the deny policy: {policy_id} : {policy}") + return policy -def update_deny_policy(project_id: str, policy_name: str): +def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: policies_client = iam_v2beta.PoliciesClient() expr = expr_pb2.Expr( expression="!resource.matchTag('12345678/env', 'prod')" ) - deny_rule = iam_v2beta.DenyRule() + deny_rule = types.DenyRule() deny_rule.denied_principals = ["principalSet://goog/public:all"] - deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] deny_rule.denial_condition = expr - policy_rule = iam_v2beta.PolicyRule() + policy_rule = types.PolicyRule() policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" policy_rule.deny_rule = deny_rule - policy = iam_v2beta.Policy() - policy.name = policy_name - policy.display_name = "Restrict xyz access for a member abc" - policy.rules = policy_rule - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - request = iam_v2beta.UpdatePolicyRequest() - request.parent = f"policies/{attachment_point}/denypolicies" + policy = types.Policy() + policy.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + policy.display_name = "Restrict xyz access for a member abc" + policy.rules = [policy_rule] + policy.etag = etag + + request = types.UpdatePolicyRequest() request.policy = policy - response = policies_client.update_policy(request=request) - print(f"Updated the deny policy : {response}") + policies_client.update_policy(request=request) + print(f"Updated the deny policy: {policy_id}") -def delete_deny_policy(project_id: str, policy_name: str): +def delete_deny_policy(project_id: str, policy_id: str) -> None: policies_client = iam_v2beta.PoliciesClient() - request = iam_v2beta.DeletePolicyRequest() + request = types.DeletePolicyRequest() attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - request.name = f"policies/{attachment_point}/denypolicies/{policy_name}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + + policies_client.delete_policy(request=request) + print(f"Deleted the deny policy: {policy_id}") + + +if __name__ == "__main__": + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" - operation = policies_client.delete_policy(request=request) - print(f"Deleted the deny policy: {operation}") + # Test the policy lifecycle. + create_deny_policy(project_id, policy_id) + list_deny_policy(project_id) + policy = get_deny_policy(project_id, policy_id) + update_deny_policy(project_id, policy_id, policy.etag) + delete_deny_policy(project_id, policy_id) diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index d0d0ecd..23a5625 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -14,6 +14,7 @@ import os import re +import uuid import pytest from _pytest.capture import CaptureFixture @@ -26,25 +27,33 @@ @pytest.fixture -def deny_policy(): - policy_name = "limit-project-deletion" +def deny_policy(capsys: CaptureFixture) -> None: + policy_id = f"limit-project-deletion-{uuid.uuid4()}" - create_deny_policy(PROJECT_ID, policy_name) + # Create the Deny policy. + create_deny_policy(PROJECT_ID, policy_id) - yield policy_name + yield policy_id - delete_deny_policy(PROJECT_ID, policy_name) + # Delete the Deny policy and assert if deleted. + delete_deny_policy(PROJECT_ID, policy_id) + out, _ = capsys.readouterr() + assert re.search(f"Deleted the deny policy: {policy_id}", out) -def test_retrieve_and_update_policy(capsys: CaptureFixture, deny_policy): - get_deny_policy(PROJECT_ID, deny_policy) +def test_retrieve_list_and_update_policy(capsys: CaptureFixture, deny_policy) -> None: + # Test policy retrieval, given the policy id. + policy = get_deny_policy(PROJECT_ID, deny_policy) out, _ = capsys.readouterr() - assert re.search("Retrieved the deny policy", out) + assert re.search(f"Retrieved the deny policy: {deny_policy}", out) + # Check if the created policy is listed. list_deny_policy(PROJECT_ID) out, _ = capsys.readouterr() + assert re.search(deny_policy, out) assert re.search("Listed all deny policies", out) - update_deny_policy(PROJECT_ID, deny_policy) + # Check if the policy rule is updated. + update_deny_policy(PROJECT_ID, deny_policy, policy.etag) out, _ = capsys.readouterr() - assert re.search("Updated the deny policy", out) + assert re.search(f"Updated the deny policy: {deny_policy}", out) From a40c6fef6eaf7361f439f8ecf26443a4267af8c7 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Fri, 1 Jul 2022 17:35:29 +0530 Subject: [PATCH 04/18] added nox files --- samples/snippets/noxfile.py | 310 +++++++++++++++++++++++++++++ samples/snippets/noxfile_config.py | 38 ++++ 2 files changed, 348 insertions(+) create mode 100644 samples/snippets/noxfile.py create mode 100644 samples/snippets/noxfile_config.py diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py new file mode 100644 index 0000000..eae93af --- /dev/null +++ b/samples/snippets/noxfile.py @@ -0,0 +1,310 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import glob +import os +from pathlib import Path +import sys +from typing import Callable, Dict, List, Optional + +import nox + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" + +# Copy `noxfile_config.py` to your directory and modify it instead. + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + "ignored_versions": [], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append(".") + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars() -> Dict[str, str]: + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG["gcloud_project_env"] + # This should error out if not set. + ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG["envs"]) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to test samples. +ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( + "True", + "true", +) + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + +# +# Style Checks +# + + +def _determine_local_import_names(start_dir: str) -> List[str]: + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session: nox.sessions.Session) -> None: + if not TEST_CONFIG["enforce_type_hints"]: + session.install("flake8", "flake8-import-order") + else: + session.install("flake8", "flake8-import-order", "flake8-annotations") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + ".", + ] + session.run("flake8", *args) + + +# +# Black +# + + +@nox.session +def blacken(session: nox.sessions.Session) -> None: + """Run black. Format code to uniform standard.""" + session.install(BLACK_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + session.run("black", *python_files) + + +# +# format = isort + black +# + + +@nox.session +def format(session: nox.sessions.Session) -> None: + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("isort", "--fss", *python_files) + session.run("black", *python_files) + + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests( + session: nox.sessions.Session, post_install: Callable = None +) -> None: + # check for presence of tests + test_list = glob.glob("*_test.py") + glob.glob("test_*.py") + test_list.extend(glob.glob("tests")) + + if len(test_list) == 0: + print("No tests found, skipping directory.") + return + + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + concurrent_args = [] + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + with open("requirements.txt") as rfile: + packages = rfile.read() + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") + else: + session.install("-r", "requirements-test.txt") + with open("requirements-test.txt") as rtfile: + packages += rtfile.read() + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + if "pytest-parallel" in packages: + concurrent_args.extend(["--workers", "auto", "--tests-per-worker", "auto"]) + elif "pytest-xdist" in packages: + concurrent_args.extend(["-n", "auto"]) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs + concurrent_args), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session: nox.sessions.Session) -> None: + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip( + "SKIPPED: {} tests are disabled for this sample.".format(session.python) + ) + + +# +# Readmegen +# + + +def _get_repo_root() -> Optional[str]: + """Returns the root folder of the project.""" + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + # .git is not available in repos cloned via Cloud Build + # setup.py is always in the library's root, so use that instead + # https://github.com/googleapis/synthtool/issues/792 + if Path(p / "setup.py").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session: nox.sessions.Session, path: str) -> None: + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) \ No newline at end of file diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py new file mode 100644 index 0000000..5b3cb3d --- /dev/null +++ b/samples/snippets/noxfile_config.py @@ -0,0 +1,38 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be inported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7"], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + # "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "gcloud_project_env": "BUILD_SPECIFIC_GCLOUD_PROJECT", + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} \ No newline at end of file From ded132e6a5ae915cf9b78c151d2453e6c7e34ccf Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Wed, 6 Jul 2022 12:04:28 +0530 Subject: [PATCH 05/18] added comments and minor refactoring --- samples/snippets/deny_policies.py | 202 ++++++++++++++++++++++--- samples/snippets/noxfile.py | 2 +- samples/snippets/noxfile_config.py | 2 +- samples/snippets/test_deny_policies.py | 2 +- 4 files changed, 180 insertions(+), 28 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index f1c9fb0..cd1187e 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -14,53 +14,121 @@ import uuid -from google.type import expr_pb2 - from google.cloud import iam_v2beta -from google.cloud.iam_v2beta import types, Policy +from google.cloud.iam_v2beta import Policy, types + +from google.type import expr_pb2 def create_deny_policy(project_id: str, policy_id: str) -> None: + """ + Create a deny policy. + You can add deny policies to organizations, folders, and projects. + Each of these resources can have up to 5 deny policies. + + Deny policies contain deny rules, which specify the following: + 1. The permissions to deny and/or exempt. + 2. The principals that are denied/exempted from those permissions. + 3. An optional condition on when to enforce the deny rules. + + Params: + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the id of the Deny policy you want to create. + """ policies_client = iam_v2beta.PoliciesClient() - expr = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'test')" - ) + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" deny_rule = types.DenyRule() + # Add one or more principals who should be denied the permissions specified in this rule. + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers#v2 deny_rule.denied_principals = ["principalSet://goog/public:all"] + + # Optionally, set the principals who should be exempted from the list of principals + # added in "DeniedPrincipals". Example, if you want to deny certain permissions + # to a group but exempt few principals, then add those here. # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + + # Set the permissions to deny. + # The permission value is of the format: service_fqdn/resource.action + # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] - deny_rule.denial_condition = expr + # Optionally, add the permissions to be exempted from this rule. + # Meaning, the deny rule will not be applicable to these permissions. + # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.create"] + + # Set the condition which will enforce the deny rule. + # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. + # The expression uses Common Expression Language syntax (CEL). + # Here we block access based on tags. + # + # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. + # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. + # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged test. + deny_rule.denial_condition = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'test')" + ) + + # Add the policy rule and a description for it. policy_rule = types.PolicyRule() policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" policy_rule.deny_rule = deny_rule policy = types.Policy() - policy.name = "Restrict access to test env project deletion" - policy.display_name = "Restrict xyz access for a member abc" + policy.display_name = "Restrict project deletion access" policy.rules = [policy_rule] - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - + # Set the policy resource path, policy rules and a unique id for the policy. request = types.CreatePolicyRequest() + # Construct the full path of the resource to which the policy is attached to. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.parent = f"policies/{attachment_point}/denypolicies" request.policy = policy request.policy_id = policy_id + # Build the create policy request. policies_client.create_policy(request=request) print(f"Created the deny policy: {policy_id}") def list_deny_policy(project_id: str) -> None: - policies_client = iam_v2beta.PoliciesClient() + """ + List all the deny policies that are attached to a resource. + A resource can have up to 5 deny policies. - request = types.ListPoliciesRequest() + project_id: ID or number of the Google Cloud project you want to use. + """ + policies_client = iam_v2beta.PoliciesClient() + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.ListPoliciesRequest() + # Construct the full path of the resource to which the policy is attached to. + # Its format is: "policies/{attachmentPoint}/denypolicies" request.parent = f"policies/{attachment_point}/denypolicies" + # Create a list request and iterate over the returned policies. policies = policies_client.list_policies(request=request) for policy in policies: @@ -69,43 +137,107 @@ def list_deny_policy(project_id: str) -> None: def get_deny_policy(project_id: str, policy_id: str) -> Policy: - policies_client = iam_v2beta.PoliciesClient() + """ + Retrieve the deny policy given the project id and policy id. - request = types.GetPolicyRequest() + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the id of the deny policy you want to retrieve. + """ + policies_client = iam_v2beta.PoliciesClient() + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.GetPolicyRequest() + # Construct the full path of the resource to which the policy is attached to. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + # Specify the policyParent and execute the GetPolicy request. policy = policies_client.get_policy(request=request) print(f"Retrieved the deny policy: {policy_id} : {policy}") return policy def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: + """ + Update the deny rules and/ or its display name after policy creation. + + project_id: ID or number of the Google Cloud project you want to use. + + policy_id: Specify the id of the Deny policy you want to retrieve. + + etag: Etag field that identifies the policy version. The etag changes each time + you update the policy. Get the etag of an existing policy by performing a GetPolicy request. + """ policies_client = iam_v2beta.PoliciesClient() - expr = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'prod')" - ) + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" deny_rule = types.DenyRule() + + # Add one or more principals who should be denied the permissions specified in this rule. + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers#v2 deny_rule.denied_principals = ["principalSet://goog/public:all"] + + # Optionally, set the principals who should be exempted from the list of principals added in "DeniedPrincipals". + # Example, if you want to deny certain permissions to a group but exempt few principals, then add those here. # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + + # Set the permissions to deny. + # The permission value is of the format: service_fqdn/resource.action + # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] - deny_rule.denial_condition = expr + # Add the permissions to be exempted from this rule. + # Meaning, the deny rule will not be applicable to these permissions. + # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.get"] + + # Set the condition which will enforce the deny rule. + # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. + # + # The expression uses Common Expression Language syntax (CEL). Here we block access based on tags. + # + # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. + # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. + # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged prod. + deny_rule.denial_condition = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'prod')" + ) + + # Set the rule description and deny rule to update. policy_rule = types.PolicyRule() - policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" + policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value prod" policy_rule.deny_rule = deny_rule - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - + # Set the policy resource path, version (etag) and the updated policy rules. policy = types.Policy() + # Construct the full path of the resource to which the policy is attached to. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" policy.name = f"policies/{attachment_point}/denypolicies/{policy_id}" - policy.display_name = "Restrict xyz access for a member abc" - policy.rules = [policy_rule] policy.etag = etag + policy.rules = [policy_rule] + # Create the update policy request. request = types.UpdatePolicyRequest() request.policy = policy @@ -114,12 +246,32 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: def delete_deny_policy(project_id: str, policy_id: str) -> None: + """ + Delete the policy if you no longer want to enforce the rules in a deny policy. + + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the id of the deny policy you want to retrieve. + """ policies_client = iam_v2beta.PoliciesClient() - request = types.DeletePolicyRequest() + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.DeletePolicyRequest() + # Construct the full path of the resource to which the policy is attached to. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + # Create the DeletePolicy request. policies_client.delete_policy(request=request) print(f"Deleted the deny policy: {policy_id}") diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index eae93af..146b05b 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -307,4 +307,4 @@ def readmegen(session: nox.sessions.Session, path: str) -> None: in_file = os.path.join(dir_, "README.rst.in") session.run( "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file - ) \ No newline at end of file + ) diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py index 5b3cb3d..d3504fc 100644 --- a/samples/snippets/noxfile_config.py +++ b/samples/snippets/noxfile_config.py @@ -35,4 +35,4 @@ # A dictionary you want to inject into your test. Don't put any # secrets here. These values will override predefined values. "envs": {}, -} \ No newline at end of file +} diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index 23a5625..854a2bb 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -16,8 +16,8 @@ import re import uuid -import pytest from _pytest.capture import CaptureFixture +import pytest from samples.snippets.deny_policies import create_deny_policy, delete_deny_policy, get_deny_policy, list_deny_policy, \ update_deny_policy From 2ef557f9b6594098789fe68e024dbff8af8c10af Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 6 Jul 2022 06:36:34 +0000 Subject: [PATCH 06/18] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- samples/snippets/deny_policies.py | 33 ++++++++++++++------------ samples/snippets/noxfile.py | 2 +- samples/snippets/test_deny_policies.py | 10 +++++--- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index cd1187e..099fb71 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -16,24 +16,23 @@ from google.cloud import iam_v2beta from google.cloud.iam_v2beta import Policy, types - from google.type import expr_pb2 def create_deny_policy(project_id: str, policy_id: str) -> None: """ - Create a deny policy. - You can add deny policies to organizations, folders, and projects. - Each of these resources can have up to 5 deny policies. - - Deny policies contain deny rules, which specify the following: - 1. The permissions to deny and/or exempt. - 2. The principals that are denied/exempted from those permissions. - 3. An optional condition on when to enforce the deny rules. - - Params: - project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the Deny policy you want to create. + Create a deny policy. + You can add deny policies to organizations, folders, and projects. + Each of these resources can have up to 5 deny policies. + + Deny policies contain deny rules, which specify the following: + 1. The permissions to deny and/or exempt. + 2. The principals that are denied/exempted from those permissions. + 3. An optional condition on when to enforce the deny rules. + + Params: + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the id of the Deny policy you want to create. """ policies_client = iam_v2beta.PoliciesClient() @@ -62,7 +61,9 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # Set the permissions to deny. # The permission value is of the format: service_fqdn/resource.action # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support - deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] + deny_rule.denied_permissions = [ + "cloudresourcemanager.googleapis.com/projects.delete" + ] # Optionally, add the permissions to be exempted from this rule. # Meaning, the deny rule will not be applicable to these permissions. @@ -206,7 +207,9 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: # Set the permissions to deny. # The permission value is of the format: service_fqdn/resource.action # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support - deny_rule.denied_permissions = ["cloudresourcemanager.googleapis.com/projects.delete"] + deny_rule.denied_permissions = [ + "cloudresourcemanager.googleapis.com/projects.delete" + ] # Add the permissions to be exempted from this rule. # Meaning, the deny rule will not be applicable to these permissions. diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 146b05b..3b3ffa5 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index 854a2bb..f0cb9cb 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -18,9 +18,13 @@ from _pytest.capture import CaptureFixture import pytest - -from samples.snippets.deny_policies import create_deny_policy, delete_deny_policy, get_deny_policy, list_deny_policy, \ - update_deny_policy +from samples.snippets.deny_policies import ( + create_deny_policy, + delete_deny_policy, + get_deny_policy, + list_deny_policy, + update_deny_policy, +) PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] From 1f500b86d6012c2a2edf4bfbde7e513bc39e745e Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Wed, 6 Jul 2022 13:33:52 +0530 Subject: [PATCH 07/18] added region tags --- samples/snippets/deny_policies.py | 39 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index cd1187e..79a2993 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -12,15 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import uuid - -from google.cloud import iam_v2beta -from google.cloud.iam_v2beta import Policy, types - -from google.type import expr_pb2 - - +# [START iam_create_deny_policy] def create_deny_policy(project_id: str, policy_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import Policy, types + + from google.type import expr_pb2 """ Create a deny policy. You can add deny policies to organizations, folders, and projects. @@ -100,9 +97,14 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # Build the create policy request. policies_client.create_policy(request=request) print(f"Created the deny policy: {policy_id}") +# [END iam_create_deny_policy] +# [START iam_list_deny_policy] def list_deny_policy(project_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + """ List all the deny policies that are attached to a resource. A resource can have up to 5 deny policies. @@ -134,9 +136,14 @@ def list_deny_policy(project_id: str) -> None: for policy in policies: print(policy.name) print("Listed all deny policies") +# [END iam_list_deny_policy] + +# [START iam_get_deny_policy] +def get_deny_policy(project_id: str, policy_id: str): + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import Policy, types -def get_deny_policy(project_id: str, policy_id: str) -> Policy: """ Retrieve the deny policy given the project id and policy id. @@ -166,9 +173,15 @@ def get_deny_policy(project_id: str, policy_id: str) -> Policy: policy = policies_client.get_policy(request=request) print(f"Retrieved the deny policy: {policy_id} : {policy}") return policy +# [END iam_get_deny_policy] +# [START iam_update_deny_policy] def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + + from google.type import expr_pb2 """ Update the deny rules and/ or its display name after policy creation. @@ -243,9 +256,14 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: policies_client.update_policy(request=request) print(f"Updated the deny policy: {policy_id}") +# [START iam_update_deny_policy] +# [START iam_delete_deny_policy] def delete_deny_policy(project_id: str, policy_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + """ Delete the policy if you no longer want to enforce the rules in a deny policy. @@ -274,9 +292,12 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: # Create the DeletePolicy request. policies_client.delete_policy(request=request) print(f"Deleted the deny policy: {policy_id}") +# [START iam_delete_deny_policy] if __name__ == "__main__": + import uuid + # Your Google Cloud project id. project_id = "your-google-cloud-project-id" # Any unique id (0 to 63 chars) starting with a lowercase alphabet. From f3c058db7f9f3c728c05591ad629773aa4af263c Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 6 Jul 2022 08:11:18 +0000 Subject: [PATCH 08/18] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- samples/snippets/deny_policies.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index 996e7aa..1bb43bb 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -16,8 +16,8 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: from google.cloud import iam_v2beta from google.cloud.iam_v2beta import Policy, types - from google.type import expr_pb2 + """ Create a deny policy. You can add deny policies to organizations, folders, and projects. @@ -99,6 +99,8 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # Build the create policy request. policies_client.create_policy(request=request) print(f"Created the deny policy: {policy_id}") + + # [END iam_create_deny_policy] @@ -138,6 +140,8 @@ def list_deny_policy(project_id: str) -> None: for policy in policies: print(policy.name) print("Listed all deny policies") + + # [END iam_list_deny_policy] @@ -175,6 +179,8 @@ def get_deny_policy(project_id: str, policy_id: str): policy = policies_client.get_policy(request=request) print(f"Retrieved the deny policy: {policy_id} : {policy}") return policy + + # [END iam_get_deny_policy] @@ -182,8 +188,8 @@ def get_deny_policy(project_id: str, policy_id: str): def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: from google.cloud import iam_v2beta from google.cloud.iam_v2beta import types - from google.type import expr_pb2 + """ Update the deny rules and/ or its display name after policy creation. @@ -260,6 +266,8 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: policies_client.update_policy(request=request) print(f"Updated the deny policy: {policy_id}") + + # [START iam_update_deny_policy] @@ -296,6 +304,8 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: # Create the DeletePolicy request. policies_client.delete_policy(request=request) print(f"Deleted the deny policy: {policy_id}") + + # [START iam_delete_deny_policy] From 91fa3cbc0888537faf6bb33d5c8dec9a638a0ad9 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Wed, 6 Jul 2022 13:49:43 +0530 Subject: [PATCH 09/18] added region tags --- samples/snippets/deny_policies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index 1bb43bb..9884437 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -268,7 +268,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: print(f"Updated the deny policy: {policy_id}") -# [START iam_update_deny_policy] +# [END iam_update_deny_policy] # [START iam_delete_deny_policy] @@ -306,7 +306,7 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: print(f"Deleted the deny policy: {policy_id}") -# [START iam_delete_deny_policy] +# [END iam_delete_deny_policy] if __name__ == "__main__": From 2d61e8242009a906b530f99c5ead43aea40e2e07 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 7 Jul 2022 21:46:47 +0530 Subject: [PATCH 10/18] modified comments acc to review --- samples/snippets/deny_policies.py | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index 9884437..f5f219d 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -25,7 +25,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: Deny policies contain deny rules, which specify the following: 1. The permissions to deny and/or exempt. - 2. The principals that are denied/exempted from those permissions. + 2. The principals that are denied, or exempted from denial. 3. An optional condition on when to enforce the deny rules. Params: @@ -42,23 +42,23 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID # - # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # The attachment point is identified by its URL-encoded resource name. Hence, replace # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" deny_rule = types.DenyRule() # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers#v2 + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers deny_rule.denied_principals = ["principalSet://goog/public:all"] - # Optionally, set the principals who should be exempted from the list of principals - # added in "DeniedPrincipals". Example, if you want to deny certain permissions - # to a group but exempt few principals, then add those here. + # Optionally, set the principals who should be exempted from the + # list of denied principals. For example, if you want to deny certain permissions + # to a group but exempt a few principals, then add those here. # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] # Set the permissions to deny. # The permission value is of the format: service_fqdn/resource.action - # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support + # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions deny_rule.denied_permissions = [ "cloudresourcemanager.googleapis.com/projects.delete" ] @@ -79,7 +79,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: expression="!resource.matchTag('12345678/env', 'test')" ) - # Add the policy rule and a description for it. + # Add the deny rule and a description for it. policy_rule = types.PolicyRule() policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" policy_rule.deny_rule = deny_rule @@ -88,9 +88,9 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: policy.display_name = "Restrict project deletion access" policy.rules = [policy_rule] - # Set the policy resource path, policy rules and a unique id for the policy. + # Set the policy resource path, policy rules and a unique ID for the policy. request = types.CreatePolicyRequest() - # Construct the full path of the resource to which the policy is attached to. + # Construct the full path of the resource to which the policy is attached. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.parent = f"policies/{attachment_point}/denypolicies" request.policy = policy @@ -125,12 +125,12 @@ def list_deny_policy(project_id: str) -> None: # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID # - # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # The attachment point is identified by its URL-encoded resource name. Hence, replace # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.ListPoliciesRequest() - # Construct the full path of the resource to which the policy is attached to. + # Construct the full path of the resource to which the policy is attached. # Its format is: "policies/{attachmentPoint}/denypolicies" request.parent = f"policies/{attachment_point}/denypolicies" @@ -151,10 +151,10 @@ def get_deny_policy(project_id: str, policy_id: str): from google.cloud.iam_v2beta import Policy, types """ - Retrieve the deny policy given the project id and policy id. + Retrieve the deny policy given the project ID and policy ID. project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the deny policy you want to retrieve. + policy_id: Specify the ID of the deny policy you want to retrieve. """ policies_client = iam_v2beta.PoliciesClient() @@ -166,12 +166,12 @@ def get_deny_policy(project_id: str, policy_id: str): # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID # - # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # The attachment point is identified by its URL-encoded resource name. Hence, replace # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.GetPolicyRequest() - # Construct the full path of the resource to which the policy is attached to. + # Construct the full path of the resource to which the policy is attached. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" @@ -195,7 +195,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the Deny policy you want to retrieve. + policy_id: Specify the ID of the Deny policy you want to retrieve. etag: Etag field that identifies the policy version. The etag changes each time you update the policy. Get the etag of an existing policy by performing a GetPolicy request. @@ -210,23 +210,23 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID # - # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # The attachment point is identified by its URL-encoded resource name. Hence, replace # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" deny_rule = types.DenyRule() # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers#v2 + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers deny_rule.denied_principals = ["principalSet://goog/public:all"] # Optionally, set the principals who should be exempted from the list of principals added in "DeniedPrincipals". - # Example, if you want to deny certain permissions to a group but exempt few principals, then add those here. + # Example, if you want to deny certain permissions to a group but exempt a few principals, then add those here. # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] # Set the permissions to deny. # The permission value is of the format: service_fqdn/resource.action - # For the list of supported permissions, see: https://cloud.google.com/iam/docs/deny-permissions-support + # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions deny_rule.denied_permissions = [ "cloudresourcemanager.googleapis.com/projects.delete" ] @@ -252,7 +252,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value prod" policy_rule.deny_rule = deny_rule - # Set the policy resource path, version (etag) and the updated policy rules. + # Set the policy resource path, version (etag) and the updated deny rules. policy = types.Policy() # Construct the full path of the resource to which the policy is attached to. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" @@ -280,7 +280,7 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: Delete the policy if you no longer want to enforce the rules in a deny policy. project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the deny policy you want to retrieve. + policy_id: Specify the ID of the deny policy you want to retrieve. """ policies_client = iam_v2beta.PoliciesClient() @@ -292,12 +292,12 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID # - # The attachment point is identified by its URL-encoded full resource name. Hence, replace + # The attachment point is identified by its URL-encoded resource name. Hence, replace # the "/" with "%2F". attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.DeletePolicyRequest() - # Construct the full path of the resource to which the policy is attached to. + # Construct the full path of the resource to which the policy is attached. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" From fe7805aaf1922a596deae10319da45c753a2f852 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Tue, 12 Jul 2022 12:04:30 +0530 Subject: [PATCH 11/18] modified comments acc to review --- samples/snippets/deny_policies.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py index f5f219d..661f99e 100644 --- a/samples/snippets/deny_policies.py +++ b/samples/snippets/deny_policies.py @@ -90,7 +90,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # Set the policy resource path, policy rules and a unique ID for the policy. request = types.CreatePolicyRequest() - # Construct the full path of the resource to which the policy is attached. + # Construct the full path of the policy. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.parent = f"policies/{attachment_point}/denypolicies" request.policy = policy @@ -171,11 +171,11 @@ def get_deny_policy(project_id: str, policy_id: str): attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.GetPolicyRequest() - # Construct the full path of the resource to which the policy is attached. + # Construct the full path of the policy. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" - # Specify the policyParent and execute the GetPolicy request. + # Execute the GetPolicy request. policy = policies_client.get_policy(request=request) print(f"Retrieved the deny policy: {policy_id} : {policy}") return policy @@ -195,7 +195,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the Deny policy you want to retrieve. + policy_id: Specify the ID of the deny policy you want to retrieve. etag: Etag field that identifies the policy version. The etag changes each time you update the policy. Get the etag of an existing policy by performing a GetPolicy request. @@ -254,7 +254,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: # Set the policy resource path, version (etag) and the updated deny rules. policy = types.Policy() - # Construct the full path of the resource to which the policy is attached to. + # Construct the full path of the policy. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" policy.name = f"policies/{attachment_point}/denypolicies/{policy_id}" policy.etag = etag @@ -297,7 +297,7 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.DeletePolicyRequest() - # Construct the full path of the resource to which the policy is attached. + # Construct the full path of the policy. # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" From 4714da271f608e4463c07b915fdd3ae10f6bddb6 Mon Sep 17 00:00:00 2001 From: Sita Lakshmi Sangameswaran Date: Tue, 12 Jul 2022 15:01:32 +0530 Subject: [PATCH 12/18] updated env var --- samples/snippets/test_deny_policies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index f0cb9cb..0b5ab46 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -26,7 +26,7 @@ update_deny_policy, ) -PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] +PROJECT_ID = os.environ["PROJECT_ID"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] From 83743d805985214cdc762d51860496815eb9def1 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 13 Jul 2022 15:49:09 +0000 Subject: [PATCH 13/18] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- samples/snippets/noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 3b3ffa5..e9eb1cb 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -88,7 +88,7 @@ def get_pytest_env_vars() -> Dict[str, str]: # DO NOT EDIT - automatically generated. # All versions used to test samples. -ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] +ALL_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] # Any default versions that should be ignored. IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] From 0b1bdf677bf79d06b85e8648c1c45a2aca3bfbb2 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 14 Jul 2022 23:03:22 +0530 Subject: [PATCH 14/18] modified acc to review comments --- samples/snippets/conftest.py | 41 ++++ samples/snippets/create_deny_policy.py | 118 +++++++++ samples/snippets/delete_deny_policy.py | 62 +++++ samples/snippets/deny_policies.py | 325 ------------------------- samples/snippets/get_deny_policy.py | 63 +++++ samples/snippets/list_deny_policies.py | 65 +++++ samples/snippets/noxfile.py | 2 +- samples/snippets/noxfile_config.py | 2 +- samples/snippets/test_deny_policies.py | 37 +-- samples/snippets/update_deny_policy.py | 113 +++++++++ 10 files changed, 475 insertions(+), 353 deletions(-) create mode 100644 samples/snippets/conftest.py create mode 100644 samples/snippets/create_deny_policy.py create mode 100644 samples/snippets/delete_deny_policy.py delete mode 100644 samples/snippets/deny_policies.py create mode 100644 samples/snippets/get_deny_policy.py create mode 100644 samples/snippets/list_deny_policies.py create mode 100644 samples/snippets/update_deny_policy.py diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py new file mode 100644 index 0000000..5f9209b --- /dev/null +++ b/samples/snippets/conftest.py @@ -0,0 +1,41 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import uuid + +from _pytest.capture import CaptureFixture +import pytest + +from samples.snippets.create_deny_policy import create_deny_policy +from samples.snippets.delete_deny_policy import delete_deny_policy + +PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] +GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] + + +@pytest.fixture +def deny_policy(capsys: CaptureFixture) -> None: + policy_id = f"limit-project-deletion-{uuid.uuid4()}" + + # Create the Deny policy. + create_deny_policy(PROJECT_ID, policy_id) + + yield policy_id + + # Delete the Deny policy and assert if deleted. + delete_deny_policy(PROJECT_ID, policy_id) + out, _ = capsys.readouterr() + assert re.search(f"Deleted the deny policy: {policy_id}", out) diff --git a/samples/snippets/create_deny_policy.py b/samples/snippets/create_deny_policy.py new file mode 100644 index 0000000..5d69a1a --- /dev/null +++ b/samples/snippets/create_deny_policy.py @@ -0,0 +1,118 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. + +# [START iam_create_deny_policy] + +def create_deny_policy(project_id: str, policy_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + from google.type import expr_pb2 + + """ + Create a deny policy. + You can add deny policies to organizations, folders, and projects. + Each of these resources can have up to 5 deny policies. + + Deny policies contain deny rules, which specify the following: + 1. The permissions to deny and/or exempt. + 2. The principals that are denied, or exempted from denial. + 3. An optional condition on when to enforce the deny rules. + + Params: + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the id of the Deny policy you want to create. + """ + policies_client = iam_v2beta.PoliciesClient() + + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + deny_rule = types.DenyRule() + # Add one or more principals who should be denied the permissions specified in this rule. + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers + deny_rule.denied_principals = ["principalSet://goog/public:all"] + + # Optionally, set the principals who should be exempted from the + # list of denied principals. For example, if you want to deny certain permissions + # to a group but exempt a few principals, then add those here. + # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + + # Set the permissions to deny. + # The permission value is of the format: service_fqdn/resource.action + # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions + deny_rule.denied_permissions = [ + "cloudresourcemanager.googleapis.com/projects.delete" + ] + + # Optionally, add the permissions to be exempted from this rule. + # Meaning, the deny rule will not be applicable to these permissions. + # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.create"] + + # Set the condition which will enforce the deny rule. + # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. + # The expression uses Common Expression Language syntax (CEL). + # Here we block access based on tags. + # + # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. + # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. + # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged test. + deny_rule.denial_condition = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'test')" + ) + + # Add the deny rule and a description for it. + policy_rule = types.PolicyRule() + policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" + policy_rule.deny_rule = deny_rule + + policy = types.Policy() + policy.display_name = "Restrict project deletion access" + policy.rules = [policy_rule] + + # Set the policy resource path, policy rules and a unique ID for the policy. + request = types.CreatePolicyRequest() + # Construct the full path of the policy. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" + request.parent = f"policies/{attachment_point}/denypolicies" + request.policy = policy + request.policy_id = policy_id + + # Build the create policy request. + policies_client.create_policy(request=request) + print(f"Created the deny policy: {policy_id}") + + +if __name__ == "__main__": + import uuid + + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" + + # Test the policy lifecycle. + create_deny_policy(project_id, policy_id) + +# [END iam_create_deny_policy] diff --git a/samples/snippets/delete_deny_policy.py b/samples/snippets/delete_deny_policy.py new file mode 100644 index 0000000..7f1ca8d --- /dev/null +++ b/samples/snippets/delete_deny_policy.py @@ -0,0 +1,62 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. + +# [START iam_delete_deny_policy] +def delete_deny_policy(project_id: str, policy_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + + """ + Delete the policy if you no longer want to enforce the rules in a deny policy. + + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the ID of the deny policy you want to retrieve. + """ + policies_client = iam_v2beta.PoliciesClient() + + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.DeletePolicyRequest() + # Construct the full path of the policy. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + + # Create the DeletePolicy request. + policies_client.delete_policy(request=request) + print(f"Deleted the deny policy: {policy_id}") + + +if __name__ == "__main__": + import uuid + + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" + + delete_deny_policy(project_id, policy_id) + +# [END iam_delete_deny_policy] diff --git a/samples/snippets/deny_policies.py b/samples/snippets/deny_policies.py deleted file mode 100644 index 661f99e..0000000 --- a/samples/snippets/deny_policies.py +++ /dev/null @@ -1,325 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# [START iam_create_deny_policy] -def create_deny_policy(project_id: str, policy_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import Policy, types - from google.type import expr_pb2 - - """ - Create a deny policy. - You can add deny policies to organizations, folders, and projects. - Each of these resources can have up to 5 deny policies. - - Deny policies contain deny rules, which specify the following: - 1. The permissions to deny and/or exempt. - 2. The principals that are denied, or exempted from denial. - 3. An optional condition on when to enforce the deny rules. - - Params: - project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the Deny policy you want to create. - """ - policies_client = iam_v2beta.PoliciesClient() - - # Each deny policy is attached to an organization, folder, or project. - # To work with deny policies, specify the attachment point. - # - # Its format can be one of the following: - # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID - # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID - # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID - # - # The attachment point is identified by its URL-encoded resource name. Hence, replace - # the "/" with "%2F". - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - - deny_rule = types.DenyRule() - # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers - deny_rule.denied_principals = ["principalSet://goog/public:all"] - - # Optionally, set the principals who should be exempted from the - # list of denied principals. For example, if you want to deny certain permissions - # to a group but exempt a few principals, then add those here. - # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] - - # Set the permissions to deny. - # The permission value is of the format: service_fqdn/resource.action - # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions - deny_rule.denied_permissions = [ - "cloudresourcemanager.googleapis.com/projects.delete" - ] - - # Optionally, add the permissions to be exempted from this rule. - # Meaning, the deny rule will not be applicable to these permissions. - # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.create"] - - # Set the condition which will enforce the deny rule. - # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. - # The expression uses Common Expression Language syntax (CEL). - # Here we block access based on tags. - # - # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. - # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. - # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged test. - deny_rule.denial_condition = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'test')" - ) - - # Add the deny rule and a description for it. - policy_rule = types.PolicyRule() - policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value test" - policy_rule.deny_rule = deny_rule - - policy = types.Policy() - policy.display_name = "Restrict project deletion access" - policy.rules = [policy_rule] - - # Set the policy resource path, policy rules and a unique ID for the policy. - request = types.CreatePolicyRequest() - # Construct the full path of the policy. - # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" - request.parent = f"policies/{attachment_point}/denypolicies" - request.policy = policy - request.policy_id = policy_id - - # Build the create policy request. - policies_client.create_policy(request=request) - print(f"Created the deny policy: {policy_id}") - - -# [END iam_create_deny_policy] - - -# [START iam_list_deny_policy] -def list_deny_policy(project_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types - - """ - List all the deny policies that are attached to a resource. - A resource can have up to 5 deny policies. - - project_id: ID or number of the Google Cloud project you want to use. - """ - policies_client = iam_v2beta.PoliciesClient() - - # Each deny policy is attached to an organization, folder, or project. - # To work with deny policies, specify the attachment point. - # - # Its format can be one of the following: - # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID - # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID - # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID - # - # The attachment point is identified by its URL-encoded resource name. Hence, replace - # the "/" with "%2F". - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - - request = types.ListPoliciesRequest() - # Construct the full path of the resource to which the policy is attached. - # Its format is: "policies/{attachmentPoint}/denypolicies" - request.parent = f"policies/{attachment_point}/denypolicies" - - # Create a list request and iterate over the returned policies. - policies = policies_client.list_policies(request=request) - - for policy in policies: - print(policy.name) - print("Listed all deny policies") - - -# [END iam_list_deny_policy] - - -# [START iam_get_deny_policy] -def get_deny_policy(project_id: str, policy_id: str): - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import Policy, types - - """ - Retrieve the deny policy given the project ID and policy ID. - - project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the deny policy you want to retrieve. - """ - policies_client = iam_v2beta.PoliciesClient() - - # Each deny policy is attached to an organization, folder, or project. - # To work with deny policies, specify the attachment point. - # - # Its format can be one of the following: - # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID - # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID - # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID - # - # The attachment point is identified by its URL-encoded resource name. Hence, replace - # the "/" with "%2F". - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - - request = types.GetPolicyRequest() - # Construct the full path of the policy. - # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" - request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" - - # Execute the GetPolicy request. - policy = policies_client.get_policy(request=request) - print(f"Retrieved the deny policy: {policy_id} : {policy}") - return policy - - -# [END iam_get_deny_policy] - - -# [START iam_update_deny_policy] -def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types - from google.type import expr_pb2 - - """ - Update the deny rules and/ or its display name after policy creation. - - project_id: ID or number of the Google Cloud project you want to use. - - policy_id: Specify the ID of the deny policy you want to retrieve. - - etag: Etag field that identifies the policy version. The etag changes each time - you update the policy. Get the etag of an existing policy by performing a GetPolicy request. - """ - policies_client = iam_v2beta.PoliciesClient() - - # Each deny policy is attached to an organization, folder, or project. - # To work with deny policies, specify the attachment point. - # - # Its format can be one of the following: - # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID - # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID - # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID - # - # The attachment point is identified by its URL-encoded resource name. Hence, replace - # the "/" with "%2F". - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - - deny_rule = types.DenyRule() - - # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers - deny_rule.denied_principals = ["principalSet://goog/public:all"] - - # Optionally, set the principals who should be exempted from the list of principals added in "DeniedPrincipals". - # Example, if you want to deny certain permissions to a group but exempt a few principals, then add those here. - # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] - - # Set the permissions to deny. - # The permission value is of the format: service_fqdn/resource.action - # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions - deny_rule.denied_permissions = [ - "cloudresourcemanager.googleapis.com/projects.delete" - ] - - # Add the permissions to be exempted from this rule. - # Meaning, the deny rule will not be applicable to these permissions. - # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.get"] - - # Set the condition which will enforce the deny rule. - # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. - # - # The expression uses Common Expression Language syntax (CEL). Here we block access based on tags. - # - # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. - # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. - # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged prod. - deny_rule.denial_condition = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'prod')" - ) - - # Set the rule description and deny rule to update. - policy_rule = types.PolicyRule() - policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value prod" - policy_rule.deny_rule = deny_rule - - # Set the policy resource path, version (etag) and the updated deny rules. - policy = types.Policy() - # Construct the full path of the policy. - # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" - policy.name = f"policies/{attachment_point}/denypolicies/{policy_id}" - policy.etag = etag - policy.rules = [policy_rule] - - # Create the update policy request. - request = types.UpdatePolicyRequest() - request.policy = policy - - policies_client.update_policy(request=request) - print(f"Updated the deny policy: {policy_id}") - - -# [END iam_update_deny_policy] - - -# [START iam_delete_deny_policy] -def delete_deny_policy(project_id: str, policy_id: str) -> None: - from google.cloud import iam_v2beta - from google.cloud.iam_v2beta import types - - """ - Delete the policy if you no longer want to enforce the rules in a deny policy. - - project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the deny policy you want to retrieve. - """ - policies_client = iam_v2beta.PoliciesClient() - - # Each deny policy is attached to an organization, folder, or project. - # To work with deny policies, specify the attachment point. - # - # Its format can be one of the following: - # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID - # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID - # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID - # - # The attachment point is identified by its URL-encoded resource name. Hence, replace - # the "/" with "%2F". - attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" - - request = types.DeletePolicyRequest() - # Construct the full path of the policy. - # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" - request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" - - # Create the DeletePolicy request. - policies_client.delete_policy(request=request) - print(f"Deleted the deny policy: {policy_id}") - - -# [END iam_delete_deny_policy] - - -if __name__ == "__main__": - import uuid - - # Your Google Cloud project id. - project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. - policy_id = f"deny-{uuid.uuid4()}" - - # Test the policy lifecycle. - create_deny_policy(project_id, policy_id) - list_deny_policy(project_id) - policy = get_deny_policy(project_id, policy_id) - update_deny_policy(project_id, policy_id, policy.etag) - delete_deny_policy(project_id, policy_id) diff --git a/samples/snippets/get_deny_policy.py b/samples/snippets/get_deny_policy.py new file mode 100644 index 0000000..abf6bb5 --- /dev/null +++ b/samples/snippets/get_deny_policy.py @@ -0,0 +1,63 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. + +# [START iam_get_deny_policy] +def get_deny_policy(project_id: str, policy_id: str): + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import Policy, types + + """ + Retrieve the deny policy given the project ID and policy ID. + + project_id: ID or number of the Google Cloud project you want to use. + policy_id: Specify the ID of the deny policy you want to retrieve. + """ + policies_client = iam_v2beta.PoliciesClient() + + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.GetPolicyRequest() + # Construct the full path of the policy. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" + request.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + + # Execute the GetPolicy request. + policy = policies_client.get_policy(request=request) + print(f"Retrieved the deny policy: {policy_id} : {policy}") + return policy + + +if __name__ == "__main__": + import uuid + + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" + + policy = get_deny_policy(project_id, policy_id) + +# [END iam_get_deny_policy] diff --git a/samples/snippets/list_deny_policies.py b/samples/snippets/list_deny_policies.py new file mode 100644 index 0000000..f83299a --- /dev/null +++ b/samples/snippets/list_deny_policies.py @@ -0,0 +1,65 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. + +# [START iam_list_deny_policy] +def list_deny_policy(project_id: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + + """ + List all the deny policies that are attached to a resource. + A resource can have up to 5 deny policies. + + project_id: ID or number of the Google Cloud project you want to use. + """ + policies_client = iam_v2beta.PoliciesClient() + + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + request = types.ListPoliciesRequest() + # Construct the full path of the resource to which the policy is attached. + # Its format is: "policies/{attachmentPoint}/denypolicies" + request.parent = f"policies/{attachment_point}/denypolicies" + + # Create a list request and iterate over the returned policies. + policies = policies_client.list_policies(request=request) + + for policy in policies: + print(policy.name) + print("Listed all deny policies") + + +if __name__ == "__main__": + import uuid + + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" + + list_deny_policy(project_id) + +# [END iam_list_deny_policy] diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index 3b3ffa5..146b05b 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -1,4 +1,4 @@ -# Copyright 2019 Google LLC +# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py index d3504fc..4fdb52d 100644 --- a/samples/snippets/noxfile_config.py +++ b/samples/snippets/noxfile_config.py @@ -25,7 +25,7 @@ "ignored_versions": ["2.7"], # Old samples are opted out of enforcing Python type hints # All new samples should feature them - "enforce_type_hints": False, + "enforce_type_hints": True, # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index f0cb9cb..7186ead 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -14,50 +14,35 @@ import os import re -import uuid from _pytest.capture import CaptureFixture -import pytest -from samples.snippets.deny_policies import ( - create_deny_policy, - delete_deny_policy, - get_deny_policy, - list_deny_policy, - update_deny_policy, -) + +from samples.snippets.get_deny_policy import get_deny_policy +from samples.snippets.list_deny_policies import list_deny_policy +from samples.snippets.update_deny_policy import update_deny_policy PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] -@pytest.fixture -def deny_policy(capsys: CaptureFixture) -> None: - policy_id = f"limit-project-deletion-{uuid.uuid4()}" - - # Create the Deny policy. - create_deny_policy(PROJECT_ID, policy_id) - - yield policy_id - - # Delete the Deny policy and assert if deleted. - delete_deny_policy(PROJECT_ID, policy_id) - out, _ = capsys.readouterr() - assert re.search(f"Deleted the deny policy: {policy_id}", out) - - -def test_retrieve_list_and_update_policy(capsys: CaptureFixture, deny_policy) -> None: +def test_retrieve_policy(capsys: CaptureFixture, deny_policy) -> None: # Test policy retrieval, given the policy id. - policy = get_deny_policy(PROJECT_ID, deny_policy) + get_deny_policy(PROJECT_ID, deny_policy) out, _ = capsys.readouterr() assert re.search(f"Retrieved the deny policy: {deny_policy}", out) + +def test_list_policies(capsys: CaptureFixture, deny_policy) -> None: # Check if the created policy is listed. list_deny_policy(PROJECT_ID) out, _ = capsys.readouterr() assert re.search(deny_policy, out) assert re.search("Listed all deny policies", out) + +def test_update_deny_policy(capsys: CaptureFixture, deny_policy) -> None: # Check if the policy rule is updated. + policy = get_deny_policy(PROJECT_ID, deny_policy) update_deny_policy(PROJECT_ID, deny_policy, policy.etag) out, _ = capsys.readouterr() assert re.search(f"Updated the deny policy: {deny_policy}", out) diff --git a/samples/snippets/update_deny_policy.py b/samples/snippets/update_deny_policy.py new file mode 100644 index 0000000..f3fbeb1 --- /dev/null +++ b/samples/snippets/update_deny_policy.py @@ -0,0 +1,113 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. + +# [START iam_update_deny_policy] +def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: + from google.cloud import iam_v2beta + from google.cloud.iam_v2beta import types + from google.type import expr_pb2 + + """ + Update the deny rules and/ or its display name after policy creation. + + project_id: ID or number of the Google Cloud project you want to use. + + policy_id: Specify the ID of the deny policy you want to retrieve. + + etag: Etag field that identifies the policy version. The etag changes each time + you update the policy. Get the etag of an existing policy by performing a GetPolicy request. + """ + policies_client = iam_v2beta.PoliciesClient() + + # Each deny policy is attached to an organization, folder, or project. + # To work with deny policies, specify the attachment point. + # + # Its format can be one of the following: + # 1. cloudresourcemanager.googleapis.com/organizations/ORG_ID + # 2. cloudresourcemanager.googleapis.com/folders/FOLDER_ID + # 3. cloudresourcemanager.googleapis.com/projects/PROJECT_ID + # + # The attachment point is identified by its URL-encoded resource name. Hence, replace + # the "/" with "%2F". + attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" + + deny_rule = types.DenyRule() + + # Add one or more principals who should be denied the permissions specified in this rule. + # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers + deny_rule.denied_principals = ["principalSet://goog/public:all"] + + # Optionally, set the principals who should be exempted from the list of principals added in "DeniedPrincipals". + # Example, if you want to deny certain permissions to a group but exempt a few principals, then add those here. + # deny_rule.exception_principals = ["principalSet://goog/group/project-admins@example.com"] + + # Set the permissions to deny. + # The permission value is of the format: service_fqdn/resource.action + # For the list of supported permissions, see: https://cloud.google.com/iam/help/deny/supported-permissions + deny_rule.denied_permissions = [ + "cloudresourcemanager.googleapis.com/projects.delete" + ] + + # Add the permissions to be exempted from this rule. + # Meaning, the deny rule will not be applicable to these permissions. + # deny_rule.exception_permissions = ["cloudresourcemanager.googleapis.com/projects.get"] + + # Set the condition which will enforce the deny rule. + # If this condition is true, the deny rule will be applicable. Else, the rule will not be enforced. + # + # The expression uses Common Expression Language syntax (CEL). Here we block access based on tags. + # + # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. + # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. + # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged prod. + deny_rule.denial_condition = expr_pb2.Expr( + expression="!resource.matchTag('12345678/env', 'prod')" + ) + + # Set the rule description and deny rule to update. + policy_rule = types.PolicyRule() + policy_rule.description = "block all principals from deleting projects, unless the principal is a member of project-admins@example.com and the project being deleted has a tag with the value prod" + policy_rule.deny_rule = deny_rule + + # Set the policy resource path, version (etag) and the updated deny rules. + policy = types.Policy() + # Construct the full path of the policy. + # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" + policy.name = f"policies/{attachment_point}/denypolicies/{policy_id}" + policy.etag = etag + policy.rules = [policy_rule] + + # Create the update policy request. + request = types.UpdatePolicyRequest() + request.policy = policy + + policies_client.update_policy(request=request) + print(f"Updated the deny policy: {policy_id}") + + +if __name__ == "__main__": + import uuid + + # Your Google Cloud project id. + project_id = "your-google-cloud-project-id" + # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + policy_id = f"deny-{uuid.uuid4()}" + # Get the etag by performing a Get policy request. + etag = "etag" + + update_deny_policy(project_id, policy_id, etag) + +# [END iam_update_deny_policy] From b58b1b449deff01247f1df5ad1740f7300a673ad Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 14 Jul 2022 17:36:18 +0000 Subject: [PATCH 15/18] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- samples/snippets/conftest.py | 1 - samples/snippets/create_deny_policy.py | 1 + samples/snippets/noxfile.py | 2 +- samples/snippets/test_deny_policies.py | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py index 5f9209b..3fb8745 100644 --- a/samples/snippets/conftest.py +++ b/samples/snippets/conftest.py @@ -18,7 +18,6 @@ from _pytest.capture import CaptureFixture import pytest - from samples.snippets.create_deny_policy import create_deny_policy from samples.snippets.delete_deny_policy import delete_deny_policy diff --git a/samples/snippets/create_deny_policy.py b/samples/snippets/create_deny_policy.py index 5d69a1a..29746c7 100644 --- a/samples/snippets/create_deny_policy.py +++ b/samples/snippets/create_deny_policy.py @@ -16,6 +16,7 @@ # [START iam_create_deny_policy] + def create_deny_policy(project_id: str, policy_id: str) -> None: from google.cloud import iam_v2beta from google.cloud.iam_v2beta import types diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py index f21323f..e9eb1cb 100644 --- a/samples/snippets/noxfile.py +++ b/samples/snippets/noxfile.py @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/samples/snippets/test_deny_policies.py b/samples/snippets/test_deny_policies.py index ff35c55..3a5bb57 100644 --- a/samples/snippets/test_deny_policies.py +++ b/samples/snippets/test_deny_policies.py @@ -16,7 +16,6 @@ import re from _pytest.capture import CaptureFixture - from samples.snippets.get_deny_policy import get_deny_policy from samples.snippets.list_deny_policies import list_deny_policy from samples.snippets.update_deny_policy import update_deny_policy From f707ae1decd3a2bd129313ad291a7ba552f5461c Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 14 Jul 2022 23:12:52 +0530 Subject: [PATCH 16/18] modified acc to review comments --- samples/snippets/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py index 5f9209b..eae2ac1 100644 --- a/samples/snippets/conftest.py +++ b/samples/snippets/conftest.py @@ -19,8 +19,8 @@ from _pytest.capture import CaptureFixture import pytest -from samples.snippets.create_deny_policy import create_deny_policy -from samples.snippets.delete_deny_policy import delete_deny_policy +import create_deny_policy +import delete_deny_policy PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] From 69a06be46f7a595d1447228cf9022146203a0c69 Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Thu, 14 Jul 2022 23:39:16 +0530 Subject: [PATCH 17/18] added init.py --- samples/snippets/__init__.py | 0 samples/snippets/conftest.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 samples/snippets/__init__.py diff --git a/samples/snippets/__init__.py b/samples/snippets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py index eae2ac1..8dd0625 100644 --- a/samples/snippets/conftest.py +++ b/samples/snippets/conftest.py @@ -19,8 +19,8 @@ from _pytest.capture import CaptureFixture import pytest -import create_deny_policy -import delete_deny_policy +from create_deny_policy import create_deny_policy +from delete_deny_policy import delete_deny_policy PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] GOOGLE_APPLICATION_CREDENTIALS = os.environ["GOOGLE_APPLICATION_CREDENTIALS"] From 79f4ac36bdae7a94514e5878c7d43b0404617bec Mon Sep 17 00:00:00 2001 From: SitaLakshmi Date: Fri, 15 Jul 2022 11:37:51 +0530 Subject: [PATCH 18/18] updated acc to review comments --- samples/snippets/create_deny_policy.py | 26 +++++++++++++------------- samples/snippets/delete_deny_policy.py | 8 ++++---- samples/snippets/get_deny_policy.py | 8 ++++---- samples/snippets/list_deny_policies.py | 8 ++++---- samples/snippets/update_deny_policy.py | 22 +++++++++++----------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/samples/snippets/create_deny_policy.py b/samples/snippets/create_deny_policy.py index 29746c7..1cc5e5b 100644 --- a/samples/snippets/create_deny_policy.py +++ b/samples/snippets/create_deny_policy.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. +# This file contains code samples that demonstrate how to create IAM deny policies. # [START iam_create_deny_policy] @@ -34,7 +34,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: Params: project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the id of the Deny policy you want to create. + policy_id: Specify the ID of the deny policy you want to create. """ policies_client = iam_v2beta.PoliciesClient() @@ -52,7 +52,7 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: deny_rule = types.DenyRule() # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers + # For more information on allowed values, see: https://cloud.google.com/iam/help/deny/principal-identifiers deny_rule.denied_principals = ["principalSet://goog/public:all"] # Optionally, set the principals who should be exempted from the @@ -76,12 +76,12 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # The expression uses Common Expression Language syntax (CEL). # Here we block access based on tags. # - # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. - # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. - # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged test. - deny_rule.denial_condition = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'test')" - ) + # Here, we create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged test. + # A tag is a key-value pair that can be attached to an organization, folder, or project. + # For more info, see: https://cloud.google.com/iam/docs/deny-access#create-deny-policy + deny_rule.denial_condition = { + "expression": "!resource.matchTag('12345678/env', 'test')" + } # Add the deny rule and a description for it. policy_rule = types.PolicyRule() @@ -94,8 +94,8 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: # Set the policy resource path, policy rules and a unique ID for the policy. request = types.CreatePolicyRequest() - # Construct the full path of the policy. - # Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}" + # Construct the full path of the resource's deny policies. + # Its format is: "policies/{attachmentPoint}/denypolicies" request.parent = f"policies/{attachment_point}/denypolicies" request.policy = policy request.policy_id = policy_id @@ -108,9 +108,9 @@ def create_deny_policy(project_id: str, policy_id: str) -> None: if __name__ == "__main__": import uuid - # Your Google Cloud project id. + # Your Google Cloud project ID. project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + # Any unique ID (0 to 63 chars) starting with a lowercase letter. policy_id = f"deny-{uuid.uuid4()}" # Test the policy lifecycle. diff --git a/samples/snippets/delete_deny_policy.py b/samples/snippets/delete_deny_policy.py index 7f1ca8d..769d8d2 100644 --- a/samples/snippets/delete_deny_policy.py +++ b/samples/snippets/delete_deny_policy.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. +# This file contains code samples that demonstrate how to delete IAM deny policies. # [START iam_delete_deny_policy] def delete_deny_policy(project_id: str, policy_id: str) -> None: @@ -23,7 +23,7 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: Delete the policy if you no longer want to enforce the rules in a deny policy. project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the deny policy you want to retrieve. + policy_id: The ID of the deny policy you want to retrieve. """ policies_client = iam_v2beta.PoliciesClient() @@ -52,9 +52,9 @@ def delete_deny_policy(project_id: str, policy_id: str) -> None: if __name__ == "__main__": import uuid - # Your Google Cloud project id. + # Your Google Cloud project ID. project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + # Any unique ID (0 to 63 chars) starting with a lowercase letter. policy_id = f"deny-{uuid.uuid4()}" delete_deny_policy(project_id, policy_id) diff --git a/samples/snippets/get_deny_policy.py b/samples/snippets/get_deny_policy.py index abf6bb5..05183cf 100644 --- a/samples/snippets/get_deny_policy.py +++ b/samples/snippets/get_deny_policy.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. +# This file contains code samples that demonstrate how to get IAM deny policies. # [START iam_get_deny_policy] def get_deny_policy(project_id: str, policy_id: str): @@ -23,7 +23,7 @@ def get_deny_policy(project_id: str, policy_id: str): Retrieve the deny policy given the project ID and policy ID. project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the deny policy you want to retrieve. + policy_id: The ID of the deny policy you want to retrieve. """ policies_client = iam_v2beta.PoliciesClient() @@ -53,9 +53,9 @@ def get_deny_policy(project_id: str, policy_id: str): if __name__ == "__main__": import uuid - # Your Google Cloud project id. + # Your Google Cloud project ID. project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + # Any unique ID (0 to 63 chars) starting with a lowercase letter. policy_id = f"deny-{uuid.uuid4()}" policy = get_deny_policy(project_id, policy_id) diff --git a/samples/snippets/list_deny_policies.py b/samples/snippets/list_deny_policies.py index f83299a..c83eac9 100644 --- a/samples/snippets/list_deny_policies.py +++ b/samples/snippets/list_deny_policies.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. +# This file contains code samples that demonstrate how to list IAM deny policies. # [START iam_list_deny_policy] def list_deny_policy(project_id: str) -> None: @@ -40,7 +40,7 @@ def list_deny_policy(project_id: str) -> None: attachment_point = f"cloudresourcemanager.googleapis.com%2Fprojects%2F{project_id}" request = types.ListPoliciesRequest() - # Construct the full path of the resource to which the policy is attached. + # Construct the full path of the resource's deny policies. # Its format is: "policies/{attachmentPoint}/denypolicies" request.parent = f"policies/{attachment_point}/denypolicies" @@ -55,9 +55,9 @@ def list_deny_policy(project_id: str) -> None: if __name__ == "__main__": import uuid - # Your Google Cloud project id. + # Your Google Cloud project ID. project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + # Any unique ID (0 to 63 chars) starting with a lowercase letter. policy_id = f"deny-{uuid.uuid4()}" list_deny_policy(project_id) diff --git a/samples/snippets/update_deny_policy.py b/samples/snippets/update_deny_policy.py index f3fbeb1..d3b8477 100644 --- a/samples/snippets/update_deny_policy.py +++ b/samples/snippets/update_deny_policy.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file contains code samples that demonstrate how to work with IAM client library's Deny feature. +# This file contains code samples that demonstrate how to update IAM deny policies. # [START iam_update_deny_policy] def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: @@ -25,7 +25,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: project_id: ID or number of the Google Cloud project you want to use. - policy_id: Specify the ID of the deny policy you want to retrieve. + policy_id: The ID of the deny policy you want to retrieve. etag: Etag field that identifies the policy version. The etag changes each time you update the policy. Get the etag of an existing policy by performing a GetPolicy request. @@ -47,7 +47,7 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: deny_rule = types.DenyRule() # Add one or more principals who should be denied the permissions specified in this rule. - # For more information on allowed values, see: https://cloud.google.com/iam/docs/principal-identifiers + # For more information on allowed values, see: https://cloud.google.com/iam/help/deny/principal-identifiers deny_rule.denied_principals = ["principalSet://goog/public:all"] # Optionally, set the principals who should be exempted from the list of principals added in "DeniedPrincipals". @@ -70,12 +70,12 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: # # The expression uses Common Expression Language syntax (CEL). Here we block access based on tags. # - # A tag is a key-value pair that can be attached to an organization, folder, or project. You can use deny policies to deny permissions based on tags without adding an IAM Condition to every role grant. - # For example, imagine that you tag all of your projects as dev, test, or prod. You want only members of project-admins@example.com to be able to perform operations on projects that are tagged prod. - # To solve this problem, you create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged prod. - deny_rule.denial_condition = expr_pb2.Expr( - expression="!resource.matchTag('12345678/env', 'prod')" - ) + # Here, we create a deny rule that denies the cloudresourcemanager.googleapis.com/projects.delete permission to everyone except project-admins@example.com for resources that are tagged prod. + # A tag is a key-value pair that can be attached to an organization, folder, or project. + # For more info, see: https://cloud.google.com/iam/docs/deny-access#create-deny-policy + deny_rule.denial_condition = { + "expression": "!resource.matchTag('12345678/env', 'prod')" + } # Set the rule description and deny rule to update. policy_rule = types.PolicyRule() @@ -101,9 +101,9 @@ def update_deny_policy(project_id: str, policy_id: str, etag: str) -> None: if __name__ == "__main__": import uuid - # Your Google Cloud project id. + # Your Google Cloud project ID. project_id = "your-google-cloud-project-id" - # Any unique id (0 to 63 chars) starting with a lowercase alphabet. + # Any unique ID (0 to 63 chars) starting with a lowercase letter. policy_id = f"deny-{uuid.uuid4()}" # Get the etag by performing a Get policy request. etag = "etag"