Terraform security role assignments can provide strong ISO 27001 audit evidence when role-to-group mappings, approvals, deployment logs, and periodic membership reviews are kept in a controlled repository and pipeline. Terraform should define and apply approved technical role allocations, while your evidence package must also show who owns each role, why it exists, who can join the assigned group, and how exceptions are reviewed. This supports ISO 27001 control 5.2, which requires that information security roles and responsibilities be defined and allocated according to organizational needs.[1]
What can Terraform automate, and what still requires a person?
For an IT manager preparing for certification, the useful distinction is between implementing a role allocation and governing it. Terraform is excellent at making approved allocations repeatable and detectable. It cannot decide whether a person is appropriate for a sensitive responsibility or whether two responsibilities create an unacceptable segregation-of-duties conflict.
| Activity | Can automation perform it? | Evidence value for ISO 27001 5.2 |
|---|---|---|
| Create a security group and assign it an Entra ID directory role | Yes, through Terraform | Shows the defined technical allocation and the exact configuration version. |
| Prevent unreviewed production changes | Yes, with pull requests, protected branches, and deployment approvals | Shows authorization before allocation changes are applied. |
| Record the role owner, purpose, review period, and ticket | Partly; store metadata in code and enforce required fields in review | Connects a platform permission to an assigned security responsibility. |
| Determine whether an employee should be in the Incident Managers group | No | Requires manager approval, role suitability assessment, and HR or identity workflow evidence. |
| Assess conflicting duties and emergency access | No, although rules can flag known conflicts | Requires documented risk acceptance or separation-of-duties approval. |
| Capture current group membership for review | Yes, as a scheduled export | Shows that the allocated responsibility remains assigned to appropriate people. |
Use code to make the technical baseline deterministic: a defined group receives a defined directory role, and changes can occur only through reviewed configuration. Keep individual membership in your identity lifecycle platform, such as Okta or Entra ID access packages, where joiner-mover-leaver approvals are retained. That separation prevents Terraform state from becoming an improvised HR system while preserving traceable responsibility allocation.
How do terraform security role assignments create usable audit evidence?
A practical pattern is to assign privileged directory roles to security groups rather than named users. The group becomes the technical expression of a documented responsibility, such as Security Incident Manager or Identity Security Administrator. The code below uses Microsoft Entra ID because it provides a common example of a centrally governed identity platform; the same evidence pattern applies to AWS IAM Identity Center permission sets, Google Cloud IAM groups, and SaaS administration roles.
At Brightpath Systems, a 240-person SaaS company using Microsoft 365, GitHub Enterprise Cloud, Jira Service Management, and AWS, the security team defined an ISO27001-Security-Incident-Managers group. The documented owner is the Director of Security Operations, membership is approved in Jira, and the group receives the Entra Security Administrator directory role. Terraform does not add employees to the group; it establishes and preserves the approved role allocation.
terraform {
required_version = ">= 1.6.0"
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "~> 3.0"
}
}
}
provider "azuread" {
tenant_id = var.tenant_id
}
resource "azuread_group" "security_incident_managers" {
display_name = "ISO27001-Security-Incident-Managers"
description = "ISO 27001 5.2: security incident coordination role. Owner: Director of Security Operations. Review: quarterly."
security_enabled = true
mail_enabled = false
prevent_duplicate_names = true
}
resource "azuread_directory_role" "security_administrator" {
template_id = "194ae4cb-b126-40b2-bd5b-6091b380977d"
}
resource "azuread_directory_role_assignment" "incident_manager_security_admin" {
role_id = azuread_directory_role.security_administrator.template_id
principal_object_id = azuread_group.security_incident_managers.object_id
}
output "iso27001_role_allocations" {
value = {
control = "ISO 27001:2022 5.2"
responsibility = "Security incident coordination"
role_owner = "director-security-operations@brightpath.example"
assignment_group = azuread_group.security_incident_managers.display_name
directory_role = "Security Administrator"
review_frequency = "Quarterly"
approval_system = "Jira Service Management"
evidence_repository = "github.com/brightpath/security-role-baseline"
}
}
The meaningful evidence is not merely the Terraform file. An auditor should be able to follow the chain from the responsibility definition to the approved change, applied resource, current group membership, and periodic review. Store the responsibility statement and role owner in a controlled role catalogue, either in the repository or in your GRC system. Reference the catalogue identifier in the pull request and change ticket.
Before production deployment, run a plan and export a concise evidence record. Avoid publishing a full Terraform state file as an artifact because state may contain sensitive identifiers, secrets, or unrelated infrastructure details.
#!/usr/bin/env bash
set -euo pipefail
mkdir -p evidence
terraform init -input=false
terraform plan -out=tfplan -input=false
terraform apply -input=false tfplan
terraform output -json iso27001_role_allocations \
> evidence/role-allocation.json
cat > evidence/deployment-manifest.txt <<EOF
control=ISO 27001:2022 5.2
repository=${GITHUB_REPOSITORY}
commit=${GITHUB_SHA}
workflow_run=${GITHUB_RUN_ID}
applied_utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
terraform_version=$(terraform version -json | jq -r '.terraform_version')
EOF
How should this run in CI/CD or scheduled jobs?
Run plans on every pull request and apply only from a protected production branch after an approver validates the business justification. For an audit, branch protection and environment approval are as important as the successful apply: they demonstrate that privileged access design changes are reviewed before implementation.
name: Apply security role baseline
on:
push:
branches: [main]
paths:
- "identity/roles/**"
schedule:
- cron: "15 6 * * 1"
jobs:
apply-and-evidence:
runs-on: ubuntu-24.04
environment: production-identity
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.8.5
- name: Authenticate using workload identity
run: az login --identity
- name: Plan, apply, and collect evidence
working-directory: identity/roles
run: ./apply-and-collect-evidence.sh
- name: Retain audit evidence
uses: actions/upload-artifact@v4
with:
name: iso27001-role-allocation-$
path: identity/roles/evidence/
retention-days: 365
The weekly scheduled run should normally produce a no-change plan. That result is useful evidence: it shows the declared allocation remained in force and detects drift caused by a direct portal change. Configure the Terraform backend with encryption, locking, and restricted access; the backend itself is part of the control environment because it holds the authoritative deployed configuration.
What monitoring and alerting hooks should accompany role automation?
Terraform detects drift when it runs, but it is not a real-time monitoring tool. Pair the Terraform baseline with Entra ID audit-log alerts for directory role assignment changes and privileged group membership changes. Send alerts to the security operations queue and create a Jira ticket automatically when the actor is not the approved deployment identity.
- Alert on additions or removals from
ISO27001-Security-Incident-Managers. - Alert on activation, deletion, or assignment changes for the Security Administrator directory role.
- Alert when a Terraform scheduled plan reports changes outside an approved pull request window.
- Export a monthly group-membership snapshot and require the named role owner to attest to it quarterly.
- Retain alert records, investigation tickets, and approved exception records with the role allocation evidence.
For Brightpath Systems, the membership snapshot is compared with approved Jira access requests. A member found in the group without an approved request triggers an incident, even if the Terraform-managed directory role itself has not changed. This closes the gap between role design evidence and actual responsibility allocation evidence.
How should you handle failed applies, drift, and emergency changes?
| Failure mode | Immediate response | Evidence to retain |
|---|---|---|
| Terraform plan shows unexpected removal of a privileged assignment | Stop the apply, investigate the source change, and require a new approval. | Failed plan, pull request discussion, corrective ticket, and final approved plan. |
| Direct administrator change causes drift | Open an incident, determine whether the change was authorized, then reconcile through code or formally accept the exception. | Audit-log event, incident record, approval, and reconciliation commit. |
| Pipeline identity loses permission or backend lock fails | Do not bypass controls with a personal administrator account; restore the workload identity or follow the emergency process. | Pipeline log, access restoration ticket, and post-incident review. |
| Urgent incident requires temporary privileged access | Use time-bound privileged access management, document the approver, and review removal after the incident. | Emergency ticket, activation log, expiry record, and retrospective approval. |
Do not automatically apply every detected drift correction. A change may reflect an emergency response, a provider-side platform change, or an unauthorized action. Require a human to classify the event, preserve the original evidence, and decide whether the declared baseline or the live configuration should become authoritative.
Start by selecting one high-impact security responsibility, mapping its owner and review cadence, and putting its group-to-role allocation through your approved Terraform pipeline before expanding the pattern to other privileged roles.