Securely Store and Use Secrets in Your Flows
For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append.mdto anykestra.io/docs/*URL for plain Markdown.
Configure sensitive values as base64-encoded environment variables so flows can reference them without exposing plain text in flow definitions or logs.
For a detailed overview of how secrets work across editions, see the Secrets concept page. For a UI-based secrets manager with access controls and audit logs, see the Enterprise Edition.
Using secrets in Kestra
Step 1: Create a .env file
Start by defining your secrets in a standard environment file:
POSTGRES_PASSWORD=actual_postgres_passwordOPENAI_KEY=actual_openai_keyAWS_ACCESS_KEY=actual_aws_access_keyAWS_SECRET_KEY=actual_aws_secret_keyStep 2: Encode and prefix your secrets
Kestra expects all secret keys to be prefixed with SECRET_ and their values base64-encoded.
The resulting .env_encoded file should look like this:
SECRET_POSTGRES_PASSWORD=base64_encoded_postgres_passwordSECRET_OPENAI_KEY=base64_encoded_openai_keySECRET_AWS_ACCESS_KEY=base64_encoded_aws_access_keySECRET_AWS_SECRET_KEY=base64_encoded_aws_secret_keyTo generate this file automatically, use the following Bash script:
while IFS='=' read -r key value; do echo "SECRET_$key=$(echo -n "$value" | base64)";done < .env > .env_encodedThis script:
- Base64-encodes all values.
- Adds the
SECRET_prefix to all variable names. - Saves the result as
.env_encoded.
You can verify the output by opening .env_encoded — it should look like the example above.
Alternatively, you can manually write the file using macros to encode secrets dynamically:
SECRET_POSTGRES_PASSWORD={{ "actual_postgres_password" | base64encode }}SECRET_OPENAI_KEY={{ "actual_openai_key" | base64encode }}SECRET_AWS_ACCESS_KEY={{ "actual_aws_access_key" | base64encode }}SECRET_AWS_SECRET_KEY={{ "actual_aws_secret_key" | base64encode }}Step 3: Point Docker to the encoded file
Update your docker-compose.yaml to use the .env_encoded file:
kestra: image: kestra/kestra:latest env_file: - .env_encodedThis ensures your secrets are loaded when Kestra starts.
Step 4: Use secrets in a flow
Once your secrets are loaded, reference them in your flows using the secret() function — without including the SECRET_ prefix.
For example, this flow connects to PostgreSQL using SECRET_POSTGRES_PASSWORD and uploads query results to AWS S3 using SECRET_AWS_ACCESS_KEY and SECRET_AWS_SECRET_KEY.
id: postgres_to_s3namespace: company.team
tasks: - id: fetch type: io.kestra.plugin.jdbc.postgresql.Query url: jdbc:postgresql://127.0.0.1:56982/ username: pg_user password: "{{ secret('POSTGRES_PASSWORD') }}" sql: select id, first_name, last_name, city from users fetchType: STORE
- id: write_to_s3 type: io.kestra.plugin.aws.s3.Upload accessKeyId: "{{ secret('AWS_ACCESS_KEY') }}" secretKeyId: "{{ secret('AWS_SECRET_KEY') }}" region: "eu-central-1" from: "{{ outputs.fetch.uri }}" bucket: "kestra-bucket" key: "data/users.csv"How secrets are resolved
When you reference a secret using {{ secret('POSTGRES_PASSWORD') }}, Kestra finds the corresponding SECRET_POSTGRES_PASSWORD environment variable, base64-decodes its value, and injects it into the execution context. The decoded value does not appear in flow definitions or logs, but base64 encoding is not encryption — secure your host environment accordingly.
Was this page helpful?