Assign the minimum required Azure RBAC permissions for GitHub Actions OIDC authentication.
This step grants access for:
- workload resource deployment
- Terraform backend storage access
This step does not change the GitHub Actions workflow yet.
It only ensures the Service Principal has the correct authorization scope.
OIDC solves authentication.
RBAC solves authorization.
That means:
- GitHub Actions can authenticate to Azure via OIDC
- but Terraform still cannot do anything unless the Service Principal has the correct RBAC roles
This is a critical separation of concerns.
The Service Principal needs access to two different scopes:
| Scope | Purpose | Role |
|---|---|---|
| Workload Resource Group | deploy / read Terraform-managed resources | Contributor |
| Backend Storage Account | read / write Terraform state | Storage Blob Data Contributor |
| Backend Storage Account | read backend metadata | Reader |
Get the workload resource group ID:
$rgWlId = az group show -n rg-workload-runbook --query id -o tsv
$rgWlIdGet the backend storage account ID:
$saId = az storage account show -g rg-tfstate-runbook -n sttfstate260221me01 --query id -o tsv
$saIdExpected:
- both IDs are returned successfully
- scope paths begin with /subscriptions/...
Grant Contributor to the Service Principal on the workload resource group:
az role assignment create `
--assignee-object-id $spId `
--assignee-principal-type ServicePrincipal `
--role "Contributor" `
--scope $rgWlIdExpected:
- role assignment is created successfully
- Service Principal can manage workload resources in rg-workload-runbook
Grant Storage Blob Data Contributor on the backend storage account:
az role assignment create `
--assignee-object-id $spId `
--assignee-principal-type ServicePrincipal `
--role "Storage Blob Data Contributor" `
--scope $saIdExpected:
- role assignment is created successfully
- Service Principal can access Terraform state blobs
Grant Reader on the backend storage account:
az role assignment create `
--assignee-object-id $spId `
--assignee-principal-type ServicePrincipal `
--role "Reader" `
--scope $saIdExpected:
- role assignment is created successfully
- Service Principal can read backend storage metadata
Verify workload resource group RBAC:
az role assignment list `
--assignee-object-id $spId `
--scope $rgWlId `
--query "[].{role:roleDefinitionName, scope:scope}" `
-o tableExpected:
- Contributor
Verify backend storage RBAC:
az role assignment list `
--assignee-object-id $spId `
--scope $saId `
--query "[].{role:roleDefinitionName, scope:scope}" `
-o tableExpected:
-
Storage Blob Data Contributor
-
Reader
- Why These Roles Were Needed
During implementation, the following issue occurred:
- OIDC login succeeded
- but Terraform backend access still failed
Root cause:
- authentication was working
- authorization was incomplete
Key lesson:
- Contributor on the workload resource group is not enough
- Terraform backend access requires separate storage-scope permissions
Recommended screenshots for this step:
- Contributor role on workload resource group
- Storage Blob Data Contributor on backend storage
- Reader role on backend storage
Suggested files:
-
04_rbac_storage_blobdatacontributor.png
Notes
-
Workload scope and backend scope should remain separate.
-
This is a better design than assigning broad subscription-level permissions.
-
Storage Blob Data Contributor is required for Terraform state operations.
-
Reader was required so Terraform could correctly access backend storage metadata.
-
In larger environments, these assignments should ideally be handled via IaC or centrally managed RBAC.
Completion Criteria
Before proceeding to Step 03:
- Service Principal has Contributor on workload resource group
- Service Principal has Storage Blob Data Contributor on backend storage
- Service Principal has Reader on backend storage
- RBAC verification commands return the expected roles