Manage GCP Apigee Environment IAM Policies

The gcp:apigee/environmentIamPolicy:EnvironmentIamPolicy resource, part of the Pulumi GCP provider, manages IAM policies for Apigee environments, controlling who can access and manage environment resources. This guide focuses on three approaches: authoritative policy replacement (EnvironmentIamPolicy), role-level binding (EnvironmentIamBinding), and member-level grants (EnvironmentIamMember).

These resources reference an existing Apigee environment by orgId and envId. The examples are intentionally small. Combine them with your own Apigee organization and environment infrastructure.

Replace the entire IAM policy for an environment

When you need complete control over environment access, you can set the entire IAM policy at once, replacing any existing permissions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/viewer",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.apigee.EnvironmentIamPolicy("policy", {
    orgId: apigeeEnvironment.orgId,
    envId: apigeeEnvironment.name,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/viewer",
    "members": ["user:jane@example.com"],
}])
policy = gcp.apigee.EnvironmentIamPolicy("policy",
    org_id=apigee_environment["orgId"],
    env_id=apigee_environment["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/apigee"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		admin, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/viewer",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = apigee.NewEnvironmentIamPolicy(ctx, "policy", &apigee.EnvironmentIamPolicyArgs{
			OrgId:      pulumi.Any(apigeeEnvironment.OrgId),
			EnvId:      pulumi.Any(apigeeEnvironment.Name),
			PolicyData: pulumi.String(admin.PolicyData),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var admin = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/viewer",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.Apigee.EnvironmentIamPolicy("policy", new()
    {
        OrgId = apigeeEnvironment.OrgId,
        EnvId = apigeeEnvironment.Name,
        PolicyData = admin.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.apigee.EnvironmentIamPolicy;
import com.pulumi.gcp.apigee.EnvironmentIamPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var admin = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/viewer")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new EnvironmentIamPolicy("policy", EnvironmentIamPolicyArgs.builder()
            .orgId(apigeeEnvironment.orgId())
            .envId(apigeeEnvironment.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:apigee:EnvironmentIamPolicy
    properties:
      orgId: ${apigeeEnvironment.orgId}
      envId: ${apigeeEnvironment.name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/viewer
            members:
              - user:jane@example.com

The EnvironmentIamPolicy resource is authoritative: it replaces the entire IAM policy on the environment. The policyData property accepts output from the getIAMPolicy data source, which defines bindings (role-to-members mappings). This approach gives you full control but overwrites any existing policy, so use it when you want to define all access in one place.

Grant a role to multiple members at once

Teams often need to grant the same role to several users without affecting other roles already assigned.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const binding = new gcp.apigee.EnvironmentIamBinding("binding", {
    orgId: apigeeEnvironment.orgId,
    envId: apigeeEnvironment.name,
    role: "roles/viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.apigee.EnvironmentIamBinding("binding",
    org_id=apigee_environment["orgId"],
    env_id=apigee_environment["name"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/apigee"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := apigee.NewEnvironmentIamBinding(ctx, "binding", &apigee.EnvironmentIamBindingArgs{
			OrgId: pulumi.Any(apigeeEnvironment.OrgId),
			EnvId: pulumi.Any(apigeeEnvironment.Name),
			Role:  pulumi.String("roles/viewer"),
			Members: pulumi.StringArray{
				pulumi.String("user:jane@example.com"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var binding = new Gcp.Apigee.EnvironmentIamBinding("binding", new()
    {
        OrgId = apigeeEnvironment.OrgId,
        EnvId = apigeeEnvironment.Name,
        Role = "roles/viewer",
        Members = new[]
        {
            "user:jane@example.com",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.apigee.EnvironmentIamBinding;
import com.pulumi.gcp.apigee.EnvironmentIamBindingArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var binding = new EnvironmentIamBinding("binding", EnvironmentIamBindingArgs.builder()
            .orgId(apigeeEnvironment.orgId())
            .envId(apigeeEnvironment.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:apigee:EnvironmentIamBinding
    properties:
      orgId: ${apigeeEnvironment.orgId}
      envId: ${apigeeEnvironment.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The EnvironmentIamBinding resource is authoritative for a single role: it sets the complete list of members for that role while preserving other roles on the environment. The members property accepts an array of identities (users, service accounts, groups). This approach works well when you manage access by role and want to define all members for that role together.

Add a single member to a role incrementally

When you need to grant access to one user without managing the full member list, you can add them individually.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.apigee.EnvironmentIamMember("member", {
    orgId: apigeeEnvironment.orgId,
    envId: apigeeEnvironment.name,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.apigee.EnvironmentIamMember("member",
    org_id=apigee_environment["orgId"],
    env_id=apigee_environment["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/apigee"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := apigee.NewEnvironmentIamMember(ctx, "member", &apigee.EnvironmentIamMemberArgs{
			OrgId:  pulumi.Any(apigeeEnvironment.OrgId),
			EnvId:  pulumi.Any(apigeeEnvironment.Name),
			Role:   pulumi.String("roles/viewer"),
			Member: pulumi.String("user:jane@example.com"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var member = new Gcp.Apigee.EnvironmentIamMember("member", new()
    {
        OrgId = apigeeEnvironment.OrgId,
        EnvId = apigeeEnvironment.Name,
        Role = "roles/viewer",
        Member = "user:jane@example.com",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.apigee.EnvironmentIamMember;
import com.pulumi.gcp.apigee.EnvironmentIamMemberArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var member = new EnvironmentIamMember("member", EnvironmentIamMemberArgs.builder()
            .orgId(apigeeEnvironment.orgId())
            .envId(apigeeEnvironment.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:apigee:EnvironmentIamMember
    properties:
      orgId: ${apigeeEnvironment.orgId}
      envId: ${apigeeEnvironment.name}
      role: roles/viewer
      member: user:jane@example.com

The EnvironmentIamMember resource is non-authoritative: it adds one member to a role without affecting other members who already have that role. The member property accepts a single identity. This is the most granular option and can be combined with EnvironmentIamBinding resources as long as they manage different roles.

Beyond these examples

These snippets focus on specific IAM management approaches: authoritative vs non-authoritative IAM management and role-level and member-level access control. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Apigee environments (orgId and envId references). They focus on IAM policy configuration rather than provisioning the underlying Apigee resources.

To keep things focused, common IAM patterns are omitted, including:

  • Conditional IAM bindings (condition blocks)
  • Custom role definitions and usage
  • Service account impersonation
  • IAM policy retrieval (data source usage)

These omissions are intentional: the goal is to illustrate how each IAM resource type is wired, not provide drop-in access control modules. See the Apigee Environment IAM Policy resource reference for all available configuration options.

Let's manage GCP Apigee Environment IAM Policies

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Selection & Conflicts
Can I use EnvironmentIamPolicy with EnvironmentIamBinding or EnvironmentIamMember?
No, EnvironmentIamPolicy cannot be used together with EnvironmentIamBinding or EnvironmentIamMember because they will conflict over the policy configuration. Choose one approach: use EnvironmentIamPolicy for full policy control, or use EnvironmentIamBinding/EnvironmentIamMember for granular management.
Can I use EnvironmentIamBinding and EnvironmentIamMember together?
Yes, but only if they don’t grant privileges to the same role. Each role must be managed by either EnvironmentIamBinding or EnvironmentIamMember, not both.
What's the difference between the three IAM resources?

Each serves a different use case:

  • EnvironmentIamPolicy: Authoritative, replaces the entire IAM policy
  • EnvironmentIamBinding: Authoritative for a specific role, preserves other roles
  • EnvironmentIamMember: Non-authoritative, adds a single member while preserving other members for the role
Configuration & Properties
Can I change envId or orgId after creating the resource?
No, both envId and orgId are immutable and cannot be changed after resource creation.
Import & Custom Roles
How do I import a resource with a custom role?
Use the full name format for custom roles: [projects/my-project|organizations/my-org]/roles/my-custom-role. For example: pulumi import gcp:apigee/environmentIamPolicy:EnvironmentIamPolicy editor "{{org_id}}/environments/{{environment}} projects/my-project/roles/my-custom-role user:jane@example.com"

Using a different cloud?

Explore security guides for other cloud providers: