Skip to content

[FR]: Support project-level custom_roles definition and IAM interpolation #4037

Description

@tomasz-ronowicz

The feature request

This introduces the ability to define project-scoped custom roles natively within a project's YAML configuration file and immediately reference those roles in the project's IAM bindings using the $custom_roles: interpolation context.

Currently, managing custom roles requires operating outside the project factory YAML (either via upstream folder/org modules or separate project-level IAM states). This enhancement allows a single YAML file to act as the complete source of truth for IAM.

Proposed solution

The implementation passes the parsed custom_roles block to the underlying project module and merges the resulting custom role IDs into the IAM context map.

Changes in project-factory/projects.tf:

module "projects" {
  source              = "../project"
  for_each            = local.projects_input
  # ... existing attributes ...
  contacts = merge(
    each.value.contacts, var.data_merges.contacts
  )
  
  # Added support for creating custom roles directly from YAML
  custom_roles = try(each.value.custom_roles, null)
}

We then extend the projects-iam module's context to support YAML interpolation ($custom_roles:my_role) by merging the locally created role IDs with any globally defined roles:

module "projects-iam" {
  source   = "../project"
  # ... existing attributes ...
  context = merge(local.ctx, {
    # ... existing context vars ...
    iam_principals = merge(
      local.ctx_iam_principals,
      lookup(local.per_project_service_agents, each.key, {}),
      lookup(local.self_sas_iam_emails, each.key, {}),
      local.projects_service_agents
    )
    
    # Expose custom role IDs for YAML IAM interpolation 
    custom_roles = merge(
      try(local.ctx.custom_roles, {}),
      module.projects[each.key].custom_role_id
    )
  })
}

To ensure users provide valid GCP role constraints, we may update the project.schema.json to enforce strict regex validation.

Role Names: Restricted to ^[a-zA-Z0-9_.]{3,64}$ (preventing invalid characters like hyphens).
Permissions: Restricted to GCP's standard service.resource.verb pattern (^[a-zA-Z-]+.[a-zA-Z-]+.[a-zA-Z-]+$).

"custom_roles": {
  "type": "object",
  "additionalProperties": false,
  "description": "Custom roles which will be created in your project. Created custom roles can be later referenced in IAM sections using YAML interpolation variable $custom_roles:my_role_name. Custom role names cannot contain hyphens (-). You can add only permissions to custom roles, so nesting roles is not possible.",
  "patternProperties": {
    "^[a-zA-Z0-9_\\\\.]{3,64}$": {
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^[a-zA-Z-]+\\.[a-zA-Z-]+\\.[a-zA-Z-]+$",
        "examples": [
          "compute.instances.start",
          "compute.instances.stop"
        ]
      }
    }
  }
}

A standalone custom_role_schema.json and Markdown documentation should be included for completeness.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions