Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/how-to-guides/starting-feast-servers-tls-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,52 @@ auth:

`cert` is an optional configuration to the public certificate path when the registry server starts in TLS(SSL) mode. Typically, this file ends with `*.crt`, `*.cer`, or `*.pem`.

### Feast client connecting to remote registry server with mTLS

If the Registry Server requires mutual TLS (mTLS), the client must present a certificate and private key in addition to trusting the server's CA certificate. Add `client_cert` and `client_key` to the registry configuration:

```yaml
project: feast-project
registry:
registry_type: remote
path: feature-registry.example.com:443
cert: /path/to/ca.crt
client_cert: /path/to/tls.crt
client_key: /path/to/tls.key
provider: local
online_store:
path: http://localhost:6566
type: remote
entity_key_serialization_version: 3
auth:
type: no_auth
```

* `cert` — CA certificate used to verify the server (or use the `SSL_CERT_FILE` / `REQUESTS_CA_BUNDLE` environment variable).
* `client_cert` — Client certificate presented to the server. Must be paired with `client_key`.
* `client_key` — Private key for the client certificate.

#### Connecting through a tunnel or proxy

When connecting through a tunnel (e.g. `gcloud compute start-iap-tunnel`) the client connects to `localhost`, but the server certificate is issued for the real service hostname. Set the `authority` field so that gRPC's TLS hostname verification passes:

```shell
# In one terminal — start the tunnel:
gcloud compute start-iap-tunnel feature-registry.example.com 443 --local-host-port=localhost:8443
```

```yaml
registry:
registry_type: remote
path: localhost:8443
cert: /path/to/ca.crt
client_cert: /path/to/tls.crt
client_key: /path/to/tls.key
authority: feature-registry.example.com
```

Without `authority`, the gRPC client would check the server certificate against `localhost`, which would fail because the certificate's Subject Alternative Name (SAN) is `feature-registry.example.com`.

## Starting feast offline server in TLS mode

To start the offline server in TLS mode, you need to provide the private and public keys using the `--key` and `--cert` arguments with the `feast serve_offline` command.
Expand Down
22 changes: 21 additions & 1 deletion docs/reference/registries/remote.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,27 @@ registry:
{% endcode %}

The optional `cert` parameter can be configured as well, it should point to the public certificate path when the Registry Server starts in SSL mode. This may be needed if the Registry Server is started with a self-signed certificate, typically this file ends with *.crt, *.cer, or *.pem.
More info about the `cert` parameter can be found in [feast-client-connecting-to-remote-registry-sever-started-in-tls-mode](../../how-to-guides/starting-feast-servers-tls-mode.md#feast-client-connecting-to-remote-registry-sever-started-in-tls-mode)

For **mutual TLS (mTLS)**, you can also configure:
* `client_cert` — Path to the client certificate presented to the server. Must be paired with `client_key`. Typically ends with `*.crt` or `*.pem`.
* `client_key` — Path to the client private key. Must be paired with `client_cert`. Typically ends with `*.key` or `*.pem`.

When connecting through a tunnel or proxy where the connection address differs from the server hostname, set:
* `authority` — Overrides the gRPC `:authority` header so the server certificate is validated against the correct hostname.

{% code title="feature_store.yaml" %}
```yaml
registry:
registry_type: remote
path: localhost:8443
cert: /path/to/ca.crt
client_cert: /path/to/tls.crt
client_key: /path/to/tls.key
authority: feature-registry.example.com
```
{% endcode %}

More info about TLS configuration can be found in [feast-client-connecting-to-remote-registry-sever-started-in-tls-mode](../../how-to-guides/starting-feast-servers-tls-mode.md#feast-client-connecting-to-remote-registry-sever-started-in-tls-mode)

## How to configure the server

Expand Down
59 changes: 50 additions & 9 deletions sdk/python/feast/infra/registry/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,25 @@ class RemoteRegistryConfig(RegistryConfig):

is_tls: bool = False
""" bool: Set to `True` if you plan to connect to a registry server running in TLS (SSL) mode.
If you intend to add the public certificate to the trust store instead of passing it via the `cert` parameter, this field must be set to `True`.
Comment thread
shuchu marked this conversation as resolved.
If you are planning to add the public certificate as part of the trust store instead of passing it as a `cert` parameters then setting this field to `true` is mandatory.
If you are planning to add the public certificate as part of the trust store instead of passing it as a `cert` parameters then setting this field to `True` is mandatory.
"""
Comment thread
jacob-bush-shopify marked this conversation as resolved.

client_cert: StrictStr = ""
""" str: Path to the client certificate for mTLS (mutual TLS) authentication.
Required when connecting to a server that enforces mutual TLS.
Must be provided together with `client_key`.
Typically this file ends with `*.crt` or `*.pem`. """

client_key: StrictStr = ""
""" str: Path to the client private key for mTLS (mutual TLS) authentication.
Must be provided together with `client_cert`.
Typically this file ends with `*.key` or `*.pem`. """

authority: StrictStr = ""
""" str: Override the gRPC :authority header for TLS connections.
Required when the connection address differs from the service hostname,
e.g. when connecting through a tunnel or proxy for local development. """


class RemoteRegistry(BaseRegistry):
def __init__(
Expand All @@ -99,19 +114,45 @@ def __init__(
def _create_grpc_channel(self, registry_config):
assert isinstance(registry_config, RemoteRegistryConfig)
if registry_config.cert or registry_config.is_tls:
cafile = os.getenv("SSL_CERT_FILE") or os.getenv("REQUESTS_CA_BUNDLE")
if not cafile and not registry_config.cert:
cafile = (
registry_config.cert
or os.getenv("SSL_CERT_FILE")
or os.getenv("REQUESTS_CA_BUNDLE")
)
if not cafile:
raise EnvironmentError(
"SSL_CERT_FILE or REQUESTS_CA_BUNDLE environment variable must be set to use secure TLS or set the cert parameter in feature_Store.yaml file under remote registry configuration."
)
with open(
registry_config.cert if registry_config.cert else cafile, "rb"
) as cert_file:
if (registry_config.client_cert and not registry_config.client_key) or (
not registry_config.client_cert and registry_config.client_key
):
raise ValueError(
"Both client_cert and client_key must be provided for mTLS. "
"Only one was set in the remote registry configuration."
)

with open(cafile, "rb") as cert_file:
trusted_certs = cert_file.read()
private_key: Optional[bytes] = None
certificate_chain: Optional[bytes] = None
if registry_config.client_cert and registry_config.client_key:
with open(registry_config.client_key, "rb") as key_file:
private_key = key_file.read()
with open(registry_config.client_cert, "rb") as cert_file:
certificate_chain = cert_file.read()
tls_credentials = grpc.ssl_channel_credentials(
root_certificates=trusted_certs
root_certificates=trusted_certs,
private_key=private_key,
certificate_chain=certificate_chain,
)

options = []
if registry_config.authority:
options.append(("grpc.default_authority", registry_config.authority))

return grpc.secure_channel(
registry_config.path, tls_credentials, options=options
)
return grpc.secure_channel(registry_config.path, tls_credentials)
else:
# Create an insecure gRPC channel
return grpc.insecure_channel(registry_config.path)
Expand Down
Loading
Loading