拒绝访问资源

本页面介绍了如何通过阻止主账号使用特定的 Identity and Access Management (IAM) 权限来拒绝其访问。

在 IAM 中,您可以使用拒绝政策拒绝访问。每个拒绝政策都会附加到 Google Cloud 组织、文件夹或项目。拒绝政策包含拒绝规则,用于标识主账号并列出主账号无法使用的权限。

拒绝政策与允许政策(也称为 IAM 政策)是相互独立的。允许政策通过向主账号授予 IAM 角色来提供对资源的访问权限。

您可以使用 Google Cloud 控制台、Google Cloud CLI 或 IAM v2 REST API 来管理拒绝政策。

准备工作

  • Enable the IAM API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • 设置身份验证。

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.

    gcloud

    In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

    Terraform

    如需在本地开发环境中使用本页面上的 Terraform 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭证设置应用默认凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

      If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

      If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

    如需了解详情,请参阅 Google Cloud 身份验证文档中的为本地开发环境设置 ADC

    Go

    如需在本地开发环境中使用本页面上的 Go 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭证设置应用默认凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

      If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

      If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

    Google Cloud

    Java

    如需在本地开发环境中使用本页面上的 Java 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭证设置应用默认凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

      If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

      If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

    Google Cloud

    Node.js

    如需在本地开发环境中使用本页面上的 Node.js 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭证设置应用默认凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

      If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

      If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

    Google Cloud

    Python

    如需在本地开发环境中使用本页面上的 Python 示例,请安装并初始化 gcloud CLI,然后使用您的用户凭证设置应用默认凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

      If you're using a local shell, then create local authentication credentials for your user account:

      gcloud auth application-default login

      You don't need to do this if you're using Cloud Shell.

      If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

    Google Cloud

    REST

    如需在本地开发环境中使用本页面上的 REST API 示例,请使用您提供给 gcloud CLI 的凭证。

      安装 Google Cloud CLI。

      如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI

    如需了解详情,请参阅 Google Cloud 身份验证文档中的使用 REST 时进行身份验证

  • 阅读拒绝政策概览

所需的角色

如需获得管理拒绝政策所需的权限,请让管理员向您授予组织的以下 IAM 角色:

  • Deny Reviewer (roles/iam.denyReviewer)(如需查看拒绝政策)
  • Deny Admin (roles/iam.denyAdmin)(如需查看、创建、更新和删除拒绝政策)

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

这些预定义角色包含管理拒绝政策所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

您需要具备以下权限才能管理拒绝政策:

  • 如需查看拒绝政策:
    • iam.denypolicies.get
    • iam.denypolicies.list
  • 如需创建、更新和删除拒绝政策:
    • iam.denypolicies.create
    • iam.denypolicies.delete
    • iam.denypolicies.get
    • iam.denypolicies.update

您也可以使用自定义角色或其他预定义角色来获取这些权限。

确定要拒绝的权限

在创建拒绝政策之前,您必须确定要拒绝的权限以及应该拒绝这些权限的主账号。

只能拒绝部分权限。如需查看您可以拒绝的权限列表,请参阅拒绝政策中支持的权限

在某些情况下,您还可以使用权限组来拒绝权限集。 如需了解详情,请参阅权限组

您可以使用 v2 REST API 管理拒绝政策,该 API 需要特殊格式的权限名称。例如,用于创建 IAM 自定义角色的权限如下所示:

  • v1 API:iam.roles.create
  • v2 API:iam.googleapis.com/roles.create

创建拒绝政策

您可以向组织、文件夹和项目中添加拒绝政策。每个资源最多可以有 500 个拒绝政策。

拒绝政策包含拒绝规则,用于指定以下内容:

  • 要拒绝的权限。
  • 这些权限拒绝的主账号。
  • 可选:在权限拒绝的范围中排除的主账号。

    例如,您可以拒绝针对某个群组的权限,但排除该群组中的特定用户。

  • 可选:条件表达式,用于指定主账号何时无法使用权限。在拒绝政策中,条件表达式只能使用资源标记类函数,不支持其他函数和运算符。

每个资源在其所有附加的拒绝政策中最多可以有 500 条拒绝规则。

拒绝政策通过资源层次结构进行继承。例如,如果您在组织级层拒绝某项权限,则在该组织内的文件夹和项目中以及每个项目中特定于服务的资源上也会被拒绝。

