WAF-SEC-020 – Least Privilege & RBAC Enforcement

Description

IAM policies MUST NOT grant wildcard actions (Action: "") combined with wildcard resources (Resource: ""). The AWS-managed AdministratorAccess policy MUST NOT be attached to roles used for automated workloads, CI/CD pipelines, or application service accounts. All IAM permissions MUST follow the principle of least privilege, granting only the minimum rights required for the intended function. Privilege escalation paths MUST be identified and eliminated using IAM Access Analyzer.

Rationale

Risk Description

Risk

Wildcard permissions allow all actions on all resources in principle and facilitate lateral movement.

Risk

Administrator roles attached to workload principals risk unintended or malicious destruction.

Requirements

  • IAM policies MUST NOT grant wildcard actions (Action: "") combined with wildcard resources (Resource: "").

  • The AWS-managed AdministratorAccess policy MUST NOT be attached to roles used for automated workloads, CI/CD pipelines, or application service accounts.

  • All IAM permissions MUST follow the principle of least privilege, granting only the minimum rights required for the intended function.

  • Privilege escalation paths MUST be identified and eliminated using IAM Access Analyzer.

Implementation Guidance

  1. Implement the required configuration as code in Terraform or equivalent IaC.

  2. Add an automated check to CI/CD so deviations are caught before deployment.

Maturity Levels

Level Name Criteria

L1

Ad hoc – control not consistently applied

* Manual evidence exists for some workloads, but coverage is unknown.

L2

Standardised – policy defined and communicated

* A version-controlled policy, ADR, or standard describes the requirement.

L3

Integrated – automated validation in CI/CD

* Terraform checks run automatically on pull requests and report results.

L4

Auditable – metrics and exceptions tracked

* Control coverage, failures, and approved exceptions are reported quarterly.

L5

Optimised – continuous improvement based on data

* Control effectiveness is measured and iteratively improved.

Checks

waf-sec-020.tf.aws.no-admin-policy-attachment

Engine: terraform | Provider: aws | Automated: Yes

AdministratorAccess managed policy must not be attached to workload IAM principals

The AWS-managed AdministratorAccess policy (arn:aws:iam::aws:policy/AdministratorAccess) must not be attached to any IAM role, user, or group used for automated workloads, applications, or CI/CD pipelines.

Scope: resource β€” aws_iam_role_policy_attachment, aws_iam_user_policy_attachment, aws_iam_group_policy_attachment

Assertions: * policy_arn not equals arn:aws:iam::aws:policy/AdministratorAccess β€” AdministratorAccess managed policy MUST NOT be attached to any IAM principal.

Remediation: Remove the AdministratorAccess attachment and replace it with a scoped IAM policy that grants only the specific actions and resources required for the workload. Use IAM Access Advisor to identify which permissions were actually used in the last 90 days as a baseline.

Compliant
resource "aws_iam_role_policy_attachment" "app_policy" {
  role       = aws_iam_role.app_role.name
  policy_arn = aws_iam_policy.app_scoped_policy.arn  # custom, least-privilege policy
}
resource "aws_iam_policy" "app_scoped_policy" {
  name = "app-scoped-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["s3:GetObject", "s3:PutObject"]
      Resource = "arn:aws:s3:::my-app-bucket/*"
    }]
  })
}
Non-Compliant
resource "aws_iam_role_policy_attachment" "bad" {
  role       = aws_iam_role.app_role.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
  # WAF-SEC-020 violation: AdministratorAccess must not be attached to workload roles
}

waf-sec-020.tf.aws.no-inline-wildcard-policy

Engine: terraform | Provider: aws | Automated: Yes

IAM policies must not combine wildcard actions with wildcard resources

Inline and managed IAM policies must not contain statements with Action: '' combined with Resource: ''. This check requires manual review or a supplementary static analysis tool (e.g., Cloudsplaining, Checkov) as Terraform plan output must be parsed for policy document content.

Scope: resource β€” aws_iam_policy, aws_iam_role_policy, aws_iam_user_policy, aws_iam_group_policy

Assertions: * policy json not contains pattern pattern "Action":\\s*"\*" β€” IAM policy must not use wildcard Action '*'. Use scoped actions instead.

Remediation: Replace wildcard actions with a specific list of required API actions. Replace wildcard resources with specific ARNs or ARN patterns. Use IAM Access Advisor to determine which actions are actually used by the role.

Compliant
resource "aws_iam_policy" "scoped" {
  name = "scoped-s3-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"]
      Resource = "arn:aws:s3:::my-bucket/*"
    }]
  })
}
Non-Compliant
resource "aws_iam_policy" "wildcard" {
  name = "bad-wildcard-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect   = "Allow"
      Action   = "*"          # WAF-SEC-020 violation
      Resource = "*"          # Combined wildcard = full admin
    }]
  })
}

waf-sec-020.tf.azurerm.no-owner-contributor-assignment

Engine: terraform | Provider: azurerm | Automated: Yes

Azure built-in Owner or Contributor roles must not be assigned to workload principals

azurerm_role_assignment resources must not use the built-in Owner or Contributor role definitions for application service principals, CI/CD pipelines, or automated workloads. Use custom or built-in roles scoped to least privilege.

Scope: resource β€” azurerm_role_assignment

Assertions: * role_definition_name not in ['Owner', 'Contributor'] β€” Owner and Contributor built-in roles must not be assigned to workload principals.

Remediation: Replace azurerm_role_assignment entries using "Owner" or "Contributor" with scoped custom roles or built-in roles that grant only the actions required (e.g., Reader, Storage Blob Contributor, Key Vault Secrets User).

Compliant
resource "azurerm_role_assignment" "app_storage" {
  scope                = azurerm_storage_account.app.id
  role_definition_name = "Storage Blob Data Contributor"
  principal_id         = azuread_service_principal.app.object_id
}
Non-Compliant
resource "azurerm_role_assignment" "bad" {
  scope                = data.azurerm_subscription.current.id
  role_definition_name = "Owner"
  principal_id         = azuread_service_principal.cicd.object_id
  # WAF-SEC-020 violation: Owner assigned to workload principal
}

waf-sec-020.tf.azurerm.custom-role-no-wildcard

Engine: terraform | Provider: azurerm | Automated: Yes

Azure custom role definitions must not include wildcard actions

azurerm_role_definition resources must not declare permissions with Action "" or NotAction "" combined with assignable scopes that grant broad access. Custom roles should list explicit actions and data actions.

Scope: resource β€” azurerm_role_definition

Assertions: * permissions not contains β€” Custom role permissions must not contain wildcard action "".

Remediation: Replace wildcard actions in azurerm_role_definition permissions blocks with explicit Microsoft.* actions required by the workload. Avoid NotAction "*" patterns.

Compliant
resource "azurerm_role_definition" "scoped" {
  name        = "App Scoped Role"
  scope       = data.azurerm_subscription.current.id
  permissions {
    actions     = ["Microsoft.Storage/storageAccounts/read"]
    not_actions = []
  }
  assignable_scopes = [data.azurerm_subscription.current.id]
}
Non-Compliant
resource "azurerm_role_definition" "wildcard" {
  name  = "Wildcard Admin"
  scope = data.azurerm_subscription.current.id
  permissions {
    actions     = ["*"]  # WAF-SEC-020 violation: wildcard action
    not_actions = []
  }
}

waf-sec-020.tf.google.no-basic-project-roles

Engine: terraform | Provider: google | Automated: Yes

GCP basic project roles must not be bound to workload principals

google_project_iam_member and google_project_iam_binding resources must not use roles/owner, roles/editor, or roles/viewer for application service accounts, CI/CD pipelines, or automated workloads.

Scope: resource β€” google_project_iam_member, google_project_iam_binding, google_organization_iam_member, google_organization_iam_binding

Assertions: * role not in ['roles/owner', 'roles/editor', 'roles/viewer'] β€” GCP basic roles must not be assigned to workload principals.

Remediation: Remove google_project_iam_member / google_project_iam_binding entries using roles/owner, roles/editor, or roles/viewer. Replace with predefined service-specific roles (e.g., roles/storage.objectAdmin) or custom roles listing only required permissions.

Compliant
resource "google_project_iam_member" "app_storage" {
  project = var.project_id
  role    = "roles/storage.objectAdmin"
  member  = "serviceAccount:${google_service_account.app.email}"
}
Non-Compliant
resource "google_project_iam_member" "bad" {
  project = var.project_id
  role    = "roles/editor"  # WAF-SEC-020 violation: overly permissive basic role
  member  = "serviceAccount:${google_service_account.cicd.email}"
}

waf-sec-020.tf.google.custom-role-no-wildcard

Engine: terraform | Provider: google | Automated: Yes

GCP custom IAM roles must not include wildcard permissions

google_project_iam_custom_role and google_organization_iam_custom_role resources must not include "*" in their permissions list. Permissions should be explicit GCP service methods.

Scope: resource β€” google_project_iam_custom_role, google_organization_iam_custom_role

Assertions: * permissions not contains β€” Custom role permissions must not contain wildcard "".

Remediation: Replace wildcard permissions in google_project_iam_custom_role with explicit permissions required by the workload. Audit the custom role using IAM Policy Analyzer or gcloud iam roles list.

Compliant
resource "google_project_iam_custom_role" "scoped" {
  project = var.project_id
  role_id = "appScoped"
  title   = "App Scoped Role"
  permissions = [
    "storage.objects.get",
    "storage.objects.create",
  ]
}
Non-Compliant
resource "google_project_iam_custom_role" "wildcard" {
  project = var.project_id
  role_id = "wildcardAdmin"
  title   = "Wildcard Admin"
  permissions = ["*"]  # WAF-SEC-020 violation: wildcard permission
}

waf-sec-020.config.stackit.stackit-identity-access

Engine: config | Provider: stackit | Automated: Yes

STACKIT access controls must follow least privilege and be documented

A version-controlled policy document must exist at docs/security/waf-sec-020-stackit-identity-access.md and document the STACKIT implementation of this control. The checker validates that the file exists and contains a normative requirement statement (MUST/SHALL/required/mandatory).

Scope: file β€” docs/security/waf-sec-020-stackit-identity-access.md

Assertions: * content matches pattern (?i)MUST|SHALL|required|mandatory|enforced|documented β€” Policy file docs/security/waf-sec-020-stackit-identity-access.md must contain a normative requirement statement.

Remediation: Create or update docs/security/waf-sec-020-stackit-identity-access.md. State the requirement, how it is implemented for STACKIT, the review cadence, and the owner.

Compliant
docs/security/waf-sec-020-stackit-identity-access.md:
- The STACKIT implementation of WAF-SEC-020 is documented.
- Implementation status and owner are recorded.
- Review cadence is defined (e.g. quarterly).
Non-Compliant
# `docs/security/waf-sec-020-stackit-identity-access.md` is missing or does not contain a normative requirement.
# WAF-SEC-020 violation: STACKIT control is not documented

waf-sec-020.config.ovh.ovh-identity-access

Engine: config | Provider: ovh | Automated: Yes

OVHcloud accounts and API keys must follow least privilege

A version-controlled policy document must exist at docs/security/waf-sec-020-ovh-identity-access.md and document the OVHcloud implementation of this control. The checker validates that the file exists and contains a normative requirement statement (MUST/SHALL/required/mandatory).

Scope: file β€” docs/security/waf-sec-020-ovh-identity-access.md

Assertions: * content matches pattern (?i)MUST|SHALL|required|mandatory|enforced|documented β€” Policy file docs/security/waf-sec-020-ovh-identity-access.md must contain a normative requirement statement.

Remediation: Create or update docs/security/waf-sec-020-ovh-identity-access.md. State the requirement, how it is implemented for OVHcloud, the review cadence, and the owner.

Compliant
docs/security/waf-sec-020-ovh-identity-access.md:
- The OVHcloud implementation of WAF-SEC-020 is documented.
- Implementation status and owner are recorded.
- Review cadence is defined (e.g. quarterly).
Non-Compliant
# `docs/security/waf-sec-020-ovh-identity-access.md` is missing or does not contain a normative requirement.
# WAF-SEC-020 violation: OVHcloud control is not documented

waf-sec-020.config.hcloud.hcloud-identity-access

Engine: config | Provider: hcloud | Automated: Yes

Hetzner Cloud project roles and API tokens must follow least privilege

A version-controlled policy document must exist at docs/security/waf-sec-020-hcloud-identity-access.md and document the Hetzner Cloud implementation of this control. The checker validates that the file exists and contains a normative requirement statement (MUST/SHALL/required/mandatory).

Scope: file β€” docs/security/waf-sec-020-hcloud-identity-access.md

Assertions: * content matches pattern (?i)MUST|SHALL|required|mandatory|enforced|documented β€” Policy file docs/security/waf-sec-020-hcloud-identity-access.md must contain a normative requirement statement.

Remediation: Create or update docs/security/waf-sec-020-hcloud-identity-access.md. State the requirement, how it is implemented for Hetzner Cloud, the review cadence, and the owner.

Compliant
docs/security/waf-sec-020-hcloud-identity-access.md:
- The Hetzner Cloud implementation of WAF-SEC-020 is documented.
- Implementation status and owner are recorded.
- Review cadence is defined (e.g. quarterly).
Non-Compliant
# `docs/security/waf-sec-020-hcloud-identity-access.md` is missing or does not contain a normative requirement.
# WAF-SEC-020 violation: Hetzner Cloud control is not documented

Evidence

Kind Required Description

iac

Required

Terraform configuration implementing the control.

governance

Required

Policy, ADR, or standard documenting the requirement.

config

Optional

Cloud console or API output confirming runtime state.

Framework Controls

ISO 27001:2022

* A.8.2 – Privileged access rights * A.8.3 – Information access restriction * A.5.15 – Access control * A.5.18 – Access rights

ISO 27017

* CLD.9.5 – Segregation in virtual computing environments

CIS Controls v8

* CIS 5 – Account Management * CIS 6 – Access Control Management

CSA STAR

* CCM IAM-09 – User Access Authorization * CCM IAM-10 – User Access Reviews

PCI DSS v4.0

* Req 7.2 – Establish access based on least privilege

SOC 2 Type II

* CC6.1 – Logical access security * CC6.3 – Authorisation and segregation of duties

GDPR

* Art. 32 – Security of processing * Art. 5(1)(f) – Integrity and confidentiality * Art. 25 – Data protection by design

NIS2

* Art. 21(2)(i) – Access control measures

DORA

* Art. 9 – Protection and prevention

EUCS (ENISA)

* IAM-01 – Identity and access management * IAM-03 – Least privilege access control

BSI C5:2020

* IDM-01 – Identity and access management policy * IDM-03 – Access control and authorisation * IDM-09 – Privileged access management

IT-Grundschutz

* ORP.4 – IdentitΓ€ts- und Berechtigungsmanagement

TISAX

* Information security – Access rights management

ANSSI SecNumCloud

* Domain – Access management and least privilege

BIO

* BIO – Toegangsrechten en autorisatiebeheer

ENS High

* op.acc.4 – Proceso de gestiΓ³n de derechos de acceso * op.acc.7 – GestiΓ³n de privilegios

UK Cyber Essentials

* CE.UAC – User access control

UK NCSC CAF

* B2.a – Identity verification, authentication and authorisation

UK GDPR

* Art. 32 – Security of processing

NIST SP 800-53

* AC-2 – Account Management * AC-3 – Access Enforcement * AC-6 – Least Privilege

NIST CSF 2.0

* PR.AA-05 – Access permissions and authorizations are managed

FedRAMP

* AC-2, AC-3, AC-6 (Moderate/High baseline)

CMMC 2.0

* AC.L2-3.1.5 – Employ the principle of least privilege

ASD Essential 8

* E8.5 – Restrict administrative privileges

IRAP

* ISM – Access control – Privileged access

CCCS PBMM

* AC-6 – Least privilege

MAS TRM

* Ch.6 – Access control

ISMAP

* Access control – Least privilege

FISC

* Technical measures – Authorisation management