One deeply-typed boundary for enterprise-wide GitHub Actions governance — the allowed-actions policy, which-organizations-may-run scope, the default
GITHUB_TOKENworkflow permissions, and enterprise self-hosted runner groups, all secure-by-default. The Enterprise-tier mirror oftf-mod-github-actions-organization. Built for integrations/github v6.x.
⚠️ ENTERPRISE CLOUD ONLY. Every resource here targets a GitHub Enterprise account and requires an enterprise-owner identity (admin:enterprise) — strictly higher than org admin.applyfails with 403/404 on Free/Team plans and on standalone organizations. See GitHub Prerequisites.
This composite module governs GitHub Actions at enterprise scope behind a single Terraform boundary:
- 🛡️ Allowed-actions policy — restrict which actions/reusable workflows may run across the whole enterprise (
all/local_only/selected), with a tunable allow-list for GitHub-owned, Marketplace-verified, and explicitowner/repo@refpatterns. - 🏢 Which-organizations scope — choose whether
all,none, or onlyselectedorganizations in the enterprise may run Actions. - 🔑 Default workflow token permissions — set the enterprise-wide default
GITHUB_TOKENscope (readbaseline /write) and whether Actions may approve pull-request reviews. - 🏃 Enterprise runner groups — a
for_eachmap of self-hosted runner groups withall/selectedorganization visibility, optional public-repo access, and workflow restriction.
💡 Why it matters: an enterprise Actions policy is the highest-altitude CI/CD control in the org chart — it can force-disable choices every downstream organization makes. Centralizing the allowed-actions policy, the read-only token baseline, and runner-group scope in one reviewable module turns enterprise supply-chain governance into code review instead of a click-ops checklist in the enterprise admin console.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- ⭐ Star this repository to help others discover this Terraform module.
- 🤝 Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- ☕ Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
This is the enterprise-scope apex of the Actions family — the org-tier counterpart is tf-mod-github-actions-organization, and it sits alongside the sibling tf-mod-github-enterprise (enterprise org / IP-allow-list / security governance). It consumes the enterprise slug and numeric org ids and emits the resolved policy plus a runner-group id map.
flowchart LR
ent["tf-mod-github-enterprise<br/>(sibling · enterprise org / IP allow-list / security)"]
entact["tf-mod-github-enterprise-actions<br/>(THIS · enterprise-scope Actions)"]
actorg["tf-mod-github-actions-organization<br/>(org-tier counterpart)"]
rg["tf-mod-github-actions-runner-group<br/>(org-scope runners)"]
repo["tf-mod-github-repository<br/>(keystone)"]
ent -- "enterprise_slug + numeric org ids" --> entact
entact -. "policy precedence<br/>(enterprise can force-disable org choices)".-> actorg
entact -- "runner_group_ids" --> rg
repo -- "repo_id (numeric)" --> actorg
style entact fill:#8957E5,color:#fff
style repo fill:#24292F,color:#fff
🔌 Consumes the
enterprise_slugand numeric org ids (fromtf-mod-github-enterprise/ the org listing); emits the resolved policy plusrunner_group_ids. See the 🔌 Cross-Module Contract.
The primary resource is github_enterprise_actions_permissions.this; a singleton workflow-permissions resource and a for_each runner-group collection share the same enterprise boundary.
flowchart TD
this["github_enterprise_actions_permissions.this<br/>(primary policy · allowed_actions + enabled_organizations)"]
workflow["github_enterprise_actions_workflow_permissions.workflow<br/>(singleton · default GITHUB_TOKEN scope = read)"]
rg["github_enterprise_actions_runner_group.runner_groups<br/>(for_each = var.runner_groups)"]
this -- "same enterprise boundary" --> workflow
this -- "same enterprise boundary" --> rg
style this fill:#8957E5,color:#fff
Resource inventory
- 🛡️
github_enterprise_actions_permissions.this— the primary policy: allowed-actions mode, enabled-organizations mode, the optional allow-list, and the optional selected-organization list. - 🔑
github_enterprise_actions_workflow_permissions.workflow— a singleton setting the enterprise defaultGITHUB_TOKENscope (readby default) and whether Actions may approve PR reviews (falseby default). Always managed, to enforce the read-only baseline. - 🏃
github_enterprise_actions_runner_group.runner_groups— afor_eachmap of enterprise self-hosted runner groups keyed by runner-group name.
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
| Provider | integrations/github ~> 6.0 (current 6.12.1) |
| Plan/edition | GitHub Enterprise Cloud (a real Enterprise account) |
⚠️ Provider source isintegrations/github, never the deprecatedhashicorp/github. Migrate old state withterraform state replace-provider. ℹ️ Auth (PAT / GitHub CLI / OAuth / GitHub App) and the target enterprise identity are provider concerns — this module declares noowner/token/app_authvariables. The provider identity must be an enterprise owner.
tf-mod-github-enterprise-actions/
├── providers.tf # terraform{} + required_providers (integrations/github ~> 6.0); no provider{} block
├── variables.tf # enterprise_slug → policy → workflow token → runner_groups; validations, secure defaults
├── main.tf # this policy + singleton workflow permissions + for_each runner groups
├── outputs.tf # id, resolved policy, default token scope, runner_group_ids map
├── SCOPE.md # design contract: in/out-of-scope, consumes/emits, token scopes, prerequisites
└── README.md # this file
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
# Secure defaults applied automatically:
# allowed_actions = "selected" (GitHub-owned + verified only)
# enabled_organizations = "all"
# default_workflow_permissions = "read" (read-only GITHUB_TOKEN)
}🔒 The empty call produces the secure baseline: only GitHub-owned and Marketplace-verified actions may run enterprise-wide, and every workflow's
GITHUB_TOKENis read-only.
Sourced from this repo's SCOPE.md.
| Input | Type | Source |
|---|---|---|
enterprise_slug |
string |
caller-supplied enterprise identifier (the enterprise the provider identity administers) |
enabled_organizations_config.organization_ids |
set(number) |
tf-mod-github-enterprise / the org listing — numeric org database ids; required only when enabled_organizations = "selected" |
runner_groups[*].selected_organization_ids |
set(number) |
tf-mod-github-enterprise / the org listing — honored only when a group's visibility = "selected" |
| Output | Description | Consumed by |
|---|---|---|
id |
Enterprise Actions permissions policy id (the enterprise) | Composition / reporting |
allowed_actions |
Resolved enterprise allowed-actions policy | Audit / compliance |
enabled_organizations |
Resolved which-orgs-can-run policy | Audit |
default_workflow_permissions |
Resolved enterprise default token scope (read-only baseline) | Compliance reporting |
can_approve_pull_request_reviews |
Resolved: whether Actions may approve PRs enterprise-wide | Compliance reporting |
runner_group_ids |
Map: runner-group name → id | tf-mod-github-actions-runner-group / org runners, reporting |
🔒 This module manages no secret material — nothing it emits is sensitive.
1 · Minimal — secure default policy + read-only token
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
allowed_actions = "selected" # GitHub-owned + verified only
enabled_organizations = "all"
# default_workflow_permissions = "read" (secure default — kept implicit)
}🔒 Even minimal, this blocks arbitrary third-party actions and pins every workflow token to read-only.
2 · Lock the enterprise down — local actions only
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
# Only actions/workflows defined inside the enterprise's own orgs may run.
allowed_actions = "local_only"
enabled_organizations = "all"
}🔒
local_onlyis the strictest non-noneposture — no Marketplace actions at all, not evenactions/checkout. Expect to vendor common actions internally.
3 · Selected actions allow-list with verified creators + explicit patterns
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
allowed_actions = "selected"
enabled_organizations = "all"
allowed_actions_config = {
github_owned_allowed = true
verified_allowed = true
patterns_allowed = [
"aws-actions/configure-aws-credentials@*",
"hashicorp/setup-terraform@*",
"azure/login@v2",
]
}
}💡
allowed_actions_configis honored only whenallowed_actions = "selected".github_owned_allowedis required by the provider when the block renders — keep ittrueso GitHub's own actions don't break.
4 · Restrict which organizations may run Actions
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
allowed_actions = "selected"
enabled_organizations = "selected"
enabled_organizations_config = {
organization_ids = [
12345678, # lending-platform org (numeric database id)
87654321, # data-platform org
]
}
}💡
organization_idsare numeric org database ids, not org login names.enabled_organizations_configis required whenenabled_organizations = "selected"(enforced at plan time).
5 · Kill switch — disable Actions for every organization
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
enabled_organizations = "none" # no org in the enterprise may run Actions
}
⚠️ noneis an enterprise-wide CI/CD off-switch — every organization's Actions stop. Use deliberately (incident response, migration freeze).
6 · Default workflow token = write (explicit opt-in)
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
# ⚠️ Grants every workflow in the enterprise a write-scoped GITHUB_TOKEN.
default_workflow_permissions = "write"
can_approve_pull_request_reviews = false # keep humans in the review loop
}
⚠️ writehands broad repository-write to every workflow token enterprise-wide. Prefer thereaddefault and elevate per-job with explicitpermissions:in the workflow YAML. Leavingcan_approve_pull_request_reviews = falsestops a workflow from satisfying required-review gates without a human.
7 · One enterprise runner group — selected-org visibility
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
runner_groups = {
"secure-linux" = {
visibility = "selected"
selected_organization_ids = [12345678, 87654321]
}
}
}🔒
visibility = "selected"(the default) scopes the runner group to named orgs — self-hosted runners can execute untrusted workflow code, so this is least-privilege by default.
8 · Runner group available to all organizations
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
runner_groups = {
"shared-pool" = {
visibility = "all" # every org in the enterprise may target this group
}
}
}
⚠️ visibility = "all"exposes the runners to every org. Note: GitHub documents a"private"value, but the API does not support it for runner groups — this module rejects it at plan time. Use"selected"to scope narrowly.
9 · Runner group restricted to specific workflows
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
runner_groups = {
"prod-deploy" = {
visibility = "selected"
selected_organization_ids = [12345678]
restricted_to_workflows = true
selected_workflows = [
"lending-platform/deploy/.github/workflows/release.yml@refs/heads/main",
]
}
}
}🔒 With
restricted_to_workflows = true, only the listed fully-qualified workflow refs may use the group. An emptyselected_workflowswith the flag on permits no workflows to run.
10 · Runner groups for_each at scale from a map(object)
locals {
runner_groups = {
"linux-general" = { visibility = "all" }
"linux-secure" = { visibility = "selected", selected_organization_ids = [12345678, 87654321] }
"gpu-ml" = { visibility = "selected", selected_organization_ids = [11112222], allows_public_repositories = false }
"windows-build" = { visibility = "selected", selected_organization_ids = [12345678] }
}
}
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
runner_groups = local.runner_groups
}
⚠️ Bulkfor_eachover many runner groups is one API write each — watch GitHub secondary rate limits on large applies (see Troubleshooting). Keys are stable runner-group names, so adding one group never churns the others.
11 · Wiring numeric org ids from tf-mod-github-enterprise
module "enterprise" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise?ref=v1.0.0"
#... manages the enterprise account and its organizations...
}
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = module.enterprise.slug
allowed_actions = "selected"
enabled_organizations = "selected"
enabled_organizations_config = {
# numeric org database ids emitted by the sibling enterprise module
organization_ids = values(module.enterprise.organization_database_ids)
}
}💡 Org-scoped selections use numeric org database ids, not slugs. The exact output name (
organization_database_idshere) comes fromtf-mod-github-enterprise.
12 · Policy + workflow token + runner groups together
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
allowed_actions = "selected"
enabled_organizations = "all"
allowed_actions_config = {
github_owned_allowed = true
verified_allowed = true
patterns_allowed = ["hashicorp/setup-terraform@v3"]
}
default_workflow_permissions = "read"
can_approve_pull_request_reviews = false
runner_groups = {
"linux-secure" = { visibility = "selected", selected_organization_ids = [12345678] }
}
}13 · 🔒 Secure / hardened enterprise baseline (recommended)
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = "financial-partners"
# Tightest practical posture short of local_only.
allowed_actions = "selected"
enabled_organizations = "selected"
allowed_actions_config = {
github_owned_allowed = true
verified_allowed = false # block non-GitHub Marketplace creators entirely
patterns_allowed = [
"hashicorp/setup-terraform@v3",
"aws-actions/configure-aws-credentials@v4",
]
}
enabled_organizations_config = {
organization_ids = [12345678, 87654321]
}
# Read-only token, no Actions PR approvals.
default_workflow_permissions = "read"
can_approve_pull_request_reviews = false
runner_groups = {
"prod-secure" = {
visibility = "selected"
selected_organization_ids = [12345678]
allows_public_repositories = false
restricted_to_workflows = true
selected_workflows = [
"lending-platform/deploy/.github/workflows/release.yml@refs/tags/v*",
]
}
}
}🔒
verified_allowed = false+ pinned@vNpatterns +selectedorg scope + read-only token + workflow-restricted runners is the hardened enterprise baseline.
🏗️ 14 · End-to-end composition — tf-mod-github-enterprise → tf-mod-github-enterprise-actions (outputs → inputs)
# ── 1) Enterprise account + organizations (sibling module) ────────────
module "enterprise" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise?ref=v1.0.0"
slug = "financial-partners"
#... org / IP-allow-list / security-analysis governance...
}
# ── 2) Enterprise-scope Actions governance (THIS module) ──────────────
module "enterprise_actions" {
source = "git::https://github.com/microsoftexpert/tf-mod-github-enterprise-actions?ref=v1.0.0"
enterprise_slug = module.enterprise.slug
allowed_actions = "selected"
enabled_organizations = "selected"
allowed_actions_config = {
github_owned_allowed = true
verified_allowed = true
patterns_allowed = ["hashicorp/setup-terraform@v3"]
}
# numeric org database ids wired from the sibling enterprise module
enabled_organizations_config = {
organization_ids = values(module.enterprise.organization_database_ids)
}
default_workflow_permissions = "read"
can_approve_pull_request_reviews = false
runner_groups = {
"enterprise-linux" = {
visibility = "selected"
selected_organization_ids = values(module.enterprise.organization_database_ids)
}
}
}
# ── 3) Org-tier Actions config can consume the enterprise policy / runner-group ids ──
output "enterprise_runner_groups" {
value = module.enterprise_actions.runner_group_ids
}🔒 The enterprise policy is the apex: it can force-disable choices that
tf-mod-github-actions-organizationmakes at org scope. Wireenterprise_slugand numeric org ids fromtf-mod-github-enterprise, never hardcode them.
Identifying parent reference
enterprise_slug(required) — slug of the GitHub Enterprise to govern. Every resource is scoped to it.
Policy (primary this resource)
allowed_actions—selected(secure default) /all/local_only.enabled_organizations—all(default) /none/selected.allowed_actions_config—github_owned_allowed,verified_allowed,patterns_allowed(honored only whenallowed_actions = "selected").enabled_organizations_config—organization_ids(required whenenabled_organizations = "selected").
Workflow token permissions (singleton)
default_workflow_permissions—read(secure default) /write.can_approve_pull_request_reviews—bool, defaultfalse.
Runner groups (for_each)
runner_groups—map(object)keyed by runner-group name; visibility, selected org ids, public-repo access, workflow restriction.
Full object schemas for nested inputs
# allowed_actions_config (honored only when allowed_actions = "selected")
object({
github_owned_allowed = optional(bool, true) # required by the provider when the block renders
verified_allowed = optional(bool, true) # allow Marketplace-verified creators
patterns_allowed = optional(set(string), []) # "owner/repo@ref" / wildcard patterns
})
# enabled_organizations_config (required when enabled_organizations = "selected")
object({
organization_ids = set(number) # numeric enterprise org database ids
})
# runner_groups (keyed by runner-group name)
map(object({
visibility = optional(string, "selected") # "all" | "selected"
selected_organization_ids = optional(set(number), []) # honored when visibility = "selected"
allows_public_repositories = optional(bool, false)
restricted_to_workflows = optional(bool, false)
selected_workflows = optional(list(string), []) # honored when restricted_to_workflows = true
}))| Output | Description |
|---|---|
id |
Enterprise Actions permissions policy id (the enterprise) |
allowed_actions |
Resolved allowed-actions policy (all / local_only / selected) |
enabled_organizations |
Resolved which-orgs-can-run policy (all / none / selected) |
default_workflow_permissions |
Resolved enterprise default GITHUB_TOKEN scope (read baseline / write) |
can_approve_pull_request_reviews |
Whether Actions may approve PR reviews enterprise-wide (false baseline) |
runner_group_ids |
Map of runner-group name → runner group id (empty when none) |
ℹ️ No
arn, nonode_id/slug(these enterprise policy resources expose none), notags_all. No outputs aresensitive— this module manages no secrets.
- Enterprise vs org scope interaction. Enterprise and organization Actions policies are separate layers. The enterprise policy is the apex: it can force-disable choices the org-tier (
tf-mod-github-actions-organization) makes — e.g. if the enterprise setsenabled_organizations = "selected"and omits an org, no org-level toggle re-enables Actions there. Model the enterprise policy as the ceiling and the org policy as the per-org floor beneath it. - Read-only token baseline and why.
default_workflow_permissionsdefaults to"read"— a read-onlyGITHUB_TOKENfor every workflow in the enterprise. Write access is a deliberate, enterprise-wide grant; prefer the read default and elevate per-job with explicitpermissions:in workflow YAML. The singleton is always managed so the baseline is enforced, not merely suggested; on destroy the provider resets toread/ no-PR-approval. allowed_actions = "selected"+ config block. The allow-list lives inallowed_actions_configand is rendered via adynamicblock only whenallowed_actions = "selected"; forall/local_onlythe block emits nothing and any leftover config is ignored.github_owned_allowedis required by the provider when the block renders (kepttrueby default). The same pattern governsenabled_organizations_configunderenabled_organizations = "selected".idsemantics.github_enterprise_actions_permissions.this.idis the enterprise itself (the policy is a singleton per enterprise) — there is nonode_id/slugfor the policy. The workflow-permissions resource'sidis the enterprise slug. Runner groups exposeidonly.- Authoritative singletons. Both the permissions policy and the workflow-permissions resource are authoritative singletons — applying overwrites the enterprise's policy wholesale. Only one instance should manage each across your whole Terraform estate, or the last
applywins and the others churn. - Runner-group visibility. Only
allandselectedare supported; GitHub documents"private"but the API rejects it, so this module rejects it at plan time.selected_organization_idsare numeric org database ids, honored only whenvisibility = "selected". - ForceNew / import.
enterprise_slugis the identity of every resource — changing it moves the resources. Import ids differ: the permissions/workflow resources import by enterprise slug; a runner group imports byenterprise-slug/<numeric-id>(see Runbook). - Eventual consistency & secondary rate limits. The GitHub REST API is eventually consistent and enforces secondary rate limits on rapid writes — bulk runner-group
for_eachcan trip them. Terraform's graph normally orders dependencies correctly; an occasional re-applyclears transient races. - No tags, no timeouts. GitHub has neither concept on these resources — do not look for a
tags/timeoutstail.
- 🔒 Secure by default.
allowed_actions = "selected"blocks arbitrary third-party actions out of the box;default_workflow_permissions = "read"keeps the token read-only. - 🪪 Least privilege. Runner groups default to
selectedvisibility and no public-repo access; Actions cannot approve PRs by default. - 🏛️ Apex governance. One authoritative enterprise policy is the ceiling every organization sits beneath — supply-chain control as code, not console clicks.
- 🤫 No secret leakage. This module owns no secret material; nothing emitted is sensitive.
- 🚫 No provider concerns leak in. No
owner/token/app_authvariables — auth and the target enterprise are the caller's provider block. - 📦 No GitHub-absent concepts. No
tags, notags_all, notimeouts, no ARNs.
terraform init -backend=false
terraform validate
terraform fmt -check
terraform plan # requires an enterprise-owner github provider (admin:enterprise)
terraform apply
terraform outputImporting existing enterprise configuration
# permissions policy + workflow permissions import by enterprise slug
terraform import github_enterprise_actions_permissions.this financial-partners
terraform import github_enterprise_actions_workflow_permissions.workflow financial-partners
# a runner group imports by enterprise-slug/<numeric-id>
terraform import 'github_enterprise_actions_runner_group.runner_groups["secure-linux"]' financial-partners/42
⚠️ Always pin the module source to a tag —?ref=v1.0.0, never a branch. Branches move; tags are immutable.
Offline proof gate (no enterprise credentials required):
terraform fmt -check # zero formatting differences
terraform validate # zero errors
tflint # core rules — no dedicated GitHub ruleset existsℹ️
terraform plan/applyrequire a livegithubprovider authenticated as an enterprise owner;init/validate/fmtrun fully offline.
id = "financial-partners"
allowed_actions = "selected"
enabled_organizations = "selected"
default_workflow_permissions = "read"
can_approve_pull_request_reviews = false
runner_group_ids = {
"enterprise-linux" = "7"
"prod-secure" = "9"
}
| Symptom | Cause | Resolution |
|---|---|---|
404 Not Found / 403 on every resource |
Not a real Enterprise account, or identity is not an enterprise owner | Confirm a GitHub Enterprise Cloud account and an admin:enterprise identity — see Prerequisites |
404 resolving the enterprise |
enterprise_slug typo / identity doesn't administer it |
Use the exact enterprise slug the identity owns |
enabled_organizations_config is required when enabled_organizations = 'selected' |
Variable validation tripped | Supply enabled_organizations_config.organization_ids, or set enabled_organizations to all/none |
visibility must be 'all' or 'selected' on a runner group |
"private" requested |
The GitHub API does not support private runner-group visibility — use selected |
| Runner group runs no workflows | restricted_to_workflows = true with an empty selected_workflows |
Populate selected_workflows, or set restricted_to_workflows = false |
| Org-level Actions toggle has no effect | Enterprise policy is force-disabling it | The enterprise policy is the ceiling — adjust enabled_organizations / allowed_actions here, not just at org scope |
default_workflow_permissions reverted to read after a destroy |
By design — the provider resets to safe defaults on destroy | Re-apply to restore write if it was intentional |
You have exceeded a secondary rate limit on bulk for_each |
Too many runner-group writes too fast | Reduce parallelism (terraform apply -parallelism=2); retry after backoff |
Classic PAT scopes
admin:enterprise— enterprise administration (allowed-actions policy, workflow permissions)manage_runners:enterprise— enterprise self-hosted runner groups
Fine-grained PAT / GitHub App permissions
- Enterprise permissions → Actions / Enterprise administration: read/write
- Enterprise self-hosted runners: read/write
- Metadata: read
⚠️ Managing enterprise resources requires an ENTERPRISE OWNER identity — a strictly higher privilege than org admin. Auth and the target enterprise are provider concerns, never module variables.
⚠️ ENTERPRISE CLOUD ONLY. These resources require a GitHub Enterprise account (not merely an org on an Enterprise plan).applyfails with404/403on Free/Team and on standalone organizations.- The provider identity must be an enterprise owner.
enterprise_slugmust identify an enterprise the identity administers.organization_ids/selected_organization_idsare numeric org database ids belonging to the enterprise — wire fromtf-mod-github-enterprise/ the org listing.- Rate limits: runner-group
for_eachis one API write each — watch secondary rate limits on large applies.
- This module's SCOPE.md — the authoritative design contract
tf-mod-github-enterprise— sibling: enterprise org / IP-allow-list / security-analysis governance (emits the enterprise slug + org ids consumed here)tf-mod-github-actions-organization— the org-tier counterpart in the Actions familytf-mod-github-actions-runner-group— org-scope runner groups (consumerunner_group_idsfor reporting)tf-mod-github-repository— keystone module of the GitHub libraryintegrations/githubprovider —github_enterprise_actions_permissions,github_enterprise_actions_workflow_permissions,github_enterprise_actions_runner_group- GitHub Docs — enforcing GitHub Actions policies for your enterprise