拒绝政策会替换允许政策。如果主账号被授予某个包含特定权限的角色,但拒绝政策指出主账号无法使用该权限,则主账号无法使用该权限。

控制台

  1. 在 Google Cloud 控制台中,前往 IAM 页面上的拒绝标签页。

    转到 IAM

  2. 选择一个项目、文件夹或组织。

  3. 点击 创建拒绝访问政策

  4. 政策名称部分中,通过执行以下操作之一来定义政策 ID:

    • 显示名字段中,输入政策的显示名。填写此字段会自动填写 ID 字段。如果您想更改政策的 ID,请更新 ID 字段中的文本。
    • ID 字段中,输入政策的 ID。
  5. 拒绝规则部分中,定义政策的拒绝规则。每项拒绝政策必须至少包含一条拒绝规则。如需添加其他拒绝规则,请点击添加拒绝规则

    对于每条拒绝规则,请执行以下操作:

    1. 拒绝的主账号字段中,添加您要禁止使用指定权限的一个或多个主账号。主账号可以是拒绝政策的主账号标识符中的任何主账号类型,但 ID 以 deleted: 开头的主账号除外。
    2. 可选:在例外主账号字段中,添加您希望能够使用指定权限的主账号,即使这些主账号包含在拒绝的主账号部分中也是如此。例如,您可以使用此字段来排除属于被拒群组的特定用户。

    3. 拒绝的权限部分中,添加您要拒绝的权限。这些权限必须在拒绝政策中受支持

      在某些情况下,您还可以使用权限组来拒绝权限集。如需了解详情,请参阅权限组

    4. 可选:添加例外权限。例外权限是指您不希望此拒绝规则拒绝的权限,即使这些权限包含在被拒绝权限列表中也是如此。例如,您可以使用此字段来排除权限组中的特定权限。

      如需添加例外权限,请点击例外权限,点击 添加其他权限,然后在权限 1 字段中输入权限。继续添加权限,直到添加完您要从拒绝政策中排除的所有权限。

    5. 可选:添加拒绝条件,以指定主账号何时无法使用权限。如需添加拒绝条件,请点击 添加拒绝条件,然后定义以下字段:

      • 标题:可选。条件目的的简要摘要。
      • 说明:可选。 条件的详细说明。
      • 条件表达式:您可以使用条件构建器条件编辑器添加条件表达式。条件构建器提供一个交互式界面,用于选择所需的条件类型、运算符以及有关表达式的其他适用详情。条件编辑器提供基于文本的界面,可使用通用表达式语言 (CEL) 语法手动输入表达式。

        拒绝条件必须基于资源标记。不支持其他函数和运算符。

  6. 点击创建

gcloud

如需为资源创建拒绝政策,请先创建包含政策的 JSON 文件。拒绝政策使用以下格式:

{
  "displayName": "POLICY_NAME",
  "rules": [
    {
      "denyRule": DENY_RULE_1
    },
    {
      "denyRule": DENY_RULE_2
    },
    {
      "denyRule": DENY_RULE_N
    }
  ]
}

请提供以下值:

  • POLICY_NAME:拒绝政策的显示名。
  • DENY_RULE_1DENY_RULE_2...DENY_RULE_N:政策中的拒绝规则。每个拒绝规则都可以包含以下字段:

    • deniedPermissions:指定的主账号无法使用的权限列表。这些权限必须在拒绝政策中受支持

      在某些情况下,您还可以使用权限组来拒绝权限集。如需了解详情,请参阅权限组

    • exceptionPermissions:指定的主账号可以使用的权限列表,即使这些权限包含在 deniedPermissions 中也是如此。例如,您可以使用此字段来排除一组权限中的特定权限。
    • deniedPrincipals:无法使用指定权限的主账号列表。如需了解如何设置主账号标识符的格式,请参阅拒绝政策的主账号标识符
    • exceptionPrincipals:可选。可以使用指定权限的主账号列表,即使这些主账号包含在 deniedPrincipals 中也是如此。例如,您可以使用此字段来排除属于被拒群组的特定用户。如需了解如何设置主账号标识符的格式,请参阅拒绝政策的主账号标识符

    • denialCondition:可选。条件表达式,用于指定主账号何时无法使用权限。包含以下字段:

    如需查看拒绝规则的示例,请参阅常见使用场景

例如,以下拒绝政策包含一个拒绝规则,该规则拒绝针对 Lucian 的一个权限:

{
  "displayName": "My deny policy.",
  "rules": [
    {
      "denyRule": {
        "deniedPrincipals": [
          "principal://goog/subject/lucian@example.com"
        ],
        "deniedPermissions": [
          "iam.googleapis.com/roles.create"
        ]
      }
    }
  ]
}

接下来,运行 gcloud iam policies create 命令:

gcloud iam policies create POLICY_ID \
    --attachment-point=ATTACHMENT_POINT \
    --kind=denypolicies \
    --policy-file=POLICY_FILE

请提供以下值:

  • POLICY_ID:拒绝政策的标识符。

  • ATTACHMENT_POINT:拒绝政策所关联的资源的标识符。如需了解如何设置此值的格式,请参阅连接点

  • POLICY_FILE:包含拒绝政策的 JSON 文件的文件路径。

默认情况下,如果此命令执行成功,将不会输出任何输出内容。如需输出详细响应,请在命令中添加 --format=json 标志。

例如,以下命令使用名为 policy.json 的文件为项目 my-project 创建名为 my-deny-policy 的拒绝政策:

gcloud iam policies create my-deny-policy \
    --attachment-point=cloudresourcemanager.googleapis.com/projects/my-project \
    --kind=denypolicies \
    --policy-file=policy.json

Terraform

如需了解如何应用或移除 Terraform 配置,请参阅基本 Terraform 命令。 如需了解详情,请参阅 Terraform 提供程序参考文档

data "google_project" "default" {
}

# Create a service account
resource "google_service_account" "default" {
  display_name = "IAM Deny Example - Service Account"
  account_id   = "example-sa"
  project      = data.google_project.default.project_id
}

# Create an IAM deny policy that denies a permission for the service account
resource "google_iam_deny_policy" "default" {
  provider     = google-beta
  parent       = urlencode("cloudresourcemanager.googleapis.com/projects/${data.google_project.default.project_id}")
  name         = "my-deny-policy"
  display_name = "My deny policy."
  rules {
    deny_rule {
      denied_principals  = ["principal://iam.googleapis.com/projects/-/serviceAccounts/${google_service_account.default.email}"]
      denied_permissions = ["iam.googleapis.com/roles.create"]
    }
  }
}

Go

如需了解如何安装和使用 IAM 客户端库,请参阅 IAM 客户端库。 如需了解详情,请参阅 IAM Go API 参考文档

如需向 IAM 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅准备工作

import (
	"context"
	"fmt"
	"io"

	iam "cloud.google.com/go/iam/apiv2"
	"cloud.google.com/go/iam/apiv2/iampb"

	"google.golang.org/genproto/googleapis/type/expr"
)

// createDenyPolicy creates a deny policy.
func createDenyPolicy(w io.Writer, projectID, policyID string) error {
	// 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.

	// projectID := "your_project_id"
	// policyID := "your_policy_id"

	ctx := context.Background()
	policiesClient, err := iam.NewPoliciesClient(ctx)
	if err != nil {
		return fmt.Errorf("NewPoliciesClient: %w", err)
	}
	defer policiesClient.Close()

	// 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".
	attachmentPoint := fmt.Sprintf(
		"cloudresourcemanager.googleapis.com%%2Fprojects%%2F%s",
		projectID,
	)

	denyRule := &iampb.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/help/deny/principal-identifiers
		DeniedPrincipals: []string{"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.
		// ExceptionPrincipals: []string{"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
		DeniedPermissions: []string{"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.
		// ExceptionPermissions: []string{"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.
		//
		// 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
		DenialCondition: &expr.Expr{
			Expression: "!resource.matchTag('12345678/env', 'test')",
		},
	}

	// Add the deny rule and a description for it.
	policyRule := &iampb.PolicyRule{
		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",
		Kind: &iampb.PolicyRule_DenyRule{
			DenyRule: denyRule,
		},
	}

	policy := &iampb.Policy{
		DisplayName: "Restrict project deletion access",
		Rules:       [](*iampb.PolicyRule){policyRule},
	}

	req := &iampb.CreatePolicyRequest{
		// Construct the full path of the resource's deny policies.
		// Its format is: "policies/ATTACHMENT_POINT/denypolicies"
		Parent:   fmt.Sprintf("policies/%s/denypolicies", attachmentPoint),
		Policy:   policy,
		PolicyId: policyID,
	}
	op, err := policiesClient.CreatePolicy(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create policy: %w", err)
	}

	policy, err = op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Policy %s created\n", policy.GetName())

	return nil
}

Java

如需了解如何安装和使用 IAM 客户端库,请参阅 IAM 客户端库。 如需了解详情,请参阅 IAM Java API 参考文档

如需向 IAM 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅准备工作


import com.google.iam.v2.CreatePolicyRequest;
import com.google.iam.v2.DenyRule;
import com.google.iam.v2.PoliciesClient;
import com.google.iam.v2.Policy;
import com.google.iam.v2.PolicyRule;
import com.google.longrunning.Operation;
import com.google.type.Expr;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateDenyPolicy {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // ID or number of the Google Cloud project you want to use.
    String projectId = "your-google-cloud-project-id";

    // Specify the id of the Deny policy you want to create.
    String policyId = "deny-policy-id";

    createDenyPolicy(projectId, policyId);
  }

  // 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.
  public static void createDenyPolicy(String projectId, String policyId)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {

    try (PoliciesClient policiesClient = PoliciesClient.create()) {
      // 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.
      String urlEncodedResource =
          URLEncoder.encode(
              "cloudresourcemanager.googleapis.com/projects/", StandardCharsets.UTF_8);
      String attachmentPoint = String.format("%s%s", urlEncodedResource, projectId);

      // Construct the full path of the resource to which the policy is attached.
      // Its format is: "policies/{attachmentPoint}/denypolicies/{policyId}"
      String policyParent = String.format("policies/%s/denypolicies", attachmentPoint);

      DenyRule denyRule =
          DenyRule.newBuilder()
              // 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
              .addDeniedPrincipals("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.
              // .addExceptionPrincipals(
              //     "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
              .addDeniedPermissions("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.
              // .addExceptionPermissions("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.
              .setDenialCondition(
                  Expr.newBuilder()
                      // 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.
                      .setExpression("!resource.matchTag('12345678/env', 'test')")
                      .setTitle("Only for test projects")
                      .build())
              .build();

      // Add the deny rule and a description for it.
      Policy policy =
          Policy.newBuilder()
              // Set the deny rule.
              .addRules(
                  PolicyRule.newBuilder()
                      // Set a description for the rule.
                      .setDescription(
                          "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")
                      .setDenyRule(denyRule)
                      .build())
              .build();

      // Set the policy resource path, policy rules and a unique ID for the policy.
      CreatePolicyRequest createPolicyRequest =
          CreatePolicyRequest.newBuilder()
              .setParent(policyParent)
              .setPolicy(policy)
              .setPolicyId(policyId)
              .build();

      // Build the create policy request.
      Operation operation =
          policiesClient
              .createPolicyCallable()
              .futureCall(createPolicyRequest)
              .get(3, TimeUnit.MINUTES);

      // Wait for the operation to complete.
      if (operation.hasError()) {
        System.out.println("Error in creating the policy " + operation.getError());
        return;
      }

      // Retrieve the policy name.
      Policy response = policiesClient.getPolicy(String.format("%s/%s", policyParent, policyId));
      String policyName = response.getName();
      System.out.println(
          "Created the deny policy: " + policyName.substring(policyName.lastIndexOf("/") + 1));
    }
  }
}

Node.js

如需了解如何安装和使用 IAM 客户端库,请参阅 IAM 客户端库。 如需了解详情,请参阅 IAM Node.js API 参考文档

如需向 IAM 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅准备工作

/**
 * TODO(developer): Uncomment and replace these variables before running the sample.
 */
// const projectId = 'YOUR_PROJECT_ID';
// const policyID = 'YOUR_POLICY_ID';

const {PoliciesClient} = require('@google-cloud/iam').v2;

const iamClient = new 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".
const attachmentPoint = `cloudresourcemanager.googleapis.com%2Fprojects%2F${projectId}`;

const 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/help/deny/principal-identifiers
  deniedPrincipals: ['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.
  // exceptionPrincipals: ['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
  deniedPermissions: ['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.
  // exceptionPermissions: ['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.
  //
  // 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
  denialCondition: {
    expression: '!resource.matchTag("12345678/env", "test")',
  },
};

async function createDenyPolicy() {
  const request = {
    parent: `policies/${attachmentPoint}/denypolicies`,
    policy: {
      displayName: 'Restrict project deletion access',
      rules: [
        {
          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',
          denyRule,
        },
      ],
    },
    policyId,
  };

  const [operation] = await iamClient.createPolicy(request);