
As mentioned in the last blog on granular RBAC, the way Scalr does IAM is a key differentiator from the competition. Scalr allows for custom roles and access policies at every scope in the product, which makes the RBAC model very flexible. That flexibility helps, but only if you manage RBAC in a way that scales. The way to do that is to automate it with the Scalr provider.
Automating RBAC is one step in a larger effort to "vend" Scalr environments, which is a best practice when onboarding new applications and teams. Typically you build a Scalr module that creates teams and associates a role with each team. The module then creates an environment and links provider credentials, policies, teams, variables, and modules to it. A team can then log into a pre-configured environment and focus on their Terraform deployments. (If you already have a vending machine for your cloud accounts and subscriptions, you can extend it to Scalr as well.) The rest of this post walks through the technical detail of automating Scalr RBAC.
There are a few objects that need to be managed:
In this tutorial, we'll use the Scalr provider to assign a team with a custom role to an environment. We'll walk through each piece of code first so you can see how it's used. Near the bottom of the post you'll find the end result: a single main.tf with all of the code in it.
First, let's set up the provider in a providers.tf. Get the provider information from https://registry.scalr.io/:
terraform {
required_providers {
scalr = {
source = "registry.scalr.io/scalr/scalr"
version= "1.0.0-rc32"
}
}
}Let's start constructing our main.tf. First we'll add a local to define the account:
##Define your account and environment ID##
locals {
account_id = "<your-account-id>"
}Next add some data sources to pull IDs:
data "scalr_environment" "example" {
name = "Research-Development"
account_id = local.account_id
}
data "scalr_role" "example" {
name = "account-min-access"
}Now, let's create a predefined set of roles that all teams will be assigned. The majority of the time, roles are created upfront and then modified as needed, this is not something that is updated frequently. For these purposes, we'll create a role, which is used for the applications teams who need to create Terraform runs only.
resource "scalr_role" "planner" {
name = "Plan Creation"
account_id = local.account_id
description = "Ability to create Terraform runs, but not approve"
permissions = [
"accounts:read",
"environments:read",
"runs:cancel",
"runs:create",
"workspaces:read",
"workspaces:set-schedule",
"workspaces:update"
]
}Next, let's add a team. Normally, you would likely want to use Terraform variables to reuse the code, but for these purposes we'll hardcode and use locals for the account/environment ID. Further down in the blog you will see all of the code with the locals defined:
resource "scalr_iam_team" "example" {
name = "myfirstscalrteam"
description = "Scalr Example Team"
account_id = local.account_id
}Lastly, we need to create an access policy to attach the role to a team and link the team to a scope in Scalr. All teams must have at least the 'account-min-access' role at the account scope to have access to Scalr, and then they can be added to the environment in which they will create runs:
##Link to the account first with minimal access##
resource "scalr_access_policy" "team_min_access_to_acc_scope" {
subject {
type = "team"
id = scalr_iam_team.example.id
}
scope {
type = "account"
id = local.account_id
}
role_ids = [
data.scalr_role.example.id
]
}
##Link to an environment with role created earlier##
resource "scalr_access_policy" "team_access_to_env_scope" {
subject {
type = "team"
id = scalr_iam_team.example.id
}
scope {
type = "environment"
id = data.scalr_environment.example.id
}
role_ids = [
scalr_role.planner.id
]
}All together, this looks like:
##Define your account ID##
locals {
account_id = "acc-sscctbisjkl35b8"
}
data "scalr_environment" "example" {
name = "Research-Development"
account_id = local.account_id
}
data "scalr_role" "example" {
name = "account-min-access"
}
resource "scalr_role" "planner" {
name = "Plan Creation"
account_id = local.account_id
description = "Ability to create Terraform runs, but not approve"
permissions = [
"accounts:read",
"environments:read",
"runs:cancel",
"runs:create",
"workspaces:read",
"workspaces:set-schedule",
"workspaces:update"
]
}
resource "scalr_iam_team" "example" {
name = "myfirstscalrteam"
description = "Scalr Example Team"
##Add your own account ID##
account_id = local.account_id
}
##Link to the account first with minimal access##
resource "scalr_access_policy" "team_min_access_to_acc_scope" {
subject {
type = "team"
id = scalr_iam_team.example.id
}
scope {
type = "account"
id = local.account_id
}
role_ids = [
data.scalr_role.example.id
]
}
##Link to an environment with role created earlier##
resource "scalr_access_policy" "team_access_to_env_scope" {
subject {
type = "team"
id = scalr_iam_team.example.id
}
scope {
type = "environment"
id = data.scalr_environment.example.id
}
role_ids = [
scalr_role.planner.id
]
}To execute this, you have a couple of options:
I'm choosing to use a VCS backed workspace:

Upon execution we see that the four resources have been created:

And can verify this by looking at each object in the account scope:
Team creation:

Role creation:

Account scope access policy:

Environment scope access policy:

What's next
Now that you have learned the basics of how to use the Scalr provider to manage IAM, you can take it to the next level with these few suggestions:
Look for more examples on other concepts coming soon.
