Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
468 changes: 159 additions & 309 deletions skills/ai-configs/aiconfig-projects/SKILL.md

Large diffs are not rendered by default.

503 changes: 503 additions & 0 deletions skills/ai-configs/aiconfig-projects/references/admin-tooling.md

Large diffs are not rendered by default.

368 changes: 368 additions & 0 deletions skills/ai-configs/aiconfig-projects/references/env-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,368 @@
# Environment Configuration

Patterns for saving SDK keys to your codebase's configuration system.

## Overview

After creating a project, you need to save the SDK keys so your application can use them. The approach depends on your existing configuration pattern.

## Common Patterns

### 1. .env Files

Most common pattern for local development and simple deployments.

#### Python
```python
def save_sdk_key_to_env(
project_key: str,
environment: str = "production",
env_file: str = ".env",
var_name: str = "LAUNCHDARKLY_SDK_KEY"
):
"""Save SDK key to .env file."""
# Get the SDK key
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

if not sdk_key:
raise ValueError(f"Could not get SDK key for {project_key}/{environment}")

# Read existing .env content
env_content = {}
if os.path.exists(env_file):
with open(env_file, "r") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#") and "=" in line:
key, value = line.split("=", 1)
env_content[key] = value

# Update or add the SDK key
env_content[var_name] = sdk_key

# Write back to .env
with open(env_file, "w") as f:
for key, value in env_content.items():
f.write(f"{key}={value}\n")

print(f"✓ Saved {var_name} to {env_file}")
```

#### Node.js/TypeScript
```typescript
import * as fs from 'fs';
import * as path from 'path';

async function saveSdkKeyToEnv(
projectKey: string,
environment: string = 'production',
envFile: string = '.env',
varName: string = 'LAUNCHDARKLY_SDK_KEY'
): Promise<void> {
const pm = new ProjectManager();
const sdkKey = await pm.getSdkKey(projectKey, environment);

if (!sdkKey) {
throw new Error(`Could not get SDK key for ${projectKey}/${environment}`);
}

// Read existing .env content
const envContent: Record<string, string> = {};
if (fs.existsSync(envFile)) {
const content = fs.readFileSync(envFile, 'utf-8');
content.split('\n').forEach((line) => {
const trimmed = line.trim();
if (trimmed && !trimmed.startsWith('#') && trimmed.includes('=')) {
const [key, ...valueParts] = trimmed.split('=');
envContent[key] = valueParts.join('=');
}
});
}

// Update or add the SDK key
envContent[varName] = sdkKey;

// Write back to .env
const lines = Object.entries(envContent).map(([key, value]) => `${key}=${value}`);
fs.writeFileSync(envFile, lines.join('\n') + '\n');

console.log(`✓ Saved ${varName} to ${envFile}`);
}
```

#### Usage
```bash
# Python
python -c "from launchdarkly.projects import save_sdk_key_to_env; save_sdk_key_to_env('my-project')"

# Node.js
node -e "require('./src/launchdarkly/env-config').saveSdkKeyToEnv('my-project')"
```

### 2. Multiple Environments

Save keys for multiple environments:

```python
# Save both production and test keys
save_sdk_key_to_env("my-project", "production", var_name="LD_SDK_KEY_PROD")
save_sdk_key_to_env("my-project", "test", var_name="LD_SDK_KEY_TEST")
```

**.env result:**
```bash
LD_SDK_KEY_PROD=sdk-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
LD_SDK_KEY_TEST=sdk-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
```

### 3. Secrets Manager Integration

For cloud deployments, integrate with secrets managers.

#### AWS Secrets Manager
```python
import boto3
import json

def save_to_aws_secrets(project_key: str, environment: str, secret_name: str):
"""Save SDK key to AWS Secrets Manager."""
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

client = boto3.client('secretsmanager')

try:
# Get existing secret
response = client.get_secret_value(SecretId=secret_name)
secrets = json.loads(response['SecretString'])
except client.exceptions.ResourceNotFoundException:
secrets = {}

# Update with new key
secrets['LAUNCHDARKLY_SDK_KEY'] = sdk_key

# Save back
client.put_secret_value(
SecretId=secret_name,
SecretString=json.dumps(secrets)
)

print(f"✓ Saved SDK key to AWS Secrets Manager: {secret_name}")

# Usage
save_to_aws_secrets("my-project", "production", "myapp/production")
```

#### GCP Secret Manager
```python
from google.cloud import secretmanager

def save_to_gcp_secrets(project_key: str, environment: str, secret_id: str, gcp_project: str):
"""Save SDK key to GCP Secret Manager."""
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

client = secretmanager.SecretManagerServiceClient()
parent = f"projects/{gcp_project}/secrets/{secret_id}"

# Add new version
response = client.add_secret_version(
request={
"parent": parent,
"payload": {"data": sdk_key.encode("UTF-8")},
}
)

print(f"✓ Saved SDK key to GCP Secret Manager: {response.name}")
```

#### Azure Key Vault
```python
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential

def save_to_azure_keyvault(project_key: str, environment: str, vault_url: str, secret_name: str):
"""Save SDK key to Azure Key Vault."""
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_url, credential=credential)

client.set_secret(secret_name, sdk_key)

print(f"✓ Saved SDK key to Azure Key Vault: {secret_name}")
```

### 4. Kubernetes Secrets

For Kubernetes deployments:

```python
import base64
import yaml

def create_k8s_secret(project_key: str, environment: str, namespace: str = "default"):
"""Generate Kubernetes secret manifest."""
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

# Encode SDK key
encoded_key = base64.b64encode(sdk_key.encode()).decode()

secret = {
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "launchdarkly-sdk-key",
"namespace": namespace
},
"type": "Opaque",
"data": {
"sdk-key": encoded_key
}
}

# Write to file
with open("k8s-secret.yaml", "w") as f:
yaml.dump(secret, f)

print("✓ Created k8s-secret.yaml")
print("Apply with: kubectl apply -f k8s-secret.yaml")
```

### 5. Configuration Files

For applications using config files (YAML, JSON, TOML):

#### YAML Config
```python
import yaml

def save_to_yaml_config(project_key: str, environment: str, config_file: str = "config.yaml"):
"""Save SDK key to YAML config file."""
pm = ProjectManager()
sdk_key = pm.get_sdk_key(project_key, environment)

# Read existing config
config = {}
if os.path.exists(config_file):
with open(config_file, "r") as f:
config = yaml.safe_load(f) or {}

# Update LaunchDarkly section
if "launchdarkly" not in config:
config["launchdarkly"] = {}

config["launchdarkly"]["sdk_key"] = sdk_key
config["launchdarkly"]["project_key"] = project_key
config["launchdarkly"]["environment"] = environment

# Write back
with open(config_file, "w") as f:
yaml.dump(config, f, default_flow_style=False)

print(f"✓ Saved SDK key to {config_file}")
```

#### JSON Config
```typescript
import * as fs from 'fs';

async function saveToJsonConfig(
projectKey: string,
environment: string,
configFile: string = 'config.json'
): Promise<void> {
const pm = new ProjectManager();
const sdkKey = await pm.getSdkKey(projectKey, environment);

// Read existing config
let config: any = {};
if (fs.existsSync(configFile)) {
config = JSON.parse(fs.readFileSync(configFile, 'utf-8'));
}

// Update LaunchDarkly section
config.launchdarkly = {
sdkKey,
projectKey,
environment,
};

// Write back
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));

console.log(`✓ Saved SDK key to ${configFile}`);
}
```

## Security Best Practices

### 1. Never Commit SDK Keys
Add to `.gitignore`:
```gitignore
# Environment files
.env
.env.local
.env.production
.env.test
# Config files with secrets
config/secrets.yaml
config/production.json
```

### 2. Use Different Keys Per Environment
```python
# Development
save_sdk_key_to_env("my-project", "test", ".env.development")

# Production (deploy separately)
save_sdk_key_to_env("my-project", "production", ".env.production")
```

### 3. Rotate Keys Regularly
```python
def rotate_sdk_key(project_key: str, environment: str):
"""
Note: This requires creating a new SDK key via API.
The LaunchDarkly API doesn't support key rotation directly.
You would need to create a new environment or reset the key in the UI.
"""
print("⚠️ SDK key rotation must be done via LaunchDarkly UI")
print(f" Go to: Project Settings → Environments → {environment} → Reset SDK Key")
```

### 4. Least Privilege Access
- API tokens for project creation: `projects:write`
- Application SDK keys: read-only by default
- Separate keys for test vs production

## Verification

After saving SDK keys, verify they work:

```python
def verify_sdk_key(sdk_key: str):
"""Verify SDK key works by testing connection."""
import ldclient
from ldclient.config import Config

config = Config(sdk_key)
client = ldclient.get()

if client.is_initialized():
print("✓ SDK key is valid and working")
return True
else:
print("✗ SDK key failed to initialize")
return False
```

## Next Steps

- [Integrate SDK in your application](../aiconfig-sdk/SKILL.md)
- [Set up project cloning](project-cloning.md)
- [Build automation scripts](iac-automation.md)
Loading
Loading