Examples/Secure S3 File Uploads from AI Agents

Secure S3 File Uploads from AI Agents

intermediatewrapProvider·openais3·3 min read

Secure S3 File Uploads from AI Agents

AWS credentials are some of the most sensitive secrets an agent can hold. wrapS3() routes all S3 operations through the Keystore vault, so your agent never touches an AWS access key or secret.

What you'll build

An agent that generates a report with OpenAI, then uploads it to S3. Both the OpenAI key and AWS credentials are resolved from the vault.

Prerequisites

  • A Keystore account with an agent token
  • OpenAI and S3 keys in your vault
  • An S3 bucket ready to receive uploads
  • Node.js 18+

Setup

1

Install dependencies

bash
1
npm install @keystore/sdk openai @aws-sdk/client-s3
2

Initialize Keystore with both providers

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Keystore from "@keystore/sdk";
import { wrapS3 } from "@keystore/sdk/wrap/s3";
import OpenAI from "openai";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

const ks = new Keystore({ agentToken: process.env.KS_TOKEN! });

// interceptAll handles OpenAI
ks.interceptAll();

// wrapS3 handles the S3 client — rewrites endpoint to the vault
const s3 = wrapS3(
  new S3Client({ region: "us-east-1" }),
  ks
);
i

S3 uses request signing rather than Bearer tokens, so it needs the dedicated wrapS3() wrapper. The vault handles AWS Signature V4 signing on your behalf.

3

Generate a report with OpenAI

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const openai = new OpenAI();

const report = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [
    {
      role: "system",
      content: "Generate a concise weekly summary report in markdown format.",
    },
    {
      role: "user",
      content: `Summarize this week's activity:
        - 15,230 API requests processed
        - 99.7% uptime
        - 3 new agents onboarded
        - Average response time: 142ms
        - 2 budget alerts triggered`,
    },
  ],
});

const reportContent = report.choices[0].message.content!;
4

Upload to S3

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const fileName = `reports/weekly-${new Date().toISOString().split("T")[0]}.md`;

await s3.send(
  new PutObjectCommand({
    Bucket: "your-reports-bucket",
    Key: fileName,
    Body: reportContent,
    ContentType: "text/markdown",
  })
);

console.log(`Report uploaded to s3://your-reports-bucket/${fileName}`);

ks.restore();

Alternative: setupEnv for S3

If you prefer environment variable configuration over wrapping:

typescript
1
2
3
4
5
6
7
8
import Keystore, { Providers } from "@keystore/sdk";

const ks = new Keystore({ agentToken: process.env.KS_TOKEN! });
ks.setupEnv([Providers.S3]);

// This sets AWS_ENDPOINT_URL_S3 to vault.keystore.com/v1/s3
// The AWS SDK reads this env var automatically
const s3 = new S3Client({ region: "us-east-1" });

Full example

typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import Keystore from "@keystore/sdk";
import { wrapS3 } from "@keystore/sdk/wrap/s3";
import OpenAI from "openai";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

async function generateAndUpload() {
  const ks = new Keystore({ agentToken: process.env.KS_TOKEN! });
  ks.interceptAll();
  const s3 = wrapS3(new S3Client({ region: "us-east-1" }), ks);

  // Generate
  const openai = new OpenAI();
  const report = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      { role: "system", content: "Generate a weekly summary in markdown." },
      {
        role: "user",
        content: "15,230 requests, 99.7% uptime, 3 new agents, 142ms avg latency.",
      },
    ],
  });

  // Upload
  const key = `reports/weekly-${new Date().toISOString().split("T")[0]}.md`;
  await s3.send(
    new PutObjectCommand({
      Bucket: "your-reports-bucket",
      Key: key,
      Body: report.choices[0].message.content!,
      ContentType: "text/markdown",
    })
  );

  console.log(`Uploaded: ${key}`);
  ks.restore();
}

generateAndUpload();

Security benefits

  • No AWS credentials in agent code — access key and secret are vault-only
  • Scoped access — the agent token can be limited to specific S3 actions
  • Audit trail — every S3 operation is logged with agent ID and object key
  • Instant revocation — kill the agent token, all S3 access stops

Next steps