More Implementation Examples

Below is an assortment of additional examples and snippets using the Sym Python SDK.

๐Ÿšง

Restrictions Apply

Your impl.py will be executed inside of a RestrictedPython environment, and as a result certain methods might not be available (e.g. all(), next()).

In addition, imports are allowed from the following modules only:

  • sym.sdk
  • requests
  • json
  • datetime

Overview

This section provides some basic examples of customized routing logic in a Flow's impl.py.

Customizing approval behavior

allow_self

The slack.channel method allows you to specify whether or not a request should allow self-approvals. This is generally useful for testing, or for resources that don't require a second party for approval.

In the following implementation, all requests for the Flow are routed to the #sym-requests Slack channel and the requester may approve their own requests.

from sym.sdk.annotations import reducer
from sym.sdk.integrations import slack

@reducer
def get_approvers(event):
    return slack.channel("#sym-requests", allow_self=True)

Modify allow_self depending on the Target

In this example, the allow_self attribute is set based on the Target selected by the requester.

The Target of a request can be found in the fields attribute of the event Payload. The Target returned is a sym.sdk.target.AccessTarget object, containing attributes configured by the sym_target in main.tf

from sym.sdk.annotations import reducer
from sym.sdk.integrations import slack

@reducer
def get_approvers(event):
      # event.payload.fields["target"] returns a Sym SDK Target ojbect
    target = event.payload.fields["target"]
    allow_self = target.name == "not-so-sensitive-db"
  
    # Only allow_self if the target is "not-so-sensitive-db"
    return slack.channel(
        "#sym-requests",
        allow_self=allow_self,
    )

Auto-approve requests

While many Sym requests will benefit from the default human-in-the-middle approval workflow, there may be some workflows that want to move a bit more seamlessly, but without losing Sym's benefits of:

  • Request context
  • Access revocation
  • Audit for compliance

For this common scenario, the on_request Hook is your friend in automated expedience

from sym.sdk.annotations import hook
from sym.sdk.templates import ApprovalTemplate

@hook
def on_request(event):
    # When a request is made in this Flow, automatically approve it.
    return ApprovalTemplate.approve()

Customizing Slack logic

Send requests to the channel they came from

Some Sym workflows will be best served in their originating context -- that is to say, they should be sent into the same channel from which they were made.

Sym's Slack Integration makes this easy by providing both access to your initiating channel (evt.run.source_channel.identifier), and a method to define a fallback channel in case our Slack App doesn't have access to the originating channel:

from sym.sdk.annotations import reducer
from sym.sdk.integrations import slack

@reducer
def get_approvers(event):
    return slack.fallback(slack.channel(event.run.source_channel.identifier), slack.channel("#sym-access"))

Passing Variables from Terraform

Sometimes you will have variable defined in your Terraform that you want to access in your Flow. These could be values set by terraform.tfvars, or even resource attributes like the ARN of an AWS Lambda!

These variables are set by the vars attribute in your sym_flow Terraform resource. They are then exposed as event.flow.vars in your impl.py.

In the following example, the request_channel of the request is passed into the impl.py as a variable set in Terraform:

resource "sym_flow" "phi" {
  name     = "phi-access"
  label    = "PHI Access"

  implementation = file("${path.module}/impl.py")
  environment_id = var.sym_environment_id

  vars = {
    request_channel = "#sym-requests"

    # An example of a variable that is not known until apply-time!
    dynamo_arn = aws_dynamodb_table.my_table.arn
  }

  params { ... } # truncated
}
from sym.sdk.annotations import reducer
from sym.sdk.integrations import slack

@reducer
def get_approvers(event):
    fvars = event.flow.vars
    return slack.channel(fvars["request_channel"], allow_self=True)