Skip to content

Commit fbca381

Browse files
Merge pull request #29 from superstreamlabs/master
release
2 parents 007187a + 66c265e commit fbca381

File tree

15 files changed

+1386
-276
lines changed

15 files changed

+1386
-276
lines changed

README.md

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ The full list is under the `./config-examples/` folder:
8585
- [AWS MSK (SCRAM)](config-examples/config.example.aws-msk.json) - AWS MSK with SCRAM authentication
8686
- [Confluent Cloud](config-examples/config.example.confluent-cloud.json) - Confluent Cloud setup
8787
- [Confluent Platform](config-examples/config.example.confluent-platform.json) - Confluent Platform setup
88-
- [Aiven Kafka](config-examples/config.example.aiven-kafka.json) - Aiven Kafka setup
88+
- [Aiven Kafka](config-examples/config.example.aiven-kafka-ssl.json) - Aiven Kafka with SSL authentication
89+
- [Aiven Kafka](config-examples/config.example.aiven-kafka-sasl.json) - Aiven Kafka with SASL SSL authentication
8990
- [Redpanda](config-examples/config.example.redpanda.json) - Redpanda setup
9091
- [OIDC Authentication](config-examples/config.example.oidc.json) - OpenID Connect authentication
9192
- [Azure AD OAuth](config-examples/config.example.azure-ad-oauth.json) - Azure Active Directory
@@ -243,11 +244,12 @@ The full list is under the `./config-examples/` folder:
243244
"vendor": "aiven",
244245
"useSasl": true,
245246
"sasl": {
246-
"mechanism": "oauthbearer",
247-
"clientId": "your-client-id",
248-
"clientSecret": "your-client-secret",
249-
"host": "https://my-oauth-server.com",
250-
"path": "/oauth/token",
247+
"mechanism": "scram-sha-256",
248+
"username": "avnadmin",
249+
"password": "*********"
250+
},
251+
"ssl": {
252+
"ca": "./certs/ca.pem"
251253
}
252254
},
253255
"file": {
@@ -376,21 +378,30 @@ The tool performs comprehensive health checks on your Kafka cluster to identify
376378
- **Quotas Configuration**: Checks if Kafka quotas are configured and being used
377379
- **Payload Compression**: Checks if payload compression is enabled on user topics
378380
- **Infinite Retention Policy**: Checks if any topics have infinite retention policy enabled
381+
- **Unclean Leader Election**: Detects if unclean.leader.election.enable is true
382+
- **ACL Enforcement**: Verifies authorizer.class.name and allow.everyone.if.no.acl.found settings
383+
- **Auto Topic Creation**: Detects if auto.create.topics.enable is true
384+
- **Message Size Consistency**: Validates message.max.bytes < replica.fetch.max.bytes < fetch.max.bytes
385+
- **Default Topic Replication**: Verifies default.replication.factor >= 3
386+
- **Controlled Shutdown**: Validates controlled.shutdown.* settings
387+
- **Consumer Lag Threshold**: Flags groups exceeding lag threshold
388+
- **Dead Consumer Groups**: Detects groups in DEAD state
389+
- **Single-Partition High Throughput**: Flags 1-partition topics > 1MB/s
379390

380391
### Confluent Cloud Health Checks
381-
- **Replication Factor vs Broker Count**: Ensures topics don't have replication factor > broker count
382392
- **Topic Partition Distribution**: Checks for balanced partition distribution across topics
383393
- **Consumer Group Health**: Identifies consumer groups with no active members
384394
- **Internal Topics Health**: Verifies system topics are healthy
385395
- **Under-Replicated Partitions**: Checks if topics have fewer in-sync replicas than configured
386-
- **Rack Awareness**: Checks rack awareness configuration for better availability
387-
- **Replica Distribution**: Ensures replicas are evenly distributed across brokers
388-
- **Metrics Configuration**: Verifies metrics accessibility
389396
- **Logging Configuration**: Confirms built-in logging availability
390397
- **Authentication Configuration**: Detects if unauthenticated access is enabled (security risk)
391398
- **Quotas Configuration**: Checks if Kafka quotas are configured and being used
392399
- **Payload Compression**: Checks if payload compression is enabled on user topics
393400
- **Infinite Retention Policy**: Checks if any topics have infinite retention policy enabled
401+
- **ACL Enforcement**: Uses Confluent Cloud API to analyze ACLs for overly permissive rules (requires API credentials)
402+
- **Consumer Lag Threshold**: Flags groups exceeding lag threshold
403+
- **Dead Consumer Groups**: Detects groups in DEAD state
404+
- **Single-Partition High Throughput**: Flags 1-partition topics > 1MB/s
394405

395406
### Aiven Kafka Health Checks
396407
- **Replication Factor vs Broker Count**: Ensures topics don't have replication factor > broker count
@@ -401,12 +412,18 @@ The tool performs comprehensive health checks on your Kafka cluster to identify
401412
- **Min In-Sync Replicas Configuration**: Checks if topics have min.insync.replicas > replication factor
402413
- **Rack Awareness**: Checks rack awareness configuration for better availability
403414
- **Replica Distribution**: Ensures replicas are evenly distributed across brokers
404-
- **Metrics Configuration**: Verifies metrics accessibility
405415
- **Logging Configuration**: Confirms built-in logging availability
406416
- **Authentication Configuration**: Detects if unauthenticated access is enabled (security risk)
407417
- **Quotas Configuration**: Checks if Kafka quotas are configured and being used
408418
- **Payload Compression**: Checks if payload compression is enabled on user topics
409419
- **Infinite Retention Policy**: Checks if any topics have infinite retention policy enabled
420+
- **Auto Topic Creation**: Detects if auto.create.topics.enable is true
421+
- **Message Size Consistency**: Validates message.max.bytes < replica.fetch.max.bytes < fetch.max.bytes
422+
- **Controlled Shutdown**: Validates controlled.shutdown.* settings
423+
- **Consumer Lag Threshold**: Flags groups exceeding lag threshold
424+
- **Dead Consumer Groups**: Detects groups in DEAD state
425+
- **Single-Partition High Throughput**: Flags 1-partition topics > 1MB/s
426+
- **ACL Enforcement**: Verifies authorizer and allow_everyone_if_no_acl_found equivalents
410427

411428
### Generic Kafka Health Checks
412429
- **Replication Factor vs Broker Count**: Ensures topics don't have replication factor > broker count
@@ -417,12 +434,21 @@ The tool performs comprehensive health checks on your Kafka cluster to identify
417434
- **Min In-Sync Replicas Configuration**: Checks if topics have min.insync.replicas > replication factor
418435
- **Rack Awareness**: Checks rack awareness configuration for better availability
419436
- **Replica Distribution**: Ensures replicas are evenly distributed across brokers
420-
- **Metrics Configuration**: Verifies JMX metrics configuration
421-
- **Logging Configuration**: Checks log4j configuration
437+
- **Metrics Configuration**: Verifies JMX/metrics exposure in broker metadata
438+
- **Logging Configuration**: Checks logging configuration
422439
- **Authentication Configuration**: Detects if unauthenticated access is enabled (security risk)
423440
- **Quotas Configuration**: Checks if Kafka quotas are configured and being used
424441
- **Payload Compression**: Checks if payload compression is enabled on user topics
425442
- **Infinite Retention Policy**: Checks if any topics have infinite retention policy enabled
443+
- **Unclean Leader Election**: Detects if unclean.leader.election.enable is true
444+
- **ACL Enforcement**: Verifies authorizer.class.name and allow.everyone.if.no.acl.found settings
445+
- **Auto Topic Creation**: Detects if auto.create.topics.enable is true
446+
- **Message Size Consistency**: Validates message.max.bytes < replica.fetch.max.bytes < fetch.max.bytes
447+
- **Default Topic Replication**: Verifies default.replication.factor >= 3 (when broker count ≥ 3)
448+
- **Controlled Shutdown**: Validates controlled.shutdown.* settings
449+
- **Consumer Lag Threshold**: Flags groups exceeding lag threshold
450+
- **Dead Consumer Groups**: Detects groups in DEAD state
451+
- **Single-Partition High Throughput**: Flags 1-partition topics > 1MB/s
426452

427453
### Health Check Status
428454
-**Pass**: Configuration is healthy and optimal
@@ -542,6 +568,20 @@ The tool includes comprehensive validation that will:
542568
|-------|------|----------|-------------|
543569
| `email` | string | No | Email address for generating report files. If not provided, no file output will be generated |
544570

571+
### Confluent Cloud ACL Analysis (Optional)
572+
573+
For enhanced ACL analysis on Confluent Cloud, provide resource API credentials and your Cluster ID. The REST endpoint is automatically derived from your broker host.
574+
575+
| Field | Type | Required | Where |
576+
|-------|------|----------|-------|
577+
| `confluent.resourceApiKey` | string | No | config file or CLI prompt |
578+
| `confluent.resourceApiSecret` | string | No | config file or CLI prompt |
579+
| `confluent.clusterId` | string | No | config file or CLI prompt |
580+
581+
Notes:
582+
- The REST endpoint is inferred from your first broker in `kafka.brokers` (host portion, without port).
583+
- If credentials are not provided, the Confluent ACL analysis is skipped.
584+
545585
## 🚨 Troubleshooting
546586

547587
### Common Issues
@@ -633,6 +673,15 @@ SuperStream Kafka Analyzer performs a comprehensive set of health checks on your
633673
- **Quotas Configuration:** Checks if Kafka quotas are configured and being used.
634674
- **Payload Compression:** Checks if payload compression is enabled on user topics.
635675
- **Infinite Retention Policy:** Checks if any topics have infinite retention policy enabled.
676+
- **Unclean Leader Election:** Detects if unclean.leader.election.enable is true.
677+
- **ACL Enforcement:** Verifies authorizer.class.name and allow.everyone.if.no.acl.found settings.
678+
- **Auto Topic Creation:** Detects if auto.create.topics.enable is true.
679+
- **Message Size Consistency:** Validates message.max.bytes < replica.fetch.max.bytes < fetch.max.bytes.
680+
- **Default Topic Replication:** Verifies default.replication.factor >= 3 (when broker count ≥ 3).
681+
- **Controlled Shutdown:** Validates controlled.shutdown.* settings.
682+
- **Consumer Lag Threshold:** Flags groups exceeding lag threshold.
683+
- **Dead Consumer Groups:** Detects groups in DEAD state.
684+
- **Single-Partition High Throughput:** Flags 1-partition topics > 1MB/s.
636685

637686
Each check provides a clear status (✅ Pass, ⚠️ Warning, ❌ Failed, ℹ️ Info) and actionable recommendations.
638687

config-examples/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ If you get an error about missing vendor field, add the appropriate vendor value
2222

2323
📚 **For detailed OIDC setup, see [OIDC-AUTH-GUIDE.md](OIDC-AUTH-GUIDE.md)**
2424

25+
## 🔒 ACL Enforcement Analysis
26+
27+
The analyzer now includes comprehensive ACL (Access Control List) enforcement checks for all major Kafka vendors:
28+
29+
- **Apache/MSK**: Verifies `authorizer.class.name` and `allow.everyone.if.no.acl.found` settings
30+
- **Aiven**: Checks `kafka_enable_authorizer` and `allow_everyone_if_no_acl_found` configuration
31+
- **Confluent Cloud**: Uses API to analyze ACLs for overly permissive rules (requires additional API credentials)
32+
33+
**Confluent Cloud ACL Analysis:**
34+
- Optional feature that requires additional API credentials
35+
- Analyzes ACLs for wildcard permissions and overly broad operations
36+
- Provides least-privilege access pattern validation
37+
- Set `confluentApiKey`, `confluentApiSecret`, and `confluentEnvironmentId` in your config
38+
2539
## Vendor-Specific Authentication Requirements
2640

2741
### AWS MSK (Amazon Managed Streaming for Apache Kafka)

config-examples/config.example.confluent-cloud.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
"formats": ["json", "csv", "html", "txt"],
1616
"includeMetadata": true
1717
},
18+
"confluent": {
19+
"resourceApiKey": "YOUR_RESOURCE_API_KEY",
20+
"resourceApiSecret": "YOUR_RESOURCE_API_SECRET",
21+
"clusterId": "lkc-xxxxx"
22+
},
1823
"email": "[email protected]",
19-
"_comment": "Confluent Cloud uses official connection methodology with SASL_SSL and PLAIN mechanism. Replace pkc-xxxxx.us-central1.gcp.confluent.cloud:9092 with your actual Confluent Cloud broker URL from your cluster overview. Use your API Key as username and API Secret as password."
24+
"_comment": "Confluent Cloud uses official connection methodology with SASL_SSL and PLAIN mechanism. Replace pkc-xxxxx...:9092 with your actual broker URL. Use your API Key as username and API Secret as password. For ACL analysis, provide resource API credentials and Cluster ID (optional). The REST endpoint is derived from your broker host."
2025
}

dashboard/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Interactive web dashboard for monitoring and analyzing Kafka cluster health and
2424
### Health Checks
2525

2626
- Comprehensive table of all health check results
27-
- Color-coded status indicators (✅ Passed, ❌ Failed, ⚠️ Warning)
27+
- Color-coded status indicators (✅ Passed, ❌ Failed)
2828
- Recommendations for each check
2929

3030
## 🛠️ Installation

dashboard/app.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,8 @@ def create_health_details_table(self, kafka_data):
311311
def get_status_emoji(self, status):
312312
"""Get emoji for status"""
313313
status_map = {
314-
'PASSED': '✅ PASSED',
315314
'FAILED': '❌ FAILED',
316-
'WARNING': '⚠️ WARNING',
317-
'INFO': 'ℹ️ INFO'
315+
'PASSED': '✅ PASSED'
318316
}
319317
return status_map.get(status, '? UNKNOWN')
320318

dashboard/components/charts.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,10 @@ def create_health_score_gauge(health_score: float, title: str = "Cluster Health
6464
def create_health_checks_summary(health_data: Dict[str, int]) -> go.Figure:
6565
"""Create health checks summary bar chart"""
6666

67-
categories = ['Passed', 'Failed', 'Warnings']
67+
categories = ['Passed', 'Failed']
6868
values = [
6969
health_data.get('passedChecks', 0),
7070
health_data.get('failedChecks', 0),
71-
health_data.get('warnings', 0)
7271
]
7372
colors = ['#28a745', '#dc3545', '#ffc107']
7473

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "superstream-kafka-analyzer",
3-
"version": "1.0.18",
3+
"version": "1.1.0",
44
"description": "Interactive utility to analyze Kafka clusters health and configuration",
55
"main": "src/cli.js",
66
"bin": {

report-examples/kafka-report.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,7 @@ <h3>🔍 Health Check Results</h3>
217217
<strong>Summary:</strong>
218218
Total: 16 |
219219
✅ Passed: 10 |
220-
❌ Failed: 0 |
221-
⚠️ Warnings: 6
220+
❌ Failed: 0
222221
</div>
223222
<div class="health-checks">
224223

src/analytics.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,7 @@ class SupabaseAnalytics {
190190
vendor: vendor || 'unknown',
191191
total_checks: results.totalChecks,
192192
passed_checks: results.passedChecks,
193-
failed_checks: results.failedChecks,
194-
warnings: results.warnings
193+
failed_checks: results.failedChecks
195194
});
196195
}
197196

src/cli.js

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ class CLI {
189189
brokerDefault = 'b-1.your-cluster.region.amazonaws.com:9092';
190190
} else if (vendorAnswer.vendor === 'aiven') {
191191
brokerMessage = 'kafka-xxxxx.aivencloud.com:12345';
192-
brokerDefault = 'superstream-test-superstream-3591.k.aivencloud.com:18848';
193192
}
194193

195194
const kafkaAnswers = await inquirer.prompt([
@@ -299,6 +298,59 @@ class CLI {
299298
console.log(chalk.gray(` Session Timeout: 45000ms`));
300299
console.log(chalk.gray(` API Key: ${confluentAnswers.username ? '***' + confluentAnswers.username.slice(-4) : 'NOT SET'}`));
301300
console.log(chalk.gray(` API Secret: ${confluentAnswers.password ? '***' + confluentAnswers.password.slice(-4) : 'NOT SET'}`));
301+
302+
// Ask for Confluent Cloud API credentials for ACL analysis (optional)
303+
const aclAnalysisAnswer = await inquirer.prompt([
304+
{
305+
type: 'confirm',
306+
name: 'enableAclAnalysis',
307+
message: 'Enable ACL analysis (requires additional API credentials)?',
308+
default: false
309+
}
310+
]);
311+
312+
if (aclAnalysisAnswer.enableAclAnalysis) {
313+
const aclCredentials = await inquirer.prompt([
314+
{
315+
type: 'input',
316+
name: 'resourceApiKey',
317+
message: 'Confluent Cloud resource API Key (for ACL analysis):',
318+
validate: (input) => {
319+
if (!input.trim()) return 'API Key is required for ACL analysis';
320+
return true;
321+
}
322+
},
323+
{
324+
type: 'password',
325+
name: 'resourceApiSecret',
326+
message: 'Confluent Cloud resource API Secret (for ACL analysis):',
327+
validate: (input) => {
328+
if (!input.trim()) return 'API Secret is required for ACL analysis';
329+
return true;
330+
}
331+
},
332+
{
333+
type: 'input',
334+
name: 'confluentClusterId',
335+
message: 'Confluent Cloud Cluster ID:',
336+
validate: (input) => {
337+
if (!input.trim()) return 'Cluster ID is required for ACL analysis';
338+
return true;
339+
}
340+
}
341+
]);
342+
343+
// Store ACL analysis credentials in config
344+
this.config.confluent = {
345+
resourceApiKey: aclCredentials.resourceApiKey,
346+
resourceApiSecret: aclCredentials.resourceApiSecret,
347+
clusterId: aclCredentials.confluentClusterId
348+
}
349+
350+
console.log(chalk.gray('🔍 ACL Analysis configuration:'));
351+
console.log(chalk.gray(` API Key: ${aclCredentials.resourceApiKey ? '***' + aclCredentials.resourceApiKey.slice(-4) : 'NOT SET'}`));
352+
console.log(chalk.gray(` Cluster ID: ${aclCredentials.confluentClusterId}`));
353+
}
302354
} else if (vendorAnswer.vendor === 'aiven') {
303355
console.log(chalk.yellow('\n🔐 Aiven Kafka Authentication'));
304356
const aivenAnswers = await inquirer.prompt([
@@ -683,7 +735,14 @@ class CLI {
683735
spinner.stop();
684736

685737
// Display summary
686-
console.log(chalk.green('\n✅ Analysis completed successfully!'));
738+
console.log(chalk.green('\n✅ Analysis completed successfully! \n'));
739+
740+
if (healthResults.failedChecks === 0) {
741+
console.log(chalk.green('🎉 All health checks passed! Your Kafka cluster is healthy. \n'));
742+
} else {
743+
console.log(chalk.red('🚨 Issues detected. Please review and fix the problems above. \n'));
744+
}
745+
687746
console.log(chalk.blue('\n📊 Analysis Summary:'));
688747
console.log(chalk.gray(`• Total Topics: ${analysisResults.summary.totalTopics}`));
689748
console.log(chalk.gray(`• Total Partitions: ${analysisResults.summary.totalPartitions}`));
@@ -740,7 +799,7 @@ class CLI {
740799
vendor: this.config.kafka.vendor,
741800
topics_count: analysisResults.summary.totalTopics,
742801
health_checks_count: healthResults ? healthResults.totalChecks : 0,
743-
has_issues: healthResults ? (healthResults.failedChecks > 0 || healthResults.warnings > 0) : false
802+
has_issues: healthResults ? (healthResults.failedChecks > 0) : false
744803
}, true); // Include detailed location
745804

746805
// Track health checks with location if available
@@ -750,7 +809,6 @@ class CLI {
750809
total_checks: healthResults.totalChecks,
751810
passed_checks: healthResults.passedChecks,
752811
failed_checks: healthResults.failedChecks,
753-
warnings: healthResults.warnings
754812
}, true); // Include detailed location
755813
}
756814

@@ -778,7 +836,7 @@ class CLI {
778836
return;
779837
}
780838

781-
const healthChecker = new HealthChecker(vendor, this.config.kafka);
839+
const healthChecker = new HealthChecker(vendor, this.config.kafka, this.config.confluent);
782840
const healthResults = await healthChecker.runHealthChecks(clusterInfo, topics, consumerGroups);
783841

784842
// Add health check results to the analysis results for file output

0 commit comments

Comments
 (0)