Skip to main content
Flyte provides a secrets injection framework that delivers secrets to task pods at runtime. Secrets are never stored in workflow code or task specifications — they are resolved by FlytePropeller at pod creation time and made available to the task container as environment variables or mounted files.

How secrets injection works

  1. A workflow author declares a secret request in their @task decorator
  2. FlytePropeller intercepts the pod creation and calls the configured secrets manager backend
  3. The secret value is injected into the pod as an environment variable or a mounted file
  4. The task code retrieves the secret using flytekit.current_context().get_secret()

Declaring secrets in task code

import flytekit
from flytekit import Secret, task, workflow

SECRET_GROUP = "my-db-credentials"
SECRET_KEY = "password"

@task(
    secret_requests=[
        Secret(
            group=SECRET_GROUP,
            key=SECRET_KEY,
            mount_requirement=Secret.MountType.ENV_VAR,  # or FILE
        )
    ]
)
def query_database() -> str:
    ctx = flytekit.current_context()
    db_password = ctx.get_secret(SECRET_GROUP, SECRET_KEY)
    # Use db_password to connect
    return "result"


@workflow
def my_wf() -> str:
    return query_database()

Backends

Kubernetes Secrets (default)

The default backend reads from Kubernetes Secret objects. Create the secret before running the workflow:
kubectl create secret generic my-db-credentials \
  --namespace flytesnacks-development \
  --from-literal=password=supersecret
The secret must exist in the same namespace as the task pod. Flyte creates namespaces per project-domain combination (e.g., flytesnacks-development).
Secret names in Flyte map to Kubernetes Secret names. The group parameter in Secret(group=..., key=...) maps to the Kubernetes Secret metadata.name. The key maps to the Secret data key.

AWS Secrets Manager

The AWS Secrets Manager backend fetches secrets from AWS at pod creation time. Enable it in FlytePropeller config:
configuration:
  inline:
    plugins:
      k8s:
        secrets:
          inject-experimental-decorators: false
    secretsWebhook:
      awsSecretManager:
        enabled: true
        region: us-east-1
Create secrets in AWS Secrets Manager with names matching the Flyte group:
aws secretsmanager create-secret \
  --name my-db-credentials \
  --secret-string '{"password": "supersecret"}'
The Flyte pod webhook injects a FLYTE_SECRETS_ENV_PREFIX environment variable and retrieves secrets before the task container starts.

HashiCorp Vault

Flyte integrates with Vault via the pod webhook. Configure Vault Agent Injector in your cluster, then annotate the default PodTemplate to instruct the injector:
# PodTemplate with Vault annotations
apiVersion: v1
kind: PodTemplate
metadata:
  name: flyte-vault-template
  namespace: flyte
template:
  metadata:
    annotations:
      vault.hashicorp.com/agent-inject: "true"
      vault.hashicorp.com/role: "flyte-task-role"
      vault.hashicorp.com/agent-inject-secret-my-db-credentials: "secret/data/my-db-credentials"
      vault.hashicorp.com/agent-inject-template-my-db-credentials: |
        {{- with secret "secret/data/my-db-credentials" -}}
        {{ .Data.data.password }}
        {{- end }}
  spec:
    containers:
      - name: default
        image: docker.io/rwgrim/docker-noop
The injected file is available at /vault/secrets/my-db-credentials inside the task container. Use Secret.MountType.FILE to read it:
@task(
    secret_requests=[
        Secret(
            group="my-db-credentials",
            key="password",
            mount_requirement=Secret.MountType.FILE,
        )
    ]
)
def query_database() -> str:
    ctx = flytekit.current_context()
    db_password = ctx.get_secret("my-db-credentials", "password")
    return db_password

Secrets for the entire workflow

Secrets can also be declared at the workflow level and inherited by all tasks:
@workflow
def my_wf() -> str:
    # All tasks inherit the secrets declared here
    return query_database()

Environment variable injection

When mount_requirement=Secret.MountType.ENV_VAR, the secret is injected as:
FLYTE_SECRETS_<GROUP>_<KEY>=<value>
For example, Secret(group="my-db-credentials", key="password") becomes:
FLYTE_SECRETS_MY_DB_CREDENTIALS_PASSWORD=supersecret

File injection

When mount_requirement=Secret.MountType.FILE, the secret is written to:
/etc/flyte/secrets/<group>/<key>
Example: /etc/flyte/secrets/my-db-credentials/password

Best practices

Always use the secret_requests parameter and ctx.get_secret(). Hardcoded secrets end up in your workflow spec and are visible to anyone with FlyteAdmin access.
Create secrets in each project-domain namespace separately (e.g., flytesnacks-development vs flytesnacks-production). This ensures tasks in different environments use different credentials.
Because secrets are resolved at runtime by FlytePropeller, you can rotate a Kubernetes Secret or update an AWS Secrets Manager value and the next workflow execution will pick up the new value automatically.
Use Kubernetes RBAC to restrict which service accounts can read which secrets. FlytePropeller’s service account only needs get access to secrets in the flyte namespace, not in task namespaces.

Build docs developers (and LLMs) love