Appearance
CI/CD Identity Least Privilege Audit — LPRIV-008, LPRIV-009
Audit of GitHub Actions deployment identity permissions across Azure and AWS. Completed April 2026 as part of the LPRIV least privilege workstream.
LPRIV-008 — github-deploy-main Azure RBAC
Identity: github-deploy-app (App ID: 8e01e97f-090c-45b1-9659-a99ded5d217c) Service Principal: 484de69a-ed8a-4202-b0b9-2616b91e1a67Type: Federated credential — GitHub Actions OIDC (Cirius-Group-Inc/azure-infra, main branch only)
Date audited: April 15, 2026
Azure RBAC Role Assignments
| Role | Scope | Subscription / Resource | Workflow Requirement |
|---|---|---|---|
Resource Policy Contributor | Management Group | d477c9f8 (tenant root) | Azure Policy assignment across all subscriptions |
Contributor | Subscription | Logging (3946532a) | Terraform resource management — all logging resources |
Resource Policy Contributor | Subscription | Logging (3946532a) | Azure Policy assignment in logging sub |
User Access Administrator | Subscription | Logging (3946532a) | RBAC role assignment in Terraform (managed identities) |
Contributor | Resource Group | rg-logging-logs | Scoped Terraform apply (superceded by sub-level Contributor) |
Key Vault Secrets User | Resource | cirius-openai-kv-prod | CI/CD secret reads during plan/apply |
Key Vault Secrets Officer | Resource | cirius-openai-kv-prod | Secret rotation via Terraform random_password resources |
Contributor | Subscription | Prod (db824d94) | Terraform resource management — all prod resources |
Key Vault Administrator | Subscription | Prod (db824d94) | Key Vault management plane (create vaults, set policies, manage keys) |
User Access Administrator | Subscription | Prod (db824d94) | RBAC role assignment in Terraform |
Contributor | Subscription | Firewall (0412f98f) | Terraform resource management — Palo Alto firewall infra |
Key Vault Administrator | Subscription | Firewall (0412f98f) | Key Vault management for firewall CMK |
Key Vault Crypto User | Subscription | Firewall (0412f98f) | CMK key operations |
Key Vault Reader | Subscription | Firewall (0412f98f) | Key Vault metadata reads |
User Access Administrator | Subscription | Firewall (0412f98f) | RBAC role assignments |
Contributor | Subscription | Identity (ac212528) | Terraform resource management — AD/identity resources |
Key Vault Administrator | Subscription | Identity (ac212528) | Key Vault management in identity sub |
Resource Policy Contributor | Subscription | Identity (ac212528) | Azure Policy assignment |
User Access Administrator | Subscription | Identity (ac212528) | RBAC role assignments |
Flagged: Contributor + User Access Administrator = Functional Owner
The combination of Contributor + User Access Administrator at subscription level is functionally equivalent to Owner in all four subscriptions where both are assigned. This is flagged per least privilege requirements.
Justification (from azure-infra CLAUDE.md): Terraform CI/CD requires Contributor to create and manage all resource types. User Access Administrator is required to assign managed identity RBAC roles (e.g., AcrPull, Key Vault Secrets User) via Terraform. Without UAA, role assignments would need to be pre-created out-of-band — a known Terraform limitation.
Flagged: Key Vault Administrator at Subscription Level
Key Vault Administrator grants full management plane access to all Key Vaults in a subscription. This is broader than necessary — typically only specific Key Vaults need management operations.
Proposed: Narrow Key Vault Administrator to specific Key Vault resources rather than subscription scope. This would require enumerating all KV management actions in Terraform.
Flagged: Resource Policy Contributor at Management Group Level
Resource Policy Contributor at the tenant management group allows assigning Azure Policies across all subscriptions. This is a very broad permission.
Justification: Required to assign HIPAA/HITRUST and ISO 27001 policies at management group scope via Terraform. There is no narrower built-in role.
Verdict: FLAGGED — Contributor + UAA = functional Owner across 4 subscriptions. Key Vault Administrator at subscription scope is broader than ideal. These are conscious tradeoffs for Terraform CI/CD. No immediate action — tracked for future hardening when custom role implementation is resourced.
LPRIV-009 — github-deploy-main AWS IAM
Identity: Per-account IAM roles assumed by GitHub Actions via OIDC from management account
Date audited: April 15, 2026
Role Structure
GitHub Actions assumes github-deploy-main in the management account (206820231356) via OIDC, then assumes per-account cross-account roles for operations in other accounts.
| Role | Account | Account ID | Policies |
|---|---|---|---|
github-deploy-main | Management | 206820231356 | AdministratorAccess (AWS managed) |
github-deploy-prod | Production | 807267566999 | AdministratorAccess (AWS managed) + AllowDescribeImages (custom) |
github-deploy-logging | Logging | 038901680748 | Custom scoped policies (see below) |
github-deploy-firewall | Networking | 238342914131 | (see Terraform) |
github-deploy-identity | Identity | 414134953818 | (see Terraform) |
github-deploy-backup | Backup | 863609217450 | (see Terraform) |
github-deploy-dev | Dev | 040067931468 | (see Terraform) |
Flagged: AdministratorAccess on Management and Prod Accounts
AdministratorAccess grants Action: "*" and Resource: "*" — the broadest possible AWS policy.
json
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}Flagged per LPRIV-009 requirements. Both github-deploy-main and github-deploy-prod use this policy.
Justification (from aws-infra Terraform — Checkov skip comment):Infrastructure deploy role requires AdministratorAccess for full IaC lifecycle management
The full IaC lifecycle (create, modify, delete any resource type) cannot easily be scoped without enumerating every action used by every Terraform resource. This is a conscious architectural decision.
Positive Finding: github-deploy-logging Uses Scoped Policies
The logging account deployment role (github-deploy-logging, internally org_access_role) uses custom purpose-built policies rather than AdministratorAccess:
GitHubDeployLoggingAccess-Firehose— Kinesis Firehose + CloudWatch Logs destination managementGitHubDeployLoggingAccess-Extra— additional logging-specific resource managementGitHubDeployLoggingAccess-ObjectLock— S3 Object Lock configuration for WORM compliance- Additional scoped policies per resource type
This pattern is the correct approach and should be adopted for other accounts over time.
Proposed Remediation Path
For accounts using AdministratorAccess, the logging account pattern should be the target state:
- Enable CloudTrail in the account to capture all API calls made by the deployment role
- Run 30-60 days of Terraform deployments to capture the full action surface
- Use IAM Access Advisor or CloudTrail analysis to enumerate exact actions used
- Build scoped policies per action group (EC2, RDS, IAM, S3, etc.)
- Replace
AdministratorAccesswith the scoped policy set
Effort: Large — significant engineering effort per account. Track as a separate story.
Verdict: FLAGGED — Action: "*" / Resource: "*" on management and prod accounts. github-deploy-logging is a positive exception demonstrating the right pattern. No immediate action — add to long-term hardening backlog.
Summary
| Story | Component | Flagged Items | Action |
|---|---|---|---|
| LPRIV-008 | github-deploy-app Azure RBAC | Contributor + UAA = Owner (4 subs); KV Admin at sub scope; Resource Policy Contributor at tenant | Document and track — required for IaC |
| LPRIV-009 | github-deploy-* AWS IAM | AdministratorAccess on main/prod accounts | Document and track — adopt logging account pattern per account |
Document History
| Date | Change | Author |
|---|---|---|
| April 2026 | Initial audit — LPRIV-008 and LPRIV-009 | Kobe |