Managing Secrets
Managing Secrets
Secrets provide a secure mechanism for storing sensitive information such as API keys, database credentials, or image registry authentication tokens. This system ensures that sensitive data is not exposed in plain text within your code or configuration files. The Secret class serves as the primary interface for interacting with and managing these secrets.
Secret Types
The system supports two primary types of secrets:
regular: A generic secret that can store any string or binary value. Use this for API keys, database passwords, or other arbitrary sensitive data.image_pull: Specifically designed for storing credentials required to pull container images from private registries.
You specify the secret type during creation.
Creating Secrets
To create a new secret, use the Secret.create class method. You must provide a unique name for the secret, its value, and optionally its type. The value can be either a string or bytes.
from typing import Union
from my_package import Secret # Assuming 'Secret' is in 'my_package'
# Create a regular string secret
await Secret.create(name="my-api-key", value="super-secret-api-key-123")
# Create a regular binary secret
await Secret.create(name="my-binary-key", value=b"\x01\x02\x03\x04\x05")
# Create an image pull secret (e.g., a Docker config.json content)
image_pull_value = """
{
"auths": {
"myregistry.example.com": {
"username": "user",
"password": "password",
"auth": "base64encodedusername:password"
}
}
}
"""
await Secret.create(name="my-image-pull-secret", value=image_pull_value, type="image_pull")
Secrets are scoped to your current organization, project, and domain configuration. The name must be unique within this scope.
Retrieving Secret Metadata
You can retrieve metadata about a specific secret using its name with the Secret.get class method. For security reasons, the actual secret value is never returned after creation. This method provides access only to the secret's name, type, creation time, and status information.
from my_package import Secret
# Retrieve metadata for a secret
my_secret = await Secret.get(name="my-api-key")
print(f"Secret Name: {my_secret.name}")
print(f"Secret Type: {my_secret.type}")
# Access other metadata like my_secret.project, my_secret.domain, my_secret.created_time, my_secret.status, my_secret.cluster_status
Attempting to access the secret's value directly from the retrieved Secret object will not work, as the value is not exposed.
Listing All Secrets
To view all secrets within your current project and domain, use the Secret.listall class method. This method returns an asynchronous iterator, allowing you to process secrets efficiently, especially when dealing with a large number of entries.
from my_package import Secret
# List all secrets
print("Listing all secrets:")
async for secret in Secret.listall():
print(f" - Name: {secret.name}, Type: {secret.type}")
# List secrets with a specific limit (for pagination)
print("\nListing up to 5 secrets:")
async for secret in Secret.listall(limit=5):
print(f" - Name: {secret.name}, Type: {secret.type}")
The limit parameter controls the maximum number of secrets fetched per batch, which is useful for pagination.
Deleting Secrets
To permanently remove a secret, use the Secret.delete class method, providing the secret's name. This action is irreversible.
from my_package import Secret
# Delete a secret
await Secret.delete(name="my-api-key")
print("Secret 'my-api-key' deleted.")
# Verify deletion (will raise an error if secret is not found)
try:
await Secret.get(name="my-api-key")
except Exception as e:
print(f"Secret 'my-api-key' no longer exists: {e}")
Asynchronous and Synchronous Usage
All methods of the Secret class are asynchronous by default, indicated by the async keyword and await calls in the examples. This allows for non-blocking operations, which is beneficial for performance in concurrent applications.
However, due to the syncify decorator applied to these methods, you can also call them synchronously if your application environment does not support async/await. When called synchronously, the methods will block until the operation completes.
from my_package import Secret
# Asynchronous usage (recommended for concurrent applications)
async def manage_secrets_async():
await Secret.create(name="async-secret", value="async-value")
secret = await Secret.get(name="async-secret")
print(f"Async Secret: {secret.name}")
await Secret.delete(name="async-secret")
# Synchronous usage (will block execution)
def manage_secrets_sync():
Secret.create(name="sync-secret", value="sync-value")
secret = Secret.get(name="sync-secret")
print(f"Sync Secret: {secret.name}")
Secret.delete(name="sync-secret")
# Example of how to run them (assuming an event loop for async)
import asyncio
asyncio.run(manage_secrets_async())
manage_secrets_sync()
Best Practices and Considerations
- Security First: Never hardcode sensitive information directly into your application code. Use this secret management system to store and retrieve credentials securely.
- Immutability: Once created, a secret's value cannot be updated. To change a secret's value, you must delete the existing secret and create a new one with the same name and the updated value.
- Naming Conventions: Use clear, descriptive names for your secrets to easily identify their purpose.
- Context Configuration: Ensure your client is properly configured with the correct organization, project, and domain settings before interacting with secrets. Operations are performed within this established context.
- Error Handling: Implement robust error handling for all secret operations, especially for
create,get, anddelete, to gracefully manage scenarios like network issues, permission errors, or non-existent secrets.