Skip to content

Commit

Permalink
[DPE-5438] Enable digest auth (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
Batalex authored Dec 17, 2024
1 parent 6d10022 commit 629982a
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 33 deletions.
2 changes: 0 additions & 2 deletions charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ parts:
charm:
build-snaps:
- rustup
charm-binary-python-packages:
- setuptools
build-packages:
- pkg-config
- libffi-dev
Expand Down
11 changes: 5 additions & 6 deletions src/managers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
quorum.auth.serverRequireSasl=true
authProvider.sasl=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
enforce.auth.enabled=true
enforce.auth.schemes=sasl
sessionRequireClientSASLAuth=true
enforce.auth.schemes=sasl,digest
audit.enable=true
admin.serverAddress=localhost
"""
Expand Down Expand Up @@ -71,7 +70,7 @@ def log_level(self) -> str:
Returns:
String with these possible values: DEBUG, INFO, WARN, ERROR
"""
config_log_level = self.config["log-level"]
config_log_level = self.config.log_level

# Remapping to WARN that is generally used in Java applications based on log4j and logback.
if config_log_level == "WARNING":
Expand Down Expand Up @@ -173,9 +172,9 @@ def zookeeper_properties(self) -> list[str]:
"""
properties = (
[
f"initLimit={self.config['init-limit']}",
f"syncLimit={self.config['sync-limit']}",
f"tickTime={self.config['tick-time']}",
f"initLimit={self.config.init_limit}",
f"syncLimit={self.config.sync_limit}",
f"tickTime={self.config.tick_time}",
]
+ DEFAULT_PROPERTIES.split("\n")
+ [
Expand Down
43 changes: 18 additions & 25 deletions src/managers/quorum.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
)
from kazoo.exceptions import BadArgumentsError, ConnectionClosedError
from kazoo.handlers.threading import KazooTimeoutError
from kazoo.security import make_acl
from kazoo.security import make_acl, make_digest_acl_credential
from ops.charm import RelationEvent

from core.cluster import ClusterState
Expand Down Expand Up @@ -197,17 +197,21 @@ def update_acls(self, event: RelationEvent | None = None) -> None:
for client in self.state.clients:
if not client.database:
continue

generated_acl = make_acl(
scheme="sasl",
credential=client.username,
read="r" in client.extra_user_roles,
write="w" in client.extra_user_roles,
create="c" in client.extra_user_roles,
delete="d" in client.extra_user_roles,
admin="a" in client.extra_user_roles,
acls = {
"read": "r" in client.extra_user_roles,
"write": "w" in client.extra_user_roles,
"create": "c" in client.extra_user_roles,
"delete": "d" in client.extra_user_roles,
"admin": "a" in client.extra_user_roles,
}

sasl_acl = make_acl(scheme="sasl", credential=client.username, **acls)
digest_acl = make_acl(
scheme="digest",
credential=make_digest_acl_credential(client.username, client.password),
**acls,
)
logger.info(f"{generated_acl=}")
logger.debug(f"{sasl_acl=}")

# FIXME: data-platform-libs should handle this when it's implemented
if client.database:
Expand All @@ -219,23 +223,12 @@ def update_acls(self, event: RelationEvent | None = None) -> None:
# Looks for newly related applications not in config yet
if client.database not in leader_chroots:
logger.info(f"CREATE CHROOT - {client.database}")
self.client.create_znode_leader(path=client.database, acls=[generated_acl])
self.client.create_znode_leader(path=client.database, acls=[sasl_acl, digest_acl])

# Looks for existing related applications
logger.debug(f"UPDATE CHROOT - {client.database}")
self.client.set_acls_znode_leader(path=client.database, acls=[generated_acl])
self.client.set_acls_znode_leader(path=client.database, acls=[sasl_acl, digest_acl])

subnodes = self.client.leader_znodes(path=client.database)
for node in subnodes:
self.client.set_acls_znode_leader(path=node, acls=[generated_acl])

# Looks for applications no longer in the relation but still in config
restricted_acl = make_acl(
scheme="sasl",
credential="super",
all=True,
)
for chroot in sorted(leader_chroots - requested_chroots, reverse=True):
if not self._is_child_of(chroot, requested_chroots):
logger.info(f"RESET ACLS CHROOT - {chroot}")
self.client.set_acls_znode_leader(path=chroot, acls=[restricted_acl])
self.client.set_acls_znode_leader(path=node, acls=[sasl_acl, digest_acl])
4 changes: 4 additions & 0 deletions tests/unit/test_quorum.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ def test_update_acls_correctly_handles_relation_chroots(ctx: Context, base_state
# Then
for _, kwargs in patched_manager["create_znode_leader"].call_args_list:
assert "/rohan" in kwargs["path"]
acls = kwargs["acls"]
assert len(acls) == 2
assert len([acl for acl in acls if acl.perms == 31 and acl.id.scheme == "sasl"]) != 0
assert len([acl for acl in acls if acl.perms == 31 and acl.id.scheme == "digest"]) != 0

_, kwargs = patched_manager["set_acls_znode_leader"].call_args_list[0]
assert "/rohan" in kwargs["path"]
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_structured_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def test_incorrect_log_level():


def test_incorrect_expose_external():
"""Accepted expose-external values must be part of the defined enumeration and uppercase."""
erroneus_values = ["", "something_else", "false,nodeport", "load_balancer"]
valid_values = ["false", "nodeport", "loadbalancer"]
check_invalid_values("expose_external", erroneus_values)
Expand Down

0 comments on commit 629982a

Please sign in to comment.