Skip to main content

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:

  1. Management: Storing and organizing secrets via the SecretService.
  2. Injection: Automatically mounting secrets into task Pods via the SecretsPodMutator admission 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:

  1. Extraction: It reads the secret requirements from the Pod's annotations.
  2. Iteration: It loops through the requested secrets.
  3. Injection: For each secret, it attempts to use the configured SecretsInjector implementations (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 TypeMechanismImplementation File
K8s (Default)Mounts K8s Secrets as volumes or environment variables.k8s_secrets_injector.go
AWSInjects a sidecar/init-container to pull from AWS Secrets Manager.aws_secrets_manager_injector.go
VaultAdds annotations for the HashiCorp Vault Agent Injector.vault_secrets_injector.go
EmbeddedDirectly 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 the SecretService stores 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.