DEV Community

Spacelift team for Spacelift

Posted on • Originally published at spacelift.io

How to Manage Okta with Terraform [Example]

Security is one of the most important pillars for building robust and reliable infrastructure. Preventing unauthorized access, data breaches, and other security threats is crucial for ensuring integrity and user safety. By leveraging products such as Okta, you can fortify your organization's security and minimize these problems.

In this post, we will explore what Okta is and how to leverage it using Terraform.

What is Okta?

Okta is an identity access management (IAM) service that provides secure, centralized authentication for your organization's users. With Okta, you can easily manage user authentication to applications inside your organization using single sign-on (SSO), multi-factor authentication (MFA), and lifecycle management functionalities. Okta helps organizations streamline their access management, enhances overall security, and improves the user experience.

What is the Okta Terraform provider?

The Okta Terraform provider lets you manage (create/edit/delete) resources in your Okta account. It is very useful, especially in large organizations, where personnel, privileges, and accesses change frequently.

With the Okta Terraform provider, you can automate almost everything that you would do manually as a security administrator:

  • Creating users and groups
  • Creating policies and roles
  • Creating SAML/OIDC identity providers
  • Assigning users to different applications

💡 You might also like:

Example: How to use Okta provider with Terraform

The Terraform documentation for the Okta provider outlines how you can configure the provider, what resources you can create, and what datasources you can leverage.

provider "okta" {
 org_name  = var.org_name
 base_url  = var.base_url
 api_token = var.api_token
}
Enter fullscreen mode Exit fullscreen mode

To authenticate to Okta, in my provider block I will use an org_name, base_url, and api_token.

variable "org_name" {
 description = "The name of the Okta organization"
 type        = string
}

variable "base_url" {
 description = "The base URL of the Okta organization (e.g., okta.com)"
 type        = string
 default     = "okta.com"
}

variable "api_token" {
 description = "The API token used to authenticate with the Okta API"
 type        = string
 sensitive   = true
}
Enter fullscreen mode Exit fullscreen mode

These values can be provided either in the default block of your variables, in a tfvars file, in environment variables, or even by using the "-var" or "-var-file" options. 

E.g. terraform.tfvars file

org_name  = "dev-123456"
api_token = "your-okta-api-token"
Enter fullscreen mode Exit fullscreen mode

In my example, I will create a configuration that creates the number of users and groups I want and also takes care of their memberships:

resource "okta_user" "users" {
 for_each   = var.users
 first_name = each.value.first_name
 last_name  = each.value.last_name
 email      = each.value.email
 login      = each.value.login
}

resource "okta_group" "groups" {
 for_each    = var.groups
 name        = each.value.name
 description = each.value.description
}

resource "okta_group_membership" "memberships" {
 for_each = var.memberships
 group_id = okta_group.groups[each.value.group_name].id
 user_id  = okta_user.users[each.value.user_name].id
}
Enter fullscreen mode Exit fullscreen mode

As you can see, all resources are created with for each, to enable you to create the number of instances of a resource you want.

variable "users" {
 description = "A map of users to be created in Okta"
 type = map(object({
   first_name = string
   last_name  = string
   email      = string
   login      = string
 }))
}

variable "groups" {
 description = "A map of groups to be created in Okta"
 type = map(object({
   name        = string
   description = string
 }))
}

variable "memberships" {
 description = "A map of group memberships, associating users with groups"
 type = map(object({
   group_name = string
   user_name  = string
 }))
}
Enter fullscreen mode Exit fullscreen mode

All the variables are defined as object maps, and none of their parameters are optional, meaning that you will have to provide values for all of them.

In this example, I will create two users, two groups, and two memberships based on a tfvars file:

users = {
 user1 = {
   first_name = "user"
   last_name  = "one"
   email      = "user.one@example.com"
   login      = "user.one@example.com"
 },
 user2 = {
   first_name = "user"
   last_name  = "two"
   email      = "user.two@example.com"
   login      = "user.two@example.com"
 }
}

groups = {
 group1 = {
   name        = "group1"
   description = "An example group in Okta"
 },
 group2 = {
   name        = "group2"
   description = "Another example group in Okta"
 }
}

memberships = {
 membership1 = {
   group_name = "group1"
   user_name  = "user1"
 },
 membership2 = {
   group_name = "group2"
   user_name  = "user2"
 }
}
Enter fullscreen mode Exit fullscreen mode

This is the output of a terraform apply:

okta_user.users["user1"]: Creating...
okta_user.users["user2"]: Creating...
okta_group.groups["group1"]: Creating...
okta_group.groups["group2"]: Creating...
okta_user.users["user1"]: Creation complete after 2s [id=...]
okta_group.groups["group2"]: Creation complete after 1s [id=...]
okta_user.users["user2"]: Creation complete after 2s [id=...]
okta_group.groups["group1"]: Creation complete after 1s [id=...]

okta_group_membership.memberships["membership1"]: Creating...
okta_group_membership.memberships["membership1"]: Creation complete after 1s [id=...]
okta_group_membership.memberships["membership2"]: Creating...
okta_group_membership.memberships["membership2"]: Creation complete after 1s [id=...]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Enter fullscreen mode Exit fullscreen mode

Benefits of using Terraform for Okta

There are several benefits of using Terraform to create your Okta resources:

  • Consistency - Ensure environments are repeatable and human errors are minimized.
  • Version control - Storing your configurations in a VCS lets you track changes and revert to previous versions.
  • Scalability - Terraform scales with your needs, so as your organization grows, it will help you provision more resources.
  • Collaboration - Changes proposed through pull requests are deployed only after they are reviewed.

If you have a big organization with frequent personnel changes every month, leveraging Terraform for Okta access will make things much easier for the security team responsible for adding/removing these users.

All the benefits of using Terraform apply to the Okta provider. You can read more about it in this article.

Spacelift integration with Okta

You can use Okta as an SSO provider for Spacelift and configure it via OIDC or SAML2.0.

For both of these integrations, go to your Spacelift account first in Organization settings and select single sign-on. 

To use SAML, you will need the Single sign-on URL and the Entity ID, and for OIDC you will need the Authorized redirect URL.

Single sign-on

Next, go to Okta, create a new application, and select whether you want to configure it via SAML2.0 or OIDC. An example for OIDC is available here.

After you finish creating the application, go back to your Spacelift account and click on the setup button for the method you want to configure.

saml settings

oidc settings

Apart from integrating Spacelift with Okta for SSO, you can easily leverage any configurations you are building with Terraform from Spacelift to leverage an entire orchestration workflow.

The following Spacelift features can streamline your Okta management:

  • Contexts - You can create a context that contains the environment variables required for Okta connection and use the autoattach:label feature to ensure that all stacks with the label will automatically attach it. This means you won't need to worry about adding these details for each stack you create, which will also force you to add the same label on your Okta stacks, making them easier to manage
  • Policies - Plan policies restrict entire Okta resources from being created or just some parameters of these resources. Approval policies ensure a minimum number of approvals are met before making a change to the code. Push policies control what happens when a pull request is open or a merge happens. Notification policies control where to send notifications. These policies can also be created with the autoattach:label feature to ensure that all your stacks will have the necessary policies attached
  • Stack dependencies - To keep your state files small but retain a single end-to-end workflow, you can split your stacks into multiple smaller ones and create dependencies that also share outputs between them. This will make you respect Terraform's best practices and ensure errors are easier to find and solve.
  • Blueprints - You can leverage Blueprints to build self-service infrastructure templates for Okta, making it easier for security engineers to create new Okta resources without having to build the code themselves.

Key points

In this post, we walked you through what Okta is and how to use its Terraform provider to provision Okta resources. We also showed you the benefits of managing Okta resources with it and how Spacelift integrates with Okta.

If you want to manage Okta with Terraform, Spacelift will take your workflow to the next level while ensuring that governance is met. Create a free account today with Spacelift, or book a demo with one of our engineers to learn more.

Written by Flavius Dinu

Top comments (0)