diff --git a/.github/scripts/end2end/configs/notification_destinations.yaml b/.github/scripts/end2end/configs/notification_destinations.yaml index 4937e4ba0d..64f746f4c4 100644 --- a/.github/scripts/end2end/configs/notification_destinations.yaml +++ b/.github/scripts/end2end/configs/notification_destinations.yaml @@ -23,3 +23,21 @@ spec: host: ${NOTIF_KAFKA_HOST} port: ${NOTIF_KAFKA_PORT} destinationTopic: ${NOTIF_ALT_DEST_TOPIC} + +--- + +apiVersion: zenko.io/v1alpha2 +kind: ZenkoNotificationTarget +metadata: + name: ${NOTIF_AUTH_DEST_NAME} + labels: + app.kubernetes.io/instance: ${ZENKO_NAME} +spec: + type: kafka + host: ${NOTIF_KAFKA_AUTH_HOST} + port: ${NOTIF_KAFKA_AUTH_PORT} + destinationTopic: ${NOTIF_AUTH_DEST_TOPIC} + auth: plain + plain: + username: ${NOTIF_AUTH_DEST_USERNAME} + password: ${NOTIF_AUTH_DEST_PASSWORD} diff --git a/.github/scripts/end2end/configure-e2e-ctst.sh b/.github/scripts/end2end/configure-e2e-ctst.sh index 13efe07b3e..b7d5d727a0 100755 --- a/.github/scripts/end2end/configure-e2e-ctst.sh +++ b/.github/scripts/end2end/configure-e2e-ctst.sh @@ -11,6 +11,37 @@ KAFKA_HOST_PORT=${KAFKA_HOST_PORT:1:-1} export NOTIF_KAFKA_HOST=${KAFKA_HOST_PORT%:*} export NOTIF_KAFKA_PORT=${KAFKA_HOST_PORT#*:} +export NOTIF_KAFKA_AUTH_HOST="${ZENKO_NAME}-base-queue-auth-0" +export NOTIF_KAFKA_AUTH_HOST_PORT="$NOTIF_KAFKA_AUTH_HOST:$NOTIF_KAFKA_PORT" +export NOTIF_KAFKA_AUTH_PORT=9094 + +# Add an extra SASL_PLAIN Kafka listener, to support testing authenticated Kafka for bucket notifications +kubectl get zookeepercluster "${ZENKO_NAME}-base-quorum" -o json | jq '. +| .metadata |= {namespace, name: "\(.name)-auth" } +| del(.spec.labels) +| del(.spec.persistence) +| .spec.storageType |= "ephemeral" +| del(.spec.pod.affinity) +| del(.spec.pod.labels) +| del(.status) +' | kubectl apply -f - +kubectl wait --for=jsonpath='{.status.readyReplicas}'=1 --timeout 10m zookeepercluster "${ZENKO_NAME}-base-quorum-auth" + +kubectl get kafkacluster "${ZENKO_NAME}-base-queue" -o json | jq '. +| .metadata |= {namespace, name: "\(.name)-auth" } +| del(.status) +| .spec.listenersConfig.internalListeners |= . + [{containerPort: 9094, name: "auth", type: "sasl_plaintext", usedForInnerBrokerCommunication: false}] +| .spec.readOnlyConfig |= (. + " +sasl.enabled.mechanisms=PLAIN +listener.name.auth.plain.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username=\"'"$NOTIF_AUTH_DEST_USERNAME"'\" password=\"'"$NOTIF_AUTH_DEST_PASSWORD"'\" user_'"$NOTIF_AUTH_DEST_USERNAME"'=\"'"$NOTIF_AUTH_DEST_PASSWORD"'\"; +") +| del(.spec.brokerConfigGroups.default.storageConfigs[].pvcSpec) +| .spec.brokerConfigGroups.default.storageConfigs[].emptyDir |= {medium: "Memory"} +| .spec.zkAddresses |= ["'"${ZENKO_NAME}-base-quorum-auth-0.${ZENKO_NAME}-base-quorum-auth-headless:2181"'"] +| .spec.cruiseControlConfig.capacityConfig |= ({brokerCapacities: [{brokerId: "-1", capacity: {DISK: "1000", CPU: "100", NW_IN: "1000", NW_OUT: "1000"}}]} | tostring) +' | kubectl apply -f - +kubectl wait --for=jsonpath='{.status.state}'=ClusterRunning --timeout 10m kafkacluster "${ZENKO_NAME}-base-queue-auth" + UUID=$(kubectl get secret -l app.kubernetes.io/name=backbeat-config,app.kubernetes.io/instance=end2end \ -o jsonpath='{.items[0].data.config\.json}' | base64 -di | jq .extensions.replication.topic) UUID=${UUID%.*} @@ -48,6 +79,7 @@ kubectl run kafka-topics \ --command -- bash -c \ "kafka-topics.sh --create --topic $NOTIF_DEST_TOPIC --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $NOTIF_ALT_DEST_TOPIC --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ + kafka-topics.sh --create --topic $NOTIF_AUTH_DEST_TOPIC --bootstrap-server $NOTIF_KAFKA_AUTH_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $AZURE_ARCHIVE_STATUS_TOPIC --partitions 10 --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $AZURE_ARCHIVE_STATUS_TOPIC_2_NV --partitions 10 --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $AZURE_ARCHIVE_STATUS_TOPIC_2_V --partitions 10 --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ diff --git a/.github/scripts/end2end/configure-e2e.sh b/.github/scripts/end2end/configure-e2e.sh index 26a18fd732..e471255d7b 100755 --- a/.github/scripts/end2end/configure-e2e.sh +++ b/.github/scripts/end2end/configure-e2e.sh @@ -67,7 +67,7 @@ kubectl run kafka-topics \ "kafka-topics.sh --create --topic $UUID.backbeat-replication-replay-0 --partitions 5 --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $UUID.backbeat-data-mover --partitions 5 --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ kafka-topics.sh --create --topic $NOTIF_DEST_TOPIC --bootstrap-server $KAFKA_HOST_PORT --if-not-exists ; \ - kafka-topics.sh --create --topic $NOTIF_ALT_DEST_TOPIC --bootstrap-server $KAFKA_HOST_PORT --if-not-exists " + kafka-topics.sh --create --topic $NOTIF_ALT_DEST_TOPIC --bootstrap-server $KAFKA_HOST_PORT --if-not-exists" kubectl run ${POD_NAME} \ --image ${E2E_IMAGE} \ diff --git a/.github/scripts/end2end/run-e2e-ctst.sh b/.github/scripts/end2end/run-e2e-ctst.sh index 195f3241c0..a96b154ba7 100755 --- a/.github/scripts/end2end/run-e2e-ctst.sh +++ b/.github/scripts/end2end/run-e2e-ctst.sh @@ -59,6 +59,10 @@ DR_ADMIN_SECRET_ACCESS_KEY=$(kubectl get secret end2end-pra-management-vault-adm KAFKA_HOST_PORT=$(kubectl get secret -l app.kubernetes.io/name=backbeat-config,app.kubernetes.io/instance=end2end \ -o jsonpath='{.items[0].data.config\.json}' | base64 -di | jq .kafka.hosts) KAFKA_HOST_PORT=${KAFKA_HOST_PORT:1:-1} +KAFKA_PORT=${KAFKA_HOST_PORT#*:} + +KAFKA_AUTH_HOST="end2end-base-queue-auth-0" +KAFKA_AUTH_HOST_PORT="$KAFKA_AUTH_HOST:$KAFKA_PORT" TIME_PROGRESSION_FACTOR=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath="{.metadata.annotations.zenko\.io/time-progression-factor}") INSTANCE_ID=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath='{.status.instanceID}') @@ -93,9 +97,14 @@ WORLD_PARAMETERS="$(jq -c <" bucket And one notification destination When i subscribe to "" notifications for destination @@ -94,6 +94,23 @@ Feature: Bucket notifications | Versioning suspended | s3:ObjectTagging:Delete | s3:ObjectTagging:Delete | without | filter | receive | 0 | | Versioning suspended | s3:ObjectAcl:Put | s3:ObjectAcl:Put | without | filter | receive | 0 | + @2.6.0 + @PreMerge + @Flaky + @BucketNotification + Scenario Outline: Receive notification for configured events in authenticated notification destinations + Given a "" bucket + And one authenticated notification destination + When i subscribe to "" notifications for destination + And a "" event is triggered "" "" + Then i should "" a notification for "" event in destination + + Examples: + | versioningConfiguration | subscribedNotificationType | notificationType | enable | filterType | shouldReceive | destination | + | Non versioned | s3:ObjectCreated:* | s3:ObjectCreated:Put | without | filter | receive | 0 | + | Versioned | s3:ObjectCreated:* | s3:ObjectCreated:Copy | without | filter | receive | 0 | + | Versioning suspended | s3:ObjectCreated:* | s3:ObjectCreated:Put | without | filter | receive | 0 | + @2.6.0 @PreMerge @BucketNotification @@ -130,7 +147,7 @@ Feature: Bucket notifications @PreMerge @Flaky @BucketNotification - Scenario Outline: Recieve notification for configured events with correct filter + Scenario Outline: Receive notification for configured events with correct filter Given a "" bucket And one notification destination When i subscribe to "" notifications for destination with "" filter @@ -168,7 +185,7 @@ Feature: Bucket notifications @PreMerge @Flaky @BucketNotification - Scenario Outline: Recieve notification in multiple destinations + Scenario Outline: Receive notification in multiple destinations Given a "" bucket And two notification destinations When i subscribe to "" notifications for destination diff --git a/tests/ctst/steps/notifications.ts b/tests/ctst/steps/notifications.ts index e2c802f7ef..69f1176c11 100644 --- a/tests/ctst/steps/notifications.ts +++ b/tests/ctst/steps/notifications.ts @@ -103,14 +103,32 @@ async function putAcl(world: Zenko, objName: string) { await S3.putObjectAcl(world.getCommandParameters()); } -Given('one notification destination', function (this: Zenko) { +function setNotificationDestination(world: Zenko, destination: string, topic: string, hosts: string) { const notificationDestinations = []; notificationDestinations.push({ - destinationName: this.parameters.NotificationDestination, - topic: this.parameters.NotificationDestinationTopic, - hosts: this.parameters.KafkaHosts, + destinationName: destination, + topic, + hosts, }); - this.addToSaved('notificationDestinations', notificationDestinations); + world.addToSaved('notificationDestinations', notificationDestinations); +} + +Given('one notification destination', function (this: Zenko) { + setNotificationDestination( + this, + this.parameters.NotificationDestination, + this.parameters.NotificationDestinationTopic, + this.parameters.KafkaHosts, + ); +}); + +Given('one authenticated notification destination', function (this: Zenko) { + setNotificationDestination( + this, + this.parameters.NotificationDestinationAuth, + this.parameters.NotificationDestinationTopicAuth, + this.parameters.KafkaAuthHosts, + ); }); Given('two notification destinations', function (this: Zenko) { diff --git a/tests/ctst/world/Zenko.ts b/tests/ctst/world/Zenko.ts index ef94be2d6c..f66a04158a 100644 --- a/tests/ctst/world/Zenko.ts +++ b/tests/ctst/world/Zenko.ts @@ -55,8 +55,13 @@ export interface ZenkoWorldParameters extends ClientOptions { NotificationDestinationTopic: string; NotificationDestinationAlt: string; NotificationDestinationTopicAlt: string; + NotificationDestinationAuth: string; + NotificationDestinationTopicAuth: string; + NotificationDestinationAuthUsername: string; + NotificationDestinationAuthPassword: string; KafkaExternalIps: string; KafkaHosts: string; + KafkaAuthHosts: string; PrometheusService: string; KeycloakUsername: string; KeycloakPassword: string;