> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agno.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets & API Keys

> Configure API keys and database credentials for your deployment

Secrets are stored in YAML files locally and synced to AWS Secrets Manager for production.

## Quick Setup

```bash theme={null}
# Copy example files
cp infra/secrets/prd_api_secrets.example.yml infra/secrets/prd_api_secrets.yml
cp infra/secrets/prd_db_secrets.example.yml infra/secrets/prd_db_secrets.yml
```

<Note>
  The `infra/secrets/` directory is excluded from version control (see `.gitignore`). Treat these files with the same security as passwords.
</Note>

## API Keys

### Required

| Service | Get Key At                                                           | Used For   |
| ------- | -------------------------------------------------------------------- | ---------- |
| OpenAI  | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) | All agents |

### Optional

| Service | Get Key At                                   | Used For             |
| ------- | -------------------------------------------- | -------------------- |
| Exa     | [dashboard.exa.ai](https://dashboard.exa.ai) | Pal research feature |

### Set your keys

Edit `infra/secrets/prd_api_secrets.yml`:

```yaml infra/secrets/prd_api_secrets.yml theme={null}
OPENAI_API_KEY: "sk-your-key-here"
EXA_API_KEY: "exa-your-key-here"  # Optional
```

### Verify keys work

Before deploying, test that your keys are valid:

```bash theme={null}
# Test OpenAI - should return a list of models
curl -s https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY" | head -20

# Test Exa (optional) - should return search results
curl -s https://api.exa.ai/search \
  -H "x-api-key: $EXA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "test", "numResults": 1}'
```

## Database Credentials

Edit `infra/secrets/prd_db_secrets.yml`:

```yaml infra/secrets/prd_db_secrets.yml theme={null}
DB_USER: "ai"
DB_PASS: "YourSecurePassword123"
```

Generate a secure password:

```bash theme={null}
openssl rand -base64 24
```

<Warning>
  **Avoid special characters** in `DB_PASS`: `@`, `#`, `%`, `&`, `"`, `'`

  These require URL encoding and cause silent connection failures. Stick to alphanumeric characters and `!`.

  Safe example: `MySecurePass123!`
</Warning>

### How credentials flow

```
prd_db_secrets.yml → AWS Secrets Manager → ECS Task → App environment
```

| File                 | Variable  | Becomes in App |
| -------------------- | --------- | -------------- |
| `prd_db_secrets.yml` | `DB_USER` | `DB_USER`      |
| `prd_db_secrets.yml` | `DB_PASS` | `DB_PASS`      |

## How Secrets Work

### Local Development

Apps read secrets directly from YAML files:

```python dev_resources.py theme={null}
dev_fastapi = FastApi(
    ...
    secrets_file=infra_settings.infra_root.joinpath("infra/secrets/dev_api_secrets.yml"),
)
```

### Production

Secrets are stored in AWS Secrets Manager and injected into ECS tasks:

```python prd_resources.py theme={null}
# API secrets (OpenAI, Exa)
prd_secret = SecretsManager(
    name=f"{infra_settings.prd_key}-secrets",
    secret_files=[infra_settings.infra_root.joinpath("infra/secrets/prd_api_secrets.yml")],
)

# Database secrets
prd_db_secret = SecretsManager(
    name=f"{infra_settings.prd_key}-db-secrets",
    secret_files=[infra_settings.infra_root.joinpath("infra/secrets/prd_db_secrets.yml")],
)
```

<Note>
  **Why two secrets?** API keys and database credentials are stored separately for security isolation. You can rotate one without affecting the other.
</Note>

## Verify Secrets in AWS

After deploying (`ag infra up prd:aws`), verify secrets were created:

```bash theme={null}
aws secretsmanager list-secrets \
  --query "SecretList[?contains(Name, 'agentos-aws-template-prd')].[Name]" \
  --output table
```

<Note>
  If you changed `infra_name` in `settings.py`, replace `agentos-aws-template` with your value.
</Note>

Expected output:

```
-------------------------------------------
|              ListSecrets               |
+----------------------------------------+
|  agentos-aws-template-prd-secrets      |
|  agentos-aws-template-prd-db-secrets   |
+----------------------------------------+
```

To view secret values (be careful - this exposes credentials):

```bash theme={null}
aws secretsmanager get-secret-value \
  --secret-id agentos-aws-template-prd-secrets \
  --query SecretString --output text
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="SecretNotFoundException">
    The secret doesn't exist yet. Run `ag infra up prd:aws` to create it from your YAML files.
  </Accordion>

  <Accordion title="Database connection fails silently">
    Check for special characters in `DB_PASS`. Remove any `@`, `#`, `%`, `&` characters and redeploy.
  </Accordion>

  <Accordion title="API key not working in production">
    1. Verify the key works locally (use the curl commands above)
    2. Check the secret was updated: `aws secretsmanager get-secret-value --secret-id {name}`
    3. Redeploy the task to pick up new secrets: `ag infra patch prd:aws::service`
  </Accordion>
</AccordionGroup>
