Skip to content

Commit 8452830

Browse files
razvanclaude
andcommitted
refactor(openlineage): use credentialsSecretName instead of AuthenticationClass
Follows the operator-rs change: read the OpenLineage backend bearer token from the connection's `credentialsSecretName` Secret (key `apiKey`) instead of resolving a Static AuthenticationClass. See stackabletech/decisions#90 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6f6212d commit 8452830

10 files changed

Lines changed: 47 additions & 152 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ All notable changes to this project will be documented in this file.
1616
`event-listener.properties` pointing at the backend `host`/`port`, with the cluster's `trino.uri`
1717
and namespace). The backend connection is inlined or references an `OpenLineageConnection`
1818
resource. TLS server verification against a `secretClass` CA is imported into the coordinator
19-
truststore, and a bearer token from a Static `AuthenticationClass` is injected at startup without
20-
landing in the ConfigMap ([#914]).
19+
truststore, and a bearer token from the connection's `credentialsSecretName` Secret is injected at
20+
startup without landing in the ConfigMap ([#914]).
2121

2222
### Changed
2323

Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.nix

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/modules/trino/pages/usage-guide/openlineage.adoc

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ IMPORTANT: With TLS server verification, the `host` must match a Subject Alterna
7171
== Authentication
7272

7373
Backends that require authentication (for example DataHub, or a Marquez instance behind a gateway) expect a bearer token on each request.
74-
Configure this by referencing an xref:concepts:authentication.adoc[`AuthenticationClass`] from the connection via `authenticationClassRef`:
74+
Configure this by setting `credentialsSecretName` on the connection to the name of a Secret holding the token:
7575

7676
[source,yaml]
7777
----
@@ -86,32 +86,20 @@ spec:
8686
inline:
8787
host: marquez
8888
port: 5000
89-
authenticationClassRef: openlineage-auth # <1>
89+
credentialsSecretName: openlineage-token # <1>
9090
...
9191
---
92-
apiVersion: authentication.stackable.tech/v1alpha1
93-
kind: AuthenticationClass
94-
metadata:
95-
name: openlineage-auth
96-
spec:
97-
provider:
98-
static: # <2>
99-
userCredentialsSecret:
100-
name: openlineage-token # <3>
101-
---
10292
apiVersion: v1
10393
kind: Secret
10494
metadata:
10595
name: openlineage-token
106-
namespace: default # <4>
96+
namespace: default # <2>
10797
stringData:
108-
apiKey: "s3cr3t-bearer-token" # <5>
98+
apiKey: "s3cr3t-bearer-token" # <3>
10999
----
110-
<1> References an `AuthenticationClass` by name (cluster-scoped). If omitted, no authentication is used.
111-
<2> Only the `static` provider is supported for OpenLineage. Other providers (LDAP, OIDC, TLS) are rejected with an error.
112-
<3> Name of the Secret holding the token. Must exist in the same namespace as the `TrinoCluster`.
113-
<4> The Secret must be in the cluster's namespace so it can be projected into the coordinator.
114-
<5> The token must be stored under the fixed key `apiKey`. The token is mounted as a file into the coordinator and resolved into the event listener configuration at startup, so it never appears in the ConfigMap or the pod's environment.
100+
<1> Name of the Secret holding the token. If omitted, no authentication is used. The Secret must exist in the same namespace as the `TrinoCluster`.
101+
<2> The Secret must be in the cluster's namespace so it can be projected into the coordinator.
102+
<3> The token must be stored under the fixed key `apiKey`. The token is mounted as a file into the coordinator and resolved into the event listener configuration at startup, so it never appears in the ConfigMap or the pod's environment.
115103

116104
The operator translates this into the OpenLineage HTTP transport's `api-key` (bearer) authentication.
117105
Combine it with the `tls` block above when the backend also needs TLS server verification.

extra/crds.yaml

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -922,12 +922,11 @@ spec:
922922
OpenLineage connection definition as a resource.
923923
Learn more about [OpenLineage](https://openlineage.io/).
924924
properties:
925-
authenticationClassRef:
925+
credentialsSecretName:
926926
description: |-
927-
Name of an [`AuthenticationClass`](https://docs.stackable.tech/home/nightly/concepts/authentication) used
928-
to authenticate against the OpenLineage backend. The `AuthenticationClass` is cluster-scoped
929-
and referenced by name; it is resolved at runtime via
930-
[`OpenLineageConnectionSpec::resolve_authentication_class`]. If not specified, no
927+
Name of a Secret containing the API key used to authenticate against the OpenLineage
928+
backend. The API key must be stored under the key `apiKey`. The Secret must be located in
929+
the same namespace as the workload using this connection. If not specified, no
931930
authentication is used.
932931
nullable: true
933932
type: string
@@ -4455,12 +4454,11 @@ spec:
44554454
OpenLineage connection definition as a resource.
44564455
Learn more about [OpenLineage](https://openlineage.io/).
44574456
properties:
4458-
authenticationClassRef:
4457+
credentialsSecretName:
44594458
description: |-
4460-
Name of an [`AuthenticationClass`](https://docs.stackable.tech/home/nightly/concepts/authentication) used
4461-
to authenticate against the OpenLineage backend. The `AuthenticationClass` is cluster-scoped
4462-
and referenced by name; it is resolved at runtime via
4463-
[`OpenLineageConnectionSpec::resolve_authentication_class`]. If not specified, no
4459+
Name of a Secret containing the API key used to authenticate against the OpenLineage
4460+
backend. The API key must be stored under the key `apiKey`. The Secret must be located in
4461+
the same namespace as the workload using this connection. If not specified, no
44644462
authentication is used.
44654463
nullable: true
44664464
type: string

rust/operator-binary/src/config/open_lineage.rs

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ use stackable_operator::{
2222
commons::tls_verification::{
2323
CaCert, TlsClientDetails, TlsClientDetailsError, TlsServerVerification, TlsVerification,
2424
},
25-
crd::{
26-
authentication::core::v1alpha1::{AuthenticationClass, AuthenticationClassProvider},
27-
openlineage::{self, v1alpha1::OpenLineageJob},
28-
},
25+
crd::openlineage::{self, v1alpha1::OpenLineageJob},
2926
k8s_openapi::api::core::v1::{SecretVolumeSource, Volume, VolumeMount},
3027
};
3128

@@ -76,16 +73,6 @@ pub enum Error {
7673
source: openlineage::v1alpha1::OpenLineageError,
7774
},
7875

79-
#[snafu(display("failed to resolve the OpenLineage AuthenticationClass"))]
80-
ResolveAuthenticationClass {
81-
source: openlineage::v1alpha1::OpenLineageError,
82-
},
83-
84-
#[snafu(display(
85-
"unsupported AuthenticationClass provider {provider:?} for OpenLineage; only the Static provider is supported"
86-
))]
87-
UnsupportedAuthenticationProvider { provider: String },
88-
8976
#[snafu(display(
9077
"failed to build volumes and mounts for the OpenLineage backend TLS CA certificate"
9178
))]
@@ -172,21 +159,14 @@ impl ResolvedOpenLineageConfig {
172159
init_container_extra_start_commands
173160
.extend(openlineage_tls_truststore_commands(&connection.tls));
174161

175-
// Authentication: resolve the connection's `authenticationClassRef` (Static provider only)
176-
// into its credentials Secret, mount it and reference the token via a `${file:...}`
177-
// placeholder so it is resolved at startup and never lands in the ConfigMap.
178-
if let Some(auth_class) = connection
179-
.resolve_authentication_class(client)
180-
.await
181-
.context(ResolveAuthenticationClassSnafu)?
182-
{
183-
let secret_name = openlineage_auth_secret_name(&auth_class)
184-
.map_err(|provider| UnsupportedAuthenticationProviderSnafu { provider }.build())?;
185-
162+
// Authentication: when the connection sets `credentialsSecretName`, mount that Secret and
163+
// reference the token via a `${file:...}` placeholder so it is resolved at startup and never
164+
// lands in the ConfigMap. The token must be stored under the `apiKey` Secret key.
165+
if let Some(secret_name) = &connection.credentials_secret_name {
186166
volumes.push(Volume {
187167
name: OPENLINEAGE_AUTH_VOLUME_NAME.to_string(),
188168
secret: Some(SecretVolumeSource {
189-
secret_name: Some(secret_name),
169+
secret_name: Some(secret_name.clone()),
190170
..SecretVolumeSource::default()
191171
}),
192172
..Volume::default()
@@ -214,22 +194,6 @@ impl ResolvedOpenLineageConfig {
214194
}
215195
}
216196

217-
/// Extracts the credentials Secret name from a resolved OpenLineage [`AuthenticationClass`].
218-
///
219-
/// Only the `Static` provider is supported (its Secret holds the bearer token under
220-
/// [`OPENLINEAGE_AUTH_SECRET_KEY`]). Any other provider returns `Err(provider_name)` so the caller
221-
/// can surface a clear error naming the offending provider.
222-
pub(crate) fn openlineage_auth_secret_name(
223-
auth_class: &AuthenticationClass,
224-
) -> Result<String, String> {
225-
match &auth_class.spec.provider {
226-
AuthenticationClassProvider::Static(provider) => {
227-
Ok(provider.user_credentials_secret.name.clone())
228-
}
229-
other => Err(other.to_string()),
230-
}
231-
}
232-
233197
/// Init-container commands that add the backend's `SecretClass` CA certificate to the client
234198
/// truststore (which is the JVM default truststore, see `config::jvm`). Returns an empty list when
235199
/// no import is needed: no TLS, `verification.none` (plain `http`), or WebPKI verification (trusted
@@ -248,54 +212,10 @@ fn openlineage_tls_truststore_commands(tls: &TlsClientDetails) -> Vec<String> {
248212

249213
#[cfg(test)]
250214
mod tests {
251-
use stackable_operator::{
252-
commons::tls_verification::Tls,
253-
crd::authentication::{
254-
core::v1alpha1::{
255-
AuthenticationClass, AuthenticationClassProvider, AuthenticationClassSpec,
256-
},
257-
r#static, tls,
258-
},
259-
k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta,
260-
};
215+
use stackable_operator::commons::tls_verification::Tls;
261216

262217
use super::*;
263218

264-
fn auth_class(provider: AuthenticationClassProvider) -> AuthenticationClass {
265-
AuthenticationClass {
266-
metadata: ObjectMeta::default(),
267-
spec: AuthenticationClassSpec { provider },
268-
}
269-
}
270-
271-
#[test]
272-
fn secret_name_extracted_from_static_provider() {
273-
let ac = auth_class(AuthenticationClassProvider::Static(
274-
r#static::v1alpha1::AuthenticationProvider {
275-
user_credentials_secret: r#static::v1alpha1::UserCredentialsSecretRef {
276-
name: "ol-token".to_string(),
277-
},
278-
},
279-
));
280-
281-
assert_eq!(openlineage_auth_secret_name(&ac).unwrap(), "ol-token");
282-
}
283-
284-
#[test]
285-
fn non_static_provider_is_rejected_naming_the_provider() {
286-
let ac = auth_class(AuthenticationClassProvider::Tls(
287-
tls::v1alpha1::AuthenticationProvider {
288-
client_cert_secret_class: None,
289-
},
290-
));
291-
292-
let err = openlineage_auth_secret_name(&ac).unwrap_err();
293-
assert!(
294-
err.to_lowercase().contains("tls"),
295-
"error should name the offending provider, got: {err}"
296-
);
297-
}
298-
299219
fn tls_details(verification: Option<TlsVerification>) -> TlsClientDetails {
300220
TlsClientDetails {
301221
tls: verification.map(|verification| Tls { verification }),

0 commit comments

Comments
 (0)