Easily build complex reports
Monitoring and efficiency metrics
Custom cost allocation tags
Network cost visibility
Organizational cost hierarchies
Budgeting and budget alerts
Discover active resources
Consumption-based insights
Alerts for unexpected charges
Automated AWS cost savings
Discover cost savings
Unified view of AWS discounts
COGS and business metrics
Model savings plans
Collaborate on cost initiatives
Create and manage your teams
Automate cloud infrastructure
Cloud cost issue tracking
Detect cost spikes
by Danielle Vansia
Contents
In this post, we demonstrate how to automate new user and team setup for SaaS applications via Okta and infrastructure as code techniques using Terraform. Organizations will typically have established user groups and permissions in their identity management system. Mapping this structure to new SaaS tools for initial setup can often be chaotic. By using Terraform to automate Okta SSO group management, Okta administrators and DevOps teams can provision their entire organization structure inside Vantage in seconds.
If you are just getting started with Terraform, see our introduction to Terraform and FinOps as Code.
Your organization just started using Vantage. As the Okta administrator, you have a set of existing Okta groups with users that will need to access Vantage. You want to use Terraform and have these user groups in Okta be reflected in Vantage, with the same group members. You have a CSV file that contains the list of groups you need to manage.
Workflow diagram of Okta–Terraform–Vantage configuration
In this demo, we’ll complete the following steps:
When Okta users from these designated groups access Vantage for the first time, they’re seamlessly integrated as new Vantage users. They’re automatically assigned to a corresponding Vantage team based on their Okta group affiliation.
As shown in the diagram below, a DevOps team user logs in to Vantage via Okta. They belong to the DevOps Okta group. The groups field in the SSO payload matches this user with the corresponding DevOps Vantage team. They will also have access to Vantage resources (e.g., folders and Costs Reports) that have explicit access granted to the DevOps team.
groups
Workflow diagram of Okta–Vantage SSO and resource access
This tutorial assumes you have an intermediate knowledge of Terraform and Okta. For Terraform, you should know how to create a basic configuration, have a basic understanding of for_each loops, and an understanding of how to use variables. For Okta, you should know how to navigate the Okta console, set up an application integration, and manage users and groups.
for_each
You’ll need to be an Okta administrator for your organization with the ability to assign applications to groups and create a SAML SSO application. See the Okta documentation for details on administrator permissions.
You’ll also need to create a service app that provides Terraform access to your Okta account. With the service app, you can create a private key pair as your client credentials. You’ll need the service app’s client ID and a private key to configure in your Okta Terraform provider configuration. Ensure the service app is granted the following scopes: okta.groups.manage, okta.users.manage, and okta.policies.manage. For more information on how to configure this service app, see the Okta documentation.
okta.groups.manage
okta.users.manage
okta.policies.manage
You can also reference this Okta workshop for detailed instructions and a video on setting up an Okta–Terraform integration.
For Vantage, you will need to be an organization owner with an active account and at least one provider connection. You will also need a Vantage API token with READ and WRITE scopes enabled.
READ
WRITE
To create a SAML SSO connection between Okta and Vantage, follow the Vantage SSO documentation. Enable SSO group mapping so you can automatically assign users to Vantage teams that match the name of a corresponding Okta group. Once configured in Vantage, your SSO connection will look like the following image.
Vantage SSO configuration screen
In this example, the organization’s domain is @company.com. Note the SSO Team Assignment toggle is enabled. If a user tries to log in to Vantage with a company.com email address, they will be redirected to their organization’s Okta login screen.
@company.com
company.com
All demo files are also included in the FinOps as Code demo repo.
To begin, create a new project directory and move to it:
mkdir okta-terraform && cd okta-terraform
Create a Terraform configuration file and call it okta-vantage.tf. Create variables.tf to store some Vantage and Okta configuration values. Create providers.tf to store the provider configurations.
okta-vantage.tf
variables.tf
providers.tf
touch okta-vantage.tf touch variables.tf touch providers.tf
Add the following values to variables.tf.
variable "okta_org_name" { type = string description = "Okta org name" default = "<YOUR_ORG>" } variable "okta_base_url" { type = string description = "Okta base url" default = "okta.com" } variable "okta_client_id" { type = string description = "Okta client ID" default = "<YOUR_OKTA_CLIENT_ID>" } variable "vantage_workspace_token" { type = string description = "Vantage workspace token" default = "<YOUR_VANTAGE_WORKSPACE>" }
okta_org_name
dev-123456
okta_base_url
okta.com
oktapreview.com
okta_client_id
vantage_workspace_token
wrkspc_12345
You’ll also need to store the Vantage API token. You can export this token as an environment variable.
export VANTAGE_API_TOKEN=<YOUR_VANTAGE_API_TOKEN>
Open providers.tf and declare the Vantage and Okta providers. Declare all the variables stored in the variables.tf in the Okta provider configuration block. (The vantage_workspace_token variable will be used later. No additional provider configuration options need to be declared for Vantage.)
In this demo, we assume you are storing the private_key in the same directory as your configuration and it’s called rsa.pem.
private_key
rsa.pem
terraform { required_providers { vantage = { source = "vantage-sh/vantage" } okta = { source = "okta/okta" } } } provider "okta" { org_name = var.okta_org_name base_url = var.okta_base_url client_id = var.okta_client_id scopes = ["okta.groups.manage", "okta.users.manage", "okta.policies.manage"] private_key = "${path.module}/rsa.pem" }
Save and run the init command to initialize the configuration and download the latest providers.
init
terraform init
As the Okta administrator, you already know the names of the groups that will need access to Vantage. These names are currently stored in a single-column CSV file, which you can decode and iterate over in your configuration. For this demo, we’ll create a local variable that holds the CSV content and another that decodes it. Typically, this file would be in an external location, outside of this configuration.
local
See the Terraform documentation for more information on working with CSV files.
Open okta-vantage.tf and add the following block.
locals { okta_group_csv_content = <<-CSV name Engineering DevOps Finance CSV okta_groups = csvdecode(local.okta_group_csv_content) }
Next, assign the Vantage app to each of these groups in Okta. You need to obtain the IDs for each group as well as the ID for the Vantage app. You can use the okta_group and okta_app data sources to get both sets of IDs. When calling the okta_group data source, use a for_each loop to iterate over the CSV file and get the group information for each of the listed groups. For okta_app, set the label equal to Vantage to access your previously created application.
okta_group
okta_app
label
Vantage
data "okta_group" "group_info" { for_each = { for k, group in local.okta_groups : k => group } name = each.value.name } data "okta_app" "app_info" { label = "Vantage" }
Next, use the okta_app_group_assignments resource to assign the Vantage app to each group.
okta_app_group_assignments
resource "okta_app_group_assignments" "vantage_app" { app_id = data.okta_app.app_info.id dynamic "group" { for_each = data.okta_group.group_info content { id = group.value.id } } }
Add the following resource blocks to the configuration to create cost reporting resources in Vantage. These blocks create a Vantage folder and Cost Report for each team.
resource
resource "vantage_folder" "group_folders" { for_each = { for group in local.okta_groups : group.name => group } title = each.value.name workspace_token = var.vantage_workspace_token } resource "vantage_cost_report" "group_reports" { for_each = { for group in local.okta_groups : group.name => group } folder_token = vantage_folder.group_folders[each.key].token filter = "costs.provider = 'aws' AND (tags.name, tags.value) IN (('team', '${lower(each.value.name)}'))" title = "${each.value.name} Costs" }
The above configuration blocks perform the following actions:
vantage_folder
[Team] Costs
DevOps Costs
filter
team
devops
engineering
finance
Now that the Vantage resources are created, you can create teams that exactly match the names of the Okta groups. Remember, when a user logs in to Vantage via Okta, Okta sends the groups parameter in the SSO payload, so Vantage can map the user to a corresponding Vantage team with that same name.
Add a block for the vantage_team resource that uses the CSV list of groups for the team name.
vantage_team
resource "vantage_team" "okta_team" { for_each = { for group in local.okta_groups : group.name => group } name = each.value.name description = "Team automatically created from Okta group ${each.value.name}" }
If you were to deploy the current configuration, an Okta user in the list of groups could log in to Vantage via SSO and automatically be added to the corresponding Vantage team. The user could view all folders and Cost Reports previously created, regardless of team.
If you want to take this one step further and lock down permissions to each of the previously created folders and Cost Reports, you can use access grants to allow or deny a Vantage team access to specific folders or reports.
This step is optional, and you can deploy the current Terraform configuration without completing this step.
Use the vantage_access_grant resource to grant each Vantage team you created explicit access to their corresponding folder. For example, a user on the Engineering team will be allowed access to the Engineering folder. Because the Engineering Cost Report is inside the Engineering folder, that Cost Report will inherit this same access grant.
vantage_access_grant
Use a for_each loop to iterate through each of the created teams from the vantage_team resource. For team_token, set the value to the token that was generated when the team was created. For resource_token, call the vantage_folder.group_folders resource to access each of the folders that was previously created.
team_token
token
resource_token
vantage_folder.group_folders
resource "vantage_access_grant" "okta_team_access_grant" { for_each = { for team_name, team in vantage_team.okta_team : team_name => team } team_token = each.value.token resource_token = vantage_folder.group_folders[each.key].token access = "allowed" }
For the last step, you need to remove access from the Everyone team for all previously created resources. In Vantage, the Everyone team is the default team a user belongs to. If you remove access from the Everyone team to a folder or Cost Report, then only teams who were explicitly granted access to that folder can access it. In this case, only Engineering will be able to view and edit the Engineering folder, and so on.
Everyone
Because you have not interacted with the Everyone team via the current configuration, call the vantage_teams data source to get information for all teams in Vantage.
vantage_teams
data "vantage_teams" "teams_info" { }
You need to access the token for the Everyone team to reference when you assign that team a denied grant. Create a local variable that uses a for loop to iterate through the previously received team data and accesses the token for the Everyone team.
for
In addition, create a local variable for all the previously created folder tokens.
locals { everyone_team_token = { for team in data.vantage_teams.teams_info.teams : team.name => team.token if team.name == "Everyone" } folder_tokens = { for key, folder in vantage_folder.group_folders : key => folder.token } }
Finally, use the vantage_access_grant resource to create a denied access grant. Use a for_each loop to iterate through the local.folder_tokens variable. Reference the local.everyone_team_token variable for the Everyone team and assign denied access to each folder and Cost Report under it.
local.folder_tokens
local.everyone_team_token
denied
resource "vantage_access_grant" "okta_team_deny_grant" { for_each = local.folder_tokens team_token = local.everyone_team_token["Everyone"] resource_token = each.value access = "denied" }
Save your configuration and deploy with the plan and apply commands:
plan
apply
terraform plan terraform apply
Once deployed, the Vantage app will be assigned to each of the target groups in Okta.
Vantage app assigned to all Okta groups
When a DevOps user logs in to Vantage via Okta, they will see only their DevOps report within the DevOps folder, filtered to costs tagged by their team.
Cost Report for the example DevOps team in the Vantage console
In conclusion, using Terraform to automate Okta SSO group access not only streamlines the onboarding process to new SaaS applications like Vantage but also ensures consistent user access across platforms. By seamlessly integrating Okta with Vantage through Terraform, organizations can effortlessly synchronize user groups, facilitate team-based access controls, and enhance overall operational efficiency in managing identity and access management workflows.
MongoDB Atlas is the cost-effective choice for production workloads where high-availability is a requirement.
Grafana is a strong competitor to the monitoring and observability features of Datadog for a fraction of the price.
AWS is implementing a policy update that will no longer allow Reserved Instances and Savings Plans to be shared across end customers.