Introduction
At $currentJob, we wanted to allow our end-users of Okta, who are administrators in their respective platforms, to view or manage applications they are responsible for. An easy example is our Salesforce Team. We want them to manage everything related to Salesforce. But how can we do that in a way that requires limited or low administration overhead?
- Introduction
- The initial project
- The Problem - Scaling Groups and Scaling App Lookups
- Filing Issue
- Waiting… Resolution and Forgetting
- Building it out
The initial project
When we initially started our project, we were using 4.11.0 of the Terraform Module, and in some cases, even older versions to fix some issues we had with that specific version. This was great, as it could have us do a wildcard lookup with groups, so we could extract the information we needed for a resource set.
The original plan:
- Allow an administrator or technical owner To have read (and potentially edit access):
- To all of the applications under their domain
- To all of the groups under their domain
- View
- Allow for automatic expansion of groups and applications as they were added and as Terraform would apply
This sounds simple: We already had all the things needed to go in, and we just needed to bump up to version 4.12. Unfortunately, that’s not the case.
The Problem - Scaling Groups and Scaling App Lookups
While the okta_apps
function was in the provider, it didn’t seem to do anything or work at all.
For example, the ability to use something simple:
|
|
It would return errors, even though the 4.12 docs mentioned support for the label_prefix
statement.
This ruined our plans.
We tried to find workarounds, but we didn’t like any of our ideas, so we just decided to wait.
Finding similarities
Unfortunately, we couldn’t find any similar issues with the actual error/problem (Terraform failing to run) or any possible similar work to see if we could find any workarounds. But @exitcode0 had the same use case as what we were trying to achieve.
So, there were obviously some positive use case situations here.
Filing Issue
This ruined our plans and needed to be announced/made others aware, so I/we ($currentJob) filed an Okta Support case and a Github Issue #2251 shortly after a very long back-and-forth about Okta Resource Sets and whether the Terraform resource was working for anyone else on Slack.
Waiting… Resolution and Forgetting
Since we couldn’t progress, we moved on to another part of the Terraform project, and life moved on.
Issues Resolved
So about a month and a half later, the issue was finally closed and resolved with a merged PR, and the module appeared to do exactly what we wanted. It added the ability to do lookups and searches on either name or filter, allowing us more flexibility with our lookup queries.
Forgetting
Life moved on to the point where I forgot what type of code we were writing in the module. That made it difficult to progress or continue forward with anything. So we ended up rewriting the whole module, as it was faster and easier to do soβbecause what we needed had a lot, and I mean a lot, of data lookups.
A Happy Bonus
So, not only did we resolve our issues, but we also resolved three other issues in the same release, all of which pertain to ORNs and Resource Sets, making the potential for the admin module even better.
Building it out
So how did we do it?
Variables
Hereβs a breakdown of the key variables that help this module function. These control what resources are targeted, what roles are assigned, and how deeply customized the setup can be.
π Environment and Context
environment
: Tells the module if you’re working in a preview or production Okta instance, but can be omitted if you would prefer to use theokta_org_metadata
data.admin_role_type
: Picks which type of admin role to assign (built-in or custom).
π€ Who Gets Admin Roles?
-
Group-Based Assignment
admin_assignment_group_names
: Exact group names to assign roles to.admin_assignment_group_patterns
: Fuzzy patterns to dynamically match group names.admin_assignment_group_ids
: Assign roles to groups using known group IDs.
-
User-Based Assignment
admin_user_logins
: Directly assign roles to specific user logins.admin_user_search_patterns
: Pattern-based user search (e.g., all emails starting with “admin”).
π What Resources Are Managed?
-
Applications
managed_app_names
,managed_app_labels
: Target apps by exact name or label.managed_app_patterns
: Find apps dynamically with search patterns.managed_app_ids
: Use when you have the app ID directly.
-
Groups
managed_group_names
,managed_group_patterns
,managed_group_ids
: Target groups by name, pattern, or ID.
π¨ Custom Roles (When admin_role_type = "CUSTOM"
)
-
Role Config
custom_role_id
: Use an existing custom role.custom_role_label
,custom_role_description
: For creating a new custom role.custom_role_permissions
: Fine-grained control over what the role can do, validated against a large list of supported permissions.
-
Resource Set Config
resource_set_name
,resource_set_description
: Required when creating a new resource set for custom roles.resource_set_id
: Optionally reuse an existing one.
π’ Notifications and Compatibility
admin_notifications
: Control which types of admin alerts users get. Highly customizable.disable_notifications
: Legacy variable. Kept for backward compatibility.lookup_existing_role_subscription
: Enables reuse of existing role subscriptions if needed.
Data Lookups
π Organization Metadata
-
data "okta_org_metadata" "current"
- Retrieves metadata about the current Okta organization (e.g., name, subdomain, settings).
π± Applications to Be Managed by Admins
-
data "okta_app" "managed_apps_by_name"
- Looks up applications using exact names via the
label
field. - Source:
var.managed_app_names
.
- Looks up applications using exact names via the
-
data "okta_app" "managed_apps_by_label"
- Looks up applications using the exact
label
. - Source:
var.managed_app_labels
.
- Looks up applications using the exact
-
data "okta_apps" "managed_apps_by_pattern"
- Searches for active applications whose labels match a pattern.
- Uses the
q
search parameter. - Source:
var.managed_app_patterns
.
-
data "okta_app" "managed_apps_by_id"
- Retrieves applications by their exact Okta ID.
- Source:
var.managed_app_ids
.
π₯ Groups to Receive Admin Roles
-
data "okta_groups" "admin_groups_by_pattern"
- Searches for groups where the profile name contains a given pattern.
- Uses
search = "profile.name co \"<pattern>\""
. - Source:
var.admin_assignment_group_patterns
.
-
data "okta_group" "admin_groups_by_name"
- Looks up groups by exact name.
- Source:
var.admin_assignment_group_names
.
-
data "okta_group" "admin_groups_by_id"
- Retrieves groups by their exact Okta group ID.
- Source:
var.admin_assignment_group_ids
.
π₯ Groups to Be Managed by Admins
-
data "okta_groups" "managed_groups_by_pattern"
- Searches for groups by pattern (profile name contains a given substring).
- Source:
var.managed_group_patterns
.
-
data "okta_group" "managed_groups_by_name"
- Looks up groups by exact name.
- Source:
var.managed_group_names
.
-
data "okta_group" "managed_groups_by_id"
- Retrieves groups by their Okta group ID.
- Source:
var.managed_group_ids
.
π§βπ» Users for Admin Role Assignments
-
data "okta_users" "admin_users"
- Searches for users whose profile fields start with a given value.
- Source:
var.admin_user_search_patterns
.
-
data "okta_users" "admin_users_by_login"
- Searches for specific users by login using exact match.
- Source:
var.admin_user_logins
.
βοΈ Role Subscription Lookup
-
data "okta_role_subscription" "existing"
- Conditionally retrieves an existing admin notification role subscription.
- Controlled by:
var.lookup_existing_role_subscription
andvar.admin_role_type
.
Local Blocks
Local variables are where things get stitched together. Here’s how we prepare all the pieces to work together effectively:
π Org & Environment Setup
- Pull in current org ID and domain from Okta metadata.
- Decide what “partition” we’re working in β
oktapreview
orokta
.
πΉ Managed Applications
-
Collect applications to be managed by admins from:
- Names
- Labels
- Patterns (fuzzy search)
- IDs
-
Merge and flatten them all into a single list (
all_managed_apps
). -
Extract app IDs and convert them into API resource URIs.
πΉ Managed Groups
-
Collect groups to be managed using:
- Exact names
- Patterns
- IDs
-
Build full URIs for these as well.
π§βπ» Admin Users & Groups
-
Collect users and groups that should receive admin roles using:
- Exact matches
- Search patterns
- Direct IDs
-
Build ORNs (Okta Resource Names) for each admin user and group.
β¨ Role & Assignment Logic
- Determine whether you’re using a custom or standard role.
- If custom, use a provided ID or fallback to one created within the module.
- Gather URI-style member entries for users/groups receiving custom roles.
π’ Notifications & Validation
- Handle notification subscriptions differently depending on role type.
- Include a fail-fast validation block to make sure custom roles have all required inputs.
These locals do the hard work of abstracting input formats into API-ready data, so the rest of the module can stay clean and predictable.
Administrator Roles
This is where the actual admin roles get created and assigned. Depending on whether youβre using a custom or standard role, different resources are deployed.
β¨ Custom Admin Roles
-
If you choose a custom role (
admin_role_type = "CUSTOM"
), the module:- Creates a new custom admin role if a
custom_role_label
is provided. - Creates a resource set with the apps and groups that the role can manage.
- Assigns the role to the specified users and/or groups using that resource set.
- Creates a new custom admin role if a
βοΈ Standard Admin Roles
-
If you pick a built-in Okta role like
USER_ADMIN
,GROUP_MEMBERSHIP_ADMIN
, etc.:- Assigns that role directly to user IDs via
okta_user_admin_roles
. - If the role supports targeting groups (like
GROUP_MEMBERSHIP_ADMIN
,HELP_DESK_ADMIN
,USER_ADMIN
), it links those admin groups to the groups theyβll manage. - If the role supports app targeting (like
APP_ADMIN
), it links admin groups to the apps theyβll manage.
- Assigns that role directly to user IDs via
π’ Notifications
- Uses
okta_role_subscription
to manage which notifications assigned admins will receive. - If legacy notification support is needed, the module falls back to a basic unsubscribed announcement setup.
- Custom roles do not support notifications directly, so those blocks are skipped when custom roles are in use.
This structure makes it easy to scale from a few admins with static assignments to dynamic, role-based access at scale.
Outputs
These outputs are helpful for debugging, logging, or passing data downstream into other modules. Theyβre split into useful categories.
π’ Org and Context
org_id
,org_url
,partition
: Identify the Okta tenant and its environment (prod or preview).
π¨βπΌ Admin Role Insights
admin_role_type
,is_standard_role
,using_custom_role
: Tell you what kind of role is being used.custom_role_id
,custom_role_permissions
: Expose details when a custom role is used.
πΉ Resource Set
resource_set_id
: ID for the resource set (apps and groups the role can manage).
π Managed Applications
managed_apps
,managed_app_ids
: Full details and IDs of apps admins will manage.
π Admin Groups (Who Gets Roles)
admin_groups
,admin_group_ids
: Group info for those receiving admin rights.
π Managed Groups (Who Is Managed)
managed_groups
,managed_group_ids
: Group info for those being managed by admins.
π§βπ» Admin Users
admin_users
,admin_user_ids
: User details and IDs of people who become admins.
πΉ ORNs (Okta Resource Names)
admin_user_orns
,admin_group_orns
,managed_group_orns
: Useful for audit logging and referencing identities within Okta APIs.
π Assignment Tracking
user_admin_role_assignments
: Shows which roles were given to which users.group_admin_role_assignments
: Tracks group-based role assignments, whether app-based or group-based.custom_role_assignments
: Gives a summary of any custom roles that were assigned β including role ID, resource set ID, and member count.
Putting it all together
And then, hopefully, when I can get the chance and approval, we can publish the Terraform Module, but at least this gives you an idea the complexity and the massive scope that this does to try and pull everything in to do all you need it to.