Overview of Secret Management
Flyte provides a robust secret management system designed to securely deliver credentials—such as database passwords, API keys, and service tokens—to your tasks at runtime. Instead of hardcoding sensitive information or manually managing Kubernetes secrets for every task, you use Flyte's unified API and automated injection mechanism.
The system operates in two distinct stages:
- Management: Storing and organizing secrets via the
SecretService. - Injection: Automatically mounting secrets into task Pods via the
SecretsPodMutatoradmission webhook.
Secret Identifiers and Scoping
Every secret in Flyte is identified by a SecretIdentifier, which consists of three parts:
- Project: The Flyte project (e.g.,
flytesnacks). - Domain: The execution domain (e.g.,
development,production). - Name: A unique name for the secret (e.g.,
db_password).
Flyte supports hierarchical scoping. You can define a secret that is global (no project or domain), domain-wide, or specific to a project and domain. The SecretService enforces that if you provide a project, you must also provide a domain.
// From secret/service/secret_service.go
func validateScope(domain, project string) error {
if domain == "" && project != "" {
return fmt.Errorf("project-scoped secrets must also specify a domain, got project=%q domain=%q", project, domain)
}
return nil
}
Stage 1: Secret Management via SecretService
The SecretService (located in secret/service/secret_service.go) implements the gRPC/Connect API for managing secrets. When you create a secret using flytectl or the Flyte UI, the SecretService persists it as a Kubernetes Secret in a dedicated namespace (configured via webhook.kubernetes.namespace).
Storage and Naming
To ensure secret names are valid Kubernetes resource names and to prevent collisions across scopes, Flyte encodes and hashes the identifiers. The getK8sSecretName function generates a hashed name for the Kubernetes resource while using an encoded string (containing the org, domain, project, and name) as the key within the Secret's data map.
// From secret/service/secret_service.go
func getK8sSecretName(_ context.Context, id *secretpb.SecretIdentifier) (string, string, error) {
// ... validation ...
encoded := flytesecret.EncodeSecretName(defaultOrganization, id.GetDomain(), id.GetProject(), id.GetName())
return encoded, flytesecret.EncodeK8sSecretName(encoded), nil
}
Stage 2: Secret Injection via Webhook
When a Flyte task is executed, Flyte Propeller creates a Kubernetes Pod. This Pod contains annotations that specify which secrets the task requires. The SecretsPodMutator (in flyteplugins/go/tasks/pluginmachinery/secret/secrets_pod_mutator.go) is a Kubernetes admission webhook that intercepts these Pod creation requests.
The Mutation Process
The mutator performs the following steps:
- Extraction: It reads the secret requirements from the Pod's annotations.
- Iteration: It loops through the requested secrets.
- Injection: For each secret, it attempts to use the configured
SecretsInjectorimplementations (e.g., K8s, AWS, Vault) to modify the Pod spec.
// From flyteplugins/go/tasks/pluginmachinery/secret/secrets_pod_mutator.go
func (s *SecretsPodMutator) Mutate(ctx context.Context, pod *corev1.Pod) (newP *corev1.Pod, podChanged bool, errResponse *admission.Response) {
secrets, err := secretUtils.UnmarshalStringMapToSecrets(pod.GetAnnotations())
// ... error handling ...
for _, secret := range secrets {
mutatedPod, injected, err := s.injectSecret(ctx, secret, pod)
// ...
pod = mutatedPod
}
return pod, len(secrets) > 0, nil
}
Supported Secret Injectors
Flyte supports multiple backends for secret delivery. Each backend implements the SecretsInjector interface, which defines how to modify a Pod to include a secret.
| Injector Type | Mechanism | Implementation File |
|---|---|---|
| K8s (Default) | Mounts K8s Secrets as volumes or environment variables. | k8s_secrets_injector.go |
| AWS | Injects a sidecar/init-container to pull from AWS Secrets Manager. | aws_secrets_manager_injector.go |
| Vault | Adds annotations for the HashiCorp Vault Agent Injector. | vault_secrets_injector.go |
| Embedded | Directly fetches values during pod creation (requires high-privilege webhook). | embedded_secret_manager.go |
Example: K8s Injection
The K8sSecretInjector is the most common implementation. It maps the Flyte SecretIdentifier back to the hashed Kubernetes Secret name created by the SecretService and adds a Volume and VolumeMount to the task Pod.
Configuration
You configure the secret management system in the flyte-pod-webhook section of your Flyte deployment. Key settings include:
secretManagerType: The primary injector to use (e.g.,K8s,AWS,Vault).secretEnvVarPrefix: The prefix used when injecting secrets as environment variables (defaults to_UNION_).kubernetes.namespace: The namespace where theSecretServicestores its managed secrets.
If a secret is requested but cannot be found by any of the enabled injectors, the webhook will reject the Pod creation with a NotFoundAcrossAllScopesMsg ("none of the secret managers injected secret"), preventing the task from running with missing credentials.