AWS Viewer Integrations with Python
Problem
You are building an interactive Python application which needs to assume an AWS IAM role in order to access a private AWS resource, like S3. The content must authenticate to an identity provider configured to be validated by AWS using the viewer’s credentials. For example, you might need to read data from an IAM-role-restricted S3 bucket.
Solution
The examples below illustrate how to use the OAuth integrations feature of Posit Connect to delegate authorization for access to an external provider’s resources. In this case, we are focusing on S3 within AWS. These examples use the viewer’s OIDC token to assume an AWS IAM role that provides temporary session credentials to the content. These credentials are used to call the AWS API on behalf of the content viewer.
Ensure the following dependencies are installed:
boto3
shiny
posit-sdk>=0.9.0
When publishing the content to Connect make sure the following environment variables are set for the deployed content:
AWS_REGION
AWS_BUCKET_NAME
AWS_S3_FILEPATH
app.py
# -*- coding: utf-8 -*-
# mypy: ignore-errors
import os
import io
import pandas as pd
import boto3
from posit.connect import Client
from posit.connect.external import aws
from shiny import App, Inputs, Outputs, Session, render, ui
= ui.page_fluid(ui.h2("S3 Data Viewer"), ui.output_data_frame("data_grid"))
app_ui
def server(i: Inputs, o: Outputs, session: Session):
"""
Shiny for Python example application that shows user information and
the first few rows from a table hosted in Databricks.
"""
# Obtain AWS credentials and start a session:
# 1. If running on Posit Connect, perform a credential exchange with the
# user session token that is provided within the session header.
# 2. If running locally, initialize a session using your preferred method.
# This example assumes the use of the aws cli to authenticate.
if os.getenv("POSIT_PRODUCT") == "CONNECT":
= Client()
client = session.http_conn.headers.get(
session_token "Posit-Connect-User-Session-Token"
)= aws.get_credentials(client, session_token)
aws_credentials = boto3.Session(
aws_session =aws_credentials["aws_access_key_id"],
aws_access_key_id=aws_credentials["aws_secret_access_key"],
aws_secret_access_key=aws_credentials["aws_session_token"],
aws_session_token
)else:
# Use default credentials from environment/config
= boto3.Session()
aws_session
# Create an S3 client using the AWS session
= aws_session.client("s3")
s3
# Define bucket and key (file path)
= os.getenv("AWS_BUCKET_NAME")
bucket_name = os.getenv("AWS_S3_FILEPATH")
key
# Get the object from S3 and read it as a DataFrame
= s3.get_object(Bucket=bucket_name, Key=key)
obj = obj["Body"].read()
csv_content = pd.read_csv(io.BytesIO(csv_content))
df
@render.data_frame
def data_grid():
# Return the DataFrame to display in the data grid
return df
= App(app_ui, server) app