DEV Community

Jamal Ibrahim Umar
Jamal Ibrahim Umar

Posted on

Keyless by Default: Securing FarmOps Desk without a Single Static Secret

Part of the H0: Hack the Zero Stack submission. See the project on Devpost.


Every hackathon submission that uses AWS from Vercel usually starts the same way: "paste your AWS_ACCESS_KEY_ID into Vercel's environment variables." It's easy, and it works. It's also the single most common cause of cloud supply-chain attacks.

Major breaches like SolarWinds or the Toyota customer leak often start with a static credential that someone forgot to rotate, or accidentally checked into a code repository.

For the H0 hackathon, I built FarmOps Desk on Vercel + Aurora PostgreSQL + Bedrock. My goal was strict security: Zero static AWS credentials anywhere in the project, deployment, or CI pipeline.

Here is how I made the entire application "keyless."

The "Keycard" Approach (OIDC)

Instead of giving Vercel a permanent "master key" (a static AWS credential), I set up a system where Vercel requests a temporary, 15-minute "keycard" every time a function runs.

This is powered by Vercel's OIDC (OpenID Connect) integration with AWS:

  1. When a Vercel function wakes up, Vercel gives it a cryptographically signed identity token.
  2. The function hands this token to AWS.
  3. AWS verifies the token, checks that it came from my specific Vercel project, and hands back a temporary session that expires in 15 minutes.

If a malicious actor somehow compromises the Vercel environment, they don't get a permanent key. They get a temporary session that evaporates almost immediately.

The Two-Role Split: Minimizing Blast Radius

A common mistake is creating a single AWS Role that has permissions to do everything (access the database, call the AI, read storage). That creates a massive blast radius. If the AI service is compromised, the database goes with it.

I split the permissions into two strictly isolated roles:

1. The Database Role (AWS_ROLE_ARN)

  • Only has permission to connect to the Aurora PostgreSQL database.
  • Has a strict "Permission Boundary" ensuring it can never be used to access Bedrock or S3.

2. The AI Role (BEDROCK_ROLE_ARN)

  • Only has permission to invoke the Bedrock Nova models.
  • Has zero access to read or write to the database.

By doing this, a bug or breach in the AI code path can be shut down entirely without affecting the database, and vice versa.

The Code: Simpler Than You'd Think

Thanks to modern SDKs, going keyless doesn't require thousands of lines of boilerplate.

For the database, I use the @aws-sdk/rds-signer to fetch a fresh token dynamically every time a new database connection is made. No passwords are ever stored on disk:

// lib/db.ts
const pool = new Pool({
  host: process.env.PGHOST,
  user: process.env.PGUSER,
  // Fetch a fresh 15-minute token dynamically instead of using a static password
  password: () => signer.getAuthToken(), 
  ssl: true,
});
Enter fullscreen mode Exit fullscreen mode

For the Bedrock AI models, Vercel provides a helper that automatically trades the OIDC token for temporary AWS credentials:

// lib/ai/bedrock.ts
import { awsCredentialsProvider } from '@vercel/functions/oidc';

export function getBedrockRuntime() {
  return new BedrockRuntimeClient({
    region: 'us-east-1',
    credentials: awsCredentialsProvider({
      roleArn: process.env.BEDROCK_ROLE_ARN!,
    }),
  });
}
Enter fullscreen mode Exit fullscreen mode

Handling Voice AI with Nova Sonic

A unique challenge of building an agricultural AI is that farmers' hands are often dirty or busy. The assistant needs a voice mode. I used Amazon Bedrock Nova Sonic for real-time, bidirectional voice streaming.

However, serverless environments like Vercel usually struggle with long-lived bidirectional streams. By default, the underlying HTTP/2 session drops after the first voice turn.

To solve this, I deployed a dedicated "Sonic Bridge" service to a long-running Amazon EC2 instance. The bridge uses a custom NodeHttp2Handler that extends the session timeouts to 5 minutes, letting the farmer keep an open conversation with the AI while walking through the poultry house.

The Keyless Deployment to EC2:
Usually, deploying to EC2 from GitHub Actions means storing an SSH private key or an AWS_ACCESS_KEY_ID in your GitHub repository secrets. That is exactly what I wanted to avoid.

Instead, I set up a fully keyless CI/CD pipeline for the bridge:

  1. GitHub Actions uses its built-in OIDC provider to prove its identity to AWS.
  2. AWS grants GitHub a short-lived session, assuming a strictly scoped IAM role.
  3. The GitHub runner uses AWS Systems Manager (SSM) to securely send the deployment tarball and execute the bash rollout script directly on the EC2 instance.

Zero SSH keys. Zero static AWS credentials in GitHub. If the GitHub repository is ever compromised, there is no permanent key for an attacker to steal—just an OIDC trust policy that only works when triggered by a push to the main branch.

Scaling the Database (Next Steps)

Note: While not strictly required for hackathon traffic, production Vercel functions can easily exhaust Aurora's connection limits due to serverless concurrency.

To prevent the database from crashing under load, the production architecture places AWS RDS Proxy in front of Aurora. RDS Proxy acts like a traffic cop, multiplexing hundreds of Vercel connections down to a safe handful for Aurora. (I've included a comprehensive guide on my proxy setup in the project repository).

Why keyless architecture matters

Keyless authentication is a deliberate engineering decision. It is inherently harder to set up initially than pasting environment variables, but it is the production-grade answer for cloud security.

Shippable software is software that doesn't leak credentials. By eliminating static keys entirely, FarmOps can accept real customer data on day one without needing a "we'll rotate the keys before launch" excuse.

Links


Built for the H0 Hack the Zero Stack hackathon (#H0Hackathon). Deployed on Vercel, Amazon Aurora PostgreSQL as primary backend, Amazon Bedrock for AI. Zero static AWS credentials in the project. I created this piece of content for the purposes of entering the hackathon.

Top comments (0)