Back to Feast

Feast Client with RBAC

examples/operator-rbac/3-client-rbac-test-local.ipynb

0.63.06.9 KB
Original Source

Feast Client with RBAC

Example Using outside of Kubernetes for local testing

This notebook will test Feast authentication outside of Kubernetes for local testing.

When running outside of Kubernetes, you need to manually set the service account token in the LOCAL_K8S_TOKEN environment variable. The token can be retrieved from a running pod using:

sh

kubectl exec <pod-name> -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

To authenticate Feast externally, set the retrieved token as an environment variable:

sh

export LOCAL_K8S_TOKEN="your-service-account-token"

Test Cases

User TypeServiceAccountRoleBinding AssignedExpected Behavior in output
Read-Onlyfeast-user-safeast-readerCan read from the feature store, but cannot write.
Unauthorizedfeast-unauthorized-user-saNoneAccess should be denied in test.py.
Adminfeast-admin-safeast-writerCan read and write feature store data.

Feature Store settings

The Operator create client feature store ConfigMap containing the feature_store.yaml settings. We can retrieve it and port froward to local as we are testing locally.

python
!kubectl get configmap feast-sample-kubernetes-auth-client -n feast -o jsonpath='{.data.feature_store\.yaml}' > client/feature_repo/feature_store.yaml

Update the client/feature_repo/feature_store.yaml to look like below:

python
project: feast_rbac
provider: local
offline_store:
    host: localhost
    type: remote
    port: 8081
online_store:
    path: http://localhost:8082
    type: remote
registry:
    path: localhost:8083
    registry_type: remote
auth:
    type: kubernetes
entity_key_serialization_version: 3

The function below is executed to support the preparation of client testing.

Run Port Forwarding for All Services for local testing

python
import subprocess

# Define services and their local ports
services = {
    "offline_store": ("feast-sample-kubernetes-auth-offline", 8081),
    "online_store": ("feast-sample-kubernetes-auth-online", 8082),
    "registry": ("feast-sample-kubernetes-auth-registry", 8083),
}

# Start port-forwarding for each service
port_forward_processes = {}
for name, (service, local_port) in services.items():
    cmd = f"kubectl port-forward svc/{service} -n feast {local_port}:80"
    process = subprocess.Popen(cmd, shell=True)
    port_forward_processes[name] = process
    print(f"Port forwarding {service} -> localhost:{local_port}")

Function to retrieve a Kubernetes service account token and set it as an environment variable

python
import subprocess
import os

def get_k8s_token(service_account):
    namespace = "feast"

    if not service_account:
        raise ValueError("Service account name is required.")

    result = subprocess.run(
        ["kubectl", "create", "token", service_account, "-n", namespace],
        capture_output=True, text=True, check=True
    )

    token = result.stdout.strip()

    if not token:
        return None  # Silently return None if token retrieval fails

    os.environ["LOCAL_K8S_TOKEN"] = token
    return "Token Retrieved: ***** (hidden for security)"

Generating training data. The following test functions were copied from the test_workflow.py template but we added try blocks to print only the relevant error messages, since we expect to receive errors from the permission enforcement modules.

python
!cat client/feature_repo/test.py
python
import os

# Set the FEAST_REPO_PATH before importing check_permissions
os.environ["FEAST_REPO_PATH"] = "client/feature_repo"

Test Read-Only Feast User

Step 1: Set the Token

python
get_k8s_token("feast-user-sa")

Step 2: Test permission functions to validate permission on fetching online, offline or perform write operation

python
from client.feature_repo.test import  check_permissions

# Call the function
#Run test.py script from pod to test RBAC for client-readonly-user.
# verify the logs for write operation will show below message 
# --- Write to Feature Store ---
#*** PERMISSION DENIED *** User lacks permission to modify the feature store.

check_permissions()

Step 3: Test permission functions to validate permission on fetching online feature views

Required:

  • The Bearer token exported above as LOCAL_K8S_TOKEN
python
# Run Curl command to test the RBAC for client-readonly-user.
!curl -X POST http://localhost:8082/get-online-features -H "Content-Type: application/json" -H "Authorization: Bearer $LOCAL_K8S_TOKEN" -d '{"features": ["driver_hourly_stats:conv_rate","driver_hourly_stats:acc_rate"], "entities":{"driver_id": [1001, 1002]}}'

Test Unauthorized Feast User

Step 1: Test permission functions to validate unauthorized user cant access any objects

python
# Retrieve and store the token
get_k8s_token("feast-unauthorized-user-sa")
python
check_permissions()

Step 2: Run API request for Unauthorized User, Unauthorized user should not be able to even view the objects.

Required:

  • The Bearer token exported above as LOCAL_K8S_TOKEN
python
# Run Curl command to test the RBAC for client-readonly-user.
!curl -X POST http://localhost:8082/get-online-features -H "Content-Type: application/json" -H "Authorization: Bearer $LOCAL_K8S_TOKEN" -d '{"features": ["driver_hourly_stats:conv_rate","driver_hourly_stats:acc_rate"], "entities":{"driver_id": [1001, 1002]}}'

Test Admin Feast User

Step 1: Test permissions function to validate Admin user can access all objects

python
# Retrieve and store the token
get_k8s_token("feast-admin-sa")
python
check_permissions()

Step 2: Run API request for Admin User, Admin user should be able to perform all operations on the objects.

Required:

  • The Bearer token exported above as LOCAL_K8S_TOKEN
python
# Run Curl command to test the RBAC for client-readonly-user.
!curl -X POST http://localhost:8082/get-online-features -H "Content-Type: application/json" -H "Authorization: Bearer $LOCAL_K8S_TOKEN" -d '{"features": ["driver_hourly_stats:conv_rate","driver_hourly_stats:acc_rate"], "entities":{"driver_id": [1001, 1002]}}'

Note: Currently, remote materialization not available in Feast when using the Remote Client Workaround: Consider using running it from pod like

kubectl exec deploy/feast-sample-kubernetes-auth -itc online -- bash -c 'feast materialize-incremental $(date -u +"%Y-%m-%dT%H:%M:%S")

Terminate the process

python
for name, process in port_forward_processes.items():
    process.terminate()
    print(f"Stopped port forwarding for {name}")

Next: Uninstall the Operator and all Feast objects