Skip to content

Add Kbs events - #360

Open
yairpod wants to merge 4 commits into
trusted-execution-clusters:mainfrom
yairpod:kbs_events
Open

Add Kbs events#360
yairpod wants to merge 4 commits into
trusted-execution-clusters:mainfrom
yairpod:kbs_events

Conversation

@yairpod

@yairpod yairpod commented Sep 6, 2026

Copy link
Copy Markdown
Member

Adding kubernetes events to KBS by creating an Event Proxy that will monitor the KBS and emit events as needed.

Summary by Sourcery

Add a KBS event proxy that surfaces attestation activity as Kubernetes events while integrating its binary, image, deployment, documentation, and end-to-end verification into the operator.

New Features:

  • Add a KBS event proxy that forwards RCAR traffic and emits Kubernetes events for attestation outcomes and resource access decisions.
  • Deploy the proxy alongside KBS and expose its configurable image through generated operator manifests.

Enhancements:

  • Centralize Kubernetes event recording and resource reflector utilities in the shared library.
  • Update KBS networking and TLS configuration so external traffic is handled by the proxy while KBS remains internal to the pod.

Build:

  • Add the kbs-event-proxy crate and container image build, release, and push targets.

Deployment:

  • Include the event proxy sidecar, image configuration, service-account usage, and related deployment settings in Trustee resources.

Documentation:

  • Document the event proxy architecture, RCAR event behavior, deployment, TLS, RBAC, and verification procedures.

Tests:

  • Add end-to-end coverage verifying successful attestation emits an AttestationSucceeded event on the Machine resource.

Chores:

  • Add development-container configuration and licensing coverage for the new files.

@yairpod
yairpod requested a review from Jakob-Naucke September 6, 2026 06:49
@openshift-ci

openshift-ci Bot commented Sep 6, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: yairpod

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

@sourcery-ai

sourcery-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR adds a TLS-capable KBS reverse-proxy sidecar that inspects RCAR authentication, attestation, and resource responses, correlates sessions, and records Kubernetes events. It integrates the proxy into Trustee pod generation, image resolution, RBAC/runtime configuration, build and release automation, documentation, and end-to-end testing.

Sequence diagram for RCAR attestation event recording

sequenceDiagram
    participant Node
    participant Proxy as KBS Event Proxy
    participant KBS
    participant Kubernetes

    Node->>Proxy: POST /kbs/v0/auth
    Proxy->>KBS: Forward auth request
    KBS-->>Proxy: 200 + kbs-session-id
    Proxy->>Proxy: Store session tee_type
    Proxy-->>Node: Return auth response

    Node->>Proxy: POST /kbs/v0/attest
    Proxy->>KBS: Forward attest request
    KBS-->>Proxy: Attestation response
    alt non-200 response
        Proxy->>Kubernetes: record_event AttestationFailed on TrustedExecutionCluster
    end
    Proxy-->>Node: Return attest response

    Node->>Proxy: GET /kbs/v0/resource/default/{machine_id}/root
    Proxy->>KBS: Forward resource request
    KBS-->>Proxy: Resource response
    Proxy->>Kubernetes: lookup_machine_ref
    alt 200 response
        Proxy->>Kubernetes: record_event AttestationSucceeded on Machine
    else 401 response
        Proxy->>Kubernetes: record_event AttestationFailed on Machine
    else 403 response
        Proxy->>Kubernetes: record_event ResourcePolicyDenied on Machine
    end
    Proxy-->>Node: Return resource response
Loading

File-Level Changes

Change Details Files
Introduces a Kubernetes-aware reverse proxy that forwards KBS traffic, tracks RCAR sessions, and emits attestation-related events.
  • Adds TLS-capable HTTP forwarding to an internal KBS endpoint.
  • Correlates auth sessions and classifies attest/resource responses.
  • Records success, failure, and policy-denial events against Machine or TrustedExecutionCluster resources.
  • Adds Kubernetes object lookups, session expiry, request limits, and configurable runtime arguments.
kbs-event-proxy/Cargo.toml
kbs-event-proxy/src/main.rs
docs/design/kbs-event-proxy.md
Deploys the proxy as a KBS sidecar and moves externally exposed KBS traffic through it.
  • Binds KBS to localhost port 8081 and exposes the proxy on port 8080.
  • Shares KBS TLS volumes with the proxy and configures proxy-to-KBS forwarding.
  • Adds the operator ServiceAccount and downward-API pod-name environment variable.
  • Passes the proxy image through operator configuration and related-image resolution.
operator/src/trustee.rs
operator/src/main.rs
lib/src/endpoints.rs
lib/src/images.rs
api/trusted-cluster-gen.go
test_utils/src/lib.rs
Integrates the new proxy binary into workspace builds, container publishing, and generated deployment manifests.
  • Adds the crate to the Cargo workspace and unified Containerfile build/output stages.
  • Adds image build, push, and manifest-generation targets.
  • Documents the component in the README and architecture design.
Cargo.toml
Containerfile
Makefile
README.md
docs/design/operator-architecture.md
Adds end-to-end coverage for successful attestation event emission.
  • Runs a virtual attestation flow and waits for AttestationSucceeded on the corresponding Machine.
  • Updates KBS deployment test call sites for the proxy image argument.
tests/attestation.rs
operator/src/trustee.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="kbs-event-proxy/src/main.rs" line_range="209" />
<code_context>
+    };
+    record_event(
+        &state.recorder,
+        &machine_ref,
+        event_type,
+        reason,
</code_context>
<issue_to_address>
**🚨 issue (security):** The proxy attempts to publish `events.k8s.io` events, but the diff adds no `events.k8s.io` permissions to the operator ClusterRole. Kubernetes denies these publishes with RBAC `forbidden` errors, so none of the new events are created.

**Triggers:** When the generated operator RBAC manifests are applied without an independently added events rule.

**Suggested fix:** Add `events.k8s.io` permissions for `events` with at least `create` and `patch` to the ClusterRole used by `trusted-cluster-operator`, and regenerate the bundled manifests.
</issue_to_address>

### Comment 2
<location path="tests/attestation.rs" line_range="364-372" />
<code_context>
+    assert!(has_encrypted_root, "VM {ENCRYPTED_ROOT_ASSERT}");
+    test_ctx.info("Attestation successful, verifying KBS proxy events");
+
+    let machines: Api<Machine> = Api::namespaced(client.clone(), namespace);
+    let machine_list = machines.list(&Default::default()).await?;
+    let machine_name = machine_list.items.first()
+        .expect("No Machine found in namespace")
+        .metadata
+        .name
+        .as_ref()
+        .expect("Machine should have a name");
+
+    wait_for_event(client, namespace, machine_name, "AttestationSucceeded", scaled_timeout(60)).await?;
+    test_ctx.info("Event AttestationSucceeded verified on Machine");
</code_context>
<issue_to_address>
**issue (testing):** The test selects the first Machine returned by an unordered namespace-wide list instead of the Machine created for `vm_name`. With more than one Machine, it waits for `AttestationSucceeded` on the wrong resource and fails or validates an unrelated event.

**Triggers:** When the test namespace already contains another Machine or the API returns a different item first.

**Suggested fix:** Derive the expected Machine name from `att_ctx`/`vm_name`, or filter the list by the VM identity before waiting for the event.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and this changes the KBS trust boundary and routes all attestation and secret-release traffic through a new TLS-terminating proxy, so a proxy or deployment mistake could affect every attestation or expose/release secrets. Reverting restores the old routing, but requests handled incorrectly while the proxy is live and any resulting access or disclosures cannot be undone.

Blocking findings: kbs-event-proxy/src/main.rs:209, tests/attestation.rs:372


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread kbs-event-proxy/src/main.rs
Comment thread tests/attestation.rs
Comment on lines +364 to +372
let machines: Api<Machine> = Api::namespaced(client.clone(), namespace);
let machine_list = machines.list(&Default::default()).await?;
let machine_name = machine_list.items.first()
.expect("No Machine found in namespace")
.metadata
.name
.as_ref()
.expect("Machine should have a name");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (testing): The test selects the first Machine returned by an unordered namespace-wide list instead of the Machine created for vm_name. With more than one Machine, it waits for AttestationSucceeded on the wrong resource and fails or validates an unrelated event.

Triggers: When the test namespace already contains another Machine or the API returns a different item first.

Suggested fix: Derive the expected Machine name from att_ctx/vm_name, or filter the list by the VM identity before waiting for the event.

@yairpod
yairpod force-pushed the kbs_events branch 2 times, most recently from 02abcc9 to 0c648ab Compare September 6, 2026 07:54
@yairpod

yairpod commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

/test azure-integration-test

1 similar comment
@yairpod

yairpod commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

/test azure-integration-test

@yairpod
yairpod requested a review from alicefr September 7, 2026 09:01
| `AttestationFailed` | Warning | Machine | Resource endpoint returns 401 for `default/{machine-id}/root` |
| `ResourcePolicyDenied` | Warning | Machine | Resource endpoint returns 403 for `default/{machine-id}/root` |

The proxy emits `AttestationFailed` on the TrustedExecutionCluster (not on a Machine) at the attest step because the RCAR protocol does not carry a machine identifier at that point. The session carries only the TEE type.

@alicefr alicefr Sep 7, 2026

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.

Right now we don't have it yet, but in the future the uuid of the machine should be provided as initdata as part of the attestation. In this way, it should be possible to extrapolate which machine failed the attestation

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

So we can create a ticket to continue this work when the uuid is provided.

Comment thread docs/design/kbs-event-proxy.md Outdated
Comment on lines +85 to +87
### Container image

The proxy binary is built in the unified `Containerfile` alongside the other operator components. It uses its own distribution stage based on `fedora:43` and exposes port 8080.

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.

nit: Is this really necessary?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I can remove this section

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed

Comment thread docs/design/kbs-event-proxy.md
Comment thread kbs-event-proxy/src/main.rs Outdated
}

fn machine_id_from_path(path: &str) -> Option<&str> {
let stripped = path.strip_prefix("/kbs/v0/resource/default/")?;

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.

can we use a constant here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You mean instead of the API path? sure

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.

Yes, moving this to a constant

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Comment thread kbs-event-proxy/src/main.rs Outdated
Comment on lines +111 to +112
let machines: Api<Machine> = Api::default_namespaced(client.clone());
let machine_name = format!("machine-{machine_id}");

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.

Any chance to use the cache and store here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moved to Store

Comment thread kbs-event-proxy/src/main.rs Outdated
Comment on lines +305 to +311
if path == "/kbs/v0/auth" && backend.status == StatusCode::OK {
handle_auth_response(&state, &body_bytes, &backend.headers).await;
} else if path == "/kbs/v0/attest" {
handle_attest_response(&state, &req_headers, backend.status).await;
} else if path.starts_with("/kbs/v0/resource/default/") {
handle_resource_response(&state, &path, backend.status).await;
}

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.

Can we use some constant for the path here as well

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed

Comment thread tests/attestation.rs
}
}

virt_test! {

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.

Instead of adding a new test can we simply extend an existing one

@alicefr

alicefr commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

@yairpod thanks for this work! It is already a huge step forward. What I'm a bit afraid is for the failed attestation, that we are firing an event without the possibility of saying at which machine it was corresponding.

iroykaufman and others added 2 commits September 7, 2026 16:52
Signed-off-by: Roy Kaufman <rkaufman@redhat.com>
Move new_recorder, spawn_reflector, and sync_cache from the operator
crate to trusted-cluster-operator-lib so kbs-event-proxy can use them
without duplicating code.

Signed-off-by: Yair Podemsky <ypodemsk@redhat.com>
Assisted-by: AI
Add a reverse proxy sidecar container to the KBS pod that observes
RCAR attestation HTTP traffic and emits Kubernetes events for
attestation activity.

The proxy sits between the Service and KBS, inspecting request/response
pairs to emit AttestationSucceeded (per Machine), AttestationFailed
(on TrustedExecutionCluster), and ResourcePolicyDenied (per Machine)
events. Session cookies correlate auth, attest, and resource steps.

- New crate: kbs-event-proxy (axum-based reverse proxy)
- KBS binds to 127.0.0.1:8081, proxy serves on 0.0.0.0:8080
- TLS on both hops when a certificate is configured
- KBS pod uses trusted-cluster-operator ServiceAccount
- Add events.k8s.io RBAC to ClusterRole
- Add kbs-event-proxy to unified Containerfile build

Signed-off-by: Yair Podemsky <ypodemsk@redhat.com>
Assisted-by: AI
Verify that the kbs-event-proxy sidecar emits an AttestationSucceeded
event on the Machine after a successful attestation and key release.

Signed-off-by: Yair Podemsky <ypodemsk@redhat.com>
Assisted-by: AI
@openshift-ci

openshift-ci Bot commented Sep 7, 2026

Copy link
Copy Markdown

@yairpod: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/azure-integration-test 1b43842 link false /test azure-integration-test

Full PR test history. Your PR dashboard.

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. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants