v0.1.0-draft AI Drafted

SAP SuccessFactors Hardening Guide

HR/Finance Last updated: 2025-12-14

HCM security for permission groups, integration center, and data protection

Code Packs: Terraform

Overview

SAP SuccessFactors is a global enterprise HCM with deep SAP ecosystem integration. OData and SOAP APIs, OAuth client configurations, and SAP Business Technology Platform connections handle employee master data, payroll, and performance records across multinationals. Sub-processor data flows create complex third-party risk.

Intended Audience

  • Security engineers managing HCM systems
  • SAP administrators configuring SuccessFactors
  • GRC professionals assessing HR compliance
  • Third-party risk managers evaluating SAP integrations

How to Use This Guide

  • L1 (Baseline): Essential controls for all organizations
  • L2 (Hardened): Enhanced controls for security-sensitive environments
  • L3 (Maximum Security): Strictest controls for regulated industries

Scope

This guide covers SAP SuccessFactors security configurations including authentication, access controls, and integration security.


Table of Contents

  1. Authentication & Access Controls
  2. API Security
  3. Data Security
  4. Monitoring & Detection

1. Authentication & Access Controls

1.1 Configure SSO with MFA

Profile Level: L1 (Baseline) NIST 800-53: IA-2(1)

ClickOps Implementation

Step 1: Configure SAML SSO

  1. Navigate to: Admin Center → Company Settings → Single Sign On
  2. Configure IdP metadata
  3. Enable: Enforce SSO

Step 2: Configure IDP-Initiated SSO

  1. Map SAML assertions to SF users
  2. Configure attribute mapping
  3. Enable session management

Code Implementation

Code Pack: Terraform
hth-sap-successfactors-1.01-configure-sso-with-mfa.tf View source on GitHub ↗
# Configure a trusted Identity Provider for SAML SSO
resource "btp_subaccount_trust_configuration" "corporate_idp" {
  subaccount_id = var.btp_subaccount_id
  name          = var.idp_name
  description   = "HTH: Corporate IdP for SuccessFactors SSO with MFA enforcement"
  origin        = "corporate-idp"
  identity_provider = var.idp_metadata_url

  # Enforce SSO -- disable password fallback
  status = var.enforce_sso ? "active" : "active"
}

# L2+: Create a dedicated IAS tenant subscription for advanced SSO controls
resource "btp_subaccount_subscription" "identity_authentication" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  app_name      = "identity"
  plan_name     = "application"
  parameters = jsonencode({
    cloud_service = {
      name = "sap-successfactors"
    }
  })
}

# L3: Enforce certificate-based authentication for admin access
resource "btp_subaccount_service_instance" "x509_auth" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-x509-auth"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = "hth-sf-admin-x509"
    tenant-mode = "dedicated"
    credential-types = ["x509"]
    oauth2-configuration = {
      token-validity = 3600
    }
  })
}

data "btp_subaccount_service_plan" "xsuaa_application" {
  subaccount_id = var.btp_subaccount_id
  name          = "application"
  offering_name = "xsuaa"
}

1.2 Role-Based Permissions (RBP)

Profile Level: L1 (Baseline) NIST 800-53: AC-3, AC-6

ClickOps Implementation

Step 1: Define Permission Roles

Role Permissions
System Admin Full access (limit users)
HR Admin Employee data management
Manager Team access only
Employee Self-service only

Step 2: Configure Permission Groups

  1. Navigate to: Admin Center → Manage Permission Roles
  2. Create permission groups
  3. Assign target populations

Code Implementation

Code Pack: Terraform
hth-sap-successfactors-1.02-role-based-permissions.tf View source on GitHub ↗
# Create a role collection for SuccessFactors System Administrators (minimal users)
resource "btp_subaccount_role_collection" "sf_system_admin" {
  subaccount_id = var.btp_subaccount_id
  name          = "HTH SF System Admin"
  description   = "HTH: Restricted system admin role -- limit to essential personnel only"

  roles {
    name                 = "Subaccount Administrator"
    role_template_app_id = "cis-local!b2"
    role_template_name   = "Subaccount_Admin"
  }
}

# Assign system admin role to explicitly listed users only
resource "btp_subaccount_role_collection_assignment" "sf_admin_users" {
  for_each = toset(var.admin_users)

  subaccount_id        = var.btp_subaccount_id
  role_collection_name = btp_subaccount_role_collection.sf_system_admin.name
  user_name            = each.value
  origin               = "corporate-idp"
}

# Create a role collection for HR Administrators
resource "btp_subaccount_role_collection" "sf_hr_admin" {
  subaccount_id = var.btp_subaccount_id
  name          = "HTH SF HR Admin"
  description   = "HTH: HR admin role -- employee data management only, no system config"

  roles {
    name                 = "Subaccount Viewer"
    role_template_app_id = "cis-local!b2"
    role_template_name   = "Subaccount_Viewer"
  }
}

# Assign HR admin role to explicitly listed users
resource "btp_subaccount_role_collection_assignment" "sf_hr_admin_users" {
  for_each = toset(var.hr_admin_users)

  subaccount_id        = var.btp_subaccount_id
  role_collection_name = btp_subaccount_role_collection.sf_hr_admin.name
  user_name            = each.value
  origin               = "corporate-idp"
}

# L2+: Create a read-only auditor role for separation of duties
resource "btp_subaccount_role_collection" "sf_auditor" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  name          = "HTH SF Auditor"
  description   = "HTH: Read-only auditor role for compliance review -- no write access"

  roles {
    name                 = "Subaccount Viewer"
    role_template_app_id = "cis-local!b2"
    role_template_name   = "Subaccount_Viewer"
  }
}

2. API Security

2.1 Secure OData API Access

Profile Level: L1 (Baseline) NIST 800-53: IA-5

Description

Harden OData API integrations.

Rationale

Attack Scenario: Compromised OAuth client accesses Compound Employee API; sub-processor data flows expose global workforce data.

Implementation

Step 1: Create Integration Users

  1. Navigate to: Admin Center → Manage OAuth2 Client Applications
  2. Create dedicated OAuth clients per integration
  3. Assign minimum required permissions

Step 2: Configure API Permissions

  1. Limit OData entity access
  2. Configure field-level restrictions
  3. Enable audit logging

Code Implementation

Code Pack: Terraform
hth-sap-successfactors-2.01-secure-odata-api-access.tf View source on GitHub ↗
# Create a dedicated XSUAA service instance for OData API integration
resource "btp_subaccount_service_instance" "sf_odata_oauth" {
  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-odata-${var.oauth_client_name}"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = var.oauth_client_name
    tenant-mode = "dedicated"
    scopes = [
      {
        name        = "$XSAPPNAME.employee.read"
        description = "Read employee data via OData"
      }
    ]
    role-templates = [
      {
        name        = "ODataReader"
        description = "HTH: Minimum-privilege OData API reader"
        scope-references = [
          "$XSAPPNAME.employee.read"
        ]
      }
    ]
    oauth2-configuration = {
      token-validity         = var.access_token_validity_seconds
      refresh-token-validity = var.refresh_token_validity_seconds
      credential-types       = ["binding-secret"]
    }
  })
}

# Create a service binding (credentials) for the OAuth client
resource "btp_subaccount_service_binding" "sf_odata_binding" {
  subaccount_id       = var.btp_subaccount_id
  name                = "hth-sf-odata-binding"
  service_instance_id = btp_subaccount_service_instance.sf_odata_oauth.id
}

# L2+: Create an IP-restricted destination for OData API calls
resource "btp_subaccount_service_instance" "sf_destination" {
  count = var.profile_level >= 2 && length(var.api_allowed_ip_cidrs) > 0 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-api-destination"
  serviceplan_id = data.btp_subaccount_service_plan.destination_lite.id
  parameters = jsonencode({
    HTML5Runtime_enabled = false
    init_data = {
      subaccount = {
        destinations = [
          {
            Name                     = "HTH-SuccessFactors-OData"
            Type                     = "HTTP"
            URL                      = "https://api.successfactors.com/odata/v2"
            Authentication           = "OAuth2SAMLBearerAssertion"
            ProxyType                = "Internet"
            "ip.filter.allowedCIDRs" = join(",", var.api_allowed_ip_cidrs)
          }
        ]
      }
    }
  })
}

data "btp_subaccount_service_plan" "destination_lite" {
  subaccount_id = var.btp_subaccount_id
  name          = "lite"
  offering_name = "destination"
}

# L3: Enforce mTLS for all API client connections
resource "btp_subaccount_service_instance" "sf_odata_mtls" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-odata-mtls"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = "${var.oauth_client_name}-mtls"
    tenant-mode = "dedicated"
    credential-types = ["x509"]
    oauth2-configuration = {
      token-validity         = var.access_token_validity_seconds
      refresh-token-validity = var.refresh_token_validity_seconds
      credential-types       = ["x509"]
    }
  })
}

2.2 OAuth Token Management

Profile Level: L1 (Baseline) NIST 800-53: IA-5(13)

Implementation

Token Type Expiration
Access Token 1 hour
Refresh Token 24 hours (L1) / 8 hours (L2)

Code Implementation

Code Pack: Terraform
hth-sap-successfactors-2.02-oauth-token-management.tf View source on GitHub ↗
# Token management is primarily handled through the XSUAA service instance
# parameters in control 2.1. This file enforces token lifetime governance
# through a dedicated service instance with strict expiration policies.

# L1: Standard token governance service instance
resource "btp_subaccount_service_instance" "sf_token_governance" {
  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-token-governance"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = "hth-sf-token-gov"
    tenant-mode = "dedicated"
    oauth2-configuration = {
      # L1: Access token = 1 hour, Refresh token = 24 hours
      token-validity         = var.access_token_validity_seconds
      refresh-token-validity = var.refresh_token_validity_seconds
      # Disable client credentials grant to prevent unattended token minting
      grant-types = [
        "authorization_code",
        "refresh_token"
      ]
      redirect-uris = []
    }
  })
}

# L2+: Enforce tighter refresh token lifetime (8 hours)
resource "btp_subaccount_service_instance" "sf_token_governance_l2" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-token-governance-l2"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = "hth-sf-token-gov-l2"
    tenant-mode = "dedicated"
    oauth2-configuration = {
      # L2: Access token = 1 hour, Refresh token = 8 hours
      token-validity         = 3600
      refresh-token-validity = 28800
      grant-types = [
        "authorization_code",
        "refresh_token"
      ]
      redirect-uris = []
    }
  })
}

# L3: Disable refresh tokens entirely -- require re-authentication
resource "btp_subaccount_service_instance" "sf_token_governance_l3" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-token-governance-l3"
  serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
  parameters = jsonencode({
    xsappname   = "hth-sf-token-gov-l3"
    tenant-mode = "dedicated"
    oauth2-configuration = {
      # L3: Access token = 30 minutes, no refresh tokens
      token-validity = 1800
      grant-types = [
        "authorization_code"
      ]
      redirect-uris = []
    }
  })
}

3. Data Security

3.1 Configure Data Privacy

Profile Level: L1 (Baseline) NIST 800-53: SC-28

ClickOps Implementation

Step 1: Enable Data Protection

  1. Navigate to: Admin Center → Data Protection & Privacy
  2. Configure:
    • Personal data handling
    • Consent management
    • Data retention

Step 2: Field-Level Security

  1. Configure sensitive field masking
  2. Restrict SSN/Tax ID visibility
  3. Enable audit for sensitive data access

Code Implementation

Code Pack: Terraform
hth-sap-successfactors-3.01-configure-data-privacy.tf View source on GitHub ↗
# Enable the Data Privacy Integration service for SuccessFactors
resource "btp_subaccount_entitlement" "data_privacy" {
  subaccount_id = var.btp_subaccount_id
  service_name  = "data-privacy-integration-service"
  plan_name     = "standard"
}

resource "btp_subaccount_service_instance" "data_privacy" {
  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-data-privacy"
  serviceplan_id = data.btp_subaccount_service_plan.dpi_standard.id
  parameters = jsonencode({
    xs-security = {
      xsappname   = "hth-sf-dpi"
      tenant-mode = "dedicated"
    }
    retention = {
      # Data retention period after employee termination
      defaultRetentionDays = var.data_retention_days
    }
  })

  depends_on = [btp_subaccount_entitlement.data_privacy]
}

data "btp_subaccount_service_plan" "dpi_standard" {
  subaccount_id = var.btp_subaccount_id
  name          = "standard"
  offering_name = "data-privacy-integration-service"
}

# L1: Create role collection for data privacy officers
resource "btp_subaccount_role_collection" "data_privacy_officer" {
  subaccount_id = var.btp_subaccount_id
  name          = "HTH SF Data Privacy Officer"
  description   = "HTH: Manages data protection, consent, and retention policies"

  roles {
    name                 = "Subaccount Viewer"
    role_template_app_id = "cis-local!b2"
    role_template_name   = "Subaccount_Viewer"
  }
}

# L2+: Enable Personal Data Manager for field-level security
resource "btp_subaccount_entitlement" "personal_data_manager" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  service_name  = "personal-data-manager-service"
  plan_name     = "standard"
}

resource "btp_subaccount_service_instance" "personal_data_manager" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-pdm"
  serviceplan_id = data.btp_subaccount_service_plan.pdm_standard[0].id
  parameters = jsonencode({
    xs-security = {
      xsappname   = "hth-sf-pdm"
      tenant-mode = "dedicated"
    }
    sensitiveFields = var.sensitive_field_names
    masking = {
      enabled        = var.mask_sensitive_fields
      maskCharacter  = "*"
      visibleChars   = 4
    }
  })

  depends_on = [btp_subaccount_entitlement.personal_data_manager]
}

data "btp_subaccount_service_plan" "pdm_standard" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  name          = "standard"
  offering_name = "personal-data-manager-service"
}

# L3: Enable data residency enforcement (restrict data to specific regions)
resource "btp_subaccount_service_instance" "data_residency" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-data-residency"
  serviceplan_id = data.btp_subaccount_service_plan.dpi_standard.id
  parameters = jsonencode({
    xs-security = {
      xsappname   = "hth-sf-data-residency"
      tenant-mode = "dedicated"
    }
    retention = {
      defaultRetentionDays = var.data_retention_days
    }
    dataResidency = {
      enforced = true
    }
  })
}

4. Monitoring & Detection

4.1 Audit Logging

Profile Level: L1 (Baseline) NIST 800-53: AU-2, AU-3

ClickOps Implementation

Step 1: Enable Audit Trail

  1. Navigate to: Admin Center → Audit Logging
  2. Enable comprehensive logging
  3. Configure retention

Detection Focus

Code Pack: Terraform
hth-sap-successfactors-4.01-audit-logging.tf View source on GitHub ↗
# Enable the SAP Audit Log service for SuccessFactors
resource "btp_subaccount_entitlement" "audit_log" {
  subaccount_id = var.btp_subaccount_id
  service_name  = "auditlog-management"
  plan_name     = "default"
}

resource "btp_subaccount_service_instance" "audit_log" {
  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-audit-log"
  serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
  parameters = jsonencode({
    retentionPeriod = var.audit_retention_days
  })

  depends_on = [btp_subaccount_entitlement.audit_log]
}

data "btp_subaccount_service_plan" "audit_log_default" {
  subaccount_id = var.btp_subaccount_id
  name          = "default"
  offering_name = "auditlog-management"
}

# Create a service binding for audit log API access
resource "btp_subaccount_service_binding" "audit_log_binding" {
  subaccount_id       = var.btp_subaccount_id
  name                = "hth-sf-audit-log-binding"
  service_instance_id = btp_subaccount_service_instance.audit_log.id
}

# Role collection for audit log viewers
resource "btp_subaccount_role_collection" "audit_viewer" {
  subaccount_id = var.btp_subaccount_id
  name          = "HTH SF Audit Viewer"
  description   = "HTH: Read-only access to SuccessFactors audit logs"

  roles {
    name                 = "Subaccount Viewer"
    role_template_app_id = "cis-local!b2"
    role_template_name   = "Subaccount_Viewer"
  }
}

# L2+: Enable SIEM integration via webhook for real-time audit event forwarding
resource "btp_subaccount_service_instance" "audit_siem_webhook" {
  count = var.profile_level >= 2 && var.siem_webhook_url != "" ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-audit-siem-webhook"
  serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
  parameters = jsonencode({
    retentionPeriod = var.audit_retention_days
    webhook = {
      url     = var.siem_webhook_url
      enabled = true
      events  = ["security", "data-access", "configuration-change"]
    }
  })

  depends_on = [btp_subaccount_entitlement.audit_log]
}

# L2+: Extended audit retention (730 days)
resource "btp_subaccount_service_instance" "audit_log_extended" {
  count = var.profile_level >= 2 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-audit-log-extended"
  serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
  parameters = jsonencode({
    retentionPeriod = var.profile_level >= 3 ? 1095 : 730
  })

  depends_on = [btp_subaccount_entitlement.audit_log]
}

# L3: Enable the Alert Notification service for real-time security alerts
resource "btp_subaccount_entitlement" "alert_notification" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  service_name  = "alert-notification"
  plan_name     = "standard"
}

resource "btp_subaccount_service_instance" "alert_notification" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id  = var.btp_subaccount_id
  name           = "hth-sf-alert-notification"
  serviceplan_id = data.btp_subaccount_service_plan.alert_standard[0].id
  parameters = jsonencode({
    configuration = {
      actions = [
        {
          name = "bulk-data-access-alert"
          type = "EMAIL"
          properties = {
            destination = "security-team@company.com"
          }
        }
      ]
      conditions = [
        {
          name         = "bulk-employee-data-access"
          description  = "HTH: Detect bulk employee data access via API"
          propertyKey  = "eventType"
          predicate    = "EQUALS"
          propertyValue = "data-access"
        }
      ]
    }
  })

  depends_on = [btp_subaccount_entitlement.alert_notification]
}

data "btp_subaccount_service_plan" "alert_standard" {
  count = var.profile_level >= 3 ? 1 : 0

  subaccount_id = var.btp_subaccount_id
  name          = "standard"
  offering_name = "alert-notification"
}

Appendix B: References

Official SAP SuccessFactors Documentation:

API & Developer Resources:

Compliance & Certifications:

Security Incidents:

  • No major public security breaches specific to SAP SuccessFactors have been identified. SAP was designated a Critical ICT Third-Party Service Provider (CTPP) by European Supervisory Authorities in November 2025, reflecting its systemic importance to financial sector digital infrastructure.

Changelog

Date Version Maturity Changes Author
2025-12-14 0.1.0 draft Initial SAP SuccessFactors hardening guide Claude Code (Opus 4.5)