Overview
Cluster Secrets provide secure storage and management of sensitive information like API keys, database credentials, and certificates. Secrets are encrypted at rest and in transit, and can be securely injected into cluster environments without exposing sensitive data in configuration files.Endpoints
List Secrets
Copy
GET https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets
Get Secret Details
Copy
GET https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets/{secret_name}
Create Secret
Copy
POST https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets
Update Secret
Copy
PUT https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets/{secret_name}
Delete Secret
Copy
DELETE https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets/{secret_name}
List Secrets
Query Parameters
Parameter | Type | Required | Description |
---|---|---|---|
type | string | No | Filter by secret type: api_key , database , certificate , file , generic |
category | string | No | Filter by category: ml_services , databases , cloud_providers , custom |
include_values | boolean | No | Include decrypted values (requires elevated permissions) |
search | string | No | Search secrets by name or description |
Request Examples
Copy
# List all secrets for a cluster
curl -X GET "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets" \
-H "Authorization: Bearer YOUR_API_KEY"
# List API key secrets only
curl -X GET "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets?type=api_key" \
-H "Authorization: Bearer YOUR_API_KEY"
Create Secret
Request Body
Parameter | Type | Required | Description |
---|---|---|---|
name | string | Yes | Secret name (must be unique within cluster) |
description | string | No | Secret description |
type | string | Yes | Secret type |
category | string | No | Secret category for organization |
value | string | Yes | Secret value (will be encrypted) |
environment_variable | string | No | Environment variable name to expose secret as |
file_path | string | No | File path to mount secret as (for file-type secrets) |
permissions | object | No | Access permissions for the secret |
expiration_date | string | No | Optional expiration date (ISO 8601) |
rotation_policy | object | No | Automatic rotation configuration |
tags | array | No | Tags for organization |
Request Examples
Copy
# Create API key secret
curl -X POST "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "wandb_api_key",
"description": "Weights & Biases API key for experiment tracking",
"type": "api_key",
"category": "ml_services",
"value": "your-actual-wandb-api-key-here",
"environment_variable": "WANDB_API_KEY",
"tags": ["wandb", "ml-tracking"]
}'
# Create database credentials
curl -X POST "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "postgres_credentials",
"description": "PostgreSQL database credentials",
"type": "database",
"category": "databases",
"value": "{\"username\": \"dbuser\", \"password\": \"secure_password\", \"host\": \"db.example.com\", \"port\": 5432, \"database\": \"ml_data\"}",
"environment_variable": "DATABASE_URL",
"expiration_date": "2024-12-31T23:59:59Z"
}'
# Create SSL certificate file
curl -X POST "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ssl_certificate",
"description": "SSL certificate for HTTPS endpoints",
"type": "certificate",
"category": "security",
"value": "-----BEGIN CERTIFICATE-----\nMIIC...\n-----END CERTIFICATE-----",
"file_path": "/etc/ssl/certs/app.crt",
"permissions": {
"read_only": true,
"file_mode": "0644"
}
}'
Get Secret Details
Copy
# Get secret metadata (no values)
curl -X GET "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets/wandb_api_key" \
-H "Authorization: Bearer YOUR_API_KEY"
# Get secret with decrypted value (requires special permissions)
curl -X GET "https://api.tensorone.ai/v1/clusters/cluster_abc123/secrets/wandb_api_key?include_value=true" \
-H "Authorization: Bearer YOUR_API_KEY"
Response Schema
Copy
{
"success": true,
"data": {
"secrets": [
{
"name": "wandb_api_key",
"description": "Weights & Biases API key for experiment tracking",
"type": "api_key",
"category": "ml_services",
"environment_variable": "WANDB_API_KEY",
"file_path": null,
"encrypted": true,
"expiration_date": null,
"rotation_policy": {
"enabled": false
},
"permissions": {
"read_only": true,
"allowed_users": ["ml_engineer"]
},
"usage_statistics": {
"last_accessed": "2024-01-15T14:30:00Z",
"access_count": 47
},
"tags": ["wandb", "ml-tracking"],
"created_at": "2024-01-10T09:00:00Z",
"updated_at": "2024-01-10T09:00:00Z"
},
{
"name": "postgres_credentials",
"description": "PostgreSQL database credentials",
"type": "database",
"category": "databases",
"environment_variable": "DATABASE_URL",
"file_path": null,
"encrypted": true,
"expiration_date": "2024-12-31T23:59:59Z",
"rotation_policy": {
"enabled": true,
"rotation_interval_days": 90,
"next_rotation": "2024-04-10T09:00:00Z",
"notification_days_before": 7
},
"permissions": {
"read_only": false,
"allowed_users": ["database_admin", "ml_engineer"]
},
"usage_statistics": {
"last_accessed": "2024-01-15T16:45:00Z",
"access_count": 234
},
"tags": ["postgresql", "database"],
"created_at": "2024-01-10T10:30:00Z",
"updated_at": "2024-01-12T15:20:00Z"
}
],
"total_count": 8,
"secret_types": {
"api_key": 4,
"database": 2,
"certificate": 1,
"generic": 1
}
}
}
Use Cases
ML Training Setup
Set up comprehensive secrets for ML training workflows.Copy
def setup_training_secrets(cluster_id, training_config):
"""Set up all necessary secrets for ML training"""
secrets_setup = {
"ml_services": [],
"data_sources": [],
"cloud_storage": [],
"monitoring": []
}
# ML service API keys
if training_config.get("use_wandb"):
wandb_secret = {
"name": "wandb_api_key",
"description": "W&B API key for experiment tracking",
"type": "api_key",
"category": "ml_services",
"value": training_config["wandb_key"],
"environment_variable": "WANDB_API_KEY",
"tags": ["wandb", "experiment-tracking"]
}
result = create_cluster_secret(cluster_id, wandb_secret)
secrets_setup["ml_services"].append(result)
if training_config.get("use_huggingface"):
hf_secret = {
"name": "huggingface_token",
"description": "HF token for model downloads",
"type": "api_key",
"category": "ml_services",
"value": training_config["hf_token"],
"environment_variable": "HUGGINGFACE_HUB_TOKEN",
"tags": ["huggingface", "models"]
}
result = create_cluster_secret(cluster_id, hf_secret)
secrets_setup["ml_services"].append(result)
# Database connections
if training_config.get("database_config"):
db_config = training_config["database_config"]
db_secret = {
"name": "training_database",
"description": "Training data database connection",
"type": "database",
"category": "databases",
"value": json.dumps(db_config),
"environment_variable": "TRAINING_DB_URL",
"expiration_date": training_config.get("db_expiry"),
"tags": ["database", "training-data"]
}
result = create_cluster_secret(cluster_id, db_secret)
secrets_setup["data_sources"].append(result)
# Cloud storage credentials
if training_config.get("s3_config"):
s3_config = training_config["s3_config"]
s3_secret = {
"name": "s3_credentials",
"description": "S3 credentials for dataset access",
"type": "cloud_provider",
"category": "cloud_providers",
"value": json.dumps(s3_config),
"environment_variable": "S3_CREDENTIALS",
"tags": ["aws", "s3", "datasets"]
}
result = create_cluster_secret(cluster_id, s3_secret)
secrets_setup["cloud_storage"].append(result)
# Monitoring and alerting
if training_config.get("slack_webhook"):
slack_secret = {
"name": "slack_webhook",
"description": "Slack webhook for training notifications",
"type": "webhook",
"category": "monitoring",
"value": training_config["slack_webhook"],
"environment_variable": "SLACK_WEBHOOK_URL",
"tags": ["slack", "notifications"]
}
result = create_cluster_secret(cluster_id, slack_secret)
secrets_setup["monitoring"].append(result)
return secrets_setup
# Example training configuration
training_config = {
"use_wandb": True,
"wandb_key": "your-wandb-key",
"use_huggingface": True,
"hf_token": "your-hf-token",
"database_config": {
"host": "training-db.company.com",
"port": 5432,
"database": "ml_training",
"username": "trainer",
"password": "secure_password"
},
"s3_config": {
"access_key_id": "AKIAI...",
"secret_access_key": "wJalr...",
"bucket": "ml-training-data",
"region": "us-west-2"
},
"slack_webhook": "https://hooks.slack.com/services/..."
}
secrets = setup_training_secrets("cluster_training_001", training_config)
Production Deployment Secrets
Manage secrets for production model deployments.Copy
async function setupProductionSecrets(clusterId, deploymentConfig) {
console.log('Setting up production secrets...');
const secrets = [];
// API authentication secrets
if (deploymentConfig.apiKeys) {
for (const [service, apiKey] of Object.entries(deploymentConfig.apiKeys)) {
const secret = {
name: `${service}_api_key`,
description: `API key for ${service} service`,
type: 'api_key',
category: 'api_authentication',
value: apiKey,
environment_variable: `${service.toUpperCase()}_API_KEY`,
permissions: {
read_only: true,
allowed_roles: ['production_service']
},
tags: [service, 'production', 'api']
};
const result = await createSecret(clusterId, secret);
secrets.push(result);
}
}
// Database credentials with rotation
if (deploymentConfig.database) {
const dbSecret = {
name: 'production_database',
description: 'Production database credentials',
type: 'database',
category: 'databases',
value: JSON.stringify(deploymentConfig.database),
environment_variable: 'DATABASE_URL',
rotation_policy: {
enabled: true,
rotation_interval_days: 60,
notification_days_before: 7
},
permissions: {
read_only: true,
allowed_roles: ['database_client']
},
tags: ['database', 'production', 'rotating']
};
const result = await createSecret(clusterId, dbSecret);
secrets.push(result);
}
// SSL/TLS certificates
if (deploymentConfig.certificates) {
for (const [name, certConfig] of Object.entries(deploymentConfig.certificates)) {
const certSecret = {
name: `ssl_cert_${name}`,
description: `SSL certificate for ${name}`,
type: 'certificate',
category: 'security',
value: certConfig.certificate,
file_path: certConfig.path,
permissions: {
read_only: true,
file_mode: '0644'
},
expiration_date: certConfig.expiry,
tags: ['ssl', 'certificate', 'security']
};
const result = await createSecret(clusterId, certSecret);
secrets.push(result);
// Also create private key if provided
if (certConfig.privateKey) {
const keySecret = {
name: `ssl_key_${name}`,
description: `SSL private key for ${name}`,
type: 'certificate',
category: 'security',
value: certConfig.privateKey,
file_path: certConfig.keyPath,
permissions: {
read_only: true,
file_mode: '0600'
},
tags: ['ssl', 'private-key', 'security']
};
const keyResult = await createSecret(clusterId, keySecret);
secrets.push(keyResult);
}
}
}
// Monitoring and alerting credentials
if (deploymentConfig.monitoring) {
for (const [service, config] of Object.entries(deploymentConfig.monitoring)) {
const monitoringSecret = {
name: `${service}_monitoring`,
description: `${service} monitoring credentials`,
type: 'monitoring',
category: 'monitoring',
value: JSON.stringify(config),
environment_variable: `${service.toUpperCase()}_CONFIG`,
tags: [service, 'monitoring', 'production']
};
const result = await createSecret(clusterId, monitoringSecret);
secrets.push(result);
}
}
console.log(`Created ${secrets.length} production secrets`);
return secrets;
}
// Example production deployment configuration
const productionConfig = {
apiKeys: {
openai: 'sk-...your-openai-key',
stripe: 'sk_live_...your-stripe-key',
sendgrid: 'SG....your-sendgrid-key'
},
database: {
type: 'postgresql',
host: 'prod-db.company.com',
port: 5432,
database: 'production',
username: 'prod_user',
password: 'ultra_secure_password',
ssl: true,
pool_size: 20
},
certificates: {
api: {
certificate: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----',
path: '/etc/ssl/certs/api.crt',
keyPath: '/etc/ssl/private/api.key',
expiry: '2024-12-31T23:59:59Z'
}
},
monitoring: {
datadog: {
api_key: 'dd_api_key_here',
app_key: 'dd_app_key_here',
site: 'datadoghq.com'
},
prometheus: {
endpoint: 'https://prometheus.company.com',
username: 'prometheus_user',
password: 'prometheus_password'
}
}
};
await setupProductionSecrets('cluster_prod_001', productionConfig);
Secret Rotation Management
Implement automatic secret rotation workflows.Copy
def manage_secret_rotation(cluster_id):
"""Manage automatic secret rotation"""
# Get all secrets with rotation policies
response = requests.get(
f"https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets",
headers={"Authorization": f"Bearer {API_KEY}"}
)
if not response.json()["success"]:
return {"error": "Failed to get secrets"}
secrets = response.json()["data"]["secrets"]
rotation_needed = []
for secret in secrets:
rotation_policy = secret.get("rotation_policy", {})
if rotation_policy.get("enabled"):
next_rotation = rotation_policy.get("next_rotation")
notification_days = rotation_policy.get("notification_days_before", 7)
if next_rotation:
from datetime import datetime, timedelta
rotation_date = datetime.fromisoformat(next_rotation.replace('Z', '+00:00'))
notification_date = rotation_date - timedelta(days=notification_days)
if datetime.now() >= notification_date:
rotation_needed.append({
"secret_name": secret["name"],
"next_rotation": next_rotation,
"days_until_rotation": (rotation_date - datetime.now()).days,
"type": secret["type"],
"category": secret["category"]
})
# Process rotation notifications and automatic rotations
rotation_results = []
for secret_info in rotation_needed:
days_left = secret_info["days_until_rotation"]
if days_left <= 0:
# Automatic rotation needed
result = perform_secret_rotation(cluster_id, secret_info["secret_name"])
rotation_results.append({
"secret_name": secret_info["secret_name"],
"action": "rotated",
"success": result.get("success", False),
"details": result
})
elif days_left <= 7:
# Send notification
result = send_rotation_notification(cluster_id, secret_info)
rotation_results.append({
"secret_name": secret_info["secret_name"],
"action": "notification_sent",
"days_until_rotation": days_left,
"success": result.get("success", False)
})
return {
"cluster_id": cluster_id,
"secrets_checked": len(secrets),
"rotation_needed": len(rotation_needed),
"actions_taken": len(rotation_results),
"results": rotation_results
}
def perform_secret_rotation(cluster_id, secret_name):
"""Perform automatic secret rotation"""
# Get current secret details
current_secret = get_secret_details(cluster_id, secret_name, include_value=True)
if not current_secret["success"]:
return {"success": False, "error": "Failed to get current secret"}
secret_data = current_secret["data"]
secret_type = secret_data["type"]
# Generate new secret value based on type
new_value = None
if secret_type == "database":
# For database secrets, generate new password
import secrets
import string
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
new_password = ''.join(secrets.choice(alphabet) for _ in range(32))
# Parse existing database config
import json
db_config = json.loads(secret_data["value"])
db_config["password"] = new_password
new_value = json.dumps(db_config)
# TODO: Update actual database password
elif secret_type == "api_key":
# For API keys, would need service-specific rotation logic
return {"success": False, "error": f"Automatic rotation not supported for {secret_type}"}
if new_value:
# Update secret with new value
update_payload = {
"value": new_value,
"rotation_policy": {
**secret_data["rotation_policy"],
"last_rotation": datetime.now().isoformat(),
"next_rotation": (datetime.now() + timedelta(days=secret_data["rotation_policy"]["rotation_interval_days"])).isoformat()
}
}
response = requests.put(
f"https://api.tensorone.ai/v1/clusters/{cluster_id}/secrets/{secret_name}",
headers={"Authorization": f"Bearer {API_KEY}"},
json=update_payload
)
return response.json()
return {"success": False, "error": "Could not generate new secret value"}
Error Handling
Copy
{
"success": false,
"error": {
"code": "SECRET_NOT_FOUND",
"message": "Secret 'invalid_secret' not found in cluster",
"details": {
"cluster_id": "cluster_abc123",
"secret_name": "invalid_secret",
"suggestion": "Check secret name or list available secrets"
}
}
}
Security Considerations
- Encryption: All secrets are encrypted at rest using AES-256-GCM
- Access Control: Implement strict role-based access control for secrets
- Audit Logging: All secret access is logged for security auditing
- Rotation: Implement regular secret rotation for sensitive credentials
- Least Privilege: Grant minimal necessary permissions for secret access
- Transit Security: Secrets are encrypted in transit using TLS 1.3
Best Practices
- Secret Naming: Use descriptive, consistent naming conventions
- Regular Rotation: Implement automatic rotation for critical secrets
- Access Monitoring: Monitor secret access patterns for anomalies
- Environment Isolation: Keep production and development secrets separate
- Backup Strategy: Maintain secure backups of critical secrets
- Documentation: Document secret purposes and rotation procedures
Authorizations
API key authentication. Use 'Bearer YOUR_API_KEY' format.
Path Parameters
Body
application/json
Response
201 - application/json
Secret created successfully
The response is of type object
.