Common Secrets Patterns
This guide covers common patterns and best practices for working with secrets that apply across all Julep SDKs.
Secret Management Lifecycle
The typical lifecycle for secrets in Julep applications includes:
Creation : Establishing new secrets
Retrieval : Accessing secret metadata (not values)
Usage : Referencing secrets in tasks and tools
Update : Rotating or changing secret values
Deletion : Removing secrets when no longer needed
Naming Conventions
Consistent naming helps with secret organization:
Use snake_case formatting (e.g., aws_access_key
)
Be descriptive but concise
Include service name as prefix (stripe_secret_key
vs just secret_key
)
For multiple environments, include environment prefix (dev_stripe_key
, prod_stripe_key
)
Secret Reference Patterns
When using secrets in tasks, you have several reference patterns available:
Direct Reference
Reference a secret directly by name:
secret_name : openai_api_key
Multiple Secrets
For operations requiring multiple secrets:
secrets :
service_api_key : "api_key_secret_name"
service_auth_token : "auth_token_secret_name"
Expression Reference
Reference secrets within expressions:
arguments :
headers :
Authorization : "$ f'Bearer {secrets.api_token}'"
LLM Provider Keys
Store LLM API keys with standard names for automatic lookup:
# Python SDK
client.secrets.create(
name = "OPENAI_API_KEY" ,
value = "sk-..."
)
# Node.js SDK
await julep.secrets.create({
name: 'ANTHROPIC_API_KEY' ,
value: 'sk-ant-...'
}) ;
Error Handling
Common error scenarios when working with secrets:
Secret Not Found : The referenced secret doesn’t exist
Permission Denied : No access to the requested secret
Validation Error : Secret name doesn’t match required format
Duplicate Name : Attempting to create a secret with a name that already exists
Handle these consistently across your application:
# Python SDK
from julep.exceptions import SecretNotFoundError, ValidationError
try :
secret = client.secrets.get( name = "non_existent_secret" )
except SecretNotFoundError:
# Handle missing secret
print ( "Secret not found, using default value" )
except ValidationError as e:
# Handle validation error
print ( f "Invalid secret name: { e } " )
// Node.js SDK
try {
const secret = await julep . secrets . get ({ name: 'non_existent_secret' });
} catch ( error ) {
if ( error . code === 'not_found' ) {
// Handle missing secret
console . log ( 'Secret not found, using default value' );
} else if ( error . code === 'validation_error' ) {
// Handle validation error
console . log ( `Invalid secret name: ${ error . message } ` );
}
}
Testing with Secrets
For testing applications that use secrets:
Create a separate set of test secrets with appropriate prefixes
Use mocking in unit tests to avoid requiring real secrets
For integration tests, use dedicated test accounts and credentials
Never use production secrets in test environments
Example of mocking secrets for testing:
# Python mock example
import pytest
from unittest.mock import patch
@pytest.fixture
def mock_secrets ():
return {
"api_key" : "mock-api-key-123" ,
"auth_token" : "mock-token-456"
}
@patch ( "julep.client.Secrets.get" )
def test_with_mock_secrets ( mock_get , mock_secrets ):
mock_get.return_value = mock_secrets
# Test code that uses secrets
// JavaScript mock example
jest . mock ( '@julep/sdk' , () => {
return {
Julep: jest . fn (). mockImplementation (() => {
return {
secrets: {
get: jest . fn (). mockResolvedValue ({
name: 'api_key' ,
value: 'mock-api-key-123'
})
}
};
})
};
});
Migrating from Environment Variables
When migrating from environment variables to Julep secrets:
Create a list of all environment variables used in your application
Create corresponding secrets in Julep with the same names
Update your code to reference Julep secrets instead of environment variables
Validate functionality before removing the original environment variables
Migration script example:
import os
from julep import Julep
client = Julep( api_key = "your_api_key" )
# List of environment variables to migrate
env_vars_to_migrate = [
"OPENAI_API_KEY" ,
"STRIPE_SECRET_KEY" ,
"DATABASE_URL" ,
"AUTH_TOKEN"
]
# Migrate each environment variable to a Julep secret
for env_var in env_vars_to_migrate:
value = os.environ.get(env_var)
if value:
try :
client.secrets.create(
name =env_var.lower(), # Convert to snake_case
value =value,
description = f "Migrated from environment variable { env_var } "
)
print ( f "Successfully migrated { env_var } to Julep secret" )
except Exception as e:
print ( f "Failed to migrate { env_var } : { e } " )
else :
print ( f "Environment variable { env_var } not found" )
See all 28 lines
Integration with External Secret Managers
For organizations using external secret managers, you can sync to Julep:
# Example syncing AWS Secrets Manager to Julep
import boto3
from julep import Julep
# Initialize clients
julep_client = Julep( api_key = "your_api_key" )
aws_client = boto3.client( 'secretsmanager' )
# Get secrets from AWS
response = aws_client.list_secrets()
for secret in response[ 'SecretList' ]:
# Get the secret value
secret_value = aws_client.get_secret_value( SecretId =secret[ 'ARN' ])
# Create or update the secret in Julep
try :
julep_client.secrets.create(
name = f "aws_ { secret[ 'Name' ] } " ,
value =secret_value[ 'SecretString' ],
description = f "Synced from AWS Secrets Manager: { secret[ 'Name' ] } " ,
metadata ={
"source" : "aws" ,
"arn" : secret[ 'ARN' ],
"sync_date" : datetime.now().isoformat()
}
)
print ( f "Synced secret { secret[ 'Name' ] } " )
except Exception :
# Secret already exists, update it
julep_client.secrets.update(
name = f "aws_ { secret[ 'Name' ] } " ,
value =secret_value[ 'SecretString' ],
metadata ={
"source" : "aws" ,
"arn" : secret[ 'ARN' ],
"sync_date" : datetime.now().isoformat()
}
)
print ( f "Updated secret { secret[ 'Name' ] } " )
See all 39 lines
Security Best Practices
Limit who has access to create and manage secrets
Never log secret values, even in debug environments
Rotate secrets regularly, especially for high-value credentials
Use the most specific scope possible for each secret
Audit secret usage and access patterns
Use metadata to track important information about secrets
Implement an encrypted backup strategy for critical secrets
Next Steps