はじめに
クリアコードはFluentdの開発に参加しています。 Fluentdのプラグインの中で、AWSのkinesisというサービスに対応するプラグイン(fluent-plugin-kinesis)があります。 このプラグインはEKS(AWSのマネージドk8sサービス)でのPod毎に認証トークンを紐づける仕組み(IRSA)に対応していませんでした。 fluent-plugin-kinesisでIRSAによってサービスへのアクセスをEKS上からできるようにした話を書きます。
IAM Roles for Service Accounts (IRSA)という機能はAWSのIAMという概念が分かっていないと解説するのが難しいのでまずは軽く解説します。 その後に、IRSA対応をFluentdプラグインでやるにはどのようにするといいかを解説します。
IAMとは
IAMとはパスワードやアクセスキーを共有せず、柔軟なアクセス制限をユーザーに対して行う仕組みです。 このIAMを使うことで非rootユーザーを作成し、必要な権限を必要なだけユーザーに付与できます。 S3を参照できるだけのIAMを作成しある非rootユーザーに紐付けると、そのユーザーはS3のバケットのコンテンツしか参照することができない、という状態を作ることができます。
IAM Roles for Service Accounts (IRSA)とは
IAM Roles for Service Accounts (IRSA)という機能はIAMの認証情報をEKS上のPod毎に割り当てられるようにする仕組みです。 1 k8s上でIAMを割り当てる仕組みはkube2iam、kiamなどがあります。 kube2iamに関してはワーカーにIAMを割り当てます。 kiamはノード全体に対してIAMを割り当てます。 これらのFLOSSのソリューションに対して、 IRSAではPodに対してIAMを割り当てられるようになっています。 つまり、Pod毎に最小のIAMロールを与えることが可能になります。
EKSクラスターを準備する
IRSAはAWSのEKSクラスターのPod内の認証方法なので、EKSクラスターを立ち上げます。
EKSクラスターの操作に必要なツールの準備
Amazon EKSクラスターの操作にはawsコマンドのインストールとkubernetesの操作を行うためのkubectlのインストールとAWS EKSのクラスターの操作のためのeksctlのインストールがそれぞれ必要です。
aws cli
、kubectl
、eksctl
がそれぞれインストールされたものとして認証情報を入れ込んでいきます。
awsコマンドに認証情報を入れるには、
$ aws configure [--profile awesome_profile]
として対話的にアクセスキーID、シークレットを入力します。
defaultプロファイルではないプロファイルを作成して認証情報を作成する際には--profile profile_name
オプションを追加してください。
無事に入力が完了すると、aws configure list
を実行すると以下の表示になります
$ aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> None None
access_key ****************MPLE shared-credentials-file
secret_key ****************mPlE shared-credentials-file
region ap-northeast-1 config-file ~/.aws/config
ここでは東京リージョンをデフォルトリージョンとして設定しています。
EKSクラスターのデプロイ
AWSにEKSクラスターをデプロイしてみます。kinesis-eks
という名前のk8s 1.17のクラスターをデプロイします。
$ eksctl create cluster --name kinesis-eks --approve
[ℹ] eksctl version 0.29.1
[ℹ] using region ap-northeast-1
[ℹ] setting availability zones to [ap-northeast-1d ap-northeast-1c ap-northeast-1a]
[ℹ] subnets for ap-northeast-1d - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ] subnets for ap-northeast-1c - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ] subnets for ap-northeast-1a - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ] nodegroup "ng-cb168d52" will use "ami-0aa15614ef924fd1e" [AmazonLinux2/1.17]
[ℹ] using Kubernetes version 1.17
[ℹ] creating EKS cluster "kinesis-eks" in "ap-northeast-1" region with un-managed nodes
[ℹ] will create 2 separate CloudFormation stacks for cluster itself and the initial nodegroup
[ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-1 --cluster=kinesis-eks'
[ℹ] CloudWatch logging will not be enabled for cluster "kinesis-eks" in "ap-northeast-1"
[ℹ] you can enable it with 'eksctl utils update-cluster-logging --enable-types={SPECIFY-YOUR-LOG-TYPES-HERE (e.g. all)} --region=ap-northeast-1 --cluster=kinesis-eks'
[ℹ] Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "kinesis-eks" in "ap-northeast-1"
[ℹ] 2 sequential tasks: { create cluster control plane "kinesis-eks", 2 sequential sub-tasks: { no tasks, create nodegroup "ng-cb168d52" } }
[ℹ] building cluster stack "eksctl-kinesis-eks-cluster"
[ℹ] deploying stack "eksctl-kinesis-eks-cluster"
[ℹ] building nodegroup stack "eksctl-kinesis-eks-nodegroup-ng-cb168d52"
[ℹ] --nodes-min=2 was set automatically for nodegroup ng-cb168d52
[ℹ] --nodes-max=2 was set automatically for nodegroup ng-cb168d52
[ℹ] deploying stack "eksctl-kinesis-eks-nodegroup-ng-cb168d52"
[ℹ] waiting for the control plane availability...
[✔] saved kubeconfig as "~/.kube/config"
[ℹ] no tasks
[✔] all EKS cluster resources for "kinesis-eks" have been created
[ℹ] adding identity "arn:aws:iam::788574296432:role/eksctl-kinesis-eks-nodegroup-ng-c-NodeInstanceRole-J3Y9CGYRQ8MB" to auth ConfigMap
[ℹ] nodegroup "ng-cb168d52" has 0 node(s)
[ℹ] waiting for at least 2 node(s) to become ready in "ng-cb168d52"
[ℹ] nodegroup "ng-cb168d52" has 2 node(s)
[ℹ] node "ip-192-168-53-252.ap-northeast-1.compute.internal" is ready
[ℹ] node "ip-192-168-6-22.ap-northeast-1.compute.internal" is ready
[ℹ] kubectl command should work with "~/.kube/config", try 'kubectl get nodes'
[✔] EKS cluster "kinesis-eks" in "ap-northeast-1" region is ready
数十分待つと、デプロイが完了しました。
$ eksctl utils associate-iam-oidc-provider --cluster kinesis-eks --approve
[ℹ] eksctl version 0.29.1
[ℹ] using region ap-northeast-1
[ℹ] will create IAM Open ID Connect provider for cluster "kinesis-eks" in "ap-northeast-1"
[✔] created IAM Open ID Connect provider for cluster "kinesis-eks" in "ap-northeast-1"
デプロイできました。
IRSAで利用するIAMの認証情報を保持するサービスアカウントもEKSクラスターへデプロイしましょう。 KinesisプラグインのIRSA認証を試すのに、今回はKinesis Data Firehoseというサービスを使ってIRSA認証の動作確認をします。 この記事ではポリシーの作成手順を省略するため、AWS Kinesis Firehoseサービスを全て制御できる既存のポリシーを利用します。
従って、この記事で作成するEKSクラスタに作成するサービスアカウントに紐付けるKinesis Firehoseの権限にはarn:aws:iam::aws:policy/AmazonKinesisFirehoseFullAccessを指定します。 2
$ eksctl create iamserviceaccount --name kinesis-eks-serviceaccount --namespace default --cluster kinesis-eks --attach-policy-arn arn:aws:iam::aws:policy/AmazonKinesisFirehoseFullAccess --approve
[ℹ] eksctl version 0.29.1
[ℹ] using region ap-northeast-1
[ℹ] 1 existing iamserviceaccount(s) (kube-system/aws-node) will be excluded
[ℹ] 1 iamserviceaccount (default/kinesis-eks-serviceaccount) was included (based on the include/exclude rules)
[ℹ] 1 iamserviceaccount (kube-system/aws-node) was excluded (based on the include/exclude rules)
[!] serviceaccounts that exists in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
[ℹ] 1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount "default/kinesis-eks-serviceaccount", create serviceaccount "default/kinesis-eks-serviceaccount" } }
[ℹ] building iamserviceaccount stack "eksctl-kinesis-eks-addon-iamserviceaccount-default-kinesis-eks-serviceaccount"
[ℹ] deploying stack "eksctl-kinesis-eks-addon-iamserviceaccount-default-kinesis-eks-serviceaccount"
[ℹ] created serviceaccount "default/kinesis-eks-serviceaccount"
kubectlでサービスアカウントが作成できているかを確認します。
$ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 17m
kinesis-eks-serviceaccount 1 3m42s
サービスアカウントが作成できていることが確認できました。
ここまでで、IRSAの動作確認をするためのEKSクラスターを立てることができました。
fluent-plugin-kinesisにIRSA対応を入れる
fluent-plugin-kinesisの開発元には、この記事を執筆している時点ではIRSA対応が入っていません。 AWS SDK Rubyのドキュメントを参照すると、IRSAの認証トークンを処理するクラスはAws::AssumeRoleWebIdentityCredentialsクラスであることがわかります。 つまり、このIRSAを処理するクラスを使って認証情報を取得すると良いことになります。
fluent-plugin-kinesisではAWSの認証情報を取り扱う共通モジュールがあります。
このモジュールにはAws::AssumeRoleWebIdentityCredentials
クラスを扱うコードパスがないため、以下のようにしてそのコードパスを追加します。
diff --git a/lib/fluent/plugin/kinesis_helper/client.rb b/lib/fluent/plugin/kinesis_helper/client.rb
index ba6da75..6870883 100644
--- a/lib/fluent/plugin/kinesis_helper/client.rb
+++ b/lib/fluent/plugin/kinesis_helper/client.rb
@@ -46,6 +46,20 @@ module Fluent
desc "A URL for a regional STS API endpoint, the default is global"
config_param :sts_endpoint_url, :string, default: nil
end
+ # Refer to the following link for additional parameters that could be added:
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/STS/Client.html#assume_role_with_web_identity-instance_method
+ config_section :web_identity_credentials, multi: false do
+ desc "The Amazon Resource Name (ARN) of the role to assume"
+ config_param :role_arn, :string
+ desc "An identifier for the assumed role session"
+ config_param :role_session_name, :string
+ desc "The absolute path to the file on disk containing the OIDC token"
+ config_param :web_identity_token_file, :string, default: nil #required
+ desc "An IAM policy in JSON format"
+ config_param :policy, :string, default: nil
+ desc "The duration, in seconds, of the role session (900-43200)"
+ config_param :duration_seconds, :time, default: nil
+ end
config_section :instance_profile_credentials, multi: false do
desc "Number of times to retry when retrieving credentials"
config_param :retries, :integer, default: nil
@@ -149,6 +163,17 @@ module Fluent
credentials_options[:client] = Aws::STS::Client.new(region: @region)
end
options[:credentials] = Aws::AssumeRoleCredentials.new(credentials_options)
+ when @web_identity_credentials
+ c = @web_identity_credentials
+ credentials_options[:role_arn] = c.role_arn
+ credentials_options[:role_session_name] = c.role_session_name
+ credentials_options[:web_identity_token_file] = c.web_identity_token_file
+ credentials_options[:policy] = c.policy if c.policy
+ credentials_options[:duration_seconds] = c.duration_seconds if c.duration_seconds
+ if @region
+ credentials_options[:client] = Aws::STS::Client.new(:region => @region)
+ end
+ options[:credentials] = Aws::AssumeRoleWebIdentityCredentials.new(credentials_options)
when @instance_profile_credentials
c = @instance_profile_credentials
credentials_options[:retries] = c.retries if c.retries
これで、以下のように<web_identity_credentials>
セクションを記入すると、IRSAによる認証情報がkinesisプラグインに渡されるようになります。
region ap-northeast-1
<web_identity_credentials>
role_arn "#{ENV['AWS_ROLE_ARN']}"
role_session_name test-kinesis-session-name
web_identity_token_file "#{ENV['AWS_WEB_IDENTITY_TOKEN_FILE']}"
</web_identity_credentials>
動作確認用のDockerコンテナを作成する
EKSにPodとして載せるのであれば、Dockerコンテナを作成する必要があります。 Dockerコンテナとしても動くようにするため、設定ファイルは自己完結的にします。
FROM fluent/fluentd:v1.11.3-debian-1.0
LABEL maintainer="Hiroshi Hatake <hatake@clear-code.com>"
USER root
WORKDIR /home/fluent
ENV PATH /fluentd/vendor/bundle/ruby/2.6.0/bin:$PATH
ENV GEM_PATH /fluentd/vendor/bundle/ruby/2.6.0
ENV GEM_HOME /fluentd/vendor/bundle/ruby/2.6.0
# skip runtime bundler installation
ENV FLUENTD_DISABLE_BUNDLER_INJECTION 1
COPY Gemfile* /fluentd/
COPY fluent-plugin-kinesis-*.gem /fluentd/
RUN buildDeps="sudo make gcc g++ libc-dev libffi-dev" \
runtimeDeps="" \
&& apt-get update \
&& apt-get upgrade -y \
&& apt-get install \
-y --no-install-recommends \
$buildDeps $runtimeDeps net-tools \
&& gem install /fluentd/fluent-plugin-kinesis-*.gem --no-document \
&& gem sources --clear-all \
&& SUDO_FORCE_REMOVE=yes \
apt-get purge -y --auto-remove \
-o APT::AutoRemove::RecommendsImportant=false \
$buildDeps \
&& rm -rf /var/lib/apt/lists/* \
&& gem sources --clear-all \
&& rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem
# Copy configuration files
COPY ./conf/fluent.conf /fluentd/etc/
COPY ./conf/conf.d/* /fluentd/etc/conf.d/
# Copy plugins
# COPY plugins /fluentd/plugins/
COPY entrypoint.sh /fluentd/entrypoint.sh
# Environment variables
ENV FLUENTD_OPT=""
ENV FLUENTD_CONF="fluent.conf"
# Overwrite ENTRYPOINT to run fluentd as root for /var/log / /var/lib
ENTRYPOINT ["tini", "--", "/fluentd/entrypoint.sh"]
設定ファイルなどは以下。
entrypoint.sh
Dockerコンテナのエントリポイントのスクリプトを作成します。
#!/usr/bin/env sh
exec fluentd -c /fluentd/etc/${FLUENTD_CONF} -p /fluentd/plugins --gemfile /fluentd/Gemfile ${FLUENTD_OPT}
conf/fluent.conf
@include conf.d/*.conf
<label @mainstream>
<match **>
@type kinesis_firehose
@id out_kinesis_firehose
region ap-northeast-1
delivery_stream_name "#{ENV['FIREHOSE_STREAM_NAME'] || fluentd-streams}"
<web_identity_credentials>
role_arn "#{ENV['AWS_ROLE_ARN']}"
role_session_name test-kinesis-session-name
web_identity_token_file "#{ENV['AWS_WEB_IDENTITY_TOKEN_FILE']}"
</web_identity_credentials>
<buffer>
flush_interval 10s
chunk_limit_size 1m
flush_thread_burst_interval 1
flush_thread_count 2
</buffer>
</match>
</label>
conf/conf.d/source.conf
<source>
@type forward
@id input1
@label @mainstream
port 24224
</source>
<source>
@type sample
@label @mainstream
rate 1
tag raw.sample
</source>
<filter **>
@type stdout
</filter>
コンテナをビルドします。 今回はテスト用のコンテナを登録するリポジトリをDockerHubに作成しておきました。
$ docker build . -t cosmo0920/fluent-plugin-kinesis-test:latest
Sending build context to Docker daemon 57.86kB
Step 1/17 : FROM fluent/fluentd:v1.11.3-debian-1.0
---> 2f58cab1fbc5
Step 2/17 : LABEL maintainer="Hiroshi Hatake <hatake@clear-code.com>"
---> Using cache
---> e764fb51b05e
Step 3/17 : USER root
---> Using cache
---> ad1cbc950fc4
Step 4/17 : WORKDIR /home/fluent
---> Using cache
---> 6ab5210d0cca
Step 5/17 : ENV PATH /fluentd/vendor/bundle/ruby/2.6.0/bin:$PATH
---> Using cache
---> f73ed93424a7
Step 6/17 : ENV GEM_PATH /fluentd/vendor/bundle/ruby/2.6.0
---> Using cache
---> 8934937eb22c
Step 7/17 : ENV GEM_HOME /fluentd/vendor/bundle/ruby/2.6.0
---> Using cache
---> 1576b82df73b
Step 8/17 : ENV FLUENTD_DISABLE_BUNDLER_INJECTION 1
---> Using cache
---> a7e2b0997fc1
Step 9/17 : COPY Gemfile* /fluentd/
---> Using cache
---> df851794c5a0
Step 10/17 : COPY fluent-plugin-kinesis-*.gem /fluentd/
---> Using cache
---> 9e7ad33fb02c
Step 11/17 : RUN buildDeps="sudo make gcc g++ libc-dev libffi-dev" runtimeDeps="" && apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends $buildDeps $runtimeDeps net-tools && gem install /fluentd/fluent-plugin-kinesis-*.gem --no-document && gem sources --clear-all && SUDO_FORCE_REMOVE=yes apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps && rm -rf /var/lib/apt/lists/* && gem sources --clear-all && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem
---> Using cache
---> 557e659729b6
Step 12/17 : COPY ./conf/fluent.conf /fluentd/etc/
---> 56e9c62c231a
Step 13/17 : COPY ./conf/conf.d/* /fluentd/etc/conf.d/
---> a2206c909b34
Step 14/17 : COPY entrypoint.sh /fluentd/entrypoint.sh
---> 5d4646527c9a
Step 15/17 : ENV FLUENTD_OPT=""
---> Running in 00794bc3a32a
Removing intermediate container 00794bc3a32a
---> 6a5a3dc5496b
Step 16/17 : ENV FLUENTD_CONF="fluent.conf"
---> Running in aa963bc519be
Removing intermediate container aa963bc519be
---> 572c5a904178
Step 17/17 : ENTRYPOINT ["tini", "--", "/fluentd/entrypoint.sh"]
---> Running in d68c0af31d16
Removing intermediate container d68c0af31d16
---> c765c2784157
Successfully built c765c2784157
Successfully tagged cosmo0920/fluent-plugin-kinesis-test:latest
テスト用のコンテナを登録するリポジトリにビルドしたDockerイメージをプッシュします。
$ docker push cosmo0920/fluent-plugin-kinesis-test:latest
The push refers to repository [docker.io/cosmo0920/fluent-plugin-kinesis-test]
456dfd0e8641: Pushed
77a5ea4872ea: Pushed
0270d19e61c5: Pushed
59b09b04fdb6: Layer already exists
24cc1822f3a7: Layer already exists
584adec8072e: Layer already exists
b836309a29a2: Layer already exists
6326e503330a: Layer already exists
781b24f9ba07: Layer already exists
1302bac58683: Layer already exists
1563364acccb: Layer already exists
04cbaaf60ef1: Layer already exists
2e9de320a378: Layer already exists
15364b93b273: Layer already exists
d85310698a88: Layer already exists
07cab4339852: Layer already exists
latest: digest: sha256:17c80a7d68941636921fb4e31297b1d37c85a87e1fdf04f6c99c06dd4419f08a size: 3659
EKSクラスタを用いて動作確認する
動作確認に用いたFirehoseのサービスの構成
AWS Kinesis Data Firehoseはストリーム名をfluentd-streams
、配信先をS3のfluentd-eks-firehose
バケットに、送信方法はDirect PUT and other sourcesを指定してあります。
今回の記事はIRSA対応を主に解説したい記事のため、設定方法の解説は省略します。
k8sのPodとその周辺の定義ファイルを用意する
k8sではConfigMapにより、Podで使用する設定ファイルなどの内容を差し替える機能があります。
作成したテスト用Dockerfileでも動作確認を行うことは可能ですが、in_sample
からのサンプルイベントを流した時に標準出力でイベントの内容を確認できない状態になっているため、その辺りを修正したConfigMapを定義します。
また、fluent-plugin-kinesisが動作するEKSのPodにfirehoseのIRSAの認証情報をアタッチしたいため、このサービスアカウントの情報もPodの定義ファイルに記入します。
deployment.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
namespace: default
labels:
k8s-app: fluentd-logging
version: v1
data:
fluent.conf: |
<source>
@type forward
@id input1
@label @mainstream
port 24224
</source>
<source>
@type sample
@label @mainstream
rate 1
tag raw.sample
</source>
<label @mainstream>
<filter **>
@type stdout
</filter>
<match **>
@type kinesis_firehose
@id out_kinesis_firehose
region ap-northeast-1
delivery_stream_name fluentd-streams
<web_identity_credentials>
role_arn "#{ENV['AWS_ROLE_ARN']}"
role_session_name test-kinesis-session-name
web_identity_token_file "#{ENV['AWS_WEB_IDENTITY_TOKEN_FILE']}"
</web_identity_credentials>
<buffer>
flush_interval 10s
chunk_limit_size 1m
flush_thread_burst_interval 1
flush_thread_count 2
</buffer>
</match>
</label>
---
apiVersion: v1
kind: Pod
metadata:
name: fluentd-kinesis-test
namespace: default
labels:
k8s-app: fluentd-logging
version: v1
spec:
serviceAccountName: kinesis-eks-serviceaccount
containers:
- image: docker.io/cosmo0920/fluent-plugin-kinesis-test:latest
name: fluentd-kinesis-test
volumeMounts:
- name: config-volume
mountPath: /fluentd/etc
volumes:
- name: config-volume
configMap:
name: fluentd-config
EKSクラスタにデプロイします。
$ kubectl apply -f deployment.yaml
configmap/fluentd-config created
pod/fluentd-kinesis-test created
デプロイした直後はコンテナが作成されているという表示になります。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
fluentd-kinesis-test 0/1 ContainerCreating 0 10s
しばらく経つと、STATUS
がRunning
に変わります。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
fluentd-kinesis-test 1/1 Running 0 14s
fluent-kinesis-test
という名前のPodのログを取得してみます。
$ kubectl logs fluentd-kinesis-test
2020-10-15 08:21:16 +0000 [info]: parsing config file is succeeded path="/fluentd/etc/fluent.conf"
2020-10-15 08:21:16 +0000 [info]: gem 'fluent-plugin-kinesis' version '3.2.3'
2020-10-15 08:21:16 +0000 [info]: gem 'fluentd' version '1.11.4'
2020-10-15 08:21:16 +0000 [warn]: both of Plugin @id and path for <storage> are not specified. Using on-memory store.
2020-10-15 08:21:16 +0000 [warn]: both of Plugin @id and path for <storage> are not specified. Using on-memory store.
2020-10-15 08:21:16 +0000 [info]: using configuration file: <ROOT>
<source>
@type forward
@id input1
@label @mainstream
port 24224
</source>
<source>
@type sample
@label @mainstream
rate 1
tag "raw.sample"
</source>
<label @mainstream>
<filter **>
@type stdout
</filter>
<match **>
@type kinesis_firehose
@id out_kinesis_firehose
region "ap-northeast-1"
delivery_stream_name "fluentd-streams"
<web_identity_credentials>
role_arn "arn:aws:iam::123456789012:role/eksctl-kinesis-eks-addon-iamserviceaccount-d-Role1-SUPERPOWER"
role_session_name "test-kinesis-session-name"
web_identity_token_file "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
</web_identity_credentials>
<buffer>
flush_interval 10s
chunk_limit_size 1m
flush_thread_burst_interval 1
flush_thread_count 2
</buffer>
</match>
</label>
</ROOT>
2020-10-15 08:21:16 +0000 [info]: starting fluentd-1.11.4 pid=6 ruby="2.6.6"
2020-10-15 08:21:16 +0000 [info]: spawn command to main: cmdline=["/usr/local/bin/ruby", "-Eascii-8bit:ascii-8bit", "/fluentd/vendor/bundle/ruby/2.6.0/bin/fluentd", "-c", "/fluentd/etc/fluent.conf", "-p", "/fluentd/plugins", "--gemfile", "/fluentd/Gemfile", "--under-supervisor"]
2020-10-15 08:21:17 +0000 [info]: adding filter in @mainstream pattern="**" type="stdout"
2020-10-15 08:21:17 +0000 [info]: adding match in @mainstream pattern="**" type="kinesis_firehose"
2020-10-15 08:21:17 +0000 [info]: adding source type="forward"
2020-10-15 08:21:17 +0000 [info]: adding source type="sample"
2020-10-15 08:21:17 +0000 [warn]: #0 both of Plugin @id and path for <storage> are not specified. Using on-memory store.
2020-10-15 08:21:17 +0000 [warn]: #0 both of Plugin @id and path for <storage> are not specified. Using on-memory store.
2020-10-15 08:21:17 +0000 [info]: #0 starting fluentd worker pid=11 ppid=6 worker=0
2020-10-15 08:21:17 +0000 [info]: #0 [input1] listening port port=24224 bind="0.0.0.0"
2020-10-15 08:21:17 +0000 [info]: #0 fluentd worker is now running worker=0
2020-10-15 08:21:18.081312494 +0000 raw.sample: {"message":"sample"}
2020-10-15 08:21:19.082577481 +0000 raw.sample: {"message":"sample"}
2020-10-15 08:21:20.083657521 +0000 raw.sample: {"message":"sample"}
2020-10-15 08:21:21.084679969 +0000 raw.sample: {"message":"sample"}
# ...
しばらくすると、S3にfirehoseに入れられたログが入れられます。
aws s3 ls
コマンドを実行すると、バケットが作成されていることが分かります。
$ aws s3 ls
# ...
2020-10-15 11:52:43 fluentd-eks-firehose
ここまでで、下記のAWS Kinesis FirehoseによるS3へのログの送信の動作が確認できました。
Fluentd Kinesis plugin Pod ---> AWS Kinesis Data Firehose ---> S3 bucket
EKSクラスタを削除する
動作確認が終了したので、EKSクラスタを削除します。
$ eksctl delete cluster --name kinesis-eks
[ℹ] eksctl version 0.29.1
[ℹ] using region ap-northeast-1
[ℹ] deleting EKS cluster "kinesis-eks"
[ℹ] deleted 0 Fargate profile(s)
[✔] kubeconfig has been updated
[ℹ] cleaning up AWS load balancers created by Kubernetes objects of Kind Service or Ingress
[ℹ] 3 sequential tasks: { delete nodegroup "ng-cb168d52", 2 sequential sub-tasks: { 2 sequential sub-tasks: { delete IAM role for serviceaccount "default/kinesis-eks-serviceaccount", delete serviceaccount "default/kinesis-eks-serviceaccount" }, delete IAM OIDC provider }, delete cluster control plane "kinesis-eks" [async] }
[ℹ] will delete stack "eksctl-kinesis-eks-nodegroup-ng-cb168d52"
[ℹ] waiting for stack "eksctl-kinesis-eks-nodegroup-ng-cb168d52" to get deleted
[ℹ] will delete stack "eksctl-kinesis-eks-addon-iamserviceaccount-default-kinesis-eks-serviceaccount"
[ℹ] waiting for stack "eksctl-kinesis-eks-addon-iamserviceaccount-default-kinesis-eks-serviceaccount" to get deleted
[ℹ] deleted serviceaccount "default/kinesis-eks-serviceaccount"
[ℹ] will delete stack "eksctl-kinesis-eks-cluster"
[✔] all cluster resources were deleted
kinesis-eks
という名前のEKSクラスタは削除されました。
開発元にIRSA対応のパッチをフィードバック
作成したIRSA対応のパッチにについてはkinesisプラグインの開発元にフィードバック済みです。 https://github.com/awslabs/aws-fluent-plugin-kinesis/pull/208 Issueチケットも前後してしまいましたが、切っています。 https://github.com/awslabs/aws-fluent-plugin-kinesis/issues/209
この記事では解説していませんがIRSA対応を行うにあたって、テストコードの追加も行っていますので興味のある方は上記URLから確認してみてください。
まとめ
fluent-plugin-kinesisのIRSA対応を実施した話を説明してみました。
AWSでは全てのリソースへリソースネーム(ARN)が振られています。
このリソースネームはEKSクラスタ上に作成したサービスアカウントにも振られています。
IRSAの仕組みに載っかってPodにサービスアカウントを紐づけると、動作しているPodにはAWS_ROLE_ARN
環境変数とAWS_WEB_IDENTITY_TOKEN_FILE
環境変数が紐づきます。
これらにより、それぞれサービスアカウントに紐づいたリソースネーム(ARN)と認証情報が記載されたファイルパスが参照可能になります。
この二つの環境変数はサービスアカウントを紐付けたPodであれば自動的に付与される情報のため、
EKSクラスターを使用するユーザーは定義ファイルにてこれら二つの環境変数を参照すると、適切な認証情報をPod内のプログラムに与えることができます。
当社では、お客さまからの技術的なご質問・ご依頼に有償にて対応するFluentdサポートサービスを提供しています。Fluentd/Fluent Bitをエンタープライズ環境において導入/運用されるSIer様、サービス提供事業者様は、お問い合わせフォームよりお問い合わせください。
-
公式の詳細な解説記事はこちらです: https://aws.amazon.com/jp/blogs/news/introducing-fine-grained-iam-roles-service-accounts/ ↩
-
当然のことながら、プロダクションで使う際にはFullAccessの権限ではなく、より細分化したIAM Roleのarnを指定するべきです ↩