
Здесь мы будем использовать source-коннектор S3, который входит в состав Apache Camel Kafka (подробнее см. здесь), и на его примере покажем, как сконфигурировать коннектор, чтобы он использовал секрет.
Описанная здесь процедура настройки универсальна и подходит для коннекторов любых типов. Мы будем применять коннектор S3 для подключения к хранилищу Amazon AWS S3 и загрузки файлов из корзины (bucket) S3 в топик (topic) Apache Kafka. Для подключения к хранилищу S3 нам потребуются следующие учетные данные AWS: ключ доступа (access key) и секретный ключ (secret key). Итак, начнем с того, что подготовим секрет с учетными данными.
Создаем секрет с учетными данными
Первым делом создаем простейший файл свойств aws-credentials.properties и прописываем в него учетные данные, вот так:
aws_access_key_id=AKIAIOSFODNN7EXAMPLEaws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Указанные здесь учетные данные должны обеспечивать доступ к корзине S3, откуда будут читаться данные. Теперь из этого файла нужно сгенерировать секрет, это делается следующей командой:
$ kubectl create secret generic aws-credentials --from-file=./aws-credentials.properties
Собираем новый контейнерный образ с коннектором
Далее необходимо подготовить новый Docker-образ с нашим коннектором. Если используется Strimzi, то Dockerfile для добавления нашего коннектора выглядит вот так:
FROM strimzi/kafka:0.16.1-kafka-2.4.0USER root:rootCOPY ./my-plugins/ /opt/kafka/plugins/USER 1001
Если применяется Red Hat AMQ Streams, то Dockerfile выглядит вот так:
FROM registry.redhat.io/amq7/amq-streams-kafka-23:1.3.0USER root:rootCOPY ./my-plugins/ /opt/kafka/plugins/USER jboss:jboss
Затем, используя Dockerfile, надо выполнить сборку контейнерного образа, содержащего необходимые нам коннекторы, и разместить его в реестре. Если у вас нет своего частного реестра, то можно использовать публичные реестры, например Quay или Docker Hub.
Разворачиваем Apache Kafka Connect
Итак, имея контейнерный образ, мы можем развернуть Apache Kafka Connect путем создания следующего ресурса в Kubernetes:
apiVersion: kafka.strimzi.io/v1alpha1kind: KafkaConnectmetadata: name: my-connect-clusterspec: image: docker.io/scholzj/kafka:camel-kafka-2.4.0 replicas: 3 bootstrapServers: my-cluster-kafka-bootstrap:9092 externalConfiguration: volumes: - name: aws-credentials secret: secretName: aws-credentials config: config.providers: file config.providers.file.class: org.apache.kafka.common.config.provider.FileConfigProvider key.converter: org.apache.kafka.connect.json.JsonConverter value.converter: org.apache.kafka.connect.json.JsonConverter key.converter.schemas.enable: false value.converter.schemas.enable: false
На что надо обратить внимание в этом описании? Во-первых, на поле image, которое говорит оператору развертывания Apache Kafka Connect, какой образ надо при этом использовать то есть тот образ, куда мы включили нужные нам коннекторы. В нашем примере собранный на предыдущем шаге контейнерный образ размещен в реестре Docker Hub по адресу scholzj/kafka:camel-kafka-2.4.0, поэтому у нас поле image выглядит следующим образом:
image: docker.io/scholzj/kafka:camel-kafka-2.4.0
Во-вторых, секция externalConfiguration:
externalConfiguration: volumes: - name: aws-credentials secret: secretName: aws-credentials
Здесь мы говорим оператору монтировать Kubernetes-секрет aws-credentials (мы создали его выше) в podы Apache Kafka Connect. Перечисленные здесь секреты будут монтироваться с путем /opt/kafka/external-configuration/, где это имя секрета.
И наконец, обратите внимание на секцию config, где мы говорим, что Apache Kafka Connect использует FileConfigProvider в качестве провайдера конфигурации:
config: config.providers: file config.providers.file.class: org.apache.kafka.common.config.provider.FileConfigProvider
Провайдер конфигурации это такой способ не прописывать параметры непосредственно в конфигурации, а брать их из другого источника. В нашем случае мы создаем провайдера конфигурации с именем file, который будет использовать класс FileConfigProvider. Этот провайдер входит в состав Apache Kafka. FileConfigProvider может читать файлы свойств и извлекать из них значения, и мы будем использовать его для загрузки API-ключей для нашей учетной записи Amazon AWS.
Создаем коннектор, используя Apache Kafka Connect REST API
Обычно надо подождать минуту-другую, пока выполнится развертывание Apache Kafka Connect, прежде чем создавать экземпляр коннектора. В предыдущих версиях Strimzi и Red Hat AMQ Streams для этого надо было использовать REST API. Теперь же мы можем создать коннектор, выполнив POST для следующего JSONа:
{ "name": "s3-connector", "config": { "connector.class": "org.apache.camel.kafkaconnector.CamelSourceConnector", "tasks.max": "1", "camel.source.kafka.topic": "s3-topic", "camel.source.maxPollDuration": "10000", "camel.source.url": "aws-s3://camel-connector-test?autocloseBody=false", "key.converter": "org.apache.kafka.connect.storage.StringConverter", "value.converter": "org.apache.camel.kafkaconnector.converters.S3ObjectConverter", "camel.component.aws-s3.configuration.access-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_access_key_id}", "camel.component.aws-s3.configuration.secret-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_secret_access_key}", "camel.component.aws-s3.configuration.region": "US_EAST_1" }}
Конфигурация коннектора содержит API-ключи AWS в полях camel.component.aws-s3.configuration.access-key и camel.component.aws-s3.configuration.secret-key. Вместо того, чтобы прописывать значения напрямую, мы просто ссылаемся на провайдер конфигурации file, чтобы загрузить поля aws_access_key_id и aws_secret_access_key из нашего файла aws-credentials.properties.
Обратите внимание, как именно мы ссылаемся на провайдера конфигурации: указываем путь к файлу, который надо использовать, и через двоеточие имя ключа, который надо извлечь, вот так:
"camel.component.aws-s3.configuration.access-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_access_key_id}"
И вот так:
"camel.component.aws-s3.configuration.secret-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_secret_access_key}"
Выполнить POST этих результатов в Apache Kafka Connect REST API можно, например, с помощью команды curl
$ curl -X POST -H "Content-Type: application/json" -d connector-config.json http://my-connect-cluster-connect-api:8083/connectors
Одно из преимуществ провайдеров конфигурации заключается в том, что они позволят не светить те параметры конфигурации, которые нужно держать в секрете:
$ curl http://my-connect-cluster-connect-api:8083/connectors/s3-connector{ "name": "s3-connector", "config": { "connector.class": "org.apache.camel.kafkaconnector.CamelSourceConnector", "camel.source.maxPollDuration": "10000", "camel.source.url": "aws-s3://camel-connector-test?autocloseBody=false", "camel.component.aws-s3.configuration.region": "US_EAST_1", "camel.component.aws-s3.configuration.secret-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_secret_access_key}", "tasks.max": "1", "name": "s3-connector", "value.converter": "org.apache.camel.kafkaconnector.converters.S3ObjectConverter", "camel.component.aws-s3.configuration.access-key": "${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_access_key_id}", "key.converter": "org.apache.kafka.connect.storage.StringConverter", "camel.source.kafka.topic": "s3-topic" }, "tasks": [ { "connector": "s3-connector", "task": 0 } ], "type": "source"}
Создаем коннектор при помощи оператора Strimzi
Начиная с версии 0.16.0 в Strimzi также появился новый оператор для создания коннекторов с использованием следующего пользовательского YAML ресурса(в KafkaConnector можно напрямую использовать и провайдер конфигурации):
apiVersion: kafka.strimzi.io/v1alpha1kind: KafkaConnectormetadata: name: s3-connector labels: strimzi.io/cluster: my-connect-clusterspec: class: org.apache.camel.kafkaconnector.CamelSourceConnector tasksMax: 1 config: key.converter: org.apache.kafka.connect.storage.StringConverter value.converter: org.apache.camel.kafkaconnector.converters.S3ObjectConverter camel.source.kafka.topic: s3-topic camel.source.url: aws-s3://camel-connector-test?autocloseBody=false camel.source.maxPollDuration: 10000 camel.component.aws-s3.configuration.access-key: ${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_access_key_id} camel.component.aws-s3.configuration.secret-key: ${file:/opt/kafka/external-configuration/aws-credentials/aws-credentials.properties:aws_secret_access_key} camel.component.aws-s3.configuration.region: US_EAST_1
Подводим итоги
У безопасности секретов в Kubernetes есть свои ограничения, и любой пользователь с правами на выполнение внутри контейнера в любом случае сможет прочитать подключенные секреты. Но описанный в данной статье способ как минимум позволяет не раскрывать учетные данные, API-ключи и другие секретные сведения при использовании REST API или пользовательских ресурсов в KafkaConnector.