akeyless-agentcore-runtime 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,168 @@
1
+ """Configuration from environment variables and explicit overrides."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass
7
+ from typing import Literal
8
+
9
+ from akeyless_agentcore.paths import default_agentcore_secret_prefix
10
+
11
+ AccessType = Literal[
12
+ "access_key",
13
+ "api_key",
14
+ "aws_iam",
15
+ "azure_ad",
16
+ "gcp",
17
+ "universal_identity",
18
+ "jwt",
19
+ ]
20
+ CloudProvider = Literal["aws_iam", "azure_ad", "gcp"]
21
+
22
+ DEFAULT_GATEWAY = "https://api.akeyless.io"
23
+ DEFAULT_SECRET_CACHE_TTL_SECONDS = 5 * 60
24
+ DEFAULT_TOKEN_EXPIRY_MARGIN_SECONDS = 60
25
+
26
+
27
+ def _read_env(name: str) -> str | None:
28
+ value = os.environ.get(name)
29
+ if value is None:
30
+ return None
31
+ trimmed = value.strip()
32
+ return trimmed or None
33
+
34
+
35
+ def _parse_positive_float(raw: str | None, fallback: float) -> float:
36
+ if raw is None:
37
+ return fallback
38
+ try:
39
+ parsed = float(raw)
40
+ except ValueError:
41
+ return fallback
42
+ return parsed if parsed >= 0 else fallback
43
+
44
+
45
+ def _parse_access_type(raw: str | None) -> AccessType:
46
+ value = (raw or "aws_iam").lower()
47
+ allowed: tuple[AccessType, ...] = (
48
+ "access_key",
49
+ "api_key",
50
+ "aws_iam",
51
+ "azure_ad",
52
+ "gcp",
53
+ "universal_identity",
54
+ "jwt",
55
+ )
56
+ if value not in allowed:
57
+ raise ValueError(
58
+ f'Unsupported AKEYLESS_ACCESS_TYPE "{raw}". '
59
+ "Expected access_key, api_key, aws_iam, azure_ad, gcp, universal_identity, or jwt."
60
+ )
61
+ return value # type: ignore[return-value]
62
+
63
+
64
+ def _cloud_provider_for_access_type(access_type: AccessType) -> CloudProvider | None:
65
+ if access_type in ("aws_iam", "azure_ad", "gcp"):
66
+ return access_type
67
+ return None
68
+
69
+
70
+ @dataclass
71
+ class AkeylessRuntimeConfig:
72
+ gateway_url: str = DEFAULT_GATEWAY
73
+ secret_prefix: str = "/"
74
+ access_type: AccessType = "aws_iam"
75
+ access_id: str | None = None
76
+ access_key: str | None = None
77
+ uid_token: str | None = None
78
+ jwt: str | None = None
79
+ token: str | None = None
80
+ cloud_id: str | None = None
81
+ cloud_provider: CloudProvider | None = None
82
+ secret_cache_ttl_seconds: float = DEFAULT_SECRET_CACHE_TTL_SECONDS
83
+ token_expiry_margin_seconds: float = DEFAULT_TOKEN_EXPIRY_MARGIN_SECONDS
84
+
85
+
86
+ def config_from_env(**overrides: object) -> AkeylessRuntimeConfig:
87
+ access_type = overrides.get("access_type") or _parse_access_type(
88
+ _read_env("AKEYLESS_ACCESS_TYPE")
89
+ )
90
+
91
+ secret_prefix = overrides.get("secret_prefix")
92
+ if secret_prefix is None:
93
+ secret_prefix = _read_env("AKEYLESS_SECRET_PREFIX") or default_agentcore_secret_prefix() or "/"
94
+
95
+ cloud_provider = overrides.get("cloud_provider")
96
+ if cloud_provider is None:
97
+ cloud_provider = _cloud_provider_for_access_type(access_type)
98
+
99
+ return AkeylessRuntimeConfig(
100
+ gateway_url=overrides.get("gateway_url")
101
+ or _read_env("AKEYLESS_GATEWAY_URL")
102
+ or DEFAULT_GATEWAY,
103
+ secret_prefix=str(secret_prefix),
104
+ access_type=access_type, # type: ignore[arg-type]
105
+ access_id=overrides.get("access_id") or _read_env("AKEYLESS_ACCESS_ID"),
106
+ access_key=overrides.get("access_key")
107
+ or _read_env("AKEYLESS_ACCESS_KEY")
108
+ or _read_env("AKEYLESS_API_KEY"),
109
+ uid_token=overrides.get("uid_token")
110
+ or _read_env("AKEYLESS_UID_TOKEN")
111
+ or _read_env("AKEYLESS_UNIVERSAL_IDENTITY_TOKEN"),
112
+ jwt=overrides.get("jwt") or _read_env("AKEYLESS_JWT"),
113
+ token=overrides.get("token") or _read_env("AKEYLESS_TOKEN"),
114
+ cloud_id=overrides.get("cloud_id") or _read_env("AKEYLESS_CLOUD_ID"),
115
+ cloud_provider=cloud_provider, # type: ignore[arg-type]
116
+ secret_cache_ttl_seconds=overrides.get("secret_cache_ttl_seconds")
117
+ or _parse_positive_float(
118
+ _read_env("AKEYLESS_SECRET_CACHE_TTL_SECONDS"),
119
+ DEFAULT_SECRET_CACHE_TTL_SECONDS,
120
+ ),
121
+ token_expiry_margin_seconds=overrides.get("token_expiry_margin_seconds")
122
+ or _parse_positive_float(
123
+ _read_env("AKEYLESS_TOKEN_EXPIRY_MARGIN_SECONDS"),
124
+ DEFAULT_TOKEN_EXPIRY_MARGIN_SECONDS,
125
+ ),
126
+ )
127
+
128
+
129
+ def validate_config(config: AkeylessRuntimeConfig) -> None:
130
+ if not config.gateway_url.strip():
131
+ raise ValueError("gateway_url is required")
132
+
133
+ if config.token and config.token.strip():
134
+ return
135
+
136
+ if config.access_type in ("access_key", "api_key"):
137
+ if not config.access_id or not config.access_key:
138
+ raise ValueError(
139
+ "access_id and access_key are required for access_key/api_key authentication "
140
+ "(or set token / AKEYLESS_TOKEN)"
141
+ )
142
+ return
143
+
144
+ if config.access_type == "universal_identity":
145
+ if not config.uid_token:
146
+ raise ValueError(
147
+ "uid_token is required for universal_identity authentication "
148
+ "(or set token / AKEYLESS_TOKEN)"
149
+ )
150
+ return
151
+
152
+ if config.access_type == "jwt":
153
+ if not config.access_id or not config.jwt:
154
+ raise ValueError(
155
+ "access_id and jwt are required for jwt authentication "
156
+ "(or set token / AKEYLESS_TOKEN)"
157
+ )
158
+ return
159
+
160
+ if config.access_type in ("aws_iam", "azure_ad", "gcp"):
161
+ if not config.access_id:
162
+ raise ValueError(
163
+ f"{config.access_type} authentication requires access_id "
164
+ "(or set token / AKEYLESS_TOKEN)"
165
+ )
166
+ return
167
+
168
+ raise ValueError(f"Unsupported access type: {config.access_type}")
@@ -0,0 +1,79 @@
1
+ """Path helpers for resolving Akeyless secret names on AgentCore."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from typing import Any
8
+
9
+
10
+ def normalize_path(path: str) -> str:
11
+ trimmed = path.strip()
12
+ if not trimmed:
13
+ return "/"
14
+ with_leading = trimmed if trimmed.startswith("/") else f"/{trimmed}"
15
+ collapsed = "/".join(part for part in with_leading.split("/") if part)
16
+ return f"/{collapsed}" if collapsed else "/"
17
+
18
+
19
+ def join_secret_path(prefix: str, name: str) -> str:
20
+ base = normalize_path(prefix)
21
+ segment = name.strip().lstrip("/")
22
+ if not segment:
23
+ return base
24
+ if base == "/":
25
+ return f"/{segment}"
26
+ return f"{base}/{segment}"
27
+
28
+
29
+ def stringify_secret_value(value: Any) -> str:
30
+ if value is None:
31
+ return ""
32
+ if isinstance(value, str):
33
+ return value
34
+ if isinstance(value, (int, float, bool)):
35
+ return str(value)
36
+ if isinstance(value, (bytes, bytearray)):
37
+ return bytes(value).decode("utf-8")
38
+ return json.dumps(value)
39
+
40
+
41
+ def pick_secret_from_response(requested_path: str, data: dict[str, Any] | None) -> str:
42
+ if not data:
43
+ raise ValueError("Akeyless returned an empty secret payload")
44
+
45
+ trimmed = requested_path.strip()
46
+ candidates = [
47
+ trimmed,
48
+ normalize_path(trimmed),
49
+ trimmed.lstrip("/"),
50
+ ]
51
+
52
+ for key in candidates:
53
+ if key in data:
54
+ return stringify_secret_value(data[key])
55
+
56
+ raise ValueError(f'No value for "{requested_path}" in Akeyless response')
57
+
58
+
59
+ def format_structured_response(data: Any) -> str:
60
+ if data is None:
61
+ raise ValueError("Akeyless returned an empty response")
62
+ if isinstance(data, str):
63
+ return data
64
+ return json.dumps(data)
65
+
66
+
67
+ def agentcore_environment() -> str:
68
+ for key in ("AKEYLESS_ENV", "AGENTCORE_ENV", "ENVIRONMENT"):
69
+ value = os.environ.get(key, "").strip().lower()
70
+ if value:
71
+ return value
72
+ return "production"
73
+
74
+
75
+ def default_agentcore_secret_prefix() -> str | None:
76
+ agent_name = os.environ.get("AGENTCORE_AGENT_NAME", "").strip()
77
+ if not agent_name:
78
+ return None
79
+ return f"/bedrock-agentcore/{agent_name}/{agentcore_environment()}"
@@ -0,0 +1,31 @@
1
+ """AgentCore tool integrations for Akeyless secrets."""
2
+
3
+ from akeyless_agentcore.tools.service import SecretToolService
4
+
5
+ __all__ = [
6
+ "GATEWAY_TOOL_SCHEMA",
7
+ "SecretToolService",
8
+ "create_mcp_server",
9
+ "create_strands_tools",
10
+ "gateway_lambda_handler",
11
+ "run_mcp_server",
12
+ ]
13
+
14
+
15
+ def __getattr__(name: str):
16
+ if name in ("create_mcp_server", "run_mcp_server"):
17
+ from akeyless_agentcore.tools.mcp import create_mcp_server, run_mcp_server
18
+
19
+ return {"create_mcp_server": create_mcp_server, "run_mcp_server": run_mcp_server}[name]
20
+ if name == "create_strands_tools":
21
+ from akeyless_agentcore.tools.strands import create_strands_tools
22
+
23
+ return create_strands_tools
24
+ if name in ("gateway_lambda_handler", "GATEWAY_TOOL_SCHEMA"):
25
+ from akeyless_agentcore.tools.gateway import GATEWAY_TOOL_SCHEMA, gateway_lambda_handler
26
+
27
+ return {
28
+ "gateway_lambda_handler": gateway_lambda_handler,
29
+ "GATEWAY_TOOL_SCHEMA": GATEWAY_TOOL_SCHEMA,
30
+ }[name]
31
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,103 @@
1
+ """AgentCore Gateway Lambda handler and tool schema for Akeyless secrets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Any
7
+
8
+ from akeyless_agentcore.tools.service import SecretToolService, SecretType
9
+
10
+ GATEWAY_TOOL_SCHEMA: dict[str, Any] = {
11
+ "inlinePayload": [
12
+ {
13
+ "name": "list_akeyless_secrets",
14
+ "description": (
15
+ "List Akeyless secret names under a path prefix. "
16
+ "Returns names only, never secret values."
17
+ ),
18
+ "inputSchema": {
19
+ "type": "object",
20
+ "properties": {
21
+ "prefix": {
22
+ "type": "string",
23
+ "description": "Optional Akeyless path prefix (defaults to AKEYLESS_SECRET_PREFIX)",
24
+ }
25
+ },
26
+ },
27
+ },
28
+ {
29
+ "name": "get_akeyless_secret",
30
+ "description": (
31
+ "Fetch a secret value from Akeyless using cloud identity authentication. "
32
+ "Use json_key to return a single field from JSON secrets."
33
+ ),
34
+ "inputSchema": {
35
+ "type": "object",
36
+ "properties": {
37
+ "name": {
38
+ "type": "string",
39
+ "description": "Secret name or full path starting with /",
40
+ },
41
+ "path": {
42
+ "type": "string",
43
+ "description": "Optional full Akeyless path overriding prefix + name",
44
+ },
45
+ "secret_type": {
46
+ "type": "string",
47
+ "enum": ["static", "dynamic", "rotated"],
48
+ "description": "Secret type (default: static)",
49
+ },
50
+ "json_key": {
51
+ "type": "string",
52
+ "description": "Return only this key from a JSON secret",
53
+ },
54
+ "ignore_cache": {
55
+ "type": "boolean",
56
+ "description": "Bypass in-memory secret cache",
57
+ },
58
+ },
59
+ "required": ["name"],
60
+ },
61
+ },
62
+ ]
63
+ }
64
+
65
+
66
+ def gateway_lambda_handler(event: dict[str, Any], context: Any) -> dict[str, Any]:
67
+ """Lambda entrypoint for AgentCore Gateway MCP tool invocations."""
68
+ service = SecretToolService()
69
+ tool_name = "unknown"
70
+ if context and getattr(context, "client_context", None):
71
+ custom = getattr(context.client_context, "custom", None) or {}
72
+ tool_name = custom.get("bedrockAgentCoreToolName", "unknown")
73
+
74
+ try:
75
+ if "list_akeyless_secrets" in tool_name:
76
+ result = service.list_secrets(prefix=event.get("prefix"))
77
+ elif "get_akeyless_secret" in tool_name:
78
+ secret_type = event.get("secret_type", "static")
79
+ if secret_type not in ("static", "dynamic", "rotated"):
80
+ secret_type = "static"
81
+ result = service.get_secret(
82
+ event["name"],
83
+ path=event.get("path"),
84
+ secret_type=secret_type, # type: ignore[arg-type]
85
+ json_key=event.get("json_key"),
86
+ ignore_cache=bool(event.get("ignore_cache", False)),
87
+ )
88
+ else:
89
+ result = service.get_secret(event.get("name", "")) if event.get("name") else None
90
+ if result is None:
91
+ return _lambda_response({"ok": False, "error": f"Unknown tool: {tool_name}"}, status=400)
92
+
93
+ status = 200 if result.ok else 400
94
+ body = json.loads(result.to_json())
95
+ return _lambda_response(body, status=status)
96
+ except KeyError as exc:
97
+ return _lambda_response({"ok": False, "error": f"Missing required field: {exc}"}, status=400)
98
+ except Exception as exc:
99
+ return _lambda_response({"ok": False, "error": str(exc)}, status=500)
100
+
101
+
102
+ def _lambda_response(body: dict[str, Any], status: int = 200) -> dict[str, Any]:
103
+ return {"statusCode": status, "body": json.dumps(body)}
@@ -0,0 +1,70 @@
1
+ """FastMCP server exposing Akeyless secrets as AgentCore Runtime MCP tools."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from akeyless_agentcore.tools.service import SecretToolService, SecretType
8
+
9
+ try:
10
+ from mcp.server.fastmcp import FastMCP
11
+ except ImportError as exc: # pragma: no cover - optional dependency
12
+ raise ImportError(
13
+ "MCP support requires the 'mcp' package. Install with: pip install 'akeyless-agentcore-runtime[mcp]'"
14
+ ) from exc
15
+
16
+
17
+ def create_mcp_server(
18
+ *,
19
+ name: str = "akeyless-secrets",
20
+ service: SecretToolService | None = None,
21
+ host: str = "0.0.0.0",
22
+ stateless_http: bool = True,
23
+ ) -> FastMCP:
24
+ """Create a FastMCP server with Akeyless secret tools."""
25
+ tool_service = service or SecretToolService()
26
+ mcp = FastMCP(name, host=host, stateless_http=stateless_http)
27
+
28
+ @mcp.tool()
29
+ def list_akeyless_secrets(prefix: str | None = None) -> str:
30
+ """List Akeyless secret names under a path prefix. Returns names only, never values.
31
+
32
+ Args:
33
+ prefix: Optional Akeyless path prefix. Defaults to AKEYLESS_SECRET_PREFIX.
34
+ """
35
+ return tool_service.list_secrets(prefix=prefix).to_json()
36
+
37
+ @mcp.tool()
38
+ def get_akeyless_secret(
39
+ name: str,
40
+ path: str | None = None,
41
+ secret_type: SecretType = "static",
42
+ json_key: str | None = None,
43
+ ignore_cache: bool = False,
44
+ ) -> str:
45
+ """Fetch a secret value from Akeyless. Authenticates with cloud identity (AWS IAM by default).
46
+
47
+ Use json_key when the secret is JSON and you only need one field (e.g. OPENAI_API_KEY).
48
+ Use secret_type='dynamic' or 'rotated' for non-static secrets.
49
+
50
+ Args:
51
+ name: Short secret name (resolved with AKEYLESS_SECRET_PREFIX) or full path starting with /
52
+ path: Optional full Akeyless path; overrides prefix + name resolution
53
+ secret_type: static, dynamic, or rotated
54
+ json_key: Return only this key from a JSON secret
55
+ ignore_cache: Bypass the in-memory secret cache
56
+ """
57
+ return tool_service.get_secret(
58
+ name,
59
+ path=path,
60
+ secret_type=secret_type,
61
+ json_key=json_key,
62
+ ignore_cache=ignore_cache,
63
+ ).to_json()
64
+
65
+ return mcp
66
+
67
+
68
+ def run_mcp_server(**kwargs: Any) -> None:
69
+ """Run the Akeyless MCP server with streamable HTTP (AgentCore-compatible)."""
70
+ create_mcp_server(**kwargs).run(transport="streamable-http")
@@ -0,0 +1,144 @@
1
+ """Shared secret tool logic for MCP, Strands, and Gateway deployments."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import dataclass
7
+ from typing import Any, Literal
8
+
9
+ from akeyless_agentcore.client import AkeylessRuntimeClient, GetSecretOptions
10
+
11
+ SecretType = Literal["static", "dynamic", "rotated"]
12
+
13
+
14
+ @dataclass
15
+ class ToolResponse:
16
+ ok: bool
17
+ data: dict[str, Any]
18
+ error: str | None = None
19
+
20
+ def to_json(self) -> str:
21
+ payload = {"ok": self.ok, **self.data}
22
+ if self.error:
23
+ payload["error"] = self.error
24
+ return json.dumps(payload)
25
+
26
+
27
+ class SecretToolService:
28
+ """Implements secret operations exposed as AgentCore tools."""
29
+
30
+ def __init__(self, client: AkeylessRuntimeClient | None = None) -> None:
31
+ self._client = client or AkeylessRuntimeClient()
32
+
33
+ @property
34
+ def client(self) -> AkeylessRuntimeClient:
35
+ return self._client
36
+
37
+ def list_secrets(self, prefix: str | None = None) -> ToolResponse:
38
+ """List secret names under a prefix. Never returns secret values."""
39
+ try:
40
+ names = self._client.list_secrets_sync(prefix=prefix)
41
+ return ToolResponse(
42
+ ok=True,
43
+ data={
44
+ "secrets": names,
45
+ "count": len(names),
46
+ "prefix": prefix or self._client.config.secret_prefix,
47
+ },
48
+ )
49
+ except Exception as exc:
50
+ return ToolResponse(ok=False, data={}, error=str(exc))
51
+
52
+ def get_secret(
53
+ self,
54
+ name: str,
55
+ *,
56
+ path: str | None = None,
57
+ secret_type: SecretType = "static",
58
+ json_key: str | None = None,
59
+ ignore_cache: bool = False,
60
+ ) -> ToolResponse:
61
+ """Fetch a secret value. Use json_key to return a single field from JSON secrets."""
62
+ try:
63
+ raw = self._fetch_by_type(
64
+ name=name,
65
+ path=path,
66
+ secret_type=secret_type,
67
+ ignore_cache=ignore_cache,
68
+ )
69
+ if json_key:
70
+ value = self._extract_json_key(raw, json_key)
71
+ return ToolResponse(
72
+ ok=True,
73
+ data={
74
+ "name": name,
75
+ "path": path or self._client.resolve_path(name),
76
+ "json_key": json_key,
77
+ "value": value,
78
+ "secret_type": secret_type,
79
+ },
80
+ )
81
+
82
+ return ToolResponse(
83
+ ok=True,
84
+ data={
85
+ "name": name,
86
+ "path": path or self._client.resolve_path(name),
87
+ "value": raw,
88
+ "secret_type": secret_type,
89
+ },
90
+ )
91
+ except Exception as exc:
92
+ return ToolResponse(ok=False, data={"name": name}, error=str(exc))
93
+
94
+ def _fetch_by_type(
95
+ self,
96
+ *,
97
+ name: str,
98
+ path: str | None,
99
+ secret_type: SecretType,
100
+ ignore_cache: bool,
101
+ ) -> str:
102
+ if secret_type == "dynamic":
103
+ return self._client.get_dynamic_secret_sync(
104
+ name,
105
+ path=path,
106
+ ignore_cache=ignore_cache,
107
+ )
108
+ if secret_type == "rotated":
109
+ return self._client.get_rotated_secret_sync(
110
+ name,
111
+ path=path,
112
+ ignore_cache=ignore_cache,
113
+ )
114
+
115
+ return self._client.get_secret_sync(
116
+ name,
117
+ GetSecretOptions(
118
+ path=path,
119
+ ignore_cache=ignore_cache,
120
+ allow_dynamic_fallback=True,
121
+ ),
122
+ )
123
+
124
+ @staticmethod
125
+ def _extract_json_key(raw: str, json_key: str) -> str:
126
+ try:
127
+ data = json.loads(raw)
128
+ except json.JSONDecodeError as exc:
129
+ raise ValueError(f"Secret is not valid JSON; cannot extract key {json_key!r}") from exc
130
+ if not isinstance(data, dict):
131
+ raise ValueError("Secret JSON must be an object to extract a key")
132
+ if json_key not in data:
133
+ raise ValueError(f"Key {json_key!r} not found in secret JSON")
134
+ return stringify_value(data[json_key])
135
+
136
+
137
+ def stringify_value(value: Any) -> str:
138
+ if value is None:
139
+ return ""
140
+ if isinstance(value, str):
141
+ return value
142
+ if isinstance(value, (int, float, bool)):
143
+ return str(value)
144
+ return json.dumps(value)
@@ -0,0 +1,44 @@
1
+ """In-process Strands tools for agents that call Akeyless without Gateway."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from akeyless_agentcore.tools.service import SecretToolService, SecretType
8
+
9
+ try:
10
+ from strands import tool
11
+ except ImportError as exc: # pragma: no cover - optional dependency
12
+ raise ImportError(
13
+ "Strands tools require strands-agents. Install with: "
14
+ "pip install 'akeyless-agentcore-runtime[strands]'"
15
+ ) from exc
16
+
17
+
18
+ def create_strands_tools(service: SecretToolService | None = None) -> list[Any]:
19
+ """Return Strands tool callables backed by the shared SecretToolService."""
20
+ tool_service = service or SecretToolService()
21
+
22
+ @tool
23
+ def list_akeyless_secrets(prefix: str | None = None) -> str:
24
+ """List Akeyless secret names under a path prefix. Returns names only, never values."""
25
+ return tool_service.list_secrets(prefix=prefix).to_json()
26
+
27
+ @tool
28
+ def get_akeyless_secret(
29
+ name: str,
30
+ path: str | None = None,
31
+ secret_type: SecretType = "static",
32
+ json_key: str | None = None,
33
+ ignore_cache: bool = False,
34
+ ) -> str:
35
+ """Fetch a secret from Akeyless. Use json_key for a single field from JSON secrets."""
36
+ return tool_service.get_secret(
37
+ name,
38
+ path=path,
39
+ secret_type=secret_type,
40
+ json_key=json_key,
41
+ ignore_cache=ignore_cache,
42
+ ).to_json()
43
+
44
+ return [list_akeyless_secrets, get_akeyless_secret]