Enforcing Device AuthN & Compliance at Pinterest

Pinterest Engineering
Pinterest Engineering Blog
9 min readJan 24, 2023

--

Armen Tashjian | Security Engineer, Corporate Security

Flow map from User to Okta to External Identity Provider to Device Compliance Check with an arrow back to Okta “User redirected back to Okta to proceed with authentication.”

Intro

Pinterest has enforced the use of managed and compliant devices in our Okta authentication flow, using a passwordless implementation, so that access to our tools always requires a healthy Pinterest device.

Following the phishing-based attacks against our peers in the tech industry, Pinterest decided to take a two pronged approach to defend against similar attacks. We decided to:

  1. Require a managed and healthy Pinterest device be used to access all Pinterest resources, even when in the possession of valid credentials
  2. Require FIDO2 credentials for user authentication

In this post, we’ll be focusing on how we required the use of Pinterest managed devices in our Okta authentication flow.

Image 1: A user on an Android device is prevented from authenticating. Image 2: A user on macOS is warned about some compliance failures.

Why Device AuthN & Compliance

There are a few driving forces behind this initiative:

  • With the introduction of our PinFlex WFH policy, we expected an increased number of employees interacting with Pinterest tools and services outside of the office.
  • For employee facing tools, Pinterest is a SaaS-first company, which means that the vast majority of our tools are internet accessible. These tools will remain internet-accessible either by choice, or because of the lack of native IP-based allowlisting capabilities.
  • Our appetite for network-centric security controls has diminished. While that doesn’t mean that VPN or on-premise network-based access will be entirely going away, we recognize that our default position won’t be to force users to be on a particular network in order to access resources, especially a SaaS tool.
  • We have a set of important security controls that only exist on company-managed devices and/or Mobile BYOD with MDM.

We feel that requiring a managed and healthy device for authentication mitigates some of the lost security boundaries described above, by ensuring that:

  • Phished user credentials (whether password, OTP, or push notification) will not result in access to Pinterest resources.
  • Internet-accessible Pinterest tools, including those that may contain sensitive data, cannot be accessed from unmanaged or unknown devices.
  • Managed devices will be in a hardened state, making it more difficult for adversaries to gain a foothold.

Integrating with Okta

While researching the different integration options within Okta, a few things became apparent for Okta Classic customers:

  1. The existing bespoke device related integrations that do exist between MDM providers and Okta, such as Device Trust with Jamf or WS1, do not provide comprehensive solutions to customers.
  2. If an Okta customer or a potential vendor wants to integrate with Okta to do something “interesting” with the authentication flow, the only avenue for doing so is to establish mutual trust with some external identity provider (IdP), where those “interesting” things can take place.

Therefore, we didn’t have much of a choice but to build and route users to our own custom identity provider. Zuul (apologies Netflix) is an OIDC identity provider that the Pinterest security team built, in order to incorporate our device auth and compliance requirements into the Okta authentication flow.

Flow map from User to Okta to External Identity Provider to Device Compliance Check with an arrow back to Okta “User redirected back to Okta to proceed with authentication.”
Image 3: High level flow diagram of Okta authentication with idP Routing/Discovery

Like some of the vendors in this space, we integrate our IdP with Okta using IdP Routing/Discovery, where our IdP acts as a trusted external identity provider. We integrate with Okta using the “IdP as SSO” approach, rather than the “IdP as a Factor/MFA” approach, as the latter conflicts with our FIDO2 implementation.

At its core, and from Okta’s perspective, our IdP is nothing more than a compliant OIDC IdP. However, now that we are in the critical path for SSO authentication, the entire experience, as well as the success of the authentication request, can be enhanced to enforce the use of a managed and compliant device.

Mutual TLS Authentication

One of the challenges that needs to be overcome with any device-based solution is being able to associate an authentication attempt with a specific device. This requirement is why a certificate-based approach was an attractive option.

We issue certificates to all managed devices, including desktop and mobile platforms, through our MDM solution, which requires users to authenticate in order for a credential to be issued to the device. This allows us to:

  1. Determine the user identity before interacting with them (e.g. FIDO2) by encoding the user identity in the PKI certificate issued to the device during MDM enrollment
  2. Associate an authentication attempt with a physical device, as the certificate was issued to that device during enrollment
  3. Avoid platform-specific agents, as certificate-based authentication is natively supported on the platforms that we support at Pinterest, so we are able to take advantage of a platform-agnostic approach to authentication

Our custom IdP only supports mTLS authentication with client certificates, using certificates that are tied both to a user and device. Without a valid client certificate, which is only distributed to managed devices, authentication to our IdP is not possible.

For applications that don’t support Mutual TLS authentication, for the reasons described in the followup blog post, a workaround exists to revert back to password-based authentication.

Issues with External IdP Solutions

Another hurdle to overcome is Okta’s lack of “enforcement” of an external identity provider. Although we can route users to an external identity provider, Okta does not provide the tools necessary to properly enforce the use of an identity provider.

Okta clearly indicates that the use of IdP Routing, and corresponding IdP Routing Rules, is not a security control:

Routing rules improve the end-user sign-in experience, but they don’t provide security enhancements. You need to configure user authentication policies for your IdPs independently of your routing rules.

This effectively means that we cannot rely on external IdP as being anything more than an “optional” form of authentication. Without taking any additional steps to enforce the use of an external IdP, it is trivial to bypass the use of an external IdP by reverting back to Okta username/password-based authentication.

In the quote above, Okta alludes to “user authentication policies” as a method of enforcement. Had these referenced policies been actual “application sign-on policies,” enforcement would have been a non-issue. Unfortunately, the only Okta policies that exist are “global sign-on” policies, which cannot account for the inevitable application exceptions that you will likely run into, and are therefore not practical to use.

SAML Inline Hooks — “Custom” App Sign-on Policies

SAML Inline Hooks allow for an external service to modify a SAML assertion before that SAML Assertion is signed by Okta. On the surface, that’s not really relevant to a device authentication solution, but there is one notable return type that piqued our interest: the ability to reject an access attempt by returning an error.

The requests sent by Okta in a SAML Inline Hook contain some relevant information about an application access attempt, including:

  1. The application that is being accessed
  2. The user attempting to access the application
  3. How the user’s Okta session was established

In the examples below, note the difference between the “sessions” in these two app access attempts.

Access attempt to reject (external IdP not used)

{
"context":
{
"protocol":
{
"issuer":
{
"id": "app_id",
"name": "application_name",
"uri": "http://www.okta.com/<app_id>"
}
},
"session":
{
"idp":
{
"id": "okta_idp_id",
"type": "OKTA"
}
}
}
}

Access attempt to allow (external IdP used)

{
"context":
{
"protocol":
{
"issuer":
{
"id": "app_id",
"name": "application_name",
"uri": "http://www.okta.com/<app_id>"
}
},
"session":
{
"idp":
{
"id": "zuul_idp_id",
"type": "SOCIAL"
}
}
}
}

This means that we can programmatically make an access-based decision for every single application access attempt. For an access attempt that should proceed, we return an empty response. For access attempts that need to be rejected, we throw an error. In other words, we can overcome whatever limitations exist in Okta app sign-on policies by bolting on our own custom app sign-on policy using an inline hook.

To improve the user experience, we also revoke a user’s Okta session when this error is surfaced.

In the example below, a user has established an Okta session with one of the many ways that IdP routing can be bypassed, in an attempt to bypass our device requirements. Yet, they still cannot access an application that requires our external IdP.

User is directed to a 400 bad request screen and has to be redirected back to the hompage.
Image 4: SAML Inline Hook blocks an application access attempt, due to an Okta session that was not established with the correct idP

Although SAML Inline Hooks represent a good temporary solution for us, this is by no means ideal. SAML Inline Hooks must be enabled on a per application basis and can only be enabled on applications that are manually configured in Okta, so some reconfiguration of apps might be necessary. We are planning to reconfigure applications that were downloaded from the Okta Integration Network for the sole purpose of enabling our SAML Inline Hook on those applications.

We are hopeful that Okta will release something, in either Okta Classic or OIE, that allows for us to natively enforce an IdP on a per application basis, with a configuration that also allows FIDO2 enforcement. Alternatively, an “Inline Hook” for general authentication that can be universally applied to every Okta app would also be an interesting alternative.

Device Compliance

Now that every Okta authentication attempt requires users to authenticate against our IdP, we have the opportunity to evaluate the health of a device. The intent of our compliance policies is to enforce our security hardening guidelines to ensure that the fleet of devices that are capable of accessing our tools are in compliance and in a hardened state.

In the event that a device with compliance failures attempts to authenticate, we can take a few actions, including presenting a warning to the user, or for some policies, blocking the authentication attempt altogether.

User is directed to a screen that reads “There are one or more issues with your device. Warnings: chrome_running_versions and uptime.”
Image 5: A user on macOS is warned about some compliance failures.

Our compliance framework allows for some capabilities that were important to us and are not commonly seen in other solutions. This includes:

  1. Policies that are defined as code, allowing us to create complex policies if necessary
  2. Policies that can take into account data from as many data sources as needed. We currently integrate with Splunk, Chef, Workspace One, and osquery, with more integrations planned.
  3. “Actions” that are executed upon the failure of a policy, two of which we show in this blog post (Block/Warn)
  4. The ability to slowly shard a new policy across the fleet, using our existing production framework for deploying experiments

Below we’ve created an example policy to ensure that a user authenticating to Okta is doing so from a device that is owned by them and logged in on that device with a matching username.

Image 6: A user on macOS is prevented from authenticating as their device is failing the example policy “username_mismatch”.

Below is the code associated with this example policy. In order to perform this evaluation, we take data collected from two different data sources (Airwatch MDM and osquery), and compare the usernames with the person attempting to authenticate to Okta.

@device_policy(
name="username_mismatch",
decider="zuul_device_policy_username_mismatch",
actions=[PolicyAction.BLOCK],
users=["atashjian"],
devices=[PolicyScope.ALL_DEVICES],
user_exception=[],
device_exception=[],
sources=[DataSource.OSQUERY, DataSource.AIRWATCH],
staleness_threshold=2400,
platforms=[DevicePlatform.MACOS],
remediation_message="The user attempting to auth, the local username on the device, "
"and the device owner, must all match."
)
def username_mismatch(device):
'''ensure that the user that's authenticating, the user logged in on the device, and the device owner match.
'''
authenticating_user = device.username
device_logged_in_user = device.collected_data[DataSource.OSQUERY].data['results']['data']['logged_in_user']['username']
airwatch_device_owner = device.collected_data[DataSource.AIRWATCH].data['UserName']
if authenticating_user == device_logged_in_user == airwatch_device_owner:
return PolicyResult(result=PolicyEval.PASS)
else:
return PolicyResult(result=PolicyEval.FAIL,
details=f"User Authenticating: {authenticating_user}, "
f"Device Owner: {airwatch_device_owner}, "
f"Logged In User: {device_logged_in_user}")

Potential future compliance policies might take into account:

  1. Patch status
  2. Malware detection
  3. Security agent health
  4. Log ingestion health
  5. Application/browser extensions
  6. Kernel/system extensions
  7. Root CAs
  8. CIS hardening guidelines
  9. And lots of other things!

Conclusion

We’ve only begun our device compliance journey, and a good amount of work lies ahead, including:

  • Continuously codifying device compliance policies
  • Additional integrations, for both collecting data, as well as performing actions in the event of failures
  • Evaluating device compliance not just at authentication time, but on a continuous basis
  • Closing the Okta enforcement gaps by enabling SAML Inline Hooks across all apps

A big thank you to our partners in IT and Traffic Engineering, for helping Corporate Security to implement this, and a special mention goes to Jason Craig, a human being.

Stay tuned for some followup blog posts, including:

  • Our FIDO2 implementation
  • A more in depth look into device compliance

For any thoughts or feedback, feel free to reach out to zuul[at]pinterest.com

Interested in learning more about this topic? Check out the second part of this blog article here: Employee-facing Mutual TLS.

To learn more about engineering at Pinterest, check out the rest of our Engineering Blog and visit our Pinterest Labs site. To explore life at Pinterest, visit our Careers page.

--

--