Skip to content

Commit

Permalink
Security : Auth & Roles
Browse files Browse the repository at this point in the history
- Security roles
- Basic Auth
  • Loading branch information
tchiotludo committed Mar 30, 2019
1 parent 77c87e3 commit 207ae67
Show file tree
Hide file tree
Showing 35 changed files with 649 additions and 152 deletions.
110 changes: 58 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# KafkaHQ
[![Build Status](https://travis-ci.org/tchiotludo/kafkahq.svg?branch=master)](https://travis-ci.org/tchiotludo/kafkahq)

> Kafka GUI for topics, topics data, consumers group, schema registry and more...
> Kafka GUI for topics, topics data, consumers group, schema registry and more...

![preview](https://user-images.githubusercontent.com/2064609/50536651-e050de80-0b56-11e9-816f-9d3aca3f1c88.gif)
Expand Down Expand Up @@ -49,7 +49,9 @@
- Configurations view
- Logs view
- Configure a node

- **Authentification and Roles**
- Read only mode
- BasicHttp with roles per user

## Quick preview
* Download [docker-compose.yml](https://raw.githubusercontent.com/tchiotludo/kafkahq/master/docker-compose.yml) file
Expand Down Expand Up @@ -78,67 +80,71 @@ docker run -d \

* Install Java 8
* Download the latest jar on [release page](https://github.com/tchiotludo/kafkahq/releases)
* Create an [configuration files](#configuration)
* Create an [configuration files](#configuration)
* Launch the application with `java -Dmicronaut.config.files=/path/to/application.yml -jar kafkahq.jar`
* Go to http://localhost:8080


## Configuration
Configuration file can by default be provided in either Java properties, YAML, JSON or Groovy files.
Configuration file example in YML :

```yml
kafkahq:
server:
# if behind a reverse proxy, path to kafkahq with trailing slash (optionnal)
base-path: ""
# Access log configuration (optionnal)
access-log:
enabled: true # true by default
name: org.kafkahq.log.access # Logger name
format: "[Date: {}] [Duration: {} ms] [Url: {} {} {}] [Status: {}] [Ip: {}] [Length: {}] [Port: {}]" # Logger format

# default kafka properties for each clients, available for admin / producer / consumer (optionnal)
clients-defaults:
consumer:
properties:
isolation.level: read_committed

# list of kafka cluster available for kafkahq
connections:
# url friendly name for the cluster
my-cluster-1:
# standard kafka properties (optionnal)
properties:
bootstrap.servers: "kafka:9092"
# schema registry url (optionnal)
schema-registry: "http://schema-registry:8085"

my-cluster-2:
properties:
bootstrap.servers: "kafka:9093"
security.protocol: SSL
ssl.truststore.location: /app/truststore.jks
ssl.truststore.password: password
ssl.keystore.location: /app/keystore.jks
ssl.keystore.password: password
ssl.key.password: password

# Topic display data options (optionnal)
topic-data:
# default sort order (OLDEST, NEWEST) (default: OLDEST)
sort: OLDEST
# max record per page (default: 50)
size: 50
```
Configuration file can by default be provided in either Java properties, YAML, JSON or Groovy files. YML Configuration
file example can be found here :[application.example.yml](application.example.yml)

* `kafkahq.server.base-path`: if behind a reverse proxy, path to kafkahq with trailing slash
* `kafkahq.clients-defaults.{{admin|producer|consumer}}.properties`: if behind a reverse proxy, path to kafkahq with trailing slash
### Kafka cluster configuration
* `kafkahq.connections` is a key value configuration with :
* `key`: must be an url friendly string the identify your cluster (`my-cluster-1` and `my-cluster-2` is the example above)
* `properties`: all the configurations found on [Kafka consumer documentation](https://kafka.apache.org/documentation/#consumerconfigs). Most important is `bootstrap.servers` that is a list of host:port of your Kafka brokers.
* `schema-registry`: the schema registry url *(optional)*

### Security
* `kafkahq.security.default-roles`: Roles available for all the user even unlogged user, roles available are :
* `topic/read`
* `topic/insert`
* `topic/delete`
* `topic/config/update`
* `node/read`
* `node/config/update`
* `topic/data/read`
* `topic/data/insert`
* `topic/data/delete`
* `group/read`
* `group/delete`
* `group/offsets/update`
* `registry/read`
* `registry/insert`
* `registry/update`
* `registry/delete`
* `registry/version/delete`

By default, security & roles is enabled by default but anonymous user have full access. You can completely disabled
security with `micronaut.security.enabled: false`.

If you need a read-only application, simply add this to your configuration files :
```yaml
kafkahq:
security:
default-roles:
- topic/read
- node/read
- topic/data/read
- group/read
- registry/read
```
#### Basic Auth
* `kafkahq.security.basic-auth`: List user & password with affected roles
* `username`: login of user
* `password`: Password in sha256, can be converted with command `echo -n "password" | sha256sum`
* `roles`: Role for current users

### Server
* `kafkahq.server.base-path`: if behind a reverse proxy, path to kafkahq with trailing slash

### Kafka admin / producer / consumer default properties
* `kafkahq.clients-defaults.{{admin|producer|consumer}}.properties`: if behind a reverse proxy, path to kafkahq with
trailing slash

### Micronaut configuration
> Since KafkaHQ is based on [Micronaut](https://micronaut.io/), you can customize configurations (server port, ssl, ...) with [Micronaut configuration](https://docs.micronaut.io/snapshot/guide/configurationreference.html#io.micronaut.http.server.HttpServerConfiguration).
> More information can be found on [Micronaut documentation](https://docs.micronaut.io/snapshot/guide/index.html#config)

Expand Down
65 changes: 65 additions & 0 deletions application.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
kafkahq:
server:
base-path: "" # if behind a reverse proxy, path to kafkahq with trailing slash (optionnal)
access-log: # Access log configuration (optionnal)
enabled: true # true by default
name: org.kafkahq.log.access # Logger name
format: "[Date: {}] [Duration: {} ms] [Url: {} {} {}] [Status: {}] [Ip: {}] [Length: {}] [Port: {}]" # Logger format

# default kafka properties for each clients, available for admin / producer / consumer (optionnal)
clients-defaults:
consumer:
properties:
isolation.level: read_committed

# list of kafka cluster available for kafkahq
connections:
my-cluster-1: # url friendly name for the cluster
properties: # standard kafka properties (optionnal)
bootstrap.servers: "kafka:9092"
schema-registry: "http://schema-registry:8085" # schema registry url (optionnal)

my-cluster-2:
properties:
bootstrap.servers: "kafka:9093"
security.protocol: SSL
ssl.truststore.location: /app/truststore.jks
ssl.truststore.password: password
ssl.keystore.location: /app/keystore.jks
ssl.keystore.password: password
ssl.key.password: password

# Topic display data options (optionnal)
topic-data:
sort: OLDEST # default sort order (OLDEST, NEWEST) (default: OLDEST)
size: 50 # max record per page (default: 50)

# Auth & Roles (optionnal)
security:
default-roles: # Roles available for all the user even unlogged user
- topic/read
- topic/insert
- topic/delete
- topic/config/update
- node/read
- node/config/update
- topic/data/read
- topic/data/insert
- topic/data/delete
- group/read
- group/delete
- group/offsets/update
- registry/read
- registry/insert
- registry/update
- registry/delete
- registry/version/delete

# Basic auth configuration
basic-auth:
user: # Username
password: pass # Password in sha256
roles: # Role for current users
- topic/read
- group/read
- group/delete
2 changes: 1 addition & 1 deletion assets/css/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ $dark: $gray-500 !default;
$yiq-contrasted-threshold: 175 !default;

// Body

$body-bg: #171819 !default;
$body-color: $white !default;

Expand All @@ -68,6 +67,7 @@ $input-border-color: transparent !default;
$input-group-addon-color: $gray-500 !default;
$input-group-addon-bg: $gray-700 !default;
$input-disabled-bg: $gray-500 !default;
$input-group-addon-border-color: $input-group-addon-bg;

$custom-file-color: $gray-500 !default;
$custom-file-border-color: $gray-700 !default;
Expand Down
1 change: 1 addition & 0 deletions assets/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

@import "../modules/templates/bootstrap";
@import "../modules/templates/layout";
@import "../modules/templates/login";
@import "../modules/templates/sidebar";

@import "../modules/datas/filter";
Expand Down
11 changes: 11 additions & 0 deletions assets/modules/templates/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ h1 {
min-width: 0;
}

h3.logo {
margin-bottom: 0;
text-align: center;
sup {
color: $yellow;
}
}

.wrapper {
display: flex;
width: 100%;
Expand Down Expand Up @@ -80,6 +88,9 @@ h1 {
&.no-side-bar {
width: 100%;
margin-left: 0;
display: flex;
justify-content: center;
flex-direction: column;
}

padding: 20px 20px 65px;
Expand Down
14 changes: 14 additions & 0 deletions assets/modules/templates/login.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.khq-login {
width: 100%;
max-width: 330px;
margin: 0 auto;
text-align: center;

padding: 40px;
background: $gray-900;
box-shadow: 0 0 40px 5px rgba($tertiary, 0.4);

> div:first-child {
margin-bottom: 40px;
}
}
8 changes: 0 additions & 8 deletions assets/modules/templates/sidebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@
background: $tertiary;
border-bottom: 4px solid $yellow;
a {
h3 {
margin-bottom: 0;
text-align: center;
sup {
color: $yellow;
}
}

&:hover {
text-decoration: none;
}
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ dependencies {
// micronaut
annotationProcessor "io.micronaut:micronaut-inject-java"
annotationProcessor "io.micronaut:micronaut-validation"
annotationProcessor "io.micronaut:micronaut-security"
compile "io.micronaut:micronaut-inject"
compile "io.micronaut:micronaut-validation"
compile 'io.micronaut:micronaut-views'
Expand Down Expand Up @@ -142,6 +143,8 @@ dependencies {
testCompile group: "io.confluent", name: "kafka-streams-avro-serde", version: confluentVersion
testCompile group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.8.+'
testCompile group: 'commons-codec', name: 'commons-codec', version: '1.11'
testImplementation 'org.hamcrest:hamcrest:2.1'
testImplementation 'org.hamcrest:hamcrest-library:2.1'
}

/**********************************************************************************************************************\
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/org/kafkahq/configs/BasicAuth.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.kafkahq.configs;

import com.google.common.hash.Hashing;
import io.micronaut.context.annotation.EachProperty;
import io.micronaut.context.annotation.Parameter;
import lombok.Getter;

import java.nio.charset.StandardCharsets;
import java.util.List;

@EachProperty("kafkahq.security.basic-auth")
@Getter
public class BasicAuth {
String username;
String password;
List<String> roles;

public BasicAuth(@Parameter String username) {
this.username = username;
}

@SuppressWarnings("UnstableApiUsage")
public boolean isValidPassword(String password) {
return this.password.equals(
Hashing.sha256()
.hashString(password, StandardCharsets.UTF_8)
.toString()
);
}
}

25 changes: 25 additions & 0 deletions src/main/java/org/kafkahq/configs/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.kafkahq.configs;

public class Role {
public static final String ROLE_TOPIC_READ = "topic/read";
public static final String ROLE_TOPIC_INSERT = "topic/insert";
public static final String ROLE_TOPIC_DELETE = "topic/delete";
public static final String ROLE_TOPIC_CONFIG_UPDATE = "topic/config/update";

public static final String ROLE_NODE_READ = "node/read";
public static final String ROLE_NODE_CONFIG_UPDATE = "node/config/update";

public static final String ROLE_TOPIC_DATA_READ = "topic/data/read";
public static final String ROLE_TOPIC_DATA_INSERT = "topic/data/insert";
public static final String ROLE_TOPIC_DATA_DELETE = "topic/data/delete";

public static final String ROLE_GROUP_READ = "group/read";
public static final String ROLE_GROUP_DELETE = "group/delete";
public static final String ROLE_GROUP_OFFSETS_UPDATE = "group/offsets/update";

public static final String ROLE_REGISTRY_READ = "registry/read";
public static final String ROLE_REGISTRY_INSERT = "registry/insert";
public static final String ROLE_REGISTRY_UPDATE = "registry/update";
public static final String ROLE_REGISTRY_DELETE = "registry/delete";
public static final String ROLE_REGISTRY_VERSION_DELETE = "registry/version/delete";
}
Loading

0 comments on commit 207ae67

Please sign in to comment.