Skip to content

Commit a4d2d08

Browse files
committed
Adds secret env_var (flyteorg#3048)
* Adds secret env name Signed-off-by: Thomas J. Fan <[email protected]> * Use env_var Signed-off-by: Thomas J. Fan <[email protected]> * Bump flyteidl Signed-off-by: Thomas J. Fan <[email protected]> * Smaller change Signed-off-by: Thomas J. Fan <[email protected]> * Add integration test Signed-off-by: Thomas J. Fan <[email protected]> * Add integration test Signed-off-by: Thomas J. Fan <[email protected]> * Use env_var Signed-off-by: Thomas J. Fan <[email protected]> * Check for file and env_var Signed-off-by: Thomas J. Fan <[email protected]> * Add check for kubectl Signed-off-by: Thomas J. Fan <[email protected]> --------- Signed-off-by: Thomas J. Fan <[email protected]>
1 parent 146c670 commit a4d2d08

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

flytekit/models/security.py

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class Secret(_common.FlyteIdlEntity):
1717
key is optional and can be an individual secret identifier within the secret For k8s this is required
1818
version is the version of the secret. This is an optional field
1919
mount_requirement provides a hint to the system as to how the secret should be injected
20+
env_var is optional. Custom environment name to set the value of the secret.
21+
If mount_requirement is ENV_VAR, then the value is the secret itself.
22+
If mount_requirement is FILE, then the value is the path to the secret file.
2023
"""
2124

2225
class MountType(Enum):
@@ -39,6 +42,7 @@ class MountType(Enum):
3942
key: Optional[str] = None
4043
group_version: Optional[str] = None
4144
mount_requirement: MountType = MountType.ANY
45+
env_var: Optional[str] = None
4246

4347
def __post_init__(self):
4448
from flytekit.configuration.plugin import get_plugin
@@ -56,6 +60,7 @@ def to_flyte_idl(self) -> _sec.Secret:
5660
group_version=self.group_version,
5761
key=self.key,
5862
mount_requirement=self.mount_requirement.value,
63+
env_var=self.env_var,
5964
)
6065

6166
@classmethod
@@ -65,6 +70,7 @@ def from_flyte_idl(cls, pb2_object: _sec.Secret) -> "Secret":
6570
group_version=pb2_object.group_version if pb2_object.group_version else None,
6671
key=pb2_object.key if pb2_object.key else None,
6772
mount_requirement=Secret.MountType(pb2_object.mount_requirement),
73+
env_var=pb2_object.env_var if pb2_object.env_var else None,
6874
)
6975

7076

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ dependencies = [
2020
"diskcache>=5.2.1",
2121
"docker>=4.0.0",
2222
"docstring-parser>=0.9.0",
23-
"flyteidl>=1.14.1",
23+
"flyteidl>=1.14.2",
2424
"fsspec>=2023.3.0",
2525
"gcsfs>=2023.3.0",
2626
"googleapis-common-protos>=1.57",

tests/flytekit/integration/remote/test_remote.py

+47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import botocore.session
2+
import shutil
23
from contextlib import ExitStack, contextmanager
34
import datetime
45
import hashlib
@@ -893,3 +894,49 @@ def retry_operation(operation):
893894

894895
remote.wait(execution=execution, timeout=datetime.timedelta(minutes=5))
895896
assert execution.outputs["o0"] == {"title": "my report", "data": [1.0, 2.0, 3.0, 4.0, 5.0]}
897+
898+
899+
@pytest.fixture
900+
def kubectl_secret():
901+
secret = "abc-xyz"
902+
# Create secret
903+
kubectl = shutil.which("kubectl")
904+
if kubectl is None:
905+
pytest.skip("kubectl not found")
906+
907+
subprocess.run([
908+
kubectl,
909+
"create",
910+
"secret",
911+
"-n",
912+
"flytesnacks-development",
913+
"generic",
914+
"my-group",
915+
f"--from-literal=token={secret}",
916+
], capture_output=True, text=True)
917+
yield secret
918+
919+
# Remove secret
920+
subprocess.run([
921+
kubectl,
922+
"delete",
923+
"secrets",
924+
"-n",
925+
"flytesnacks-development",
926+
"my-group",
927+
], capture_output=True, text=True)
928+
929+
930+
# To enable this test, kubectl must be available.
931+
@pytest.mark.skip(reason="Waiting for flyte release that includes https://github.com/flyteorg/flyte/pull/6176")
932+
@pytest.mark.parametrize("task", ["get_secret_env_var", "get_secret_file"])
933+
def test_check_secret(kubectl_secret, task):
934+
execution_id = run("get_secret.py", task)
935+
936+
remote = FlyteRemote(Config.auto(config_file=CONFIG), PROJECT, DOMAIN)
937+
execution = remote.fetch_execution(name=execution_id)
938+
execution = remote.wait(execution=execution)
939+
assert execution.closure.phase == WorkflowExecutionPhase.SUCCEEDED, (
940+
f"Execution failed with phase: {execution.closure.phase}"
941+
)
942+
assert execution.outputs['o0'] == kubectl_secret
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from flytekit import task, Secret, workflow
2+
from os import getenv
3+
4+
secret_env_var = Secret(
5+
group="my-group",
6+
key="token",
7+
env_var="MY_SECRET",
8+
mount_requirement=Secret.MountType.ENV_VAR,
9+
)
10+
secret_env_file = Secret(
11+
group="my-group",
12+
key="token",
13+
env_var="MY_SECRET_FILE",
14+
mount_requirement=Secret.MountType.FILE,
15+
)
16+
17+
18+
@task(secret_requests=[secret_env_var])
19+
def get_secret_env_var() -> str:
20+
return getenv("MY_SECRET", "")
21+
22+
23+
@task(secret_requests=[secret_env_file])
24+
def get_secret_file() -> str:
25+
with open(getenv("MY_SECRET_FILE")) as f:
26+
return f.read()

0 commit comments

Comments
 (0)