This repository is a company to the Oktane 23 Presentation on Managing Multiple Okta Deployments. This repository will cover the code and instructions mentioned in the presentation.
The Chief Revenue Officer of a fictional company is getting complaints from the Sales Engineers. They are running into Multifactor Authentication challenges logging into their Sales Pipeline App 😉. The CRO is keen to unblock the Sales Engineers and demands the Director of IT create a simpler method for logging in so they can keep productivity up through the end of the quarter. The Director of IT, who reports up to the Chief Information Officer is concerned about lowering the security when accessing confidential financial data.
How can the Director of IT build a passwordless and secure method of authentication for the Sales Engineers accessing a protected resource?
Below are the steps and instructions on how to address the challenge by utilizing the Terraform, Okta, and the Okta Terraform provider.
-
Create a custom Single Page App in your org and call it
Sales Pipeline. You can use default values for the configuration. If you would like to set up a new app from an existing Okta sample app, you can use this Okta React Sample App to get started. -
Create a user in your org and configure your email and Okta Verify factors for authentication. Make Sure in the user's profile that the
Departmentattribute is set toSales Engineering.
First is getting setup with Okta and Terraform. Luckily, all the setup is free from both Okta Terraform. Check out the links below to get started.
-
Create an Okta Developer Organization Navigate to developer.okta.com/signup to create a developer org to build and test. Terraform installed locally or a Terraform Cloud account
-
Go to app.terraform.io/public/signup/account to create a free Terraform Cloud account or developer.hashicorp.com/terraform/downloads to install the command line locally.
As the Director of IT, it's important to make sure this Terraform module cannot be used outside of the bounds of this exercise. Okta has ways to create least privilege access for its clients and prevent those who have access to the code from requesting unauthorized scopes.
-
Create an Application in your Okta Org
Creating an application will generate OAuth credentials. Switch from Client secret to Public key/Private key
-
Assign the scopes to your Terraform module
This will create guardrails for the scopes requested by Terraform when running in your environment ensuring least privilege access
NOTE: The scopes needed for this example are
okta.apps.read,okta.groups.manage,okta.groups.read,okta.authenticators.manage,okta.authenticators.read,okta.policies.manage,okta.policies.read,okta.users.manage,okta.users.read
With a test Okta tenant and Terraform setup and least privileged access defined, we can now configure the Terraform module to include the latest version of the Okta Terraform provider, and set the necessary connection information to the tenant.
-
Generate a key in the application settings page.
You can save this key to a file. Better yet, store the private key in your secrets management solution.
Note: Okta generates a PKCS #8 key that needs to be converted to PKCS #1 with the following command:
openssl rsa -in pkcs8.pem -out pkcs1.pem -traditional
-
Add the configuration keys to your Terraform configuration.
Create a file
main.tfand add these keys to the Terraform module config:org_name,base_url,client_id,scopes, andprivate_key
Here is how your Terraform Module should look after adding the configuration code block:
# Generic Terraform Config
terraform {
required_providers {
okta = {
source = "okta/okta"
version = "~> 4.4.2"
}
}
}
# Configure the Okta Provider
provider "okta" {
org_name = "{org_prefix}" # example: "dev-123456"
base_url = "{org_domain}" # example: "okta.com"
client_id = "{cient_id}" # example: "123abc456def"
scopes = ["okta.apps.read","okta.authenticators.manage","okta.authenticators.read","okta.groups.manage","okta.groups.read","okta.policies.manage","okta.policies.read","okta.users.manage","okta.users.read"]
private_key = file("pkcs1.pem") # location of your file in Step 3.1
}To get started on this journey, we need to move Sales Engineers into a group that will be used for Passwordless access. We will create a new group and a group rule that will automatically assign new Sales Engineer to the group for passwordless access. With Terraform, new objects that you create are called Resources. We will create a group resource and group rule resource in our Terraform Module.
-
Create a top-level resource first
Building what is shown in the Administration Console can take multiple steps. Some objects can be constructed in one resource.
-
Build the required components and reference the new object properties
In this example, we are creating a group first, and adding another resource for the group rule.
Note: It is best to test either in the module or after applying the changes in a development environment.
Here is the code to create the Passwordless Group and Passwordless Group Rule:
# Group Resource
resource "okta_group" "passwordless_group" {
name = "Passwordless Group"
}
# Create a Group Rule
resource "okta_group_rule" "passwordless_group_rule" {
name = "Passwordless Group Rule"
status = "ACTIVE"
group_assignments = [ okta_group.passwordless_group.id ]
expression_value = "String.stringContains(user.department,\"Sales Engineering\")"
}In moving away from passwords, you are on the way towards phishing resistance. We know all Sales Engineers can authenticate with email, but we want to encourage the use of Okta Verify as well for phishing resistance. We will setup an enrollment policy where email is REQUIRED and Okta Verify and Password are OPTIONAL. This will allow a password to be enrolled for other applications. In general, when creating a new policy object, you will have to create a policy object first and then a rule associated with that policy.
-
Create the Authenticator Enrollment Policy resource first
For this example, we want to push enrollment for non password authenticators and to include a phishing resistance factor to increase adoption of more secure authenticators and increasing convenience
-
Create a Rule for this policy
This rule can take default properties, but all policies must have rules
Note: Here is another good place to test the enrollment experience in a development environment.
Here is the code to create the Authenticator Policy and Rule:
# Passwordless Enrollment
resource "okta_policy_mfa" "passwordless_enrollment_policy" {
name = "Passwordless Authenticator Enrollment Policy"
status = "ACTIVE"
is_oie = true
groups_included = [ okta_group.passwordless_group.id ]
okta_password = {enroll = "OPTIONAL"}
okta_email = {enroll = "REQUIRED"}
okta_verify = {enroll = "OPTIONAL"}
priority = 1
}
# Create the Enrollment Rule
resource "okta_policy_rule_mfa" "passwordless_enrollment_policy_rule" {
name = "Passwordless Enrollment Rule"
policy_id = okta_policy_mfa.passwordless_enrollment_policy.id
priority = 1
}In some instances, apps may be using the Classic authentication experience. This is where username and password appear on the initial login screen. For passwordless to work, we need to switch the authentication to collect the username first to determine what factors to present to the user. We will create a Global Session Policy and a rule to support this change.
-
Create the Global Session Policy resource to enable passwordless rules for a group
We want to syphon off the members of our new group and push them to a new experience that will enable them to login without a password
-
Create a Rule in Global Session Policy to describe the new experience
Setting the primary_factor to
“PASSWORD_IDP_ANY_FACTOR”will change the login experience to identifier first
Here is the code to create the Global Session Policy and Rule:
# Passwordless Global Session Policy
resource "okta_policy_signon" "passwordless_global_session_policy" {
name = "Passwordless Global Session Policy"
status = "ACTIVE"
priority = 1
groups_included = [ okta_group.passwordless_group.id ]
}
# Passwordless Policy Rule
resource "okta_policy_rule_signon" "passwordless_global_session_policy_rule" {
name = "Global Session Policy Rule"
policy_id = okta_policy_signon.passwordless_global_session_policy.id
priority = 1
status = "ACTIVE"
access = "ALLOW"
primary_factor = "PASSWORD_IDP_ANY_FACTOR"
}Finally, we need to set the Level of Assurance for the Sales Pipeline App. To achieve this in Terraform we will be using a Data Source, or a read-only version of an existing object in the org. We will need to find the Application ID and assigned Application Sign on Policy for the Sales Pipeline App. Then, we will create a new rule to change the Level of Assurance for the Passwordless Group.
-
Find the Application and Application Sign on Policy
Use the data source to read the IDs of the application and get the associated Application Sign on Policy where we can add the rule
-
Create a Rule in the Application Sign on Policy to enforce passwordless rules for a group
Define the criteria for access to the application without a password for the Passwordless Group
This section of the code makes use of Data Sources. Data Sources are read only objects that are used to pull properties and can be used to create new resources from existing objects. Here is the code to create the Authencation Policy and Rule:
# Get the Application ID
data "okta_app" "sales_pipeline" {
label = "Sales Pipeline"
}
# Get the Application Sign on Policy
data "okta_app_signon_policy" "okta_sales_pipeline_authn_policy" {
app_id = data.okta_app.sales_pipeline.id
depends_on = [
data.okta_app.sales_pipeline
]
}
# Create the Passwordless Rule
resource "okta_app_signon_policy_rule" "passwordless_authn_rule" {
name = "Passwordless Rule"
policy_id = data.okta_app_signon_policy.okta_sales_pipeline_authn_policy.id
access = "ALLOW"
factor_mode = "1FA"
groups_included = [ okta_group.passwordless_group.id ]
priority = 1
}Congratulations for making it this far. If you want to see this module in action, you can deploy a simple SPA app and connect it to your Okta org. A good example can be found in the okta/samples-js-react repository on Github. Thank you for reading! Here is the full solution that you can copy and run in your local environment.
If you want to reset the changes to your org, simply run terraform destory from the command line.