AWS IAM Identity Center (SSO) Access Strategy

Use Sym to seamlessly shift users in and out of AWS SSO roles.

Sym's AWS SSO Strategy enables you to have:

  • Just-in-time permission set assignments to a given AWS Account
  • Just-in-time access to a given AWS SSO Group

πŸ‘

You can generate this!

You can automatically generate an AWS SSO Flow with symflow generate aws-sso!

Otherwise, follow the AWS Runtime Setup tutorial to set up your AWS dependencies.

Connect the Sym Runtime with your AWS Account

Follow the AWS Runtime Setup tutorial on the main AWS page to set up your runtime_connector module.

Add a AWS SSO Integration

Define the SSO Connector

The AWS SSO Access Strategy relies on a special module sso-connector. This module defines the AWS IAM Resources that enable Sym to manage SSO Permission Sets in your AWS Account.

provider "aws" {
  alias  = "sso"
  region = "us-east-1"

  # Change this profile name to a valid AWS profile for the AWS account where
  # your AWS SSO instance lives.
  profile = "sso"
}

# Get the AWS Account ID for the SSO profile.
data "aws_caller_identity" "sso" {
  provider = aws.sso
}

module "sso_connector" {
  source  = "symopsio/sso-connector/aws"
  version = ">= 1.0.0"

  # Provision the SSO connector in the AWS account where your AWS
  # SSO instance lives.
  providers = {
    aws = aws.sso
  }

  environment       = local.environment_name
  runtime_role_arns = [module.runtime_connector.sym_runtime_connector_role.arn]
}

Define the AWS SSO Permission Context Integration

Define a sym_integration resource with type = permission_context. This tells Sym to assume the AWS IAM Role defined by the SSO Connector module when managing your SSO Permission Sets, and will be referenced in the sym_strategy resource later.

  • external_id: The instance_arn output from module.sso_connector.settings
  • settings: The settings output from module.sso_connector
resource "sym_integration" "sso_context" {
  type = "permission_context"
  name = "sso-context-main"

  external_id = module.sso_connector.settings.instance_arn
  settings    = module.sso_connector.settings
}

Allow the Sym Runtime to Assume Roles in your SSO Account

The sso-connector module will create an AWS IAM Role in your SSO Account that has the permissions to create and remove account assignments. You will need to grant the Sym Runtime permissions to assume this role. In the runtime_connector module, add an account_id_safelist input containing your SSO Account ID.

module "runtime_connector" {
  source  = "symopsio/runtime-connector/aws"
  version = "~> 2.0"

  environment = local.environment_name

  # Allow the Runtime Connector Role to assume IAM Roles in the SSO Account as well.
  account_id_safelist = [data.aws_caller_identity.sso.account_id]
}

Add AWS SSO Access Targets

AWS SSO Permission Set Targets

Sym Targets with a type of aws_sso_permission_set enables just in time account assignments for a given permission set and AWS account.

Define sym_target resources with type = "aws_sso_permission_set" for all of the AWS SSO Permission Sets that you wish to manage.

  • account_id: The AWS Account ID for the AWS SSO Permission Set
  • permission_set_arn: The ARN of the AWS SSO Permission Set.
resource "sym_target" "sso_permission_set" {
  type  = "aws_sso_permission_set"
  name  = "aws-sso-target-main"
  label = "AWS SSO Permission Set Test Target"

  settings = {
    account_id = var.aws_sso_account_id
    permission_set_arn = aws_ssoadmin_permission_set.this.arn
  }
}

AWS SSO Group Targets

Sym Targets with a type of aws_sso_group enables just in time access to AWS SSO Groups.

Define sym_target resources with type = "aws_sso_group" for all of the AWS SSO groups that you wish to manage.

  • group_id: The ID of the AWS SSO Group. If you manage this group as an aws_identitystore_group resource in Terraform, you can use the group_id attribute to populate this value!
# An AWS SSO group to escalate users to
resource "aws_identitystore_group" "sso_group" {
  provider = aws.sso

  display_name      = "My AWS SSO Group"
  identity_store_id = one(data.aws_ssoadmin_instances.ingen_sso.identity_store_ids)
}

# AWS SSO Group Sym Target
resource "sym_target" "sso_group" {
  type = "aws_sso_group"
  name = "aws-sso-group-main"
  label = aws_identitystore_group.sso_group.display_name

  settings = {
    # The group ID to escalate users to
    group_id = aws_identitystore_group.sso_group.group_id
  }
}

Add an AWS SSO Access Strategy

Define a sym_strategy resource with type = aws_sso and include the AWS SSO Permission Context and AWS SSO Access Targets you defined above.

  • instance_arn = The instance_arn output from module.sso_connector.settings
resource "sym_strategy" "aws_sso" {
  type           = "aws_sso"
  name           = "aws-sso-strategy-main"

  integration_id = sym_integration.sso_context.id
  
  # A list of `aws_sso_permission_set` and/or `aws_sso_group` targets
  targets = [sym_target.sso_permission_set.id, sym-target.sso_group.id]

  settings = {
    instance_arn = module.sso_connector.settings.instance_arn
  }
}

Add the AWS SSO Strategy to your Flow

resource "sym_flow" "this" {
  name  = "sso-access-main"
  label = "AWS SSO Access"

  # ... other Flow attributes not shown

  params {
    strategy_id = sym_strategy.aws_sso.id

    # ... other Flow params not shown
  }
}

Full Example

You can find the complete code for this example in our AWS IAM Identity Center (SSO) Strategy Example.

🚧

Consider your session lengths

Sym access will provide your users with the keys to access escalated permissions, but AWS still governs the bounding sessions. This means:

  • If your Sym access is shorter than your default session length, users who access an escalated role will retain that role until their session times out.
  • Conversely, if your Sym access is longer than your default session length, users may be logged out and have to re-authenticate.

Advanced Concepts

Supply the AWS Account ID Dynamically

If you have many AWS Account IDs and don't want to create a Permission Set/Account ID combination for each one, you can use Dynamic Targets and a Prefetch Reducer to pull AWS Accounts dynamically!

Add an Account ID Prompt Field

In your sym_flow configuration, add a new prompt field for account_id with prefetch = true. This will add an input field "Account ID" to the Slack Request Modal. The list of accounts that a user may select from will be provided via a prefetch reducer that we will implement in a later step.

Note, this prompt field must have name = "account_id", because we are using this prompt field to populate the required account_id setting of the AWS SSO Access Target.

resource "sym_flow" "this" {
  name  = "aws_sso_access"
  label = "AWS SSO Access"

  # ... other Flow attributes not shown

  implementation = file("${path.module}/impls/aws-sso-impl.py")

  params {
    strategy_id = sym_strategy.this.id

    prompt_field {
      name     = "account_id"
      label    = "Account ID"
      type     = "string"
        prefetch = true
      required = true
    }
  
    # ... other prompt_fields and Flow params not shown
  }
}

Define a Dynamic Target

Define a target for each AWS SSO Permission Set, but with a special attribute called field_bindings. This attribute indicates that the account_id setting will be populated dynamically by the requester.

The field binding must be account_id, because this is the required setting that is being dynamically populated.

resource "sym_target" "permission-set" {
  type  = "aws_sso_permission_set"

  name  = "permission-set-name"
  label = "Permission Set Name"

  # A special attribute that indicates the `account_id` setting is dynamic
  field_bindings = ["account_id"]
  
  settings = {
    permission_set_arn = "arn:aws:sso:::permissionSet/ssoins-aaaaaaaaaaaaaaaa/ps-aaaaaaaaaaaaaaaa"
  }
}

Define a Prefetch Reducer for the Account IDs

In the first step, we added a prompt field named account_id with prefetch = true. When a user runs this Flow, Sym will look for a method in your implementation annotated with @prefetch(field_name="account_id"). This reducer should return a list of FieldOption objects, which are value and label pairs.

We will want to define a method that returns a list of Account ID and Account Names for Users to select from.

# Don't forget these imports!
from sym.sdk.annotations import prefetch
from sym.sdk.integrations import aws_sso

# ... Other reducers and hooks not shown

@prefetch(field_name="account_id")
def get_account_ids(event):
  # This gets all AWS Accounts that are direct children of this Organizational Unit.
  # If you wish to get all accounts, you may call aws_sso.list_accounts() with no parameters.
  # See: https://sdk.docs.symops.com/doc/sym.sdk.integrations.aws_sso.list_accounts.html
  all_accounts = aws_sso.list_accounts(organizational_unit_id="ou-abcd-123456789")

  # Return a list of FieldOption, where the displayed label is the Account's Name,
  # and the value is the Account ID.
  return [
      FieldOption(value=account["Id"], label=account["Name"])
      for account
      in all_accounts
  ]

With these changes, your requests should now have a type-ahead dropdown input allowing requesters to specify to which AWS Account they wish to be escalated to.