# Secret Rotation

Automatically rotate database credentials with zero downtime.

Source: https://keyenv.dev/docs/web-app/rotations/

Secret rotation automatically rotates database credentials on a schedule, eliminating manual password management and reducing security risks.

## What Is Secret Rotation?

Secret rotation automatically:

- Creates new database credentials on a configurable schedule
- Updates your environment with the new credentials
- Removes old credentials after successful rotation
- Notifies you via webhooks when rotations occur

## Supported Databases

| Database | Status | Connection Methods |
|----------|--------|-------------------|
| PostgreSQL | Supported | Direct, Lambda Proxy |
| MySQL | Supported | Direct, Lambda Proxy |

### Connection Methods

**Direct Connection**: KeyEnv connects directly to your database over the internet. Your database must be publicly accessible (with proper firewall rules) or accessible via VPN/peering.

**Lambda Proxy**: For databases in private VPCs or behind firewalls, KeyEnv can execute rotations through an AWS Lambda function deployed in your VPC. The Lambda acts as a secure bridge between KeyEnv and your private database.

## How It Works

KeyEnv uses a **two-secret strategy** for zero-downtime rotations:

1. **Setup**: You provide admin credentials for your database
2. **Two Credentials**: KeyEnv creates and maintains two sets of credentials
3. **Rotation**: When rotating, KeyEnv creates a new credential, verifies it works, then removes the old one
4. **Injection**: The active credentials are automatically injected into your environment

This approach ensures your applications always have valid credentials, even during rotation.

## Injected Secrets

When you create a rotation (e.g., named "main_database"), these secrets are automatically created in your environment:

```bash
MAIN_DATABASE_HOST       # Database hostname
MAIN_DATABASE_PORT       # Database port
MAIN_DATABASE_DATABASE   # Database name
MAIN_DATABASE_USERNAME   # Current active username
MAIN_DATABASE_PASSWORD   # Current active password
MAIN_DATABASE_URL        # Full connection URL
```

The naming convention is your rotation name converted to `UPPER_SNAKE_CASE`.

## Creating a Rotation

1. Go to **Project** → **Rotations** tab
2. Click **Create Rotation**
3. Fill in the wizard steps:

### Step 1: Database Type
Select PostgreSQL or MySQL.

### Step 2: Connection Method

Choose how KeyEnv will connect to your database:

| Method | Use Case |
|--------|----------|
| **Direct** | Database is publicly accessible or via VPN |
| **Proxied (Lambda)** | Database is in a private VPC |

### Step 3: Connection Details

| Field | Description |
|-------|-------------|
| **Host** | Database server hostname or IP |
| **Port** | Database port (5432 for PostgreSQL, 3306 for MySQL) |
| **Database** | Database name to connect to |
| **Admin Username** | Username with permission to create/drop users |
| **Admin Password** | Password for the admin user |
| **SSL Mode** | Connection encryption mode |

#### SSL Mode Options

| Mode | Description |
|------|-------------|
| **Require** | Encrypt connection, don't verify certificate (default) |
| **Verify Full** | Encrypt and verify server certificate + hostname |
| **Verify CA** | Encrypt and verify certificate authority |
| **Disable** | No encryption (only for local development) |

> **Warning**
>
> The admin credentials must have permission to create users, grant permissions, and drop users. These are stored encrypted and never logged.

### Step 3b: Lambda Proxy Configuration (if proxied)

If you selected proxied connection, you'll need to provide:

| Field | Description |
|-------|-------------|
| **Lambda ARN** | The ARN of your deployed rotation proxy Lambda |
| **AWS Region** | The AWS region where the Lambda is deployed |
| **Shared Secret** | A secret key for HMAC request signing (auto-generated if blank) |

> **Note**
>
> See [Setting Up Lambda Proxy](#setting-up-lambda-proxy) for deployment instructions.

### Step 4: Rotation Settings

| Setting | Description |
|---------|-------------|
| **Name** | A name for this rotation (becomes prefix for injected secrets) |
| **Rotation Interval** | How often to rotate (1-365 days) |

### Step 5: Test & Confirm

KeyEnv tests the connection before saving. If the test fails, check your credentials and network connectivity.

## Managing Rotations

### View Rotation Details

Click on a rotation card to see:
- **Overview**: Current status, next rotation date, injected secrets
- **History**: Past rotation events with timestamps and outcomes
- **Webhooks**: Configured webhook notifications

### Update Settings

1. Click the rotation card
2. Update the rotation interval or pause/resume the rotation
3. Save changes

### Trigger Manual Rotation

If you need to rotate credentials immediately:

1. Click the rotation card
2. Click **Rotate Now**
3. Confirm the action

Manual rotations don't affect the scheduled rotation timeline.

### Pause/Resume Rotation

To temporarily stop automatic rotations:

1. Click the rotation card
2. Toggle the status to **Paused**

Paused rotations won't run on schedule but can still be triggered manually.

### Delete a Rotation

1. Click the rotation card
2. Click **Delete**
3. Confirm deletion

> **Warning**
>
> Deleting a rotation removes the injected secrets and cleans up created database users. Make sure your applications are updated before deleting.

## Webhooks

Get notified when rotation events occur.

### Creating a Webhook

1. Click the rotation card
2. Go to the **Webhooks** tab
3. Click **Add Webhook**
4. Enter the webhook URL
5. Select events to receive

### Webhook Events

| Event | Description |
|-------|-------------|
| `rotation.started` | Rotation process has begun |
| `rotation.completed` | Rotation completed successfully |
| `rotation.failed` | Rotation failed with an error |

### Webhook Payload

```json
{
  "event": "rotation.completed",
  "rotation": {
    "id": "rot_abc123",
    "name": "main_database",
    "integration_type": "postgresql"
  },
  "timestamp": "2026-01-20T12:00:00Z",
  "version": 5
}
```

Webhooks include a signature header (`X-KeyEnv-Signature`) for verification.

## Best Practices

1. **Start with longer intervals** - Begin with 30 or 90 day rotations, then shorten as confidence grows
2. **Use webhooks** - Set up notifications to monitor rotation health
3. **Test in staging first** - Verify your application handles credential updates before enabling in production
4. **Monitor rotation history** - Check for failed rotations regularly
5. **Use connection pooling** - Connection pools handle credential changes more gracefully

## Troubleshooting

### Connection Test Fails

- Verify the database is accessible from KeyEnv's servers
- Check that the admin user has CREATE USER and GRANT permissions
- Ensure the port is open and SSL settings are correct

### Rotation Fails

Check the rotation history for error details. Common issues:

- **Auth errors**: Admin credentials may have changed or expired
- **Access errors**: Admin user may have lost permissions
- **Network errors**: Database may be temporarily unreachable

### Application Can't Connect

- Pull the latest secrets: `keyenv pull`
- Restart your application to pick up new environment variables
- Verify the rotation completed successfully in the history tab

## Setting Up Lambda Proxy

For databases in private VPCs that can't be accessed directly from the internet, you can deploy a Lambda function in your VPC to act as a rotation proxy.

### Architecture

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  KeyEnv API     │────▶│  AWS Lambda      │────▶│  Your Database  │
│  (rotation svc) │     │  (your VPC)      │     │  (private)      │
└─────────────────┘     └──────────────────┘     └─────────────────┘
```

### Deployment Steps

1. **Create an AWS Lambda function** in your VPC with access to your database subnet
2. **Deploy the KeyEnv rotation proxy code** (available in our GitHub repository)
3. **Configure VPC settings** to allow the Lambda to connect to your database
4. **Note the Lambda ARN** and provide it when creating the rotation

### Security

The Lambda proxy uses HMAC-SHA256 signed requests:

- Requests include a timestamp and signature
- Timestamps are validated within a 5-minute window (replay protection)
- Shared secret is stored encrypted in KeyEnv, never logged
- All communication uses TLS encryption

> **Note**
>
> Contact support for detailed Lambda deployment templates and assistance with VPC configuration.

## Security

- Admin credentials are encrypted at rest using AES-256-GCM
- Credentials are never logged or exposed in API responses
- Each rotation creates unique, randomly-generated passwords
- Old credentials are dropped from the database after successful rotation
- Lambda proxy requests are HMAC-signed with timestamp validation
