diff --git a/Dockerfile b/Dockerfile index 0591d037c80a31d52052bbefa16a5018e934a795..0ec7c314eec93fa50aa8529ff7079fe8929f8f25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ + ARG BASE_REGISTRY=registry1.dsop.io/ironbank ARG BASE_IMAGE=redhat/openjdk/openjdk11 ARG BASE_TAG=1.11 @@ -6,15 +7,14 @@ FROM tchiotludo/akhq:0.17.0 as base FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} -USER 0 - WORKDIR /app -COPY --from=base /app/akhq.jar . - -COPY config/* . +USER 0 -COPY scripts/* . +COPY --from=base /app . +COPY --from=base /usr/local/bin/ /usr/local/bin/ +COPY ./config . +COPY ./scripts/akhq . ENV MICRONAUT_CONFIG_FILES=/app/application.yml @@ -25,7 +25,7 @@ RUN dnf upgrade -y && \ rm -rf /var/cache/dnf && \ chmod +x /app/akhq -ENTRYPOINT ["entrypoint.sh"] +ENTRYPOINT ["docker-entrypoint.sh"] CMD ["./akhq"] diff --git a/config/application.yml b/config/application.yml index cf0394db81d854ceae8bc726dbf518508281b146..943710e3991bd0ae35b16126ac27cba7d590e139 100644 --- a/config/application.yml +++ b/config/application.yml @@ -1,172 +1,253 @@ micronaut: - application: - name: akhq - io: - watch: - paths: src/main - restart: false # enabled dev server with env vars MICRONAUT_IO_WATCH_RESTART=true - server: - thread-selection: AUTO - router: - static-resources: - react: - paths: classpath:ui - mapping: "/ui/**" - static: - paths: classpath:static - mapping: "/static/**" - swagger: - paths: classpath:META-INF/swagger - mapping: "/swagger/**" security: - enabled: false - authentication: cookie - endpoints: - login: - path: "/login" - logout: - path: "/logout" - get-allowed: true - token: - jwt: + enabled: true + # Ldap authentificaton configuration + ldap: + default: enabled: true - cookie: + context: + server: 'ldap://ldap.forumsys.com:389' + managerDn: 'cn=read-only-admin,dc=example,dc=com' + managerPassword: + search: + base: "dc=example,dc=com" + groups: enabled: true - cookie-same-site: strict + base: "dc=example,dc=com" + # OIDC authentification configuration + oauth2: + enabled: true + clients: + oidc: + client-id: "" + client-secret: "" + openid: + issuer: "" + token: + jwt: signatures: secret: generator: - secret: "pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!pleasechangeme!" - - redirect: - login-success: "${micronaut.server.context-path:}/ui" - forbidden: - url: "${micronaut.server.context-path:}/ui/login/forbidden" - unauthorized: - url: "${micronaut.server.context-path:}/ui/login/unauthorized" - login-failure: "${micronaut.server.context-path:}/ui/login/failed" - logout: "${micronaut.server.context-path:}/ui" - intercept-url-map: - - pattern: "${micronaut.server.context-path:}/ui/**" - access: "isAnonymous()" - - pattern: "${micronaut.server.context-path:}/static/**" - access: "isAnonymous()" - - pattern: "${micronaut.server.context-path:}/swagger/**" - access: "isAnonymous()" - oauth2: - login-uri: "${micronaut.server.context-path:}/oauth/login{/provider}" - callback-uri: "${micronaut.server.context-path:}/oauth/callback{/provider}" - caches: - kafka-wrapper: - record-stats: true - expire-after-write: 0s - -jackson: - serialization: - writeDatesAsTimestamps: false - -endpoints: - health: - enabled: true - sensitive: false - details-visible: anonymous - info: - enabled: true - sensitive: false - metrics: - enabled: true - sensitive: false - export: - prometheus: - enabled: true - step: PT1M - descriptions: true - prometheus: - enabled: true - sensitive: false - caches: - enabled: true - sensitive: false + secret: + server: + context-path: "" # if behind a reverse proxy, path to akhq without trailing slash (optional). Example: akhq is + # behind a reverse proxy with url http://my-server/akhq, set base-path: "/akhq". + # Not needed if you're behind a reverse proxy with subdomain http://akhq.my-server/ akhq: server: - access-log: - enabled: true - name: org.akhq.log.access - format: "[Date: {}] [Duration: {} ms] [Url: {} {}] [Status: {}] [Ip: {}] [User: {}]" - filters: - - "((?!/health).)*" + access-log: # Access log configuration (optional) + enabled: true # true by default + name: org.akhq.log.access # Logger name + format: "[Date: {}] [Duration: {} ms] [Url: {} {}] [Status: {}] [Ip: {}] [User: {}]" # Logger format + # default kafka properties for each clients, available for admin / producer / consumer (optional) clients-defaults: consumer: properties: - max.poll.records: 50 isolation.level: read_committed - # group.id: Akhq - enable.auto.commit: "false" - default.api.timeout.ms: 15000 + + # list of kafka cluster available for akhq + connections: + my-cluster-plain-text: # url friendly name for the cluster (letter, number, _, -, ... dot are not allowed here) + properties: # standard kafka properties (optional) + bootstrap.servers: "kafka:9092" + schema-registry: + url: "http://schema-registry:8085" # schema registry url (optional) + type: "confluent" # schema registry type (optional). Supported types are "confluent" (default) or "tibco" + # Basic Auth user / pass + basic-auth-username: ${UN} + basic-auth-password: ${PW} + properties: # standard kafka properties (optional) + ssl.protocol: TLS + connect: + - name: connect-1 + url: "http://connect:8083" + # Basic Auth user / pass (optional) + basic-auth-username: ${UN} + basic-auth-password: ${PW} + # ssl store configuration (optional) + ssl-trust-store: /app/truststore.jks + ssl-trust-store-password: ${PW} + ssl-key-store: /app/truststore.jks + ssl-key-store-password: ${PW} + - name: connect-2 + url: "http://connect:8084" + # Basic Auth user / pass (optional) + basic-auth-username: ${UN} + basic-auth-password: ${PW} + # ssl store configuration (optional) + ssl-trust-store: /app/truststore.jks + ssl-trust-store-password: ${PW} + ssl-key-store: /app/truststore.jks + ssl-key-store-password: ${PW} + deserialization: + protobuf: + # (optional) if descriptor-file properties are used + descriptors-folder: "/app/protobuf_desc" + topics-mapping: + - topic-regex: "album.*" + descriptor-file-base64: "" #Base64 + value-message-type: "Album" + - topic-regex: "film.*" + descriptor-file-base64: "" #Base64 + value-message-type: "Film" + - topic-regex: "test.*" + descriptor-file: "other.desc" + key-message-type: "Row" + value-message-type: "Envelope" + # Ui Cluster Options (optional) + ui-options: + topic: + default-view: ALL # default list view (ALL, HIDE_INTERNAL, HIDE_INTERNAL_STREAM, HIDE_STREAM). Overrides default + skip-consumer-groups: false # Skip loading consumer group information when showing topics. Overrides default + skip-last-record: true # Skip loading last record date information when showing topics. Overrides default + topic-data: + sort: NEWEST # default sort order (OLDEST, NEWEST) (default: OLDEST). Overrides default + + my-cluster-ssl: + properties: + bootstrap.servers: "kafka:9093" + security.protocol: SSL + ssl.truststore.location: /app/truststore.jks + ssl.truststore.password: ${PW} + ssl.keystore.location: /app/keystore.jks + ssl.keystore.password: ${PW} + ssl.key.password: ${PW} + + my-cluster-sasl: + properties: + bootstrap.servers: "kafka:9094" + security.protocol: SASL_SSL + sasl.mechanism: SCRAM-SHA-256 + sasl.jaas.config: org.apache.kafka.common.security.scram.ScramLoginModule required username="${UN}" password="${PW}"; + ssl.truststore.location: /app/truststore.jks + ssl.truststore.password: ${PW} + ssl.keystore.location: /app/keystore.jks + ssl.keystore.password: ${PW} + ssl.key.password: ${PW} pagination: - page-size: 25 - threads: 16 + page-size: 25 # number of elements per page (default : 25) + threads: 16 # Number of parallel threads to resolve page + # Topic list display options (optional) topic: - default-view: HIDE_INTERNAL - replication: 1 - retention: 86400000 - partition: 1 - internal-regexps: + retention: 172800000 # default retention period when creating topic + partition: 3 # default number of partition when creating topic + replication: 3 # default number of replicas when creating topic + internal-regexps: # list of regexp to be considered as internal (internal topic can't be deleted or updated) - "^_.*$" - "^.*_schemas$" - "^.*connect-config$" - "^.*connect-offsets$1" - "^.*connect-status$" - stream-regexps: + stream-regexps: # list of regexp to be considered as internal stream topic - "^.*-changelog$" - "^.*-repartition$" - "^.*-rekey$" + skip-consumer-groups: false # Skip loading consumer group information when showing topics + skip-last-record: false # Skip loading last record date information when showing topics + # Topic display data options (optional) topic-data: - sort: OLDEST - size: 50 - poll-timeout: 1000 + size: 50 # max record per page (default: 50) + poll-timeout: 1000 # The time, in milliseconds, spent waiting in poll if data is not available in the buffer. + # Ui Global Options (optional) + ui-options: + topic: + default-view: ALL # default list view (ALL, HIDE_INTERNAL, HIDE_INTERNAL_STREAM, HIDE_STREAM). Overrides default + skip-consumer-groups: false # Skip loading consumer group information when showing topics. Overrides default + skip-last-record: true # Skip loading last record date information when showing topics. Overrides default + topic-data: + sort: NEWEST # default sort order (OLDEST, NEWEST) (default: OLDEST). Overrides default + + # Auth & Roles (optional) security: - default-group: admin + default-group: admin # Default groups for all the user even unlogged user + # Groups definition groups: - - name: admin - roles: - - 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 - - acls/read - - connect/read - - connect/insert - - connect/update - - connect/delete - - connect/state/update - - name: reader - roles: - - topic/read - - node/read - - topic/data/read - - group/read - - registry/read - - acls/read - - connect/read - - name: no-roles - roles: [] + admin: # unique key + name: admin # Group name + roles: # roles for the group + - 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 + - acls/read + - connect/read + - connect/insert + - connect/update + - connect/delete + - connect/state/update + attributes: + # Regexp to filter topic available for group + topics-filter-regexp: "test.*" + # Regexp to filter connect configs visible for group + connects-filter-regexp: "^test.*$" + # Regexp to filter consumer groups visible for group + consumer-groups-filter-regexp: "consumer.*" + topic-reader: # unique key + name: topic-reader # Other group + roles: + - topic/read + attributes: + topics-filter-regexp: "test\\.reader.*" + + # Basic auth configuration + basic-auth: + - username: ${UN} # Username + password: ${PW} # Password in sha256 + groups: # Groups for the user + - admin + - topic-reader + + # Ldap Groups configuration (when using ldap) + ldap: + default-group: topic-reader + groups: + - name: group-ldap-1 + groups: # Akhq groups list + - topic-reader + - name: group-ldap-2 + groups: + - admin + users: + - username: ${UN} # ldap user id + groups: # Akhq groups list + - topic-reader + - username: ${UN} + groups: + - admin + + # OIDC configuration + oidc: + enabled: true + providers: + oidc: + label: "Login with OIDC" + username-field: ${UN} + groups-field: roles + default-group: topic-reader + groups: + - name: oidc-admin-group + groups: + - admin + users: + - username: ${UN} + groups: + - admin diff --git a/hardening_manifest.yaml b/hardening_manifest.yaml index 31208b1a34bd9d2864f5b1aad84fb1253e117417..82269d3902886d35ef7ca7c5314251e9636c834c 100644 --- a/hardening_manifest.yaml +++ b/hardening_manifest.yaml @@ -2,13 +2,13 @@ apiVersion: v1 # The repository name in registry1, excluding /ironbank/ -name: "opensource/apache/kafka-dashboard" +name: "opensource/tchiotludo/akhq" # List of tags to push for the repository in registry1 # The most specific version should be the first tag and will be shown # on ironbank.dsop.io tags: -- "0.16.0" +- "0.17.0" - "latest" # Build args passed to Dockerfile ARGs @@ -18,22 +18,22 @@ args: # Docker image labels labels: - org.opencontainers.image.title: "kafka-dashboard" + org.opencontainers.image.title: "akhq" ## Human-readable description of the software packaged in the image - org.opencontainers.image.description: "Kafka GUI for Apache Kafka to manage topics, topics data, consumers group and schema registry" + org.opencontainers.image.description: "AKHQ was previously Kafka GUI for Apache Kafka to manage topics, topics data, consumers group and schema registry" ## License(s) under which contained software is distributed org.opencontainers.image.licenses: "Apache License 2.0" ## URL to find more information on the image org.opencontainers.image.url: "https://hub.docker.com/r/tchiotludo/akhq" ## Name of the distributing entity, organization or individual org.opencontainers.image.vendor: "opensource" - org.opencontainers.image.version: "0.16.0" + org.opencontainers.image.version: "0.17.0" ## Keywords to help with search (ex. "cicd,gitops,golang") - mil.dso.ironbank.image.keywords: "kafka-dashboard,dataflow,processing" + mil.dso.ironbank.image.keywords: "kafka-dashboard,dataflow,processing,akhq" ## This value can be "opensource" or "commercial" mil.dso.ironbank.image.type: "opensource" ## Product the image belongs to for grouping multiple images - mil.dso.ironbank.product.name: "kafka-dashboard" + mil.dso.ironbank.product.name: "akhq" # List of resources to make available to the offline build context resources: @@ -42,7 +42,7 @@ resources: # List of project maintainers maintainers: -- name: "Jinoy Parekh" - username: "jparekh" - email: "jparekh@vivsoft.io" +- name: "Chris Byrd" + username: "crbcos" + email: "crbcos@parsons.com" cht_member: true diff --git a/scripts/akhq b/scripts/akhq index 3a4b946d825ed20b7b65e6259615eae6d51e1e43..5930e6b02b40ed46e3df160a65866683a1843d8d 100644 --- a/scripts/akhq +++ b/scripts/akhq @@ -7,4 +7,4 @@ do JAVA_OPTS="${JAVA_OPTS} ${JVM_OPT}" done -java ${JAVA_OPTS} -jar /app/akhq.jar +java ${JAVA_OPTS} -cp /app/akhq.jar:${CLASSPATH} org.akhq.App \ No newline at end of file diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh deleted file mode 100644 index 52228a691b4b239854df0cee1f460330bbb5e7db..0000000000000000000000000000000000000000 --- a/scripts/entrypoint.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh - -set -e - -if [ "${AKHQ_CONFIGURATION}" ]; then - echo "${AKHQ_CONFIGURATION}" > /app/application.yml -fi - -exec "$@" diff --git a/scripts/jvm.options b/scripts/jvm.options deleted file mode 100644 index c0460993d5fbaa9aede3954cfda20952a66b9336..0000000000000000000000000000000000000000 --- a/scripts/jvm.options +++ /dev/null @@ -1,34 +0,0 @@ -########################################################################### -# jvm.options # -# # -# - all flags defined here will be used to startup the JVM # -# - one flag should be specified per line # -# - lines that do not start with '-' will be ignored # -# - only static flags are accepted (no variables or parameters) # -# - dynamic flags will be appended to these on cassandra-env # -########################################################################### - -# Server Hotspot JVM --server - -# ensure UTF-8 encoding by default (e.g. filenames) --Dfile.encoding=UTF-8 - -# set to headless, just in case --Djava.awt.headless=true - -# generate a heap dump when an allocation from the Java heap fails -# heap dumps are created in the working directory of the JVM --XX:+HeapDumpOnOutOfMemoryError --XX:HeapDumpPath=/tmp/heapdump.log - -# Do not rely on the system configuration --Dfile.encoding=UTF-8 --Duser.timezone=UTC - -# Jmx Remote --Dcom.sun.management.jmxremote --Dcom.sun.management.jmxremote.port=8686 --Dcom.sun.management.jmxremote.local.only=false --Dcom.sun.management.jmxremote.authenticate=false --Dcom.sun.management.jmxremote.ssl=false