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

# Secrets Management

> Advanced techniques for managing sensitive information in Julep

# Secrets Management

This guide covers advanced topics for managing secrets in Julep, including security architecture, best practices, rotation policies, and integration patterns.

## Security Architecture

Secrets in Julep are stored with a layered security approach:

1. **Application-level Validation**: Secrets are validated before being stored
2. **Database Encryption**: Secrets are stored encrypted using PostgreSQL's pgcrypto extension with AES-256
3. **Access Control**: Secrets are scoped to developers and only accessible within their resources
4. **Master Key Security**: A separate master encryption key secures all stored secrets

The encryption process works as follows:

* When a secret is created, its value is encrypted using the master key
* The encrypted value is stored in the database's `value_encrypted` column
* When a secret is accessed, the value is decrypted using the master key
* The master key is stored as an environment variable, separate from the database

## Creating Effective Secret Names

Secrets should have descriptive names that follow these conventions:

* Use snake\_case formatting
* Begin with a letter and contain only alphanumeric characters and underscores
* Use a prefix to indicate the service (e.g., `aws_secret_key`, `stripe_api_key`)
* Be specific enough to understand the purpose (e.g., `gmail_oauth_token` vs `email_token`)

## Secret Rotation Best Practices

Regular rotation of secrets is a security best practice:

1. Create a new secret with a temporary name
2. Update your services to use the new secret
3. Once confirmed working, delete the old secret
4. Update the new secret's name to the standard name

For automated rotation:

```python [expandable] theme={"dark"}
from julep import Julep
import uuid

client = Julep(api_key="your_api_key")

# Generate temporary name
temp_name = f"stripe_key_rotation_{uuid.uuid4().hex[:8]}"

# Create new secret with temp name
client.secrets.create(
    name=temp_name,
    value="sk_new_value...",
    description="New Stripe API key (rotation)",
    metadata={"rotation_date": "2025-05-10"}
)

# Test the new key (implement your validation logic here)
# ...

# If valid, delete old secret and rename new one
client.secrets.delete(name="stripe_api_key")
client.secrets.update(
    name=temp_name,
    new_name="stripe_api_key",
    description="Stripe API key",
    metadata={"last_rotated": "2025-05-10"}
)
```

## Using Secrets with Different Tool Types

### API Tools

For HTTP-based tools, reference secrets in the headers or authentication:

```yaml theme={"dark"}
steps:
  - kind: tool_call
    tool: api_service
    operation: fetch_data
    arguments:
      url: "https://api.example.com/data"
      headers:
        Authorization: "$ f'Bearer {secrets.api_token}'"
```

### Database Connections

For database tools, use secrets for connection credentials:

```yaml theme={"dark"}
steps:
  - kind: tool_call
    tool: database
    operation: query
    arguments:
      query: "SELECT * FROM users LIMIT 10"
    secrets:
      db_username: "my_db_user"
      db_password: "my_db_password"
```

### AI Service Integration

For AI services that require API keys:

```yaml theme={"dark"}
steps:
  - kind: prompt
    model: "$ secrets.preferred_model"
    provider: "$ secrets.provider_name"
    prompt: "Generate creative ideas for a marketing campaign"
    api_key: "$ secrets.openai_api_key"
```

## Managing Secrets for Multi-Environment Deployments

For applications deployed across development, staging, and production environments:

1. Use consistent naming conventions with environment prefixes:
   * `dev_stripe_key`, `staging_stripe_key`, `prod_stripe_key`

2. Use metadata to tag secrets by environment:
   ```python theme={"dark"}
   client.secrets.create(
       name="stripe_api_key",
       value="sk_test_...",
       metadata={"environment": "production"}
   )
   ```

3. Filter secrets by environment when listing:
   ```python theme={"dark"}
   prod_secrets = client.secrets.list(
       metadata={"environment": "production"}
   )
   ```

## Secret Templating

For complex configurations that require multiple secrets:

```yaml theme={"dark"}
steps:
  - kind: tool_call
    tool: database
    operation: query
    arguments:
      connection_string: "$ f'mongodb+srv://{secrets.db_username}:{secrets.db_password}@{secrets.db_host}/{secrets.db_name}'"
```

## Securing LLM API Keys with Secrets

Julep automatically looks for LLM API keys in your secrets store based on the provider name. Use these naming conventions for automatic lookup:

| Provider     | Secret Name            |
| ------------ | ---------------------- |
| OpenAI       | `OPENAI_API_KEY`       |
| Anthropic    | `ANTHROPIC_API_KEY`    |
| Google       | `GOOGLE_API_KEY`       |
| Azure OpenAI | `AZURE_OPENAI_API_KEY` |
| Cohere       | `COHERE_API_KEY`       |

Example of setting up an LLM API key:

```python theme={"dark"}
client.secrets.create(
    name="OPENAI_API_KEY",
    value="sk-...",
    description="OpenAI API key for GPT-4 access"
)
```

## Audit and Monitoring

Best practices for security monitoring:

1. Regularly audit secret access and usage
2. Track changes to secrets via the `updated_at` timestamp
3. Implement secret expiration for highly sensitive data
4. Use metadata to track last review or rotation dates

Example audit script:

```python theme={"dark"}
from julep import Julep
from datetime import datetime, timedelta

client = Julep(api_key="your_api_key")

# Find secrets not rotated in over 90 days
old_threshold = datetime.now() - timedelta(days=90)
secrets = client.secrets.list()

for secret in secrets.items:
    if secret.updated_at < old_threshold:
        print(f"WARNING: Secret {secret.name} has not been rotated in over 90 days")
```

## Troubleshooting

Common issues when working with secrets:

1. **Secret Not Found**: Check that the secret name matches exactly, including case
2. **Permission Errors**: Verify the developer ID has access to the secret
3. **Encryption Errors**: Ensure the master key is correctly set in the environment
4. **Reference Errors**: Ensure the secret reference syntax is correct in expressions and templates

## Next Steps

* [Using Secrets in Julep](/guides/using-secrets) - Step-by-step guide for using secrets
* [Integration Patterns](/guides/advanced/integration-patterns) - Learn how to use secrets with integrations
* [API Reference](/api-reference#tag/secrets) - Complete API reference for secrets
