Skip to content

feat: cross app secret referencing #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 6, 2025
14 changes: 7 additions & 7 deletions helm-repo/index.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ apiVersion: v1
entries:
phase:
- apiVersion: v2
created: "2025-04-01T23:17:57.887487677+05:30"
created: "2025-04-06T14:37:10.153678271+05:30"
description: A Helm chart for deploying the Phase Secrets Manager
digest: 00fd9171966c7a0efad5992f5ca50d84c34203253b327e859ef6d0df9311e3f6
home: https://github.com/phasehq/kubernetes-secrets-operator
@@ -22,10 +22,10 @@ entries:
version: 0.3.0
phase-kubernetes-operator:
- apiVersion: v2
appVersion: 1.2.3
created: "2025-04-01T23:17:57.887872023+05:30"
appVersion: 1.2.4
created: "2025-04-06T14:37:10.153929128+05:30"
description: A Helm chart for deploying the Phase Kubernetes Operator
digest: 93e571ad092af42648a8731de51d6b1a371f5b738a5b6c5a327ca38fa90d45e4
digest: 4ae6e3dd5c7b1b18863aaaf646dbbb2ac6cc64cdc0a0b35b79ade6b3aac19e72
home: https://github.com/phasehq/kubernetes-secrets-operator
icon: https://phase.dev/apple-touch-icon.png
keywords:
@@ -41,6 +41,6 @@ entries:
- https://github.com/phasehq/kubernetes-secrets-operator
type: application
urls:
- phase-kubernetes-operator-1.2.3.tgz
version: 1.2.3
generated: "2025-04-01T23:17:57.886779868+05:30"
- phase-kubernetes-operator-1.2.4.tgz
version: 1.2.4
generated: "2025-04-06T14:37:10.15293167+05:30"
Binary file removed helm-repo/phase-kubernetes-operator-1.2.3.tgz
Binary file not shown.
Binary file added helm-repo/phase-kubernetes-operator-1.2.4.tgz
Binary file not shown.
4 changes: 2 additions & 2 deletions phase-kubernetes-operator/Chart.yaml
Original file line number Diff line number Diff line change
@@ -5,10 +5,10 @@ description: A Helm chart for deploying the Phase Kubernetes Operator
type: application

# Version of the chart
version: 1.2.3
version: 1.2.4

# Version of the application (operator) that is being deployed
appVersion: "1.2.3"
appVersion: "1.2.4"

# Keywords, maintainers, and source URLs can also be added here
keywords:
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cffi==1.15.1
requests==2.31.0
cffi==1.17.1
requests==2.32.0
PyNaCl==1.5.0
kopf==1.36.2
kopf==1.37.5
kubernetes==28.1.0
pytest==7.3.1
pyyaml==6.0.1
2 changes: 1 addition & 1 deletion src/utils/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import re
__version__ = "1.2.3"
__version__ = "1.2.4"
__ph_version__ = "v1"

description = "Securely manage application secrets and environment variables with Phase."
34 changes: 25 additions & 9 deletions src/utils/secret_referencing.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import re
from typing import Dict, List
from exceptions import EnvironmentNotFoundException
from utils.const import SECRET_REF_REGEX
from utils.phase_io import Phase

"""
Secret Referencing Syntax:
This documentation explains the syntax used for referencing secrets within the configuration.
Secrets can be referenced both locally (within the same environment) and across different environments,
with or without specifying a path.
Secrets can be referenced locally (within the same environment), across different environments,
and across different applications, with or without specifying a path.
Syntax Patterns:
@@ -40,8 +40,16 @@
- Secret Key: `STRIPE_KEY`
- Description: References a secret named `STRIPE_KEY` located at `/backend/payments/` in the current environment.
5. Cross-Application Reference:
Syntax: `${backend_api::production./frontend/SECRET_KEY}`
- Application: Different application (e.g., `backend_api`).
- Environment: Different environment (e.g., `production`).
- Path: Specifies a path within the environment (`/frontend/`).
- Secret Key: `SECRET_KEY`
- Description: References a secret named `SECRET_KEY` located at `/frontend/` in the `production` environment of the `backend_api` application.
Note:
The syntax allows for flexible secret management, enabling both straightforward local references and more complex cross-environment references.
The syntax allows for flexible secret management, enabling local references, cross-environment references, and cross-application references.
"""


@@ -74,12 +82,13 @@ def resolve_secret_reference(ref: str, secrets_dict: Dict[str, Dict[str, Dict[st
"""
Resolves a single secret reference to its actual value by fetching it from the specified environment.
The function supports both local and cross-environment secret references, allowing for flexible secret management.
The function supports local, cross-environment, and cross-application secret references, allowing for flexible secret management.
Local references are identified by the absence of a dot '.' in the reference string, implying the current environment.
Cross-environment references include an environment name, separated by a dot from the rest of the path.
Cross-application references use '::' to separate the application name from the rest of the reference.
Args:
ref (str): The secret reference string, which could be a local or cross-environment reference.
ref (str): The secret reference string, which could be a local, cross-environment, or cross-application reference.
secrets_dict (Dict[str, Dict[str, Dict[str, str]]]): A dictionary containing known secrets.
phase ('Phase'): An instance of the Phase class to fetch secrets.
current_application_name (str): The name of the current application.
@@ -88,10 +97,17 @@ def resolve_secret_reference(ref: str, secrets_dict: Dict[str, Dict[str, Dict[st
Returns:
str: The resolved secret value or the original reference if not resolved.
"""
original_ref = ref # Store the original reference
app_name = current_application_name
env_name = current_env_name
path = "/" # Default root path
key_name = ref

# Check if this is a cross-application reference
if "::" in ref:
parts = ref.split("::", 1)
app_name, ref = parts[0], parts[1]

# Parse the reference to identify environment, path, and secret key.
if "." in ref: # Cross-environment references
parts = ref.split(".", 1)
@@ -112,15 +128,15 @@ def resolve_secret_reference(ref: str, secrets_dict: Dict[str, Dict[str, Dict[st
return secrets_dict[env_name]['/'][key_name]

# If the secret is not found in secrets_dict, try to fetch it from Phase
fetched_secrets = phase.get(env_name=env_name, app_name=current_application_name, keys=[key_name], path=path)
fetched_secrets = phase.get(env_name=env_name, app_name=app_name, keys=[key_name], path=path)
for secret in fetched_secrets:
if secret["key"] == key_name:
return secret["value"]
except EnvironmentNotFoundException:
pass

# Return the reference as is if not resolved
return f"${{{ref}}}"
# Return the original secret value as is if not resolved
return f"${{{original_ref}}}"


def resolve_all_secrets(value: str, all_secrets: List[Dict[str, str]], phase: 'Phase', current_application_name: str, current_env_name: str) -> str: