WAF-SEC-010 – Identity & Access Management Baseline

Description

All AWS accounts MUST enforce MFA for all IAM users with console access. Root account usage MUST be prohibited for day-to-day operations. IAM password policy MUST meet minimum security requirements: minimum length of 14 characters, complexity requirements, password reuse prevention of at least 5 prior passwords, and maximum password age of 90 days. Service accounts MUST use IAM roles with temporary credentials rather than long-lived access keys wherever possible.

Rationale

Risk Description

Risk

Accounts without MFA can be compromised through stolen passwords or phishing.

Risk

Permanent root or user access keys enable undetected persistence and data exfiltration.

Requirements

  • All AWS accounts MUST enforce MFA for all IAM users with console access.

  • Root account usage MUST be prohibited for day-to-day operations.

  • IAM password policy MUST meet minimum security requirements: minimum length of 14 characters, complexity requirements, password reuse prevention of at least 5 prior passwords, and maximum password age of 90 days.

  • Service accounts MUST use IAM roles with temporary credentials rather than long-lived access keys wherever possible.

Implementation Guidance

  1. Document the requirement in a version-controlled policy or standard.

  2. Assign ownership and establish a review cadence (e.g., quarterly).

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

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-010.tf.aws.iam-password-policy-mfa

Engine: terraform | Provider: aws | Automated: Yes

AWS IAM account password policy must meet minimum security requirements

The aws_iam_account_password_policy resource must enforce a minimum password length of 14, all character class requirements, a minimum of 5 passwords in reuse prevention history, and a maximum password age of 90 days.

Scope: resource β€” aws_iam_account_password_policy

Assertions: * minimum_password_length greater than or equal 14 β€” IAM password policy must require a minimum of 14 characters. * require_uppercase_characters is true β€” IAM password policy must require uppercase characters. * require_lowercase_characters is true β€” IAM password policy must require lowercase characters. * require_numbers is true β€” IAM password policy must require numbers. * require_symbols is true β€” IAM password policy must require symbols. * password_reuse_prevention greater than or equal 5 β€” IAM password policy must prevent reuse of at least 5 prior passwords. * max_password_age less than or equal 90 β€” IAM password policy must set maximum password age to 90 days or less.

Remediation: Define an aws_iam_account_password_policy resource with all required attributes set. Ensure minimum_password_length >= 14, all require_* flags are true, password_reuse_prevention >= 5, and max_password_age ⇐ 90.

Compliant
resource "aws_iam_account_password_policy" "strict" {
  minimum_password_length        = 14
  require_uppercase_characters   = true
  require_lowercase_characters   = true
  require_numbers                = true
  require_symbols                = true
  allow_users_to_change_password = true
  max_password_age               = 90
  password_reuse_prevention      = 5
  hard_expiry                    = false
}
Non-Compliant
resource "aws_iam_account_password_policy" "weak" {
  minimum_password_length      = 8
  require_uppercase_characters = false
  require_symbols              = false
  # Missing password_reuse_prevention and max_password_age
}

waf-sec-010.tf.aws.no-root-access-keys

Engine: terraform | Provider: aws | Automated: Yes

Root account must not have active access keys

The AWS root account must not have active programmatic access keys. This cannot be fully checked in Terraform state but must be validated via AWS IAM credential report or Security Hub control IAM.4.

Scope: resource β€” aws_iam_user

Assertions: * name not equals root β€” Root account must not be managed as a regular IAM user resource. Remove root access keys via AWS Console.

Remediation: Navigate to AWS IAM > Security Credentials for the root account and delete all access keys. Enable MFA on the root account. Restrict root account usage to only tasks that absolutely require it (e.g., account closure, enabling MFA for the first time).

Compliant
# Root access keys are removed via AWS Console – not representable in Terraform.
# Verify with: aws iam get-account-summary | grep AccountAccessKeysPresent
# Expected: "AccountAccessKeysPresent": 0
Non-Compliant
# Root account has active access keys visible in AWS IAM > Security Credentials.
# aws iam get-account-summary output shows "AccountAccessKeysPresent": 1

waf-sec-010.tf.azurerm.conditional-access-mfa

Engine: terraform | Provider: azurerm | Automated: Yes

Azure AD Conditional Access must require MFA for privileged directory roles

An azuread_conditional_access_policy resource must target privileged Entra ID directory roles and require multi-factor authentication via grant_controls.

Scope: resource β€” azuread_conditional_access_policy

Assertions: * state equals enabled β€” Conditional Access policy must be enabled. * grant_controls attribute exists β€” Conditional Access policy must define grant_controls requiring MFA.

Remediation: Create an azuread_conditional_access_policy that includes privileged directory roles (e.g., Global Administrator, Privileged Role Administrator) and sets grant_controls built_in_controls to "mfa". Keep the policy state set to "enabled".

Compliant
resource "azuread_conditional_access_policy" "privileged_mfa" {
  display_name = "MFA for privileged roles"
  state        = "enabled"
  conditions {
    users {
      included_roles = [
        "62e90394-69f5-4237-9190-012177145e10",
        "e8611ab8-c189-46df-93df-1fe90f8e42a1",
      ]
    }
    applications {
      included_applications = ["All"]
    }
  }
  grant_controls {
    operator          = "OR"
    built_in_controls = ["mfa"]
  }
}
Non-Compliant
# No azuread_conditional_access_policy requires MFA for privileged directory roles.
# WAF-SEC-010 violation: privileged Entra ID accounts lack mandatory MFA

waf-sec-010.tf.google.project-owner-binding-mfa-ready

Engine: terraform | Provider: google | Automated: Yes

GCP project Owner bindings must be limited and coupled with documented MFA enforcement

GCP does not represent MFA policy directly in Terraform, but IAM policy bindings for project owners must be explicitly listed and limited to a small set of principals. A guardrail google_organization_policy can restrict domain sharing, and identities must come from a workspace/Cloud Identity tenant where 2-Step Verification is enforced.

Scope: resource β€” google_project_iam_policy, google_project_iam_binding, google_project_iam_member

Assertions: * role not equals roles/owner β€” GCP project-level Owner role should not be assigned via Terraform; prefer fine-grained roles. * members attribute exists β€” IAM binding must enumerate members explicitly so ownership is auditable.

Remediation: Limit google_project_iam_binding and google_project_iam_member resources using the Owner role (roles/owner) to a small whitelist. Enforce 2-Step Verification at the Cloud Identity / Workspace level. Document the exception and review process.

Compliant
data "google_iam_policy" "project" {
  binding {
    role = "roles/owner"
    members = [
      "user:admin@example.com",
    ]
  }
}

resource "google_project_iam_policy" "policy" {
  project     = var.project_id
  policy_data = data.google_iam_policy.project.policy_data
}

# Enforced in Workspace Admin console:
# Security > Authentication > 2-Step Verification > Enforcement > ON
Non-Compliant
resource "google_project_iam_binding" "owner" {
  project = var.project_id
  role    = "roles/owner"
  members = [
    "user:anyone@example.com",
    "serviceAccount:sa@example.iam.gserviceaccount.com",
  ]
}

waf-sec-010.tf.stackit.organization-owner-limit

Engine: terraform | Provider: stackit | Automated: Yes

STACKIT organization and project owners must be limited and documented

STACKIT Owner and Organization Owner roles grant full administrative access. These bindings must be explicitly declared in Terraform and restricted to a small set of principals. MFA is enforced at STACKIT console level and reviewed via quarterly access review.

Scope: resource β€” stackit_authorization_grant, stackit_resourcemanager_project_membership

Assertions: * role not in ['Owner', 'Organization Owner'] β€” STACKIT Owner/Organization Owner role must not be assigned to broad groups. * subject not matches pattern ^group: β€” STACKIT owner grants must target individual users, not generic groups.

Remediation: Limit stackit_resourcemanager_project_membership and stackit_authorization_grant resources that assign Owner or Organization Owner roles. Maintain a version-controlled allowlist and review it quarterly.

Compliant
resource "stackit_authorization_grant" "org_owner" {
  resource_id = var.stackit_organization_id
  subject     = "user:admin@example.com"
  role        = "Organization Owner"
}

# MFA is mandatory in STACKIT IAM settings for console users.
# Review documented in docs/security/access-reviews.md
Non-Compliant
resource "stackit_authorization_grant" "org_owner" {
  resource_id = var.stackit_organization_id
  subject     = "group:all-employees@example.com"
  role        = "Organization Owner"
}

waf-sec-010.tf.ovh.account-mfa-via-policy

Engine: terraform | Provider: ovh | Automated: Yes

OVHcloud IAM policy must enforce MFA for sensitive operations

OVHcloud IAM policies can require MFA for sensitive actions (e.g., managing payment, identity, or critical services). Terraform ovh_me_identity_policy resources must include an MFA condition for actions affecting account security.

Scope: resource β€” ovh_me_identity_policy

Assertions: * identities attribute exists β€” OVHcloud identity policy must enumerate identities explicitly. * rules attribute exists β€” OVHcloud identity policy must define rules.

Remediation: Create an OVHcloud IAM policy with a condition requiring MFA for critical actions. Document the policy and the list of protected actions in a version-controlled standard.

Compliant
resource "ovh_me_identity_policy" "sensitive_mfa" {
  name = "sensitive-ops-mfa"
  identities = [
    "user:admin@example.com",
  ]
  rules {
    action = "account:.*"
    effect = "allow"
    resources {
      resource {
        id    = "*"
        type  = "account"
        label = "*"
      }
    }
  }
  rules {
    action    = ".*"
    effect    = "deny"
    resources { resource { id = "*"; type = "*"; label = "*" } }
  }
  # MFA is required by an organization-wide setting documented in docs/security/ovh-iam.md
}
Non-Compliant
# No OVHcloud IAM policy requires MFA for sensitive account actions.
# MFA is not documented as enforced in the OVHcloud Control Panel.

waf-sec-010.tf.hcloud.console-mfa-ready

Engine: terraform | Provider: hcloud | Automated: Yes

Hetzner Cloud project members must be individual users with MFA documented

Hetzner Cloud projects do not expose MFA state in Terraform, but project memberships must target individual users (not robots) and be limited to required roles. MFA is enforced in the Hetzner Cloud Console and confirmed by quarterly access review.

Scope: resource β€” hcloud_project_membership

Assertions: * user_email not matches pattern ^shared-.|.@.*-shared\. β€” Hetzner Cloud project membership must not use shared mailboxes. * role not equals admin β€” Hetzner Cloud project membership should use the minimum role; avoid 'admin' where possible.

Remediation: Declare hcloud_project_membership resources only for named user accounts with minimum required roles. Disable or remove inactive members. Document MFA enablement and review cadence.

Compliant
resource "hcloud_project" "prod" {
  name        = "production"
  description = "Production workloads"
}

resource "hcloud_project_membership" "admin" {
  project_id = hcloud_project.prod.id
  user_email = "admin@example.com"
  role       = "admin"
}

# MFA enabled for all project members via Hetzner Cloud Console.
# Quarterly review recorded in docs/security/access-reviews.md
Non-Compliant
resource "hcloud_project_membership" "admin" {
  project_id = hcloud_project.prod.id
  user_email = "shared-inbox@example.com"
  role       = "admin"
}

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.5 – Secure authentication * A.5.17 – Authentication information * A.5.15 – Access control

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-01 – Identity and Access Management Policy * CCM IAM-02 – Strong Password Policy and Procedures

PCI DSS v4.0

* Req 7 – Restrict access by business need to know * Req 8 – Identify and authenticate access

SOC 2 Type II

* CC6.1 – Logical and physical access controls * CC6.2 – Provisioning and removal of access * CC6.3 – Authentication mechanisms

GDPR

* Art. 32 – Security of processing * Art. 5(1)(f) – Integrity and confidentiality

NIS2

* Art. 21(2)(i) – Human resources security and access control

DORA

* Art. 9 – Protection and prevention

EUCS (ENISA)

* IAM-01 – Identity and access management * IAM-02 – Authentication controls

BSI C5:2020

* IDM-01 – Identity and access management policy * IDM-02 – Authentication of users * IDM-09 – Privileged access rights

IT-Grundschutz

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

TISAX

* Information security – Identity and access management requirements

ANSSI SecNumCloud

* Domain – Identity and access management

BIO

* BIO – Logische toegangsbeveiliging (logical access control)

ENS High

* op.acc.5 – Mecanismo de autenticaciΓ³n * op.acc.7 – GestiΓ³n de privilegios

UK Cyber Essentials

* CE.UAC – User access control

UK NCSC CAF

* B2 – Identity and access control

UK GDPR

* Art. 32 – Security of processing

NIST SP 800-53

* AC-2 – Account Management * IA-2 – Identification and Authentication * IA-5 – Authenticator Management

NIST CSF 2.0

* PR.AA-01 – Identities and credentials are managed * PR.AA-03 – Users, services and hardware are authenticated

FedRAMP

* AC-2, IA-2, IA-5 (Moderate/High baseline)

CMMC 2.0

* AC.L2-3.1.1 – Limit system access to authorized users * IA.L2-3.5.3 – Multifactor authentication

ASD Essential 8

* E8.5 – Restrict administrative privileges * E8.7 – Multi-factor authentication

IRAP

* ISM – Identification and authentication

CCCS PBMM

* AC-2, IA-2, IA-5 – Account and authenticator management

MAS TRM

* Ch.6 – Access control

ISMAP

* Identity and access management controls

FISC

* Technical measures – User authentication and access control