Skip to content

feat: Add ConnectionRef to DataSource for pluggable external credential resolution - #6642

Merged
ntkathole merged 1 commit into
feast-dev:masterfrom
ntkathole:credentials
Aug 18, 2026
Merged

feat: Add ConnectionRef to DataSource for pluggable external credential resolution#6642
ntkathole merged 1 commit into
feast-dev:masterfrom
ntkathole:credentials

Conversation

@ntkathole

@ntkathole ntkathole commented Jul 24, 2026

Copy link
Copy Markdown
Member

What this PR does / why we need it:

Feast DataSources today have no mechanism to reference external credentials - authentication relies on ambient environment variables or a single global
offline_store config in feature_store.yaml.

This PR introduces ConnectionRef - which backend to use, how to authenticate, and where to connect - an optional reference on DataSource that points to an external credential store (Kubernetes Secrets, HashiCorp Vault, cloud secret managers, or environment variables). Credentials are resolved
at runtime by a pluggable CredentialProvider interface.

This enables:

  • HybridOfflineStore at runtime: Users configure a HybridOfflineStore via CR/feature_store.yaml, then add new data sources at runtime with their own connection_ref specifying connection_type, credentials, and connection params - no server restart needed.
  • Per-source credential isolation: Each DataSource resolves its own credentials from K8s Secrets, Vault, or other providers, removing the need for a single shared credential set.
  • Self-describing data sources: Non-sensitive connection parameters (account, warehouse, endpoint) live on the DataSource alongside the credential reference, making the source fully portable.

@ntkathole ntkathole self-assigned this Jul 24, 2026
@ntkathole
ntkathole requested a review from a team as a code owner July 24, 2026 11:11
@ntkathole
ntkathole marked this pull request as draft July 24, 2026 11:14
@codecov-commenter

codecov-commenter commented Jul 24, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 47.87234% with 147 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.96%. Comparing base (52999f1) to head (27219f5).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
sdk/python/feast/credentials.py 72.85% 38 Missing ⚠️
sdk/python/feast/infra/offline_stores/snowflake.py 7.14% 26 Missing ⚠️
sdk/python/feast/infra/offline_stores/duckdb.py 0.00% 18 Missing ⚠️
...k/python/feast/infra/offline_stores/file_source.py 11.11% 16 Missing ⚠️
sdk/python/feast/infra/offline_stores/redshift.py 12.50% 14 Missing ⚠️
sdk/python/feast/infra/offline_stores/dask.py 16.66% 8 Missing and 2 partials ⚠️
sdk/python/feast/infra/offline_stores/bigquery.py 10.00% 9 Missing ⚠️
sdk/python/feast/data_source.py 58.33% 3 Missing and 2 partials ⚠️
...ine_stores/contrib/ray_offline_store/ray_source.py 0.00% 2 Missing ⚠️
...ores/contrib/athena_offline_store/athena_source.py 50.00% 1 Missing ⚠️
... and 8 more
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           master    #6642    +/-   ##
========================================
  Coverage   46.95%   46.96%            
========================================
  Files         417      418     +1     
  Lines       51393    51672   +279     
  Branches     7438     7484    +46     
========================================
+ Hits        24132    24267   +135     
- Misses      25530    25671   +141     
- Partials     1731     1734     +3     
Flag Coverage Δ
go-feature-server 30.58% <ø> (ø)
python-unit 48.26% <47.87%> (+<0.01%) ⬆️
Files with missing lines Coverage Δ
..._sources/contrib/iceberg_catalog/iceberg_source.py 25.00% <100.00%> (+0.75%) ⬆️
...es/contrib/iceberg_catalog/unity_catalog_source.py 33.33% <100.00%> (+1.62%) ⬆️
...thon/feast/infra/offline_stores/bigquery_source.py 61.98% <100.00%> (+0.63%) ⬆️
...thon/feast/infra/offline_stores/redshift_source.py 63.44% <100.00%> (+0.51%) ⬆️
...hon/feast/infra/offline_stores/snowflake_source.py 57.51% <100.00%> (+0.56%) ⬆️
...ores/contrib/athena_offline_store/athena_source.py 45.76% <50.00%> (+0.07%) ⬆️
...trib/clickhouse_offline_store/clickhouse_source.py 55.68% <50.00%> (-0.14%) ⬇️
...ontrib/couchbase_offline_store/couchbase_source.py 42.14% <50.00%> (+0.11%) ⬆️
...ne_stores/contrib/mongodb_offline_store/mongodb.py 72.99% <50.00%> (-0.10%) ⬇️
.../contrib/mssql_offline_store/mssqlserver_source.py 47.82% <50.00%> (+0.04%) ⬆️
... and 13 more

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 52999f1...27219f5. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ntkathole
ntkathole force-pushed the credentials branch 2 times, most recently from 4f3809d to 948b262 Compare August 4, 2026 05:17
@ntkathole ntkathole changed the title feat: Add CredentialRef to DataSource for pluggable external credential resolution feat: Add ConnectionRef to DataSource for pluggable external credential resolution Aug 4, 2026
@ntkathole
ntkathole force-pushed the credentials branch 4 times, most recently from ed8fece to 35e9afc Compare August 4, 2026 06:26
@ntkathole
ntkathole marked this pull request as ready for review August 4, 2026 08:04
@ntkathole

Copy link
Copy Markdown
Member Author

@jyejare @patelchaitany @aniketpalu @Vperiodt Please review

Comment thread sdk/python/feast/credentials.py

@jyejare jyejare left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds ConnectionRef to DataSource for pluggable external credential resolution, enabling per-datasource credentials via external providers like Kubernetes Secrets, HashiCorp Vault, and cloud secret managers. The implementation is well-architected with comprehensive documentation, but has some critical security concerns and missing integration points that need addressing.

Comment thread sdk/python/feast/credentials.py
Comment thread sdk/python/feast/credentials.py
Comment thread sdk/python/feast/infra/offline_stores/snowflake.py
Comment thread sdk/python/feast/data_source.py
Comment on lines +37 to +45
message ConnectionRef {
// Credential provider type: "kubernetes", "vault", "aws-secrets-manager",
// "gcp-secret-manager", "azure-key-vault", "env".
string provider = 1;

// Provider-specific name: K8s Secret name, Vault path, env var prefix, etc.
string name = 2;

// Optional scope qualifier: K8s namespace, Vault mount, AWS region, etc.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] ConnectionRef proto should include validation constraints

The ConnectionRef proto definition lacks validation constraints that could prevent common misconfigurations. Adding field validation (e.g., required provider, valid provider types, namespace format) would catch configuration errors early rather than at runtime. This could be part of next improvement PR though.

Optional Comment!

Suggested:

Suggested change
message ConnectionRef {
// Credential provider type: "kubernetes", "vault", "aws-secrets-manager",
// "gcp-secret-manager", "azure-key-vault", "env".
string provider = 1;
// Provider-specific name: K8s Secret name, Vault path, env var prefix, etc.
string name = 2;
// Optional scope qualifier: K8s namespace, Vault mount, AWS region, etc.
message ConnectionRef {
// Credential provider type: "kubernetes", "vault", "aws-secrets-manager",
// "gcp-secret-manager", "azure-key-vault", "env".
// Required field.
string provider = 1 [(validate.rules).string.min_len = 1];
// Provider-specific name: K8s Secret name, Vault path, env var prefix, etc.
// Required field.
string name = 2 [(validate.rules).string.min_len = 1];

Comment thread sdk/python/feast/credentials.py
Comment thread sdk/python/feast/infra/offline_stores/bigquery.py
Comment thread sdk/python/feast/credentials.py
Comment on lines 266 to +291

@staticmethod
def create_filesystem_and_path(
path: str, s3_endpoint_override: str
path: str,
s3_endpoint_override: str,
resolved_credentials: Optional[Dict[str, str]] = None,
) -> Tuple[Optional[FileSystem], str]:
if path.startswith("s3://"):
s3fs = S3FileSystem(
endpoint_override=s3_endpoint_override if s3_endpoint_override else None
)
kwargs: Dict[str, Optional[str]] = {}
if s3_endpoint_override:
kwargs["endpoint_override"] = s3_endpoint_override

if resolved_credentials:
access_key = resolved_credentials.get("AWS_ACCESS_KEY_ID", "")
secret_key = resolved_credentials.get("AWS_SECRET_ACCESS_KEY", "")
session_token = resolved_credentials.get("AWS_SESSION_TOKEN")
region = resolved_credentials.get("AWS_DEFAULT_REGION")
if access_key and secret_key:
kwargs["access_key"] = access_key
kwargs["secret_key"] = secret_key
if session_token:
kwargs["session_token"] = session_token
if region:
kwargs["region"] = region

s3fs = S3FileSystem(**kwargs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] S3 credential handling should support all AWS credential types

The S3FileSystem credential handling only supports access_key/secret_key authentication but AWS supports many other credential types (IAM roles, STS, OIDC, etc.). The implementation should be more flexible to support the full range of AWS authentication methods.

Again this could be the part of future improvements. Or we should at least document that only access_key / secret_key type auth.

Suggested:

Suggested change
@staticmethod
def create_filesystem_and_path(
path: str, s3_endpoint_override: str
path: str,
s3_endpoint_override: str,
resolved_credentials: Optional[Dict[str, str]] = None,
) -> Tuple[Optional[FileSystem], str]:
if path.startswith("s3://"):
s3fs = S3FileSystem(
endpoint_override=s3_endpoint_override if s3_endpoint_override else None
)
kwargs: Dict[str, Optional[str]] = {}
if s3_endpoint_override:
kwargs["endpoint_override"] = s3_endpoint_override
if resolved_credentials:
access_key = resolved_credentials.get("AWS_ACCESS_KEY_ID", "")
secret_key = resolved_credentials.get("AWS_SECRET_ACCESS_KEY", "")
session_token = resolved_credentials.get("AWS_SESSION_TOKEN")
region = resolved_credentials.get("AWS_DEFAULT_REGION")
if access_key and secret_key:
kwargs["access_key"] = access_key
kwargs["secret_key"] = secret_key
if session_token:
kwargs["session_token"] = session_token
if region:
kwargs["region"] = region
s3fs = S3FileSystem(**kwargs)
if resolved_credentials:
# Support multiple AWS credential formats
access_key = resolved_credentials.get("AWS_ACCESS_KEY_ID") or resolved_credentials.get("access_key_id")
secret_key = resolved_credentials.get("AWS_SECRET_ACCESS_KEY") or resolved_credentials.get("secret_access_key")
session_token = resolved_credentials.get("AWS_SESSION_TOKEN") or resolved_credentials.get("session_token")
region = resolved_credentials.get("AWS_DEFAULT_REGION") or resolved_credentials.get("region")
if access_key and secret_key:
kwargs["access_key"] = access_key
kwargs["secret_key"] = secret_key
# Support role-based authentication
elif "role_arn" in resolved_credentials:
kwargs["role_arn"] = resolved_credentials["role_arn"]
if "external_id" in resolved_credentials:
kwargs["external_id"] = resolved_credentials["external_id"]

@jyejare jyejare left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR introduces a well-architected ConnectionRef feature for pluggable external credential resolution in Feast DataSources. The implementation follows good patterns with comprehensive documentation, built-in providers for Kubernetes/Vault/environment variables, and proper integration across all data source types. However, there are several critical security concerns around credential handling and some missing test coverage.

Comment thread sdk/python/feast/credentials.py
Comment thread sdk/python/feast/credentials.py Outdated
Comment thread sdk/python/feast/credentials.py
…al resolution

Signed-off-by: ntkathole <nikhilkathole2683@gmail.com>
@ntkathole
ntkathole merged commit 28bde01 into feast-dev:master Aug 18, 2026
19 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants