Skip to content

Commit b32ab01

Browse files
authored
BE: Implement audit log level (#4103)
1 parent fa9547b commit b32ab01

File tree

17 files changed

+213
-20
lines changed

17 files changed

+213
-20
lines changed

kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java

+6
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,13 @@ public static class AuditProperties {
152152
Integer auditTopicsPartitions;
153153
Boolean topicAuditEnabled;
154154
Boolean consoleAuditEnabled;
155+
LogLevel level;
155156
Map<String, String> auditTopicProperties;
157+
158+
public enum LogLevel {
159+
ALL,
160+
ALTER_ONLY //default
161+
}
156162
}
157163

158164
@PostConstruct
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

67
public enum AclAction implements PermissibleAction {
78

89
VIEW,
9-
EDIT;
10+
EDIT
11+
12+
;
13+
14+
public static final Set<AclAction> ALTER_ACTIONS = Set.of(EDIT);
1015

1116
@Nullable
1217
public static AclAction fromString(String name) {
1318
return EnumUtils.getEnum(AclAction.class, name);
1419
}
20+
21+
@Override
22+
public boolean isAlter() {
23+
return ALTER_ACTIONS.contains(this);
24+
}
1525
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/ApplicationConfigAction.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

@@ -10,9 +11,15 @@ public enum ApplicationConfigAction implements PermissibleAction {
1011

1112
;
1213

14+
public static final Set<ApplicationConfigAction> ALTER_ACTIONS = Set.of(EDIT);
15+
1316
@Nullable
1417
public static ApplicationConfigAction fromString(String name) {
1518
return EnumUtils.getEnum(ApplicationConfigAction.class, name);
1619
}
1720

21+
@Override
22+
public boolean isAlter() {
23+
return ALTER_ACTIONS.contains(this);
24+
}
1825
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

67
public enum AuditAction implements PermissibleAction {
78

8-
VIEW;
9+
VIEW
10+
11+
;
12+
13+
private static final Set<AuditAction> ALTER_ACTIONS = Set.of();
914

1015
@Nullable
1116
public static AuditAction fromString(String name) {
1217
return EnumUtils.getEnum(AuditAction.class, name);
1318
}
19+
20+
@Override
21+
public boolean isAlter() {
22+
return ALTER_ACTIONS.contains(this);
23+
}
1424
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/ClusterConfigAction.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

@@ -10,9 +11,15 @@ public enum ClusterConfigAction implements PermissibleAction {
1011

1112
;
1213

14+
public static final Set<ClusterConfigAction> ALTER_ACTIONS = Set.of(EDIT);
15+
1316
@Nullable
1417
public static ClusterConfigAction fromString(String name) {
1518
return EnumUtils.getEnum(ClusterConfigAction.class, name);
1619
}
1720

21+
@Override
22+
public boolean isAlter() {
23+
return ALTER_ACTIONS.contains(this);
24+
}
1825
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/ConnectAction.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

@@ -12,9 +13,15 @@ public enum ConnectAction implements PermissibleAction {
1213

1314
;
1415

16+
public static final Set<ConnectAction> ALTER_ACTIONS = Set.of(CREATE, EDIT, RESTART);
17+
1518
@Nullable
1619
public static ConnectAction fromString(String name) {
1720
return EnumUtils.getEnum(ConnectAction.class, name);
1821
}
1922

23+
@Override
24+
public boolean isAlter() {
25+
return ALTER_ACTIONS.contains(this);
26+
}
2027
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

67
public enum ConsumerGroupAction implements PermissibleAction {
78

89
VIEW,
910
DELETE,
10-
1111
RESET_OFFSETS
1212

1313
;
1414

15+
public static final Set<ConsumerGroupAction> ALTER_ACTIONS = Set.of(DELETE, RESET_OFFSETS);
16+
1517
@Nullable
1618
public static ConsumerGroupAction fromString(String name) {
1719
return EnumUtils.getEnum(ConsumerGroupAction.class, name);
1820
}
1921

22+
@Override
23+
public boolean isAlter() {
24+
return ALTER_ACTIONS.contains(this);
25+
}
2026
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

67
public enum KsqlAction implements PermissibleAction {
78

8-
EXECUTE;
9+
EXECUTE
10+
11+
;
12+
13+
public static final Set<KsqlAction> ALTER_ACTIONS = Set.of(EXECUTE);
914

1015
@Nullable
1116
public static KsqlAction fromString(String name) {
1217
return EnumUtils.getEnum(KsqlAction.class, name);
1318
}
1419

20+
@Override
21+
public boolean isAlter() {
22+
return ALTER_ACTIONS.contains(this);
23+
}
1524
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/PermissibleAction.java

+5
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ public sealed interface PermissibleAction permits
55
ConsumerGroupAction, SchemaAction,
66
ConnectAction, ClusterConfigAction,
77
KsqlAction, TopicAction, AuditAction {
8+
9+
String name();
10+
11+
boolean isAlter();
12+
813
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/SchemaAction.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

@@ -13,9 +14,15 @@ public enum SchemaAction implements PermissibleAction {
1314

1415
;
1516

17+
public static final Set<SchemaAction> ALTER_ACTIONS = Set.of(CREATE, DELETE, EDIT, MODIFY_GLOBAL_COMPATIBILITY);
18+
1619
@Nullable
1720
public static SchemaAction fromString(String name) {
1821
return EnumUtils.getEnum(SchemaAction.class, name);
1922
}
2023

24+
@Override
25+
public boolean isAlter() {
26+
return ALTER_ACTIONS.contains(this);
27+
}
2128
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/permission/TopicAction.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.model.rbac.permission;
22

3+
import java.util.Set;
34
import org.apache.commons.lang3.EnumUtils;
45
import org.jetbrains.annotations.Nullable;
56

@@ -9,16 +10,21 @@ public enum TopicAction implements PermissibleAction {
910
CREATE,
1011
EDIT,
1112
DELETE,
12-
1313
MESSAGES_READ,
1414
MESSAGES_PRODUCE,
1515
MESSAGES_DELETE,
1616

1717
;
1818

19+
public static final Set<TopicAction> ALTER_ACTIONS = Set.of(CREATE, EDIT, DELETE, MESSAGES_PRODUCE, MESSAGES_DELETE);
20+
1921
@Nullable
2022
public static TopicAction fromString(String name) {
2123
return EnumUtils.getEnum(TopicAction.class, name);
2224
}
2325

26+
@Override
27+
public boolean isAlter() {
28+
return ALTER_ACTIONS.contains(this);
29+
}
2430
}

kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/audit/AuditRecord.java

+14-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.provectus.kafka.ui.exception.ValidationException;
77
import com.provectus.kafka.ui.model.rbac.AccessContext;
88
import com.provectus.kafka.ui.model.rbac.Resource;
9+
import com.provectus.kafka.ui.model.rbac.permission.PermissibleAction;
910
import java.util.ArrayList;
1011
import java.util.LinkedHashMap;
1112
import java.util.List;
@@ -33,33 +34,37 @@ String toJson() {
3334
return MAPPER.writeValueAsString(this);
3435
}
3536

36-
record AuditResource(String accessType, Resource type, @Nullable Object id) {
37+
record AuditResource(String accessType, boolean alter, Resource type, @Nullable Object id) {
38+
39+
private static AuditResource create(PermissibleAction action, Resource type, @Nullable Object id) {
40+
return new AuditResource(action.name(), action.isAlter(), type, id);
41+
}
3742

3843
static List<AuditResource> getAccessedResources(AccessContext ctx) {
3944
List<AuditResource> resources = new ArrayList<>();
4045
ctx.getClusterConfigActions()
41-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.CLUSTERCONFIG, null)));
46+
.forEach(a -> resources.add(create(a, Resource.CLUSTERCONFIG, null)));
4247
ctx.getTopicActions()
43-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.TOPIC, nameId(ctx.getTopic()))));
48+
.forEach(a -> resources.add(create(a, Resource.TOPIC, nameId(ctx.getTopic()))));
4449
ctx.getConsumerGroupActions()
45-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.CONSUMER, nameId(ctx.getConsumerGroup()))));
50+
.forEach(a -> resources.add(create(a, Resource.CONSUMER, nameId(ctx.getConsumerGroup()))));
4651
ctx.getConnectActions()
4752
.forEach(a -> {
4853
Map<String, String> resourceId = new LinkedHashMap<>();
4954
resourceId.put("connect", ctx.getConnect());
5055
if (ctx.getConnector() != null) {
5156
resourceId.put("connector", ctx.getConnector());
5257
}
53-
resources.add(new AuditResource(a.name(), Resource.CONNECT, resourceId));
58+
resources.add(create(a, Resource.CONNECT, resourceId));
5459
});
5560
ctx.getSchemaActions()
56-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.SCHEMA, nameId(ctx.getSchema()))));
61+
.forEach(a -> resources.add(create(a, Resource.SCHEMA, nameId(ctx.getSchema()))));
5762
ctx.getKsqlActions()
58-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.KSQL, null)));
63+
.forEach(a -> resources.add(create(a, Resource.KSQL, null)));
5964
ctx.getAclActions()
60-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.ACL, null)));
65+
.forEach(a -> resources.add(create(a, Resource.ACL, null)));
6166
ctx.getAuditAction()
62-
.forEach(a -> resources.add(new AuditResource(a.name(), Resource.AUDIT, null)));
67+
.forEach(a -> resources.add(create(a, Resource.AUDIT, null)));
6368
return resources;
6469
}
6570

kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/audit/AuditService.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.provectus.kafka.ui.service.audit;
22

3+
import static com.provectus.kafka.ui.config.ClustersProperties.AuditProperties.LogLevel.ALTER_ONLY;
34
import static com.provectus.kafka.ui.service.MessagesService.createProducer;
45

56
import com.google.common.annotations.VisibleForTesting;
@@ -80,12 +81,13 @@ static Optional<AuditWriter> createAuditWriter(KafkaCluster cluster,
8081
}
8182
boolean topicAudit = Optional.ofNullable(auditProps.getTopicAuditEnabled()).orElse(false);
8283
boolean consoleAudit = Optional.ofNullable(auditProps.getConsoleAuditEnabled()).orElse(false);
84+
boolean alterLogOnly = Optional.ofNullable(auditProps.getLevel()).map(lvl -> lvl == ALTER_ONLY).orElse(true);
8385
if (!topicAudit && !consoleAudit) {
8486
return Optional.empty();
8587
}
8688
if (!topicAudit) {
8789
log.info("Audit initialization finished for cluster '{}' (console only)", cluster.getName());
88-
return Optional.of(consoleOnlyWriter(cluster));
90+
return Optional.of(consoleOnlyWriter(cluster, alterLogOnly));
8991
}
9092
String auditTopicName = Optional.ofNullable(auditProps.getTopic()).orElse(DEFAULT_AUDIT_TOPIC_NAME);
9193
boolean topicAuditCanBeDone = createTopicIfNeeded(cluster, acSupplier, auditTopicName, auditProps);
@@ -95,23 +97,24 @@ static Optional<AuditWriter> createAuditWriter(KafkaCluster cluster,
9597
"Audit initialization finished for cluster '{}' (console only, topic audit init failed)",
9698
cluster.getName()
9799
);
98-
return Optional.of(consoleOnlyWriter(cluster));
100+
return Optional.of(consoleOnlyWriter(cluster, alterLogOnly));
99101
}
100102
return Optional.empty();
101103
}
102104
log.info("Audit initialization finished for cluster '{}'", cluster.getName());
103105
return Optional.of(
104106
new AuditWriter(
105107
cluster.getName(),
108+
alterLogOnly,
106109
auditTopicName,
107110
producerFactory.get(),
108111
consoleAudit ? AUDIT_LOGGER : null
109112
)
110113
);
111114
}
112115

113-
private static AuditWriter consoleOnlyWriter(KafkaCluster cluster) {
114-
return new AuditWriter(cluster.getName(), null, null, AUDIT_LOGGER);
116+
private static AuditWriter consoleOnlyWriter(KafkaCluster cluster, boolean alterLogOnly) {
117+
return new AuditWriter(cluster.getName(), alterLogOnly, null, null, AUDIT_LOGGER);
115118
}
116119

117120
/**

kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/audit/AuditWriter.java

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
@Slf4j
2020
record AuditWriter(String clusterName,
21+
boolean logAlterOperationsOnly,
2122
@Nullable String targetTopic,
2223
@Nullable KafkaProducer<byte[], byte[]> producer,
2324
@Nullable Logger consoleLogger) implements Closeable {
@@ -39,6 +40,10 @@ void write(AccessContext ctx, AuthenticatedUser user, @Nullable Throwable th) {
3940
}
4041

4142
private void write(AuditRecord rec) {
43+
if (logAlterOperationsOnly && rec.resources().stream().noneMatch(AuditResource::alter)) {
44+
//we should only log alter operations, but this is read-only op
45+
return;
46+
}
4247
String json = rec.toJson();
4348
if (consoleLogger != null) {
4449
consoleLogger.info(json);

0 commit comments

Comments
 (0)