Skip to main content

Connect Microsoft Teams to Genesis on SPCS

Microsoft Bot Framework must POST activities to a publicly reachable HTTPS endpoint. Snowflake SPCS ingress is protected by Snowflake authentication, so Bot Framework cannot call an SPCS-hosted Genesis service directly. The Genesis Teams relay provides the public endpoint and forwards each activity through authenticated SPCS ingress.

Choose the deployment path

Complete the Azure Bot, Teams channel, Genesis bot credentials, and Teams app manifest steps in the direct Bot Framework runbook. On SPCS, replace only its direct messaging-endpoint step with the relay endpoint configured below.

Before you begin

You need:
  • An Azure subscription and permission to deploy a public HTTPS container
  • A Microsoft 365 tenant and an Azure Bot configured for Microsoft Teams
  • Access to administer the Genesis deployment’s Config pages
  • Snowflake permission to create a dedicated service user and role
  • The public SPCS service URL for the Genesis deployment

Register the Azure resource provider

Azure Container Apps requires the Microsoft.App resource provider. On a subscription that has never hosted a Container App it is unregistered, and container-app creation fails until registration completes:
Registration is a one-time, subscription-wide operation and can take a few minutes. Azure App Service instead requires Microsoft.Web.

Deploy the relay

Choose an immutable relay release and pull it from the public Docker Hub repository. Relay versions are independent of Genesis versions.
Use an immutable vX.Y.Z tag for production. sha-<commit> identifies a source revision, while latest moves whenever a relay release is published. Deploy the image to a public Azure container host such as Azure Container Apps or Azure App Service, expose container port 8080 over HTTPS, and configure: Store the RSA private key in the Azure host’s secret facility, mount it read-only, and set RELAY_SNOWFLAKE_PRIVATE_KEY_PATH to the mount path. For Azure Container Apps, set minimum replicas to at least 1. Its default scale-to-zero behavior is unsafe here: the relay pre-warms its Snowflake token at startup, and a cold token exchange can take tens of seconds while Bot Framework allows about 15 seconds for delivery. A cold-starting relay can therefore drop the first message. Configure the readiness probe to use /ready and the liveness probe to use /health: readiness gates traffic, while liveness restarts the container. Replica replacement for platform maintenance, node drain, and image updates happens regardless of scaling configuration, so the readiness probe matters even when replicas are pinned to 1. Without it, a replacement relay can receive activities before its Snowflake token is warm, and Bot Framework may exhaust its retries before the relay can serve, dropping the message. The relay’s activity-deduplication cache is per-instance and in memory. With N relay replicas, the same activity can be admitted up to N times. Genesis-side deduplication remains authoritative. After deployment, verify:
Do not configure Azure Bot until token_state is valid.

Configure Snowflake and Genesis

1

Create a dedicated Snowflake identity

Create a service user and a role used only by the relay. The recommended name for both is GENESIS_TEAMS_RELAY. Configure RSA key-pair authentication on the user.
Then grant that role exactly two privileges — the Genesis application role, which is what authorises the relay to reach the Genesis service endpoint, and usage on the warehouse the deployment runs against:
GENESIS_DATA_AGENTS is the Genesis application name; substitute the name your deployment used at install time. APP_PUBLIC is the application’s only application role.Confirm both grants landed:
Do not reuse a human, ACCOUNTADMIN, or application-owner credential for the relay. Record the key owner in the deployment runbook.
2

Rotate the relay key

Rotation is a two-part operation: publish the new public key in Snowflake, then point the relay at the matching new private key.
Strip the -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- lines — Snowflake stores the base64 body only.Verify what Snowflake now holds:
RSA_PUBLIC_KEY_FP is the fingerprint of the stored key and RSA_PUBLIC_KEY_LAST_SET_TIME records when it was last changed — together they confirm the rotation took effect rather than silently leaving the old key in place.For zero-downtime rotation, Snowflake accepts a second key in RSA_PUBLIC_KEY_2. Publish the new key there first, restart the relay onto the new private key, confirm /health still reports token_state valid, then clear the old key:
Update the mounted private key in the Azure secret store as part of the same change, and rotate immediately after any suspected exposure.
3

Confine the relay identity in Genesis

In the Genesis dashboard, open Config → Advanced Settings and set teams.relay_service_user to the exact Snowflake service-user name, for example GENESIS_TEAMS_RELAY.Genesis then confines requests authenticated as that identity to the Teams message, Teams health, and enabled Teams ingress-canary routes. The forwarded Bot Framework authorization header is accepted only after this identity gate passes.
4

Optional: enable ingress diagnostics

When header loss or relay routing issues are suspected, set teams.ingress_canary_enabled to true in Config → Advanced Settings. The confined relay identity (and unauthenticated callers when the flag is on) can then reach GET or POST /api/teams/ingress-canary, which returns a value-redacted summary of headers (presence, length, and a short SHA-256 prefix — never plaintext tokens). Disable the flag after troubleshooting.
5

Approve Bot Framework egress

In the Genesis dashboard, open Config → Microsoft Teams, click Approve External Access (this opens Snowsight to approve the “Teams Bot Framework” external-access reference), then Assign to Genesis. Genesis needs this external access both to fetch Microsoft’s signing metadata (to validate inbound Bot Framework tokens) and to send replies. Assigning briefly restarts the Genesis service to apply the change.

If the relay starts returning 403s

A relay that authenticates fine but gets 403s has lost its application-role grant. This failure is worth recognising on sight because every identity signal looks healthy: the service user is enabled, the key is valid, Snowflake login succeeds, and the relay’s /health still reports token_state valid. Only the authorisation to reach Genesis is gone, so the symptom presents as a Genesis permissions bug rather than a missing Snowflake grant.The grant is scoped to the Genesis application object rather than to the account, so it does not survive that object being dropped and recreated — which is what reinstalling Genesis does. The relay’s user and role are account-level and survive untouched, which is why nothing else looks wrong.Check first:
An empty result confirms it. Re-run the grants from the identity step above:
Adding that SHOW GRANTS check to the post-install runbook costs one query and removes an outage class that is otherwise slow to diagnose.

Configure Azure

  1. Before restricting Azure Container Apps ingress, verify in a live deployment whether IP restrictions accept the Azure Bot Service service tag or require CIDR ranges. Do not configure a service-tag restriction until that behavior is confirmed.
  2. In the Azure Bot resource, open Settings → Configuration.
  3. Set Messaging endpoint to:
    <bot_id> is the case-sensitive Genesis bot id, usually Eve.
  4. Leave Enable Streaming Endpoint unchecked and click Apply.

Verify the connection

  1. Confirm GET https://<relay-host>/health reports "token_state":"valid".
  2. Confirm the Genesis Teams health endpoint is reachable through the SPCS deployment and reports at least one registered bot.
  3. Install the Teams app and send the bot a direct message.
  4. Check relay logs for the request id, bot id, upstream status, and latency. The relay intentionally does not log request bodies, authorization headers, private keys, or tokens.
  5. Confirm Genesis logs show the activity was enqueued and the reply was sent.

Security boundary

The relay is trusted infrastructure. The Bot Framework JWT does not make an untrusted relay safe to operate. If the relay host or its Snowflake key is compromised, an attacker can impersonate Teams traffic to this bot and reach the Teams route only until the key is rotated.
Reduce this residual risk by keeping the relay small and patched, applying a host-specific inbound policy only after it has been verified, confining its Snowflake identity in Genesis, protecting the private key in the Azure secret store, and rotating the key immediately after suspected exposure.