Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Kerberos authentication for Kafka #762

Merged
merged 58 commits into from
Nov 13, 2024
Merged
Changes from 50 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3710b4b
added enum for either vector of autentication classes or kerberos sec…
adwk67 Sep 11, 2024
b98c155
initial kerberos impl
adwk67 Sep 13, 2024
471403d
implement kerberos specifics
adwk67 Sep 13, 2024
d90564b
wip: integration test
adwk67 Sep 19, 2024
ab47e06
revert complex enum and use parallel struct (CRD decision pending)
adwk67 Sep 20, 2024
4a855c2
call shell explicitly for kerberos probe to allow variable substitution
adwk67 Sep 20, 2024
6048906
working test
adwk67 Sep 20, 2024
35183ea
revert class name change and formatting
adwk67 Sep 20, 2024
f2dd950
added validation
adwk67 Sep 20, 2024
e5724f0
Merge branch 'main' into feat/kafka-kerberos
adwk67 Sep 20, 2024
33b3ab9
linting
adwk67 Sep 20, 2024
6bcff94
more linting
adwk67 Sep 20, 2024
e43e4fb
refactor: add kerberos to list of authentication classes instead of d…
adwk67 Sep 27, 2024
61f17c0
changelog
adwk67 Sep 27, 2024
d0c9158
reverted operator-rs ref and corrected test
adwk67 Sep 30, 2024
d0ea277
fixed changes due to operator-rs to 0.78.0
adwk67 Sep 30, 2024
eb405a9
added docs/example
adwk67 Sep 30, 2024
ed07e4e
Merge branch 'main' into feat/kafka-kerberos
adwk67 Sep 30, 2024
259fa72
improved comments
adwk67 Sep 30, 2024
13fcdc2
fixed merge conflicts
adwk67 Oct 8, 2024
edd2286
Update rust/crd/src/authentication.rs
adwk67 Oct 8, 2024
89a88db
Update rust/crd/src/lib.rs
adwk67 Oct 8, 2024
fcf34b1
Update rust/operator-binary/src/kafka_controller.rs
adwk67 Oct 8, 2024
5633a52
Update rust/operator-binary/src/kafka_controller.rs
adwk67 Oct 8, 2024
fddcd8d
Merge branch 'feat/kafka-kerberos' of github.com:stackabletech/kafka-…
adwk67 Oct 8, 2024
c2f3be0
fixed review suggestions
adwk67 Oct 8, 2024
a88146c
formatting: new lines between enum elements
adwk67 Oct 8, 2024
c32b828
review suggestions
adwk67 Oct 8, 2024
ad7aee6
add use-client-tls dimension and cleanup test
adwk67 Oct 8, 2024
ef84d73
add constants for kerberos paths
adwk67 Oct 8, 2024
2e20d5a
test: Update kerberos tests to always use TLS
sbernauer Oct 8, 2024
ed0a7df
added check that TLS is enabled for Kerberos
adwk67 Oct 8, 2024
0ad749d
regenerate charts
adwk67 Oct 8, 2024
d0c333a
formatting
adwk67 Oct 8, 2024
8aeb270
corrected validation check
adwk67 Oct 8, 2024
602b891
Update rust/operator-binary/src/kerberos.rs
adwk67 Oct 9, 2024
0da29f4
use listener volume scope for kerberos volume and replace FQDN with l…
adwk67 Oct 9, 2024
de75567
Merge branch 'main' into feat/kafka-kerberos
adwk67 Oct 9, 2024
7be6257
added custom iamge usage from previous merge from main
adwk67 Oct 9, 2024
3aa923a
Update rust/crd/src/authentication.rs
adwk67 Oct 16, 2024
203b52d
remove unecessary test
adwk67 Oct 16, 2024
5b6b7de
removed unused Error
adwk67 Oct 16, 2024
ed30069
regenerate charts
adwk67 Oct 16, 2024
2d4feac
combine cases where internal tls is required
adwk67 Oct 16, 2024
cb8301d
working test with broker listeners instead of listener bootstrap
adwk67 Oct 23, 2024
40ea435
merge main and fix conflicts
adwk67 Oct 23, 2024
c852a1b
add listener for bootstrapper
adwk67 Nov 5, 2024
b8aa750
Merge branch 'main' into feat/kafka-kerberos
adwk67 Nov 5, 2024
57b7ffc
removed duplicate check
adwk67 Nov 5, 2024
344ddf7
add bootstrap configs for client_auth as well
adwk67 Nov 6, 2024
2131479
Merge branch 'main' into feat/kafka-kerberos
adwk67 Nov 7, 2024
109ad3c
use correct port in discovery for kerberos. Removed bootstrap changes…
adwk67 Nov 7, 2024
6ced9a5
use discovery in kerberos test
adwk67 Nov 7, 2024
7526455
Merge branch 'main' into feat/kafka-kerberos
adwk67 Nov 7, 2024
b6f3c60
added unit test for kerberos config
adwk67 Nov 7, 2024
c9336ed
added note about client connections and ports
adwk67 Nov 11, 2024
20fccb9
Update docs/modules/kafka/pages/usage-guide/security.adoc
adwk67 Nov 12, 2024
74f2cb8
clarified comment
adwk67 Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added

- Support version `3.8.0` ([#753]).
- Add support for Kerberos authentication ([#762]).
- The operator can now run on Kubernetes clusters using a non-default cluster domain.
Use the env var `KUBERNETES_CLUSTER_DOMAIN` or the operator Helm chart property `kubernetesClusterDomain` to set a non-default cluster domain ([#771]).

@@ -35,6 +36,7 @@ All notable changes to this project will be documented in this file.
[#741]: https://github.com/stackabletech/kafka-operator/pull/741
[#750]: https://github.com/stackabletech/kafka-operator/pull/750
[#753]: https://github.com/stackabletech/kafka-operator/pull/753
[#762]: https://github.com/stackabletech/kafka-operator/pull/762
[#771]: https://github.com/stackabletech/kafka-operator/pull/771
[#773]: https://github.com/stackabletech/kafka-operator/pull/773

4 changes: 4 additions & 0 deletions deploy/helm/kafka-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
@@ -565,6 +565,10 @@ spec:
Only affects client connections. This setting controls: - If clients need to authenticate themselves against the broker via TLS - Which ca.crt to use when validating the provided client certs
This will override the server TLS settings (if set) in `spec.clusterConfig.tls.serverSecretClass`.
## Kerberos provider
This affects client connections and also requires TLS for encryption. This setting is used to reference an `AuthenticationClass` and in turn, a `SecretClass` that is used to create keytabs.
type: string
required:
- authenticationClass
53 changes: 53 additions & 0 deletions docs/modules/kafka/pages/usage-guide/security.adoc
Original file line number Diff line number Diff line change
@@ -53,6 +53,10 @@ You can create your own secrets and reference them e.g. in the `spec.clusterConf
== Authentication

The internal or broker-to-broker communication is authenticated via TLS.
For client-to-server communication, authentication can be achieved with either TLS or Kerberos.

=== TLS

In order to enforce TLS authentication for client-to-server communication, you can set an `AuthenticationClass` reference in the custom resource provided by the xref:commons-operator:index.adoc[Commons Operator].

[source,yaml]
@@ -101,6 +105,55 @@ spec:
<3> The reference to a `SecretClass`.
<4> The `SecretClass` that is referenced by the `AuthenticationClass` in order to provide certificates.

=== Kerberos

Similarly, you can set an `AuthenticationClass` reference for a Kerberos authentication provider:

[source,yaml]
----
apiVersion: authentication.stackable.tech/v1alpha1
kind: AuthenticationClass
metadata:
name: kafka-client-kerberos # <2>
spec:
provider:
kerberos:
kerberosSecretClass: kafka-client-auth-secret # <3>
---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
name: kafka-client-auth-secret # <4>
spec:
backend:
kerberosKeytab:
...
---
apiVersion: kafka.stackable.tech/v1alpha1
kind: KafkaCluster
metadata:
name: simple-kafka
spec:
image:
productVersion: 3.7.1
clusterConfig:
authentication:
- authenticationClass: kafka-client-kerberos # <1>
tls:
serverSecretClass: tls # <5>
zookeeperConfigMapName: simple-kafka-znode
brokers:
roleGroups:
default:
replicas: 3
----
<1> The `clusterConfig.authentication.authenticationClass` can be set to use Kerberos for authentication. This is optional.
<2> The referenced `AuthenticationClass` that references a `SecretClass` to provide Kerberos keytabs.
<3> The reference to a `SecretClass`.
<4> The `SecretClass` that is referenced by the `AuthenticationClass` in order to provide keytabs.
<5> The SecretClass that will be used for encryption.

NOTE: When Kerberos is enabled it is also required to enable TLS for maximum security.

== [[authorization]]Authorization

27 changes: 22 additions & 5 deletions rust/crd/src/authentication.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use stackable_operator::{
schemars::{self, JsonSchema},
};

const SUPPORTED_AUTHENTICATION_CLASS_PROVIDERS: [&str; 1] = ["TLS"];
pub const SUPPORTED_AUTHENTICATION_CLASS_PROVIDERS: [&str; 2] = ["TLS", "Kerberos"];

#[derive(Snafu, Debug)]
pub enum Error {
@@ -18,9 +18,10 @@ pub enum Error {
source: stackable_operator::client::Error,
authentication_class: ObjectRef<AuthenticationClass>,
},
// TODO: Adapt message if multiple authentication classes are supported
#[snafu(display("only one authentication class is currently supported. Possible Authentication class providers are {SUPPORTED_AUTHENTICATION_CLASS_PROVIDERS:?}"))]

#[snafu(display("only one authentication class at a time is currently supported. Possible Authentication class providers are {SUPPORTED_AUTHENTICATION_CLASS_PROVIDERS:?}"))]
MultipleAuthenticationClassesProvided,

#[snafu(display(
"failed to use authentication provider [{provider}] for authentication class [{authentication_class}] - supported providers: {SUPPORTED_AUTHENTICATION_CLASS_PROVIDERS:?}",
))]
@@ -42,6 +43,12 @@ pub struct KafkaAuthentication {
/// - Which ca.crt to use when validating the provided client certs
///
/// This will override the server TLS settings (if set) in `spec.clusterConfig.tls.serverSecretClass`.
///
/// ## Kerberos provider
///
/// This affects client connections and also requires TLS for encryption.
/// This setting is used to reference an `AuthenticationClass` and in turn, a `SecretClass` that is
/// used to create keytabs.
pub authentication_class: String,
}

@@ -90,6 +97,13 @@ impl ResolvedAuthenticationClasses {
.find(|auth| matches!(auth.spec.provider, AuthenticationClassProvider::Tls(_)))
}

/// Return the (first) Kerberos `AuthenticationClass` if available
pub fn get_kerberos_authentication_class(&self) -> Option<&AuthenticationClass> {
self.resolved_authentication_classes
.iter()
.find(|auth| matches!(auth.spec.provider, AuthenticationClassProvider::Kerberos(_)))
}

/// Validates the resolved AuthenticationClasses.
/// Currently errors out if:
/// - More than one AuthenticationClass was provided
@@ -101,8 +115,11 @@ impl ResolvedAuthenticationClasses {

for auth_class in &self.resolved_authentication_classes {
match &auth_class.spec.provider {
AuthenticationClassProvider::Tls(_) => {}
_ => {
// explicitly list each branch so new elements do not get overlooked
AuthenticationClassProvider::Tls(_) | AuthenticationClassProvider::Kerberos(_) => {}
AuthenticationClassProvider::Static(_)
| AuthenticationClassProvider::Ldap(_)
| AuthenticationClassProvider::Oidc(_) => {
return Err(Error::AuthenticationProviderNotSupported {
authentication_class: ObjectRef::from_obj(auth_class),
provider: auth_class.spec.provider.to_string(),
12 changes: 11 additions & 1 deletion rust/crd/src/lib.rs
Original file line number Diff line number Diff line change
@@ -5,11 +5,11 @@ pub mod listener;
pub mod security;
pub mod tls;

use crate::authentication::KafkaAuthentication;
use crate::authorization::KafkaAuthorization;
use crate::tls::KafkaTls;

use affinity::get_affinity;
use authentication::KafkaAuthentication;
use serde::{Deserialize, Serialize};
use snafu::{OptionExt, ResultExt, Snafu};
use stackable_operator::{
@@ -63,6 +63,9 @@ pub const STACKABLE_DATA_DIR: &str = "/stackable/data";
pub const STACKABLE_CONFIG_DIR: &str = "/stackable/config";
pub const STACKABLE_LOG_CONFIG_DIR: &str = "/stackable/log_config";
pub const STACKABLE_LOG_DIR: &str = "/stackable/log";
// kerberos
pub const STACKABLE_KERBEROS_DIR: &str = "/stackable/kerberos";
pub const STACKABLE_KERBEROS_KRB5_PATH: &str = "/stackable/kerberos/krb5.conf";

const DEFAULT_BROKER_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(30);

@@ -335,6 +338,13 @@ impl KafkaRole {
}
roles
}

/// A Kerberos principal has three parts, with the form username/fully.qualified.domain.name@YOUR-REALM.COM.
/// We only have one role and will use "kafka" everywhere (which e.g. differs from the current hdfs implementation,
/// but is similar to HBase).
pub fn kerberos_service_name(&self) -> &'static str {
"kafka"
}
}

#[derive(Clone, Debug, Default, PartialEq, Fragment, JsonSchema)]
Loading