Greetings @hgm251 , here are some things to consider.
Things are working as designed: when you create a new Feature Serving or Model Serving endpoint, Databricks automatically provisions a dedicated service principal for that endpoint, and a fresh one is created whenever the endpoint itself is re-created. The service principal’s lifetime matches the endpoint’s lifetime. This is used so the endpoint can access online/synced tables independently of the user who created it and keep working even if that user leaves or loses access. This behavior also applied to the legacy “online tables” (now superseded by Lakebase synced tables), and the permission model carries over for endpoints serving features backed by these tables.
What’s happening and why
- A service principal is auto-created per endpoint at provision time—feature spec creation does not create a service principal; the endpoint creation does. If your automation deletes and re-creates the endpoint on each run, you’ll see a new service principal every time.
-
The FeatureSpec should reference the source Delta table in UC, not the online/synced table. At inference, the endpoint routes lookups through the associated online/synced table for low-latency access automatically.
-
You’ll see audit entries showing the platform granting the minimal permissions that endpoint’s service principal needs to query the online/synced table; that’s expected.
Common pitfall in the snippet
Your try/except pattern deletes and re-creates the FeatureSpec when it “already exists.” While that’s fine for FeatureSpecs, many teams use a similar pattern for the endpoint and end up re-creating it too, which triggers creation of a new service principal each run. A safer pattern is to leave the existing FeatureSpec in place and only update it when needed, and reuse the existing endpoint instead of deleting it.
Checks for Lakebase synced tables migration
- Keep the FeatureLookup table_name pointing to the source UC Delta table. Do not point it to the synced table; the endpoint automatically uses the synced/online table for low-latency lookups.
-
Ensure endpoint creator has needed privileges/ownership: USE CATALOG, USE SCHEMA, SELECT on the source table, and ownership requirements when creating the endpoint that serves features from the online/synced table.
-
Expect the endpoint-scoped service principal creation and lifecycle to persist with synced tables; the online tables docs note the endpoint permission model and call out that a unique service principal is created and tied to endpoint lifetime.
Recommended changes
- Don’t delete/recreate the FeatureSpec on “already exists”; just pass. Example from docs:
python
try:
fe.create_feature_spec(name=feature_spec_name, features=features, exclude_columns=None)
except Exception as e:
if "already exists" in str(e):
pass
else:
raise e
- Reuse the endpoint instead of recreating it. For example, check for an existing endpoint and update its config rather than creating a new one: ```python from databricks.sdk import WorkspaceClient from databricks.sdk.service.serving import EndpointCoreConfigInput, ServedEntityInput
workspace = WorkspaceClient() endpoint_name = "my-features-endpoint"
# If it exists, update; otherwise create try: existing = workspace.serving_endpoints.get(name=endpoint_name) workspace.serving_endpoints.update_config_and_wait( name=endpoint_name, config=EndpointCoreConfigInput( served_entities=[ ServedEntityInput(entity_name=feature_spec_name, scale_to_zero_enabled=True, workload_size="Small") ] ) ) except Exception: workspace.serving_endpoints.create_and_wait( name=endpoint_name, config=EndpointCoreConfigInput( served_entities=[ ServedEntityInput(entity_name=feature_spec_name, scale_to_zero_enabled=True, workload_size="Small") ] ) ) ```
- Confirm your FeatureSpec references the source Delta table and not the synced table. Example patterns in docs show
FeatureLookup(table_name="<catalog>.<schema>.<source_table>", ...) and explicitly note the endpoint uses the online/synced copy automatically.
Bottom line You probably haven’t misconfigured synced tables
The new service principals are being created because the endpoint is being re-created. Reuse existing endpoints and avoid delete/recreate patterns to prevent new service principals from appearing each run. The FeatureSpec-only code you shared doesn’t by itself create service principals; it’s the endpoint step that does.
Hope this helps, Louis.