-
Notifications
You must be signed in to change notification settings - Fork 1
Add Vault secrets provider with hash-separated keys and automatic JWT generation #109
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
base: develop
Are you sure you want to change the base?
Conversation
Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
…sistency Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
…cking Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
src/nyl/secrets/vault.py
Outdated
| - "database.credentials.username" retrieves nested fields | ||
|
|
||
| Args: | ||
| key: The key of the secret to retrieve, with optional dot notation for nested access. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Using dot notation for nested access makes it impossible to use secrets with dots in the path. We should separate the secret path with fields for nested access with a hash character followed by dot notation, e.g. path/to/secret#database.password.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in c2eea33. Changed key format to use hash separator (#) between path and field access. Now supports secrets with dots in paths: "db.prod#password" or "my-app.v2#field". Updated all tests and documentation.
|
|
||
| return result | ||
|
|
||
| def set(self, key: str, value: SecretValue, /) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot The Vault implementation should not support setting/unsetting. Let's simply raise a NotImplementedError and document this behavior. Make sure to cleanup unused code after removing these implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in c2eea33. Both set() and unset() now raise NotImplementedError with clear messages directing users to manage secrets through Vault's interface. Removed ~120 lines of unused implementation code and updated tests.
|
|
||
| def _authenticate_with_jwt(self) -> None: | ||
| """Authenticate with Vault using Kubernetes JWT token (for ArgoCD context).""" | ||
| jwt_path = Path("/var/run/secrets/kubernetes.io/serviceaccount/token") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot The workload identity method described in #108 actually does not refer to the Kubernetes token, but instead through a token issued by Nyl to assert the ArgoCD application that is being templated.
I think we should consider allowing both options: Using the Kubernetes service account for simple usage, and Nyl-issuer ArgoCD-application specific workload identities for mutli-tenant deployments.
The payload for a token could be e.g.
{
"iss": "https://my-argocd.example.com/#nyl-v1",
"aud": "https://my-vault.example.com:8200",
"sub": "project:default:application:my-argo-app",
"argocd_project": "default",
"argocd_app": "my-argo-app",
"repository": "git@github.com:example-org/manifests.git"
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in c2eea33. Added support for both authentication methods via jwt_auth_method config:
"kubernetes"(default): Uses Kubernetes service account token"nyl": Uses Nyl-issued JWT fromNYL_VAULT_JWTenv var with ArgoCD app claims
The Nyl JWT mode expects tokens with payload including argocd_project, argocd_app, and repository fields as described. Both methods coexist and are selected via configuration.
…T auth Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
src/nyl/secrets/vault.py
Outdated
| - repository: Git repository URL | ||
| """ | ||
| # Check for Nyl-issued JWT token in environment variable | ||
| jwt_token = os.environ.get("NYL_VAULT_JWT") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot But this code is Nyl, we need to generate a token here (or use one we previously generated). I think a good place for issuing a new token would be in the main entrypoint when we detect that we're running in ArgoCD with the Nyl JWT auth method enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in f399007. Nyl now generates JWT tokens internally:
- Added
src/nyl/tools/jwt.pymodule withgenerate_nyl_jwt_from_argocd_env()function - Reads ArgoCD environment variables (
ARGOCD_APP_NAME,ARGOCD_APP_PROJECT_NAME,ARGOCD_APP_SOURCE_REPO_URL) - Generates HS256-signed JWT tokens with claims:
iss,aud,sub,argocd_project,argocd_app,repository - Token generation happens in template command entrypoint (after loading secrets config, before use)
- Added
jwt_signing_keyconfig option (orNYL_VAULT_JWT_SIGNING_KEYenv var) as shared secret - VaultSecretProvider receives generated token via
set_nyl_jwt_token()method - All tests passing (26 total: 18 Vault + 8 JWT)
Co-authored-by: NiklasRosenstein <1318438+NiklasRosenstein@users.noreply.github.com>
Adds HashiCorp Vault as a read-only secrets provider to support environments where the Vault Secrets Operator cannot inject values (e.g., templated config files, Helm chart limitations). Enables secure multi-tenant deployments with flexible JWT authentication options.
Implementation
VaultSecretProvider (
src/nyl/secrets/vault.py)kubernetes(default): Kubernetes service account token for simple deploymentsnyl: Nyl automatically generates ArgoCD application-specific JWT tokens for multi-tenant environmentsVAULT_TOKENenv var or~/.vault-token(local dev)ARGOCD_APP_NAMEpresencepath/to/secret#field.nested.pathsupports secrets with dots in pathsset()andunset()raiseNotImplementedErrorJWT Token Generation (
src/nyl/tools/jwt.py)jwt_signing_key)iss,aud,sub,argocd_project,argocd_app,repositoryConfiguration
Usage
Design Notes
#): Separates secret path from field access, allowing dots in secret pathsDependencies
hvac>=2.3.0(no known vulnerabilities)pyjwt>=2.8.0for JWT token generation (no known vulnerabilities)Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.