Use this skill when the user has Prefect Secret blocks, SecretStr fields, SecretDict, or prefect.blocks.system.Secret usage to move into Orchestra. Triggers: any Prefect code using Secret.load(), .get_secret_value(), SecretStr type annotations, or external secret-store blocks (AWS Secrets Manager, Azure Key Vault) storing credentials. Never asks for real secret values — produces a checklist of what to re-enter directly in Orchestra.
80%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/migrate-to-orchestra/skills/prefect-secrets-to-orchestra/SKILL.mdThis skill produces a secrets checklist — a table of every secret name, where it came from in Prefect, and where it must be re-entered in Orchestra. It never asks for actual secret values and never writes them to any file. Prefect's encrypted Secret block store has no bulk export mechanism, so most secrets must be re-entered by hand in Orchestra — the exception is a value that already lives in AWS Secrets Manager or Azure Key Vault, which an Orchestra connection can read in place via its Credential Store.
| Prefect secret pattern | Orchestra target | Notes |
|---|---|---|
Secret.load("api-key").get() for a SaaS credential | Store on that tool's Orchestra connection credential field | Use prefect-connections-to-orchestra to identify the connection |
SecretStr field on a credential block | Store on Orchestra connection credential field | Follow prefect-connections-to-orchestra for the block type |
Secret value used inside a @task as an env var | Python connection → env var → read via os.getenv("KEY") in script | |
SecretDict | Multiple key-value entries on the relevant connection | One Orchestra field per key |
AwsSecret / AWS Secrets Manager block | Orchestra connection with Credential Store = AWS Secrets Manager | Create an Orchestra AWS Secrets Manager connection first, then point the target connection at the Secret ARN; the secret's JSON keys must match the target integration's expected fields |
AzureKeyVaultSecretReference / Azure Key Vault block (prefect-azure) | Orchestra connection with Credential Store = Azure Key Vault | Create an Orchestra Azure Key Vault connection first (service principal + vault name), then point the target connection at the secret name — not an ARN. Vault secret names take only letters, numbers and hyphens, so a Prefect block name with underscores needs renaming |
Prefect Variables (non-sensitive, Variable.get()) | Pipeline inputs: or task env_vars: — not secrets | Variables are not encrypted; treat as config, not credentials |
Hard rule (enforced always):
NEVER ask the user to paste real secret values into this chat, and never write real secret values into any file. Produce only a checklist of secret NAMES and where to enter them.
Secrets themselves do not appear in YAML. The YAML only shows where the secret will be consumed:
# Python task reading a secret from env var (set on the connection)
integration: PYTHON
integration_job: PYTHON_EXECUTE_SCRIPT
connection: python_git_prod_12345 # env vars set on this connection in Orchestra UI
parameters:
command: 'python scripts/call_api.py'
python_version: '3.12'# scripts/call_api.py — reads secret at runtime from env
import os
import requests
token = os.getenv("MY_API_TOKEN") # set on the Orchestra Python connection
response = requests.get("https://api.example.com/data", headers={"Authorization": f"Bearer {token}"})Secret.load(, .get_secret_value(), SecretStr, SecretDict, prefect.blocks.system.Secret, AwsSecretVariable.get()) from Secret blocks — Variables are non-sensitive and go to inputs: or env_vars:, not Orchestra secretsprefect-connections-to-orchestra to create the connection and enter the value in the credential field — in the UI, or through the public API / Orchestra MCP, feeding each value straight from wherever you read it out of Prefect rather than staging it in a filefrom prefect.blocks.system import Secret
from prefect import task, flow
from pydantic import SecretStr
@task
def call_external_api():
token = Secret.load("my-api-token").get()
response = requests.get("https://api.example.com", headers={"Authorization": f"Bearer {token}"})
return response.json()
@task
def write_to_snowflake(data):
# SnowflakeCredentials block holds SecretStr password
creds = SnowflakeCredentials.load("sf-prod")
conn = creds.get_client()
conn.execute("INSERT INTO ...")pipeline:
stage-fetch:
tasks:
call-external-api:
integration: PYTHON
integration_job: PYTHON_EXECUTE_SCRIPT
connection: python_git_prod_12345 # MY_API_TOKEN set on this connection
parameters:
command: 'python scripts/call_external_api.py'
python_version: '3.12'
set_outputs: true
depends_on: []
stage-load:
tasks:
write-to-snowflake:
integration: SNOWFLAKE
integration_job: SNOWFLAKE_RUN_QUERY
connection: snowflake_prod_67890 # password entered in Orchestra UI
parameters:
query: "INSERT INTO ..."
depends_on:
- call-external-apiSecrets checklist output (example):
| Secret name | Source Prefect block/pattern | Orchestra target | Action |
|--------------------|---------------------------------------|---------------------------------------------------------|-------------------------------------------|
| SNOWFLAKE_PASSWORD | SnowflakeCredentials "sf-prod".password | Snowflake connection "snowflake_prod_67890" → password | Re-enter manually in Orchestra UI |
| MY_API_TOKEN | Secret.load("my-api-token") | Python connection "python_git_prod_12345" → env var MY_API_TOKEN | Re-enter in Python connection JSON |
| GH_DEPLOY_KEY | GitHubCredentials "gh-deploy".token | Python connection "python_git_prod_12345" → deploy key | Paste private key in Orchestra UI |Variable.get() values are not encrypted — route to inputs: or env_vars: in the Orchestra pipeline, not to secretsSecretStr fields inside credential blocks follow prefect-connections-to-orchestra, not this skill — they are stored on the connection, not as standalone secretssnowflake_account, snowflake_user, snowflake_password and the rest of its required parameters, not account / user / password. In Azure Key Vault, set that whole JSON object as the secret's value rather than splitting it into one secret per field. One Prefect secret rarely maps to one store secret: a flow that loads a password on its own still needs the non-secret parameters gathered into the same JSON objectenv_vars: in the YAML file itself — only reference connection-level env vars or use Orchestra's secrets integrationSecret block is used purely for observability (e.g. masking values in logs) with no downstream consumer, it can be dropped entirelySee prefect-alerts-to-orchestra for all notification patterns.
orchestra-hq/orchestra-skills
a200887
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.