Configuration Details

Overview

This following section describes each of the resources in main.tf and walks you through the impl.py file as created via the symflow init command.

The main.tf Terraform Configuration

Terraform setup

First off, we need to declare the sym provider and org slug. Then, for the purposes of this example, we'll be using local variables to set the environment_name.

locals {
  environment_name = "main"
}

provider "sym" {
  org = "your-org-slug"
}

sym_flow

The Terraform configuration of a sym_flow can be broken down into two parts:

The basics

resource "sym_flow" "this" {
  name  = "approval"
  label = "Approval"

  implementation = "${path.module}/impl.py"
  environment_id = sym_environment.this.id
  
  vars = {
    auto_approve = "[email protected]"
  }
  ...
}

The basic configuration of a sym_flow includes:

FieldDescriptionRequired
nameA unique, human-readable identifier for the Flow. This can be used to run the Flow directly in Slack (e.g. /sym req approval)Yes
labelThe display name for the Flow. This is what you'll see in Slack.No
implementationThe path to a file where the Sym Python SDK will be used to customize the workflow. More on that later!Yes
environment_idWhat Environment this Flow belongs to. This can be helpful to separate Flows you're still iterating on and testing from Flows that are stable and used every day by your organization. Think "main" vs. "sandbox" or "prod" vs. "staging".Yes
varsA string to string map of values to pass to impl.pyNo
11721172

name, label, and environment are surfaced in the Slack modal.

The prompt fields

Different types of access requests need different types of data. That's why Flows support custom fields in the request modal! We've kept it fairly basic here with just two generic questions— "what" and "why"— but fields can be as specific as needed. Check out Prompt Fields for more information.

resource "sym_flow" "this" {
  ...

  params {
    # Each prompt_field defines a custom form field for the Slack modal that
    # requesters fill out to make their requests.
    prompt_field {
      name     = "resource"
      label    = "What do you need access to?"
      type     = "string"
      required = true
    }
  
    prompt_field {
      name     = "reason"
      label    = "Why do you need access?"
      type     = "string"
      required = true
    }
  }
}
11661166

prompt_fields_json becomes form fields for your request modal!

sym_environment

The sym_environment resource is a collection of shared configuration for your Flows. It will tell your Flow, for example, where to send errors and which integrations to use:

resource "sym_environment" "this" {
  name            = local.environment_name
  runtime_id      = sym_runtime.this.id
  error_logger_id = sym_error_logger.slack.id

  integrations = {
    slack_id = sym_integration.slack.id

    # Add your integration IDs here!
  }
}

sym_integration

sym_integration resources allow you to provide Sym with the credentials and context to connect to an external service. In this case, the Slack integration only needs your Workspace ID.

resource "sym_integration" "slack" {
  type = "slack"
  name = "${local.environment_name}-slack"

  external_id = "T12345"
}

sym_error_logger

The sym_error_logger resource configures the Slack channel destination for any warnings and errors that occur during the execution of a Flow.

resource "sym_error_logger" "slack" {
  integration_id = sym_integration.slack.id

  # Make sure that this channel has been created in your workspace
  destination    = "#sym-errors"
}

sym_runtime

The sym_runtime resource is where you declare your personal instance of the Sym Runtime. This is, for example, where you might give the Sym Runtime permission to assume a role in your own AWS account to manage IAM roles.

resource "sym_runtime" "this" {
  name = local.environment_name

  # For AWS IAM, SSO, Lambda strategies, add your context ID here! For example:
  # context_id = sym_integration.runtime_context.id
}

The impl.py Python Implementation

Now that the sym_flow resource is configured, all that's left is to write its impl.py. This is where Sym's Python SDK can be used to customize your Flow's logic.

The first thing we'll need in the impl.py is a get_approvers reducer. This is the only required part of an impl.py, and it tells Sym where to send access requests in Slack:

# First, we'll import everything we need for this impl.py
from sym.sdk.annotations import hook, reducer
from sym.sdk.integrations import slack
from sym.sdk.templates import ApprovalTemplate

# Then, we add our first reducer! `get_approvers` will be used any time a request
# is made in Sym.
@reducer
def get_approvers(event):
    """Route Sym requests to a specified channel."""

    # Make sure that this channel has been created in your workspace!
    return slack.channel("#sym-requests")

While get_approvers is the only required function in the impl.py, there is another basic, commonly used hooks: on_request.

This hook runs when the requester submits the request modal, before the event is let through, so it has the chance to modify events based on custom logic. In this example, the on_request hook is auto-approving users defined in the sym_flow.vars block, and modifying the reason field displayed in the request.

@hook
def on_request(event):
    """Auto-approve people defined in the auto-approve list in the sym_flow vars"""

    # Convert the comma-separated string defined in `sym_flow.vars` into a list of emails.
    flow_vars = event.flow.vars
    auto_approve = flow_vars["auto_approve"].split(",")

    # If the user's email matches, the request will be auto-approved
    if event.user.username in auto_approve:
        original_reason = event.payload.fields.get("reason")
        new_reason = f"Auto-approved! {original_reason}️"
        return ApprovalTemplate.approve(reason=new_reason)

Testing in Slack

Almost there! All the Terraform configuration is now written, all that's left to do is test it out. We'll start by applying the Terraform:

$ terraform init

Initializing the backend...
Initializing provider plugins...
Terraform has been successfully initialized!

$ terraform apply

sym_runtime.this: Creating...
sym_integration.slack: Creating...
sym_runtime.this: Creation complete after 1s [id=c1d119ed-9618-4b86-95c9-bc5702c04acc]
sym_integration.slack: Creation complete after 1s [id=2127a917-f92b-491a-ba63-6556734b152c]
sym_error_logger.slack: Creating...
sym_error_logger.slack: Creation complete after 0s [id=358fa690-c5bb-457e-9527-ef5aad12a542]
...

Once the terraform apply is done:

  1. Go to the Slack workspace you installed Sym in
  2. Type /sym anywhere

You should see your very first Sym Flow:

581581

Next steps

Nice job! You should have a basic Sym Approval-Only Flow up and running. Now that you've got the basics down, there are a ton of ways to tailor Sym to your organization's needs. To learn more, check out:

  • Integrated Services - Learn how Sym can automatically grant or escalate access to external services like AWS, Okta, and Aptible.
  • Approval workflows-as-code - Learn how to customize the impl.py to fit your specific rules using our Python SDK.
  • Reporting and audit - Learn how to get structured logs for all access requests and set your organization up for audit success via our Reporting framework.

📘

Check out our Examples Repo for end-to-end examples

If you're looking for some fully-baked samples of working Sym Flows, head over to our Examples Repo!