Read secrets from AWS Secrets Manager

Enhanced Advanced

This guide walks through reading a secret, such as a database password or an API key, from AWS Secrets Manager in content running on Posit Connect. The content uses the temporary credentials that an AWS integration provides, so you do not need to store long-lived AWS credentials in the content or its environment variables.

Connect does not need any Secrets Manager-specific configuration. The AWS Identity and Access Management (IAM) role that the integration assumes determines which secrets the content can read.

Prerequisites

Before you begin, make sure you have the following:

  • An AWS integration set up as described in AWS (IAM Roles), using the Service Account type (Connect 2025.03.0 or later) or the Workload Identity type (Connect 2026.06.0 or later)
  • A secret in Secrets Manager, stored as a JSON key-value string such as {"username": "...", "password": "..."}
  • Permission to edit the permissions policy of the IAM role that the integration assumes, or an AWS administrator who can edit it for you
  • A valid Connect Publisher or Administrator account

Background

With a Service Account integration, the content exchanges its content session token for AWS credentials. With a Workload Identity integration, the AWS SDK finds the credentials on its own, so the content needs no Connect-specific code. In both cases, the content then uses the AWS SDK to call the Secrets Manager GetSecretValue API.

This guide does not cover Viewer integrations, because content usually reads secrets without any viewer interaction.

Step 1: Grant the role access to the secret

The integration’s IAM role needs permission to call secretsmanager:GetSecretValue on the secret. Attach the permissions policy described in Granting access to AWS Secrets Manager to the role.

Every piece of content associated with the integration can read every secret the role allows.

Step 2: Read the secret in your content

Use the example for the authentication type of your AWS integration.

Service Account

The content exchanges its content session token for AWS credentials, then uses them to create a Secrets Manager client.

Install the following dependencies:

  • boto3
  • posit-sdk>=0.9.0
app.py
import json
import os

import boto3
from posit.connect import Client
from posit.connect.external import aws

# Exchange the content session token for AWS credentials.
client = Client()
aws_credentials = aws.get_content_credentials(client)
aws_session = boto3.Session(
    aws_access_key_id=aws_credentials["aws_access_key_id"],
    aws_secret_access_key=aws_credentials["aws_secret_access_key"],
    aws_session_token=aws_credentials["aws_session_token"],
    region_name=os.getenv("AWS_REGION"),
)

secrets = aws_session.client("secretsmanager")
response = secrets.get_secret_value(SecretId=os.getenv("AWS_SECRET_ID"))
secret = json.loads(response["SecretString"])

db_username = secret["username"]
db_password = secret["password"]

Install the following dependencies:

  • paws.security.identity
  • jsonlite
  • connectapi>=0.7.0
app.R
library(connectapi)
library(paws.security.identity)

# Exchange the content session token for AWS credentials.
client <- connect()
credentials <- get_aws_content_credentials(client)
secrets <- secretsmanager(
  config = list(
    credentials = list(
      creds = list(
        access_key_id = credentials$access_key_id,
        secret_access_key = credentials$secret_access_key,
        session_token = credentials$session_token
      )
    ),
    region = Sys.getenv("AWS_REGION")
  )
)

response <- secrets$get_secret_value(SecretId = Sys.getenv("AWS_SECRET_ID"))
secret <- jsonlite::fromJSON(response$SecretString)

db_username <- secret$username
db_password <- secret$password

Workload Identity

The AWS SDK assumes the IAM role on its own, so the content needs no Connect-specific code.

Install the following dependencies:

  • boto3
app.py
import json
import os

import boto3

# boto3 assumes the IAM role using the web identity token file and
# environment variables that the integration provides.
secrets = boto3.client("secretsmanager", region_name=os.getenv("AWS_REGION"))
response = secrets.get_secret_value(SecretId=os.getenv("AWS_SECRET_ID"))
secret = json.loads(response["SecretString"])

db_username = secret["username"]
db_password = secret["password"]

Install the following dependencies:

  • paws.security.identity
  • paws.common>=0.5.2
  • jsonlite
app.R
library(paws.security.identity)

# paws assumes the IAM role using the web identity token file and
# environment variables that the integration provides.
secrets <- secretsmanager()
response <- secrets$get_secret_value(SecretId = Sys.getenv("AWS_SECRET_ID"))
secret <- jsonlite::fromJSON(response$SecretString)

db_username <- secret$username
db_password <- secret$password

Step 3: Publish the content

The content reads the following environment variables:

  • AWS_SECRET_ID: the name or Amazon Resource Name (ARN) of the secret
  • AWS_REGION: the region that contains the secret

Workload Identity integrations set AWS_DEFAULT_REGION, so AWS_REGION is optional for them.

Publish the content with Posit Publisher, the publishing extension for Positron and VS Code. Posit Publisher supports configuring both the environment variables and the integration association when it deploys the content:

  1. In the deployment configuration file, add the environment variables to the [environment] table:

    .posit/publish/config.toml
    [environment]
    AWS_SECRET_ID = "connect/db-password"
    AWS_REGION = "us-east-1"
  2. In the Integration Requests pane, add the AWS integration. See Automatically associating integrations in the User Guide.

  3. Deploy the content.

If you publish another way, set the environment variables and associate the integration in the content settings after you deploy.

Step 4: Confirm that the content reads the secret

Open the content to confirm that it reads the secret. If it reports an error, see Troubleshooting.

Troubleshooting

AccessDeniedException on GetSecretValue

An AccessDeniedException error stating that no identity-based policy allows the secretsmanager:GetSecretValue action means the role’s permissions policy does not match the secret. Confirm that you attached the policy to the role that the integration assumes, and that its Resource names the region and account of the secret.

Secrets Manager appends six random characters to every secret name to form its ARN, so a Resource that ends with the exact secret name does not match. Confirm that the Resource ends with -?????? for a single secret, or with * for a name prefix. See Granting access to AWS Secrets Manager and the AWS Example: Wildcards.

AccessDeniedException that mentions KMS

If a customer-managed AWS Key Management Service (KMS) key encrypts the secret, the role also needs permission to use that key. See Permissions for the KMS key in the AWS documentation.

ResourceNotFoundException

A ResourceNotFoundException error means Secrets Manager did not find a secret with the given name in the region the content used. Confirm that AWS_SECRET_ID matches the secret’s name or ARN, and that AWS_REGION is the region that contains the secret.

Considerations

Temporary credentials expire after the session_duration of the integration, one hour by default. In long-running content that reads secrets repeatedly, request new credentials before they expire, or read secrets once at startup. With a Workload Identity integration, the AWS SDK refreshes credentials automatically.

The examples above read the secret once, when the content starts. Secrets Manager charges for each API call and throttles GetSecretValue requests that exceed a per-Region rate limit for the AWS account. In interactive applications, reuse the value you read instead of calling GetSecretValue on every request.