The gcp:iap/webTypeAppEngingIamPolicy:WebTypeAppEngingIamPolicy resource, part of the Pulumi GCP provider, manages IAM access control for Identity-Aware Proxy (IAP) protected App Engine applications. This guide focuses on three capabilities: role binding with member lists, time-based access conditions, and non-authoritative member additions.
These resources attach to existing App Engine applications and reference them by project and appId. The examples are intentionally small. Combine them with your own App Engine infrastructure and organizational access patterns.
Grant a role to multiple members with IamBinding
When you need to grant the same role to multiple users or service accounts, IamBinding manages the complete member list for that role while preserving other roles in the policy.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.iap.WebTypeAppEngingIamBinding("binding", {
project: app.project,
appId: app.appId,
role: "roles/iap.httpsResourceAccessor",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
binding = gcp.iap.WebTypeAppEngingIamBinding("binding",
project=app["project"],
app_id=app["appId"],
role="roles/iap.httpsResourceAccessor",
members=["user:jane@example.com"])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iap"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := iap.NewWebTypeAppEngingIamBinding(ctx, "binding", &iap.WebTypeAppEngingIamBindingArgs{
Project: pulumi.Any(app.Project),
AppId: pulumi.Any(app.AppId),
Role: pulumi.String("roles/iap.httpsResourceAccessor"),
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.Iap.WebTypeAppEngingIamBinding("binding", new()
{
Project = app.Project,
AppId = app.AppId,
Role = "roles/iap.httpsResourceAccessor",
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.iap.WebTypeAppEngingIamBinding;
import com.pulumi.gcp.iap.WebTypeAppEngingIamBindingArgs;
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 WebTypeAppEngingIamBinding("binding", WebTypeAppEngingIamBindingArgs.builder()
.project(app.project())
.appId(app.appId())
.role("roles/iap.httpsResourceAccessor")
.members("user:jane@example.com")
.build());
}
}
resources:
binding:
type: gcp:iap:WebTypeAppEngingIamBinding
properties:
project: ${app.project}
appId: ${app.appId}
role: roles/iap.httpsResourceAccessor
members:
- user:jane@example.com
The role property specifies which IAP role to grant (here, roles/iap.httpsResourceAccessor for HTTPS access). The members array lists all identities that should have this role. IamBinding is authoritative for this specific role: it replaces the member list but leaves other roles untouched. The appId and project properties identify which App Engine application to protect.
Add time-based access with IAM Conditions
Access requirements often include temporal constraints, such as granting temporary access that expires automatically.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.iap.WebTypeAppEngingIamBinding("binding", {
project: app.project,
appId: app.appId,
role: "roles/iap.httpsResourceAccessor",
members: ["user:jane@example.com"],
condition: {
title: "expires_after_2019_12_31",
description: "Expiring at midnight of 2019-12-31",
expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
},
});
import pulumi
import pulumi_gcp as gcp
binding = gcp.iap.WebTypeAppEngingIamBinding("binding",
project=app["project"],
app_id=app["appId"],
role="roles/iap.httpsResourceAccessor",
members=["user:jane@example.com"],
condition={
"title": "expires_after_2019_12_31",
"description": "Expiring at midnight of 2019-12-31",
"expression": "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iap"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := iap.NewWebTypeAppEngingIamBinding(ctx, "binding", &iap.WebTypeAppEngingIamBindingArgs{
Project: pulumi.Any(app.Project),
AppId: pulumi.Any(app.AppId),
Role: pulumi.String("roles/iap.httpsResourceAccessor"),
Members: pulumi.StringArray{
pulumi.String("user:jane@example.com"),
},
Condition: &iap.WebTypeAppEngingIamBindingConditionArgs{
Title: pulumi.String("expires_after_2019_12_31"),
Description: pulumi.String("Expiring at midnight of 2019-12-31"),
Expression: pulumi.String("request.time < timestamp(\"2020-01-01T00:00:00Z\")"),
},
})
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.Iap.WebTypeAppEngingIamBinding("binding", new()
{
Project = app.Project,
AppId = app.AppId,
Role = "roles/iap.httpsResourceAccessor",
Members = new[]
{
"user:jane@example.com",
},
Condition = new Gcp.Iap.Inputs.WebTypeAppEngingIamBindingConditionArgs
{
Title = "expires_after_2019_12_31",
Description = "Expiring at midnight of 2019-12-31",
Expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iap.WebTypeAppEngingIamBinding;
import com.pulumi.gcp.iap.WebTypeAppEngingIamBindingArgs;
import com.pulumi.gcp.iap.inputs.WebTypeAppEngingIamBindingConditionArgs;
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 WebTypeAppEngingIamBinding("binding", WebTypeAppEngingIamBindingArgs.builder()
.project(app.project())
.appId(app.appId())
.role("roles/iap.httpsResourceAccessor")
.members("user:jane@example.com")
.condition(WebTypeAppEngingIamBindingConditionArgs.builder()
.title("expires_after_2019_12_31")
.description("Expiring at midnight of 2019-12-31")
.expression("request.time < timestamp(\"2020-01-01T00:00:00Z\")")
.build())
.build());
}
}
resources:
binding:
type: gcp:iap:WebTypeAppEngingIamBinding
properties:
project: ${app.project}
appId: ${app.appId}
role: roles/iap.httpsResourceAccessor
members:
- user:jane@example.com
condition:
title: expires_after_2019_12_31
description: Expiring at midnight of 2019-12-31
expression: request.time < timestamp("2020-01-01T00:00:00Z")
The condition block adds a time-based constraint to the role binding. The expression property uses CEL (Common Expression Language) to define when access is valid; here, access expires at midnight on 2020-01-01. The title and description properties document the condition’s purpose. IAM evaluates conditions at request time, automatically denying access once the timestamp passes.
Add individual members without affecting others
In collaborative environments, you often need to grant access to one person without modifying existing permissions or coordinating with other administrators.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const member = new gcp.iap.WebTypeAppEngingIamMember("member", {
project: app.project,
appId: app.appId,
role: "roles/iap.httpsResourceAccessor",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
member = gcp.iap.WebTypeAppEngingIamMember("member",
project=app["project"],
app_id=app["appId"],
role="roles/iap.httpsResourceAccessor",
member="user:jane@example.com")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iap"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := iap.NewWebTypeAppEngingIamMember(ctx, "member", &iap.WebTypeAppEngingIamMemberArgs{
Project: pulumi.Any(app.Project),
AppId: pulumi.Any(app.AppId),
Role: pulumi.String("roles/iap.httpsResourceAccessor"),
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.Iap.WebTypeAppEngingIamMember("member", new()
{
Project = app.Project,
AppId = app.AppId,
Role = "roles/iap.httpsResourceAccessor",
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.iap.WebTypeAppEngingIamMember;
import com.pulumi.gcp.iap.WebTypeAppEngingIamMemberArgs;
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 WebTypeAppEngingIamMember("member", WebTypeAppEngingIamMemberArgs.builder()
.project(app.project())
.appId(app.appId())
.role("roles/iap.httpsResourceAccessor")
.member("user:jane@example.com")
.build());
}
}
resources:
member:
type: gcp:iap:WebTypeAppEngingIamMember
properties:
project: ${app.project}
appId: ${app.appId}
role: roles/iap.httpsResourceAccessor
member: user:jane@example.com
The member property (singular) grants access to one identity. Unlike IamBinding, IamMember is non-authoritative: it adds this member without affecting other members who have the same role. This approach works well when multiple teams manage access independently, but you must avoid using IamPolicy or IamBinding for the same role, as they would conflict.
Beyond these examples
These snippets focus on specific IAM management features: role binding and member management, time-based access with IAM Conditions, and authoritative vs non-authoritative updates. They’re intentionally minimal rather than complete access control configurations.
The examples reference pre-existing infrastructure such as App Engine applications (project and appId). They focus on configuring IAM policies rather than provisioning the applications themselves.
To keep things focused, common IAM patterns are omitted, including:
- Full policy replacement with IamPolicy resource
- Complex condition expressions (location, resource attributes)
- Service account and group membership patterns
- Policy data source for read-only access
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 IAP WebTypeAppEngingIamPolicy resource reference for all available configuration options.
Let's configure GCP Identity-Aware Proxy IAM Policies
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Selection & Conflicts
WebTypeAppEngingIamPolicy cannot be used with WebTypeAppEngingIamBinding or WebTypeAppEngingIamMember because they will conflict over policy management. Choose one approach: use WebTypeAppEngingIamPolicy for full policy control, or use WebTypeAppEngingIamBinding/WebTypeAppEngingIamMember for granular management.WebTypeAppEngingIamPolicy is authoritative and replaces the entire IAM policy. WebTypeAppEngingIamBinding is authoritative for a specific role but preserves other roles. WebTypeAppEngingIamMember is non-authoritative and adds individual members while preserving existing members for that role.IAM Conditions & Advanced Features
condition block with title, description, and expression fields. For example, to expire access at midnight on 2019-12-31, use expression request.time < timestamp("2020-01-01T00:00:00Z").Configuration & Setup
appId (the App Engine app ID), policyData (generated by gcp.organizations.getIAMPolicy), and project (the GCP project ID). Both appId and project are immutable after creation.Import & Custom Roles
[projects/my-project|organizations/my-org]/roles/my-custom-role when importing.