AWS Redshift connector
Trusted IDPAnalyticsDatabasesConnect Amazon Redshift to Scalekit with the Trusted IDP flow so agents run SQL over federated AWS credentials, with no long-lived keys stored.
AWS Redshift connector
Connect an Amazon Redshift database to Scalekit using the Trusted IDP flow. Once connected, agents built on the Scalekit Agent Connect SDK can run SQL, list tables, describe schemas, and manage queries against your Redshift cluster (provisioned or serverless) — without you ever storing long-lived AWS credentials in Scalekit.
Supports authentication: Trusted IDP
-
Install the SDK
Section titled “Install the SDK”Terminal window npm install @scalekit-sdk/nodeTerminal window pip install scalekit -
Set your credentials
Section titled “Set your credentials”Add your Scalekit credentials to your
.envfile. Find values in app.scalekit.com > Developers > API Credentials..env SCALEKIT_ENVIRONMENT_URL=<your-environment-url>SCALEKIT_CLIENT_ID=<your-client-id>SCALEKIT_CLIENT_SECRET=<your-client-secret>
How it works
Section titled “How it works”Scalekit acts as an OIDC identity provider that AWS IAM trusts. No long-lived AWS access key is ever stored. On every tool call:
- Scalekit mints a short-lived JWT signed with your environment’s OIDC signing key.
- Scalekit calls AWS STS
AssumeRoleWithWebIdentitywith that JWT. AWS validates the signature against Scalekit’s public JWKS and issues temporary credentials (about a 1-hour lifetime). - Scalekit uses those temporary credentials to call the Redshift Data API on your behalf.
- Credentials are cached and proactively refreshed near expiry.
You keep the IAM role and trust policy in your own AWS account. Scalekit never sees a long-lived AWS access key.
Prerequisites
Section titled “Prerequisites”- An AWS account where your Redshift cluster or serverless workgroup runs.
- IAM permissions in that account to create OIDC providers and roles:
iam:CreateOpenIDConnectProvider,iam:CreateRole, andiam:PutRolePolicy. - A Scalekit workspace with an environment provisioned and admin access to the dashboard.
- A Redshift target, either:
- Provisioned cluster — cluster identifier, database name, and a database user.
- Serverless workgroup — workgroup name, namespace name, and database name.
Gather your Scalekit details first
Section titled “Gather your Scalekit details first”Before you touch AWS, collect two values from the Scalekit dashboard. You paste both into AWS during the AWS-side setup.
- Environment URL (becomes the JWT
issclaim) — Go to Settings > Environment, copy the environment domain (for exampleacme-prod.scalekit.cloud), and prefix it withhttps://when AWS asks for the full URL:https://acme-prod.scalekit.cloud. - Connection ID (becomes the JWT
audclaim) — Go to AgentKit > Connectors > AWS Redshift, click Create connection, save it, and copy the Connection ID (for exampleconn_128516460753453607).
Part 1 — Set up AWS
Section titled “Part 1 — Set up AWS”Register Scalekit as an OIDC provider in AWS IAM
Section titled “Register Scalekit as an OIDC provider in AWS IAM”Register Scalekit’s environment URL as a trusted OIDC issuer in your AWS account, and register your Connection ID as the audience. This is a one-time setup per Scalekit environment.
- Sign in to the AWS Management Console and open the IAM service.
- In the left navigation pane, click Identity providers, then Add provider.
- For Provider type, select OpenID Connect.
- For Provider URL, paste your full Scalekit environment URL including
https://, for examplehttps://acme-prod.scalekit.cloud. - For Audience, paste your Connection ID, for example
conn_128516460753453607. AWS checks this against the JWT’saudclaim. - (Optional) Add tags for cost allocation or ownership tracking.
- Click Add provider.
After the provider is created, open it and copy the ARN from the top of the page. You reference this ARN in the trust policy in the next step.
arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/<YOUR_ENV_DOMAIN>Create the IAM role
Section titled “Create the IAM role”This is the role Scalekit assumes on every Redshift tool call. Its trust policy conditions on aud = <CONNECTION_ID> — the same Connection ID you registered as the audience above.
- In the IAM console, click Roles, then Create role.
- For Trusted entity type, select Web identity.
- For Identity provider, pick the provider you created above. It appears as
<YOUR_ENV_DOMAIN>. - For Audience, pick your Connection ID (for example
conn_128516460753453607). - Click Next.
- Leave Permissions policies empty for now. You attach an inline policy in the next step. Click Next.
- For Role name, enter
ScalekitRedshiftAccess(or any name — keep a note of it for the connected account). - (Optional) Add a description, for example “Federated access for Scalekit Agent Connect to Redshift”.
- Click Create role.
Because you picked your Connection ID as the audience, the wizard generates a correct trust policy with "<YOUR_ENV_DOMAIN>:aud": "<CONNECTION_ID>". After the role is created, copy its Role ARN — you paste it into Scalekit later.
arn:aws:iam::<AWS_ACCOUNT_ID>:role/ScalekitRedshiftAccessTrust policy reference
Section titled “Trust policy reference”The wizard generates the policy below. If you used the wizard, it’s already in place.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/<YOUR_ENV_DOMAIN>" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "<YOUR_ENV_DOMAIN>:aud": "<CONNECTION_ID>" } } } ]}| Placeholder | Example | What it is |
|---|---|---|
<AWS_ACCOUNT_ID> | 166424725243 | Your 12-digit AWS account number |
<YOUR_ENV_DOMAIN> | acme-prod.scalekit.cloud | Scalekit environment domain, without https:// |
<CONNECTION_ID> | conn_128516460753453607 | The Connection ID from the Scalekit dashboard |
Optional: restrict the role to one organization
Section titled “Optional: restrict the role to one organization”By default the trust policy lets any connected account backed by this connection assume the role. To restrict it to one specific organization or identifier, add a sub condition to the StringEquals block:
"Condition": { "StringEquals": { "<YOUR_ENV_DOMAIN>:aud": "<CONNECTION_ID>", "<YOUR_ENV_DOMAIN>:sub": "<CONNECTED_ACCOUNT_IDENTIFIER>" }}<CONNECTED_ACCOUNT_IDENTIFIER> is the value you set as the connected account’s identifier (typically your organization’s external ID or an email). It must match exactly.
Attach the permission policy
Section titled “Attach the permission policy”The trust policy lets Scalekit assume the role. The permission policy controls what the role can do inside AWS. Attach one of the following as an inline policy on the role, depending on your Redshift target.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "RedshiftDataAPI", "Effect": "Allow", "Action": [ "redshift-data:ExecuteStatement", "redshift-data:DescribeStatement", "redshift-data:GetStatementResult", "redshift-data:CancelStatement", "redshift-data:ListStatements", "redshift-data:ListTables", "redshift-data:ListSchemas", "redshift-data:DescribeTable" ], "Resource": "*" }, { "Sid": "RedshiftServerlessAuth", "Effect": "Allow", "Action": "redshift-serverless:GetCredentials", "Resource": "arn:aws:redshift-serverless:<REGION>:<AWS_ACCOUNT_ID>:workgroup/<WORKGROUP_ID>" } ]}{ "Version": "2012-10-17", "Statement": [ { "Sid": "RedshiftDataAPI", "Effect": "Allow", "Action": [ "redshift-data:ExecuteStatement", "redshift-data:DescribeStatement", "redshift-data:GetStatementResult", "redshift-data:CancelStatement", "redshift-data:ListStatements", "redshift-data:ListTables", "redshift-data:ListSchemas", "redshift-data:DescribeTable" ], "Resource": "*" }, { "Sid": "RedshiftProvisionedAuth", "Effect": "Allow", "Action": "redshift:GetClusterCredentials", "Resource": [ "arn:aws:redshift:<REGION>:<AWS_ACCOUNT_ID>:dbname:<CLUSTER_ID>/<DATABASE>", "arn:aws:redshift:<REGION>:<AWS_ACCOUNT_ID>:dbuser:<CLUSTER_ID>/<DB_USER>" ] } ]}| Placeholder | Example |
|---|---|
<REGION> | us-east-1 |
<AWS_ACCOUNT_ID> | 166424725243 |
<WORKGROUP_ID> (serverless) | 93725977-d43f-423a-8908-d5a64caff6ba |
<CLUSTER_ID> (provisioned) | prod-analytics |
<DATABASE> | analytics |
<DB_USER> (provisioned) | analytics_reader |
Part 2 — Set up your Redshift database
Section titled “Part 2 — Set up your Redshift database”Serverless workgroup (recommended)
Section titled “Serverless workgroup (recommended)”Serverless workgroups authenticate the IAM identity directly, so you don’t need to create a database user. AWS resolves the IAM role to an IAMR:<role-name> database role automatically.
Provisioned cluster
Section titled “Provisioned cluster”Connect to your cluster as a superuser (psql, JDBC, or Query Editor v2), then create the database user the IAM role maps to and grant it the access you want the agent to have.
-- Create the user the IAM role maps to. No password: it authenticates via IAM.CREATE USER analytics_reader WITH PASSWORD DISABLE;
-- Grant only the read access the agent needs.GRANT USAGE ON SCHEMA public TO analytics_reader;GRANT SELECT ON ALL TABLES IN SCHEMA public TO analytics_reader;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO analytics_reader;Part 3 — Create a connection and connected account in Scalekit
Section titled “Part 3 — Create a connection and connected account in Scalekit”A connected account binds one organization (or tenant) in your app to one AWS Redshift target.
- In the Scalekit dashboard, go to AgentKit > Connectors and click AWS Redshift.
- If you haven’t created a connection yet, click Create connection and save it. This is the Connection ID you used in the trust policy.
- From the connection, click Add connected account and fill in the fields below.
- Save. Scalekit creates the connected account in
ACTIVEstatus. The first STS exchange happens lazily on the first tool call.
| Field | Required | Notes |
|---|---|---|
| Identifier | Required | Becomes the JWT sub claim. Use your organization’s external ID, an email, or any stable string. If you used the sub condition in the trust policy, this must match exactly. |
| Role ARN | Required | The IAM role ARN you created in Part 1. |
| Region | Required | AWS region, for example us-east-1. |
| Database | Required | Redshift database name. |
| Cluster identifier | One of | For provisioned clusters. |
| Workgroup name | One of | For serverless workgroups. |
| Namespace name | With workgroup | Serverless namespace name. |
| DB user | Provisioned only | The username from Part 2 (for example analytics_reader); ignored for serverless. |
API equivalent (optional)
Section titled “API equivalent (optional)”To create the connected account programmatically instead of using the dashboard:
curl -X POST 'https://<YOUR_ENV_DOMAIN>/api/v1/connected_accounts' \ -H 'Authorization: Bearer <YOUR_SCALEKIT_API_TOKEN>' \ -H 'Content-Type: application/json' \ -d '{ "identifier": "acme-org-id", "connector": "redshift-<CONNECTOR_KEY>", "connected_account": { "authorization_details": { "trusted_idp": { "db_user": "analytics_reader" } }, "api_config": { "role_arn": "arn:aws:iam::166424725243:role/ScalekitRedshiftAccess", "region": "us-east-1", "database": "analytics", "workgroup_name": "analytics-wg", "namespace_name": "analytics-ns" } } }'For a provisioned cluster, replace workgroup_name and namespace_name with cluster_identifier.
What you can do
Section titled “What you can do”Connect this agent connector to let your agent:
- Execute SQL — run a SQL statement against Redshift via the Data API and get back a statement ID.
- Fetch query results — poll a statement and retrieve rows once it finishes.
- Cancel a query — stop a running statement by its statement ID.
- Discover schema — list schemas, list tables, and describe a table’s columns and types.
- Review query history — list previously submitted statements for the AWS account.
Execute tools
Section titled “Execute tools”Use execute_tool / executeTool to run a named Redshift tool for a specific user. Scalekit selects the connected account from the user identifier plus the connection, or from a connected_account_id.
// Submit a SQL statement. Returns a statement ID you poll for results.const submit = await scalekit.actions.executeTool({ toolName: 'redshift_execute_sql', identifier: 'acme-org-id', connector: 'redshift', toolInput: { sql: 'SELECT count(*) FROM orders' },});const statementId = submit.data.statement_id;
// Poll for results. status is "FINISHED" when the query completes.const result = await scalekit.actions.executeTool({ toolName: 'redshift_get_query_result', identifier: 'acme-org-id', connector: 'redshift', toolInput: { statement_id: statementId },});console.log(result.data.status); // "FINISHED"console.log(result.data.rows); // [[12345]]# Submit a SQL statement. Returns a statement ID you poll for results.submit = actions.execute_tool( tool_name="redshift_execute_sql", identifier="acme-org-id", connection_name="redshift", tool_input={"sql": "SELECT count(*) FROM orders"},)statement_id = submit.data["statement_id"]
# Poll for results. status is "FINISHED" when the query completes.result = actions.execute_tool( tool_name="redshift_get_query_result", identifier="acme-org-id", connection_name="redshift", tool_input={"statement_id": statement_id},)print(result.data["status"]) # "FINISHED"print(result.data["rows"]) # [[12345]]Troubleshoot common errors
Section titled “Troubleshoot common errors”| Error | Cause | Fix |
|---|---|---|
InvalidIdentityToken | AWS can’t reach your Scalekit issuer URL (likely a *.localhost domain). | Use a publicly reachable environment URL, or set up an ngrok tunnel. |
Not authorized to perform sts:AssumeRoleWithWebIdentity | The trust policy aud doesn’t match the Scalekit Connection ID. | Verify <CONNECTION_ID> in the trust policy matches the dashboard exactly. |
not authorized to perform: redshift-serverless:GetCredentials | Permission policy is missing the serverless auth action or is scoped to the wrong workgroup. | Check the workgroup ARN in the policy — it must be exact, including the UUID. |
db_user is required for provisioned Redshift clusters | Cluster identifier is set but db_user is empty on the connected account. | Add db_user matching the Redshift user you created in Part 2. |
must specify exactly one of cluster_identifier or workgroup_name | Both fields are set, or neither is. | Edit the connected account so exactly one is populated. |
region is required | region is missing or empty. | Set region on the connected account. |
Verify the round-trip in CloudTrail
Section titled “Verify the round-trip in CloudTrail”For each tool call, AWS CloudTrail records two events:
- An
AssumeRoleWithWebIdentityevent from auserIdentityof typeWebIdentityUser, with your Scalekit environment as the issuer. - A
redshift-data:ExecuteStatement(or related) event from the assumed role.
The RoleSessionName matches the connected account’s identifier (sanitized — + becomes -, and so on), so CloudTrail attributes activity per organization out of the box.
Reference
Section titled “Reference”JWT claims Scalekit mints
Section titled “JWT claims Scalekit mints”The JWT is signed with the active OIDC signing key of your Scalekit environment — the same key that signs your Scalekit OIDC tokens. Public keys are exposed at https://<YOUR_ENV_DOMAIN>/.well-known/jwks.json.
| Claim | Value |
|---|---|
iss | https://<YOUR_ENV_DOMAIN> |
aud | <CONNECTION_ID> (for example conn_128516460753453607) |
sub | The connected account’s identifier |
exp | Now + 5 minutes |
iat | Now |
jti | Random UUID |
Trust policy claim names
Section titled “Trust policy claim names”AWS forms the condition keys from your OIDC provider URL hostname:
<YOUR_ENV_DOMAIN>:aud<YOUR_ENV_DOMAIN>:subThere is no :iss condition key. AWS validates the issuer implicitly through the OIDC provider ARN in Principal.Federated.
Where credentials live
Section titled “Where credentials live”No long-lived AWS credentials are ever stored. Temporary STS credentials are cached for about an hour and proactively refreshed by the connector’s pre-run hook before expiry.
| Field | Where it’s stored | Encrypted? |
|---|---|---|
role_arn, region, database, cluster_identifier / workgroup_name | connected_account.api_config | No (per-tenant target config) |
db_user | connected_account.authorization_details.trusted_idp | Yes |
| Cached STS credentials (access key, secret, session token, expiry) | connected_account.authorization_details.trusted_idp | Yes |
Refresh and rotation
Section titled “Refresh and rotation”- STS credentials — cached on the connected account and refreshed by a pre-run hook about 60 seconds before expiry. No customer action needed.
- Scalekit JWT signing key — rotates per your environment’s signing-key policy. AWS picks up new keys automatically via JWKS. No customer action needed.
- AWS IAM role — rotate only if you change the role’s permissions or want to revoke Scalekit’s access.
Revoke access
Section titled “Revoke access”To immediately cut off Scalekit’s access to your Redshift, do any one of the following:
- Delete the IAM role, or
- Remove the
Federatedprincipal from the trust policy, or - Remove the OIDC provider entry in AWS IAM.
Any of these causes the next AssumeRoleWithWebIdentity call to fail with AccessDenied.
Tool list
Section titled “Tool list”Use the exact tool names from the Tool list below when you call execute_tool. If you’re not sure which name to use, list the tools available for the current user first.
redshift_cancel_query#Cancel a running Amazon Redshift SQL statement using its statement ID.1 param
Cancel a running Amazon Redshift SQL statement using its statement ID.
statement_idstringrequiredThe ID of the statement to cancel. Must be non-empty.redshift_describe_table#Describe the schema of a table in Amazon Redshift using the Redshift Data API, including column names, types, and metadata.5 params
Describe the schema of a table in Amazon Redshift using the Redshift Data API, including column names, types, and metadata.
tablestringrequiredName of the table to describe. Must be non-empty.connected_databasestringoptionalOverride the connected account's default database for this request.max_resultsintegeroptionalMaximum number of columns to return per page.next_tokenstringoptionalPagination cursor from a previous redshift_describe_table response.schemastringoptionalSchema name that contains the table.redshift_execute_sql#Execute a SQL statement against Amazon Redshift using the Redshift Data API. Returns a statement ID that can be used with redshift_get_query_result to fetch results.3 params
Execute a SQL statement against Amazon Redshift using the Redshift Data API. Returns a statement ID that can be used with redshift_get_query_result to fetch results.
sqlstringrequiredSQL statement to execute. Must be non-empty.statement_namestringoptionalOptional label for the statement, echoed back by DescribeStatement for tracking purposes.with_eventbooleanoptionalIf true, AWS publishes an EventBridge event when the statement completes.redshift_get_query_result#Retrieve the results of a previously executed Redshift SQL statement using the statement ID returned by redshift_execute_sql. Supports pagination via next_token.2 params
Retrieve the results of a previously executed Redshift SQL statement using the statement ID returned by redshift_execute_sql. Supports pagination via next_token.
statement_idstringrequiredThe statement ID returned by redshift_execute_sql. Must be non-empty.next_tokenstringoptionalPagination token from a prior redshift_get_query_result response when results spanned multiple pages.redshift_list_schemas#List schemas in an Amazon Redshift database using the Redshift Data API. Supports filtering by schema name pattern with pagination.4 params
List schemas in an Amazon Redshift database using the Redshift Data API. Supports filtering by schema name pattern with pagination.
connected_databasestringoptionalOverride the connected account's default database for this request.max_resultsintegeroptionalMaximum number of schemas to return.next_tokenstringoptionalPagination cursor from a previous redshift_list_schemas response.schema_patternstringoptionalLIKE pattern to filter schemas (e.g., public, my_schema%).redshift_list_statements#List previously executed SQL statements in Amazon Redshift using the Redshift Data API. Supports filtering by name, status, and role level with pagination.5 params
List previously executed SQL statements in Amazon Redshift using the Redshift Data API. Supports filtering by name, status, and role level with pagination.
max_resultsintegeroptionalMaximum number of statements to return.next_tokenstringoptionalPagination cursor from a previous redshift_list_statements response.role_levelbooleanoptionalWhen true, lists all statements run by the IAM role rather than just the current session.statement_namestringoptionalFilter statements by name label.statusstringoptionalFilter by execution status (e.g., FINISHED, FAILED, ABORTED, PICKED, STARTED, SUBMITTED).redshift_list_tables#List tables in an Amazon Redshift database using the Redshift Data API. Supports filtering by schema and table name patterns with pagination.5 params
List tables in an Amazon Redshift database using the Redshift Data API. Supports filtering by schema and table name patterns with pagination.
connected_databasestringoptionalOverride the connected account's default database for this request.max_resultsintegeroptionalMaximum number of tables to return.next_tokenstringoptionalPagination cursor from a previous redshift_list_tables response.schema_patternstringoptionalLIKE pattern to filter schemas (e.g., public, my_schema%).table_patternstringoptionalLIKE pattern to filter tables (e.g., orders, user%).