Teams integration with AWS lambda + Postgres & Tulip

Microsoft teams has a pretty nifty way of opening access to posting messages. This can be configured like this

After generating a webhook url, let’s store it in SSM since it is credentials for writing to a channel. For this first go ahead I’m going to store it as json with multiple key pairs, it might be better to store them separately, but this will work for now.

The general look is

"team_test1": "",
"team_test2": ""

Let’s call the paramater


Next, creating the lambda

So it grabs the possible channels from SSM and loads into key pairs for use later (the channel_name paramater)

import sys
import logging
import os
import json
import urllib3
import boto3

logger = logging.getLogger()
runtime_region = os.environ['AWS_REGION']

http = urllib3.PoolManager()
session = boto3.Session(region_name=runtime_region)
ssm = session.client('ssm')
channels = ssm.get_parameter(Name='/dev/teamsintegration/channels', WithDecryption=True)['Parameter']['Value']
channels = json.loads(channels)

def send_teams(webhook_url: str, content: str, title: str, color: str="000000") -> int:

    msg = {
            "@context": "",
            "@type": "MessageCard",
            "themeColor": color,
            "title": title,
            "text": content
    encoded_msg = json.dumps(msg).encode('utf-8')
    http.request('POST', webhook_url, body=encoded_msg)
def lambda_handler(event, context):
    content = event["content"]
    title = event["title"]
    color = event["color"]
    channel_name = event["channel_name"]
    webhook_url = channels[channel_name]

        send_teams(webhook_url, content, title,color)
        return {
        'statusCode': 200,
        'body': json.dumps(title)
    except Exception as error:

In order for the lambda to access the SSM parameter create a quick inline policy

    "Statement": [
            "Action": "ssm:DescribeParameters",
            "Effect": "Allow",
            "Resource": "*",
            "Sid": "VisualEditor0"
            "Action": "ssm:GetParameter",
            "Effect": "Allow",
            "Resource": "arn:aws:ssm:us-east-1:accountid:parameter/dev/teamsintegration/channels",
            "Sid": "VisualEditor1"
    "Version": "2012-10-17"

Ok, lets test this function out. Configure a test event like this

  "content": "some content",
  "title": "a title that is really cool",
  "color": "ff0400",
  "channel_name1": "team_test1"

Assuming that all worked you should get

To use this from Tulip my favorite method is

Grant your rds-lambda-role permission to execute the lambda.

    "Version": "2012-10-17",
    "Statement": [
            "Action": "lambda:InvokeFunction",
            "Effect": "Allow",
            "Resource": "arn:aws:lambda:us-east-1:943667677541:function:your-function-name-here",
            "Sid": "VisualEditor2"

Wrap it in a postgres function

CREATE OR REPLACE FUNCTION public.send_teams_msg(content text, title text, color text, channel_name text)
 RETURNS integer
 LANGUAGE plpgsql
AS $function$

  rows_affected int;
  create_json TEXT;
  response TEXT;
  err_context text;
RAISE INFO 'Started';	  
-- Create Json	  
	create_json row_to_json(t)
	   ) t;
SELECT into response payload FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('your-function-name-here', 'us-east-1'),

RAISE INFO 'response:%',response;

-- parse the response
select into response response::json->'response';
-- remove qutoes
select into response replace(response,'"','');

if response = 'sent' then 
	return 1;
	return 0;


Call it like this

select public.send_teams_msg('some content','the title', 'ff0400','team_test1')

Then create a connector function

Then of course you can use it in an app like this

Of course, no solution is really complete until automated so let’s Terraform this up.

So this is a somewhat incomplete .tf


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s