DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Design Zero Trust Security with Claude Code: mTLS, JWT Audience, API Key Rotation

Introduction

'Internal network is safe' is old thinking — Zero Trust verifies every request. Let Claude Code design mTLS, service accounts, and least-privilege access.

CLAUDE.md Rules

## Zero Trust Rules
- Never Trust, Always Verify
- Least privilege (even microservice-to-microservice)
- All traffic encrypted (mTLS required)
- JWT Audience: separate per service
- API Keys: rotate every 90 days
- Anomaly detection: 100 req/5min threshold
Enter fullscreen mode Exit fullscreen mode

Generated Implementation

// JWT Audience separation (prevent token reuse)
const SERVICE_AUDIENCES: Record<string, string> = {
  'api-gateway':     'api:gateway',
  'order-service':   'api:orders',
  'payment-service': 'api:payments',
};

export async function validateJWT(token: string, requiredAudience: string) {
  return jwtVerify(token, keys, {
    issuer: process.env.JWT_ISSUER!,
    audience: requiredAudience, // Service-specific audience
    algorithms: ['RS256'],
  });
}

// M2M tokens expire in 5 minutes
export async function createServiceToken(from: string, to: string) {
  return new SignJWT({ sub: `service:${from}` })
    .setExpirationTime('5m')
    .setAudience(SERVICE_AUDIENCES[to])
    .sign(privateKey);
}
Enter fullscreen mode Exit fullscreen mode
// API key: SHA256 hash stored, plaintext returned once
export async function generateApiKey(params: { userId: string; scopes: string[] }) {
  const rawKey = `mk_${randomBytes(24).toString('hex')}`;
  const keyHash = createHash('sha256').update(rawKey).digest('hex');
  await prisma.apiKey.create({
    data: { ...params, keyHash, expiresAt: new Date(Date.now() + 90*24*60*60*1000) },
  });
  return rawKey; // Show once only
}

// Anomaly detection
export async function detectAnomaly(identifier: string): Promise<void> {
  const count = await redis.incr(`anomaly:${identifier}:${Math.floor(Date.now()/300_000)}`);
  if (count >= 500) {
    await redis.set(`blocked:${identifier}`, '1', { EX: 3600 });
    throw new TooManyRequestsError('Temporarily blocked');
  }
  if (count === 100) await sendSIEMEvent({ type: 'RATE_ANOMALY', identifier, count });
}
Enter fullscreen mode Exit fullscreen mode

Summary

  1. JWT Audience per service prevents token cross-use attacks
  2. API keys: SHA256 hash stored, plaintext shown once, 90-day expiry
  3. 5-min/100 requests → SIEM alert; 500+ → 1-hour auto-block
  4. M2M tokens: 5-minute TTL for service-to-service auth

Review with **Security Pack (¥1,480)* /security-check at prompt-works.jp*

myouga (@myougatheaxo) — Axolotl VTuber.

Top comments (0)