Skip to content

Add KEP: ephemeral resources - #15

Draft
nfarhadian wants to merge 2 commits into
kcp-dev:mainfrom
nfarhadian:ephemeral-resources
Draft

Add KEP: ephemeral resources#15
nfarhadian wants to merge 2 commits into
kcp-dev:mainfrom
nfarhadian:ephemeral-resources

Conversation

@nfarhadian

Copy link
Copy Markdown

Proposes non-persisted resources served through kcp: an APIResourceSchema may declare spec.ephemeral, and the exposing APIExport nominates a webhook that answers create requests synchronously. Nothing reaches etcd.

Covers the webhook contract (EphemeralReview), the cross-shard constraint that rules out provider-supplied client certificates, why get cannot be served, and permission-claim handling.

Proposes non-persisted resources served through kcp: an APIResourceSchema
may declare spec.ephemeral, and the exposing APIExport nominates a webhook
that answers create requests synchronously. Nothing reaches etcd.

Covers the webhook contract (EphemeralReview), the cross-shard constraint
that rules out provider-supplied client certificates, why get cannot be
served, and permission-claim handling.

Signed-off-by: Naeem Farhadian <n.f.azizi@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@kcp-ci-bot kcp-ci-bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. dco-signoff: yes Indicates the PR's author has signed the DCO. labels Jul 29, 2026
@kcp-ci-bot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign xrstf for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kcp-ci-bot kcp-ci-bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Jul 29, 2026
@kcp-ci-bot

Copy link
Copy Markdown
Contributor

Hi @nfarhadian. Thanks for your PR.

I'm waiting for a kcp-dev member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kcp-ci-bot kcp-ci-bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jul 29, 2026

@mjudeikis mjudeikis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Few comments. I think API shape could be slightly different and it would simplify this a lot

name: s3.example.com
spec:
resources:
- name: bucketinfos

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I read this and thinking outloud:

// ResourceSchemaStorage defines how the resource is stored.
//
// +kubebuilder:validation:XValidation:rule="has(self.crd) != has(self.virtual)",message="Exactly one of crd or virtual must be set"
type ResourceSchemaStorage struct {
	// CRD storage defines that this APIResourceSchema is exposed as
	// CustomResourceDefinitions inside the workspaces that bind to the APIExport.
	// Like in vanilla Kubernetes, users can then create, update and delete
	// custom resources.
	//
	// +optional
	CRD *ResourceSchemaStorageCRD `json:"crd,omitempty"`

	// Virtual storage defines that this APIResourceSchema is exposed as
	// a projection of the referenced resource inside the workspaces that
	// bind to the APIExport.
	//
	// +optional
	Virtual *ResourceSchemaStorageVirtual `json:"virtual,omitempty"`
}

we have this on the ResourceSchema storage. I think if we add one more Storage type "Ephemeral" into this with config to webhook, this plays very neat. Schema dont need even to be special (no Ephemeral{} hook/marker).

If APIExport find this storage type - it does what needs to be done?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That's such a good idea, I will change it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I changed it

Comment thread keps/core/0006-ephemeral-resources.md Outdated
- name: bucketinfos
group: s3.example.com
schema: v1alpha1.bucketinfos.s3.example.com
ephemeralEndpoints:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This akk would go into ResourceSchemaStorage

Comment thread keps/core/0006-ephemeral-resources.md Outdated
Comment on lines +186 to +206
kcp does not replicate Secrets or ConfigMaps between shards, and this is deliberate.
`pkg/reconciler/cache/replication/replication_controller.go` enumerates exactly what the
cache server carries: `apiexports`, `apiresourceschemas`, `apiconversions`, webhook
configurations, `shards`, `logicalclusters`, `clusterroles`, all of it public API
metadata. `secrets` and `configmaps` appear nowhere in that list.

This has a direct consequence for any credential referenced from an APIExport. A logical
cluster lives on one shard, so a Secret in the provider's workspace exists only on the
shard hosting that workspace. But an ephemeral request arrives at the shard hosting the
**consumer's** workspace, which is generally a different one. That shard cannot read the
provider's Secret.

kcp already has the answer to this, in the identity mechanism: the APIExport controller
reads the identity Secret *locally*, on the shard that hosts the export, and publishes the
derived `status.identityHash`. The APIExport, status included, replicates. The secret
never crosses a shard boundary; a non-secret value derived from it does.

The same pattern applies to the CA bundle. `caBundleRef` is resolved on the provider's
shard and materialized into `status.ephemeralEndpoints[].caBundle`, which replicates
everywhere. A CA bundle is public by nature, so publishing it in status is safe. Providers
keep the CA-injector-friendly ConfigMap; every shard gets the bytes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This feels bit all around the place. Can you simlify, what this section trying to explain?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It is about why provider cannot simply give it's own client certificate to KCP using secret. I will change it.

uid: <request uid>
cluster: <logical cluster name>
resource: {group: s3.example.com, version: v1alpha1, resource: bucketinfos}
namespace: team-a

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we need dryRun too to give signal for side effects...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It's a good idea, but if it's "Ephemeral" nothing risky should be done with this...

My use cases for this type of resource is getting information, not doing something with it
For example:

  • Bucket Info
  • Get usage with custom time range
  • Get list of accessible resources

Comment thread keps/core/0006-ephemeral-resources.md Outdated
name: s3-info-ca
key: ca.crt
timeoutSeconds: 10
failurePolicy: Fail

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this needs more thinking. like FailurePolicy: ignore - what does it give?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I was thinking returning 503 is ambiguous sometimes, because kcp is working but the webhook is not working. We have similar dynamic in kubernetes when operator is not working, no status means there isn't any response from operator.
But you are right, probably no one uses this, it adds complexity

@xrstf

xrstf commented Jul 29, 2026

Copy link
Copy Markdown

Tbh I don't like this approach at all. It strongly feels like re-inventing what VWs are already there for.

a client that bound the APIExport expects the resource in its own workspace, not at a separate VW URL. Since the same REST storage serves both, restricting to VWs buys nothing and costs the primary use case.

Reading URLs and connecting to other endpoints is a common thing in kcp, like in APIExportEndpointSlices.

The comparison with Kubernetes' built-in ephemeral resources is lacking, since those resources are served by Kubernetes internally. It doesn't have to call out to the wider internet to answer these. This feature here however would by design turn the kcp server into a synchronous proxy to random, potentially slow and failing backends, purely for a bit of perceived convenience, since every request to an ephemeral thing has to be forwarded.

@mjudeikis

Copy link
Copy Markdown
Contributor

But you have to admit, this is useful feature. If somebody abuses it, it's their fault. Same as ValidationAdmissionWebhook is useful in kube but if abused its painful.

Signed-off-by: Naeem Farhadian <n.f.azizi@gmail.com>
@gman0

gman0 commented Jul 30, 2026

Copy link
Copy Markdown

We have virtual resources (storage: virtual), where you can project ANY virtual workspace resources into ws?

@nfarhadian

Copy link
Copy Markdown
Author

@gman0 You mean I create a workspace mount and set URL to my webhook and my webhook answers like kubernetes API. then I create an APIExport with storage: virtual
Am I getting your point right?

@gman0

gman0 commented Jul 30, 2026

Copy link
Copy Markdown

We could have a webhook virtual workspace & an endpoint slice for it, and that's it basically. You could check out the Replication VW as an example.

@ntnn

ntnn commented Jul 30, 2026

Copy link
Copy Markdown
Member

We could have a webhook virtual workspace & an endpoint slice for it, and that's it basically. You could check out the Replication VW as an example.

I like the idea of APIWebhoookExport or similar that results in an APIExportES and then reference that with type:virtual.

@xrstf

xrstf commented Jul 30, 2026

Copy link
Copy Markdown

But you have to admit, this is useful feature.

I'm not denying that it sounds useful. But if that was the only metric we go by, we'd had cluster inheritance in kcp ;-)

What irks me is that I have bad feelings about turning kcp into an open HTTPS relay. How would we make sure this is not abused to DoS a shard by causing excessive, slow, large requests? Did we remember to forbid local/cluster-internal access to exfiltrate data from random pods?

If we want to configure an external backend, then that external backend is in fact already a virtual workspace, even if it's called a "webhook". And for proxying to virtual workspaces we generally use the front-proxy, not the shards directly. Ideally this feature makes the mapping known to the front-proxy, which can then react and proxy accordingly, instead of having the shards do it.

We wanted to move away from webhooks if possible (in general in the Kube world, see CEL), but this is adding more webhooks for the primary reason of "user convenience".

@ntnn

ntnn commented Jul 30, 2026

Copy link
Copy Markdown
Member

What irks me is that I have bad feelings about turning kcp into an open HTTPS relay. How would we make sure this is not abused to DoS a shard by causing excessive, slow, large requests? Did we remember to forbid local/cluster-internal access to exfiltrate data from random pods?

Open implies that it goes to any - here the API owner has to specify the address and it can only go to said address.

And for proxying to virtual workspaces we generally use the front-proxy, not the shards directly.

Well, the shards have their own VW and the front-proxy mounts singleton/global virtual workspaces (or any http tbh).

Ideally this feature makes the mapping known to the front-proxy, which can then react and proxy accordingly, instead of having the shards do it.

This feature must exist in the virtual-workspaces because it's per APIExport; the front-proxy cannot route vw requests correctly.

We wanted to move away from webhooks if possible (in general in the Kube world, see CEL), but this is adding more webhooks for the primary reason of "user convenience".

I agree; I'd also prefer a simpler solution. As mentioned in the CC I'd prefer something that resembles KRO, but I think that will be hard to implement right, harder to use and make some use cases not possible.

Playing devils advocate - I wonder how much of ephemeral resources could already be implemented using mutating webhooks; it'd basically be the same just that the resource is persisted (and has the be created, then read and then deleted).

@mjudeikis

mjudeikis commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

I like the idea of APIWebhoookExport or similar that results in an APIExportES and then reference that with type:virtual.

This could work. We just need to hangle it right (allowed methods ,rbac, etc)

@xrstf

xrstf commented Jul 30, 2026

Copy link
Copy Markdown

Open implies that it goes to any - here the API owner has to specify the address and it can only go to said address.

Yes, but in an open platform, "API owner" is any random service provider. ;) Can this be restricted with RBAC, that someone can create an APIExport but not use webhook-based resources?

@ntnn

ntnn commented Jul 30, 2026

Copy link
Copy Markdown
Member

Yes, but in an open platform, "API owner" is any random service provider. ;) Can this be restricted with RBAC, that someone can create an APIExport but not use webhook-based resources?

Ah :D Yes, it must be gated behind a feature flag and additional authz so not just anyone can create APIExportWebhooks.
We could do it similar to logical cluster migrations and have feature-gate + separate APIExport must be bound.

@mjudeikis

Copy link
Copy Markdown
Contributor

We could have a webhook virtual workspace & an endpoint slice for it, and that's it basically. You could check out the Replication VW as an example.

so current limitation is that we dont replicate arbitrary APIExportEndpoint slices to cache servers. So resolution does not quite work. And if we try to piggyback on an existing object, it gets reconciled by default controllers.

Im checking code what needs to change, but building on VirtualResources flow is complicated/does-not-yet-works if you want BYO xEndpointSlice

mjudeikis added a commit to kcp-dev/contrib-virtual-ephemeral-resources-virtual-workspace that referenced this pull request Aug 4, 2026
Serves non-persisted, webhook-backed resources for kcp APIExports. A create
is answered synchronously by the provider's webhook and returned to the
client; nothing reaches etcd. Only the create verb is served.

Implements the counter-proposal from kcp-dev/enhancements#15: instead of a
new storage variant on APIExport with shards calling webhooks, this rides
the existing storage: virtual path by referencing an APIExportEndpointSlice.
That needs no kcp changes at all -- the reference kind is already replicated,
the URL kcp writes carries the prefix shards require, and discovery verbs are
derived from the storage's interface set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants