ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

Amazon OpenSearch Service を使ってみてハマったところまとめ

Amazon OpenSearch Service を導入しようとしてハマったところをまとめます。
記事を残してくれた数多くの人に感謝です。

ハマったところいっぱいあったんですが、
逐一メモっていなかったので思い出した順に書いていきます。

↓ 前回の Amazon OpenSearch Service 関連の記事

nekonenene.hatenablog.com

CloudWatch Logs を OpenSearch に送る Lambda 処理でエラーが出る件

f:id:nekonenene:20211113064330p:plain

CloudWatch Logs データの Amazon OpenSearch Service へのストリーミング - Amazon CloudWatch Logs』に従って進めて、
CloudWatch から OpenSearch Service にログを流すサブスクリプションフィルターを作ったあと、
最初はまずログが出せなくて困りました。

Lambda の Role に AWSLambdaBasicExecutionRole Policy をアタッチして解決しました。
いつも Lambda を新規作成する場合は勝手に作られるからその作業抜けてた。

で、ログ出すようになったら困ったのが以下のようなエラーが出ること。
どうも権限周りの話らしい。

{
    "errorType": "Error",
    "errorMessage": "{\"statusCode\":403,\"responseBody\":{\"error\":{\"root_cause\":[{\"type\":\"security_exception\",\"reason\":\"no permissions for [indices:data/write/bulk] and User [name=arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda, backend_roles=[arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda], requestedTenant=null]\"}],\"type\":\"security_exception\",\"reason\":\"no permissions for [indices:data/write/bulk] and User [name=arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda, backend_roles=[arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda], requestedTenant=null]\"},\"status\":403}}",
    "stack": [
        "Error: {\"statusCode\":403,\"responseBody\":{\"error\":{\"root_cause\":[{\"type\":\"security_exception\",\"reason\":\"no permissions for [indices:data/write/bulk] and User [name=arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda, backend_roles=[arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda], requestedTenant=null]\"}],\"type\":\"security_exception\",\"reason\":\"no permissions for [indices:data/write/bulk] and User [name=arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda, backend_roles=[arn:aws:iam::123456781234:role/ControlOpenSearchTestFromLambda], requestedTenant=null]\"},\"status\":403}}",
        "    at _homogeneousError (/var/runtime/CallbackContext.js:12:12)",
        "    at postError (/var/runtime/CallbackContext.js:29:54)",
        "    at done (/var/runtime/CallbackContext.js:58:7)",
        "    at fail (/var/runtime/CallbackContext.js:70:7)",
        "    at Object.fail (/var/runtime/CallbackContext.js:106:16)",
        "    at /var/task/index.js:43:25",
        "    at IncomingMessage.<anonymous> (/var/task/index.js:177:13)",
        "    at IncomingMessage.emit (events.js:326:22)",
        "    at endReadableNT (_stream_readable.js:1241:12)",
        "    at processTicksAndRejections (internal/process/task_queues.js:84:21)"
    ]
}

https://aws.amazon.com/jp/premiumsupport/knowledge-center/opensearch-troubleshoot-cloudwatch-logs を読んだら解決方法が書いてあって、
OpenSearch の管理画面から all_access Role に User と Backend role の両方で
AWS Role を当ててあげると解決するらしいので修正。

f:id:nekonenene:20211113065312p:plain

ちなみに、Backend role だけ割り当てると次に紹介するエラーが起こるので注意。

とりあえず上手くいって、じゃあ次に他のロググループからも同様に OpenSearch にデータを送ろうと思いました。
同名の Lambda は作れないので、最初と違って
『Create Amazon OpenSearch Service subscription filter』ではなく
『Lambda サブスクリプションフィルターを作成』を選ぶ点に注意。

f:id:nekonenene:20211113065658p:plain

じゃあそれで作成して上手くいくかと思いきや、以下のエラーが!
原因が……わからない……!!!

{
    "errorType": "Error",
    "errorMessage": "{\"statusCode\":200,\"responseBody\":{\"took\":6,\"errors\":true}}",
    "stack": [
        "Error: {\"statusCode\":200,\"responseBody\":{\"took\":6,\"errors\":true}}",
        "    at _homogeneousError (/var/runtime/CallbackContext.js:12:12)",
        "    at postError (/var/runtime/CallbackContext.js:29:54)",
        "    at done (/var/runtime/CallbackContext.js:58:7)",
        "    at fail (/var/runtime/CallbackContext.js:70:7)",
        "    at Object.fail (/var/runtime/CallbackContext.js:106:16)",
        "    at /var/task/index.js:43:25",
        "    at IncomingMessage.<anonymous> (/var/task/index.js:177:13)",
        "    at IncomingMessage.emit (events.js:412:35)",
        "    at endReadableNT (internal/streams/readable.js:1317:12)",
        "    at processTicksAndRejections (internal/process/task_queues.js:82:21)"
    ]
}

ステータスコードが 200 なのにエラー……なかなか奥が深い状態です。

しばらく謎だったんですが、
こちら ↓ の記事が解答に導いてくれました。

qiita.com

複数の type を送れないようです。

ここを記事にあるように書き換えても、ロググループの名称は @log_group から取得できるのでご安心ください。

f:id:nekonenene:20211113070141p:plain

AWS コンソールから見られない箇所がある

AWSコンソールで OpenSearch Service の「クラスターの状態」が表示されない問題がありました。
とはいえ、これは明らかに権限エラーだと表示されていたのですぐ解決できました。

OpenSearch の Role の all_access に、IAMユーザー名を User としてマッピングすれば解決です。

こういうの。
arn:aws:iam::123456781234:user/nekonenene

f:id:nekonenene:20211113070654p:plain

ただ、IAMユーザーを1つずつ割り当てるのは面倒なので、
IAM Role と IAM Group を活用していい感じに出来るのでは、などと思ったりします。

Amazon OpenSearch Service のヘルスエラー

これはあるあるのようですが、
Elasticsearchのshardとreplica - なんかかきたい』の記事にあるように、
デフォルトだと number_of_shards の数が多いために
『割り当てられていないシャード』が多く発生し、
AWSコンソールで Amazon OpenSearch Service のヘルスエラーが表示されます。

対応は簡単で、Dev Tools から例えば

POST _template/cwl-2021.11.12
{
  "index_patterns": ["cwl-*"],
  "order": 1,
  "settings": {
    "index": {
      "number_of_shards" : 2
    }
  }
}

のようにおこない、 number_of_shards を減らします。

もちろん、本番運用でなくテスト運用の場合です。
本番運用する場合のオススメの設定については AWS が書いているので、以下の記事を参考にしましょう。

Amazon Elasticsearch Service ドメインを設定するベストプラクティス | Amazon Web Services ブログ

インデックスの登録場所がわかりにくい

Stack Management > Index patterns の順に進みます。
未来の自分も忘れそう。

インデックスの自動削除(Rotation)の仕方がわからない

Index Management > State management policies のページでポリシーを作成するのですが、
JSONで書かなければならず、マジでよくわかんなかったです。

この2つの記事のおかげで、無事に設定ができました。

Kibana を使ったことある方なら知っていることも多いんでしょうが、
自分は経験ないので大変でした。なんとか、なんとなくでやってます……ムズい……。
ようやくいろいろが終わって、データ分析に使えそうです。

AWS OpenSearch Dashboards に Google 認証でログインする方法

Amazon OpenSearch Service から作成した
AWS OpenSearch Dashboards に、Google 認証(Google Workspace を用いた SAML認証)でログインできるようにする方法を解説します。

1. Amazon OpenSearch Service のドメイン作成

まずはテスト用に適当に作成します。
カスタムエンドポイントを有効化する場合は、 Route 53 で CNAME 設定を入れることを忘れないようにします。(忘れてちょっとハマった)

カスタムエンドポイントを使用する場合の参考記事: https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/customendpoint.html

f:id:nekonenene:20211112215726p:plain

f:id:nekonenene:20211112215759p:plain

f:id:nekonenene:20211112220148p:plain

f:id:nekonenene:20211112220220p:plain

デフォルト設定から以上のような箇所を変更して作成しました。

作成後、画面上部に以下のようなメッセージが表示されます。
SAML設定をあとからおこなうのですが、このドメインの設定には時間がかかるので、その間に Google 側の設定を始めます。

f:id:nekonenene:20211112220351p:plain
SAML設定はあとからおこなう

2. Google 側の設定 その1

まず前提として、 Google Admin に入れる権限が必要です。
Google Workspace の管理者権限がない場合には付与してもらってください。

まず、ウェブアプリとモバイルアプリ のページから
「アプリを追加」>「カスタムSAMLアプリの追加」をおこないます。

f:id:nekonenene:20211112221937p:plain
カスタムSAMLアプリの追加

f:id:nekonenene:20211112221905p:plain

アプリの詳細をわかりやすいように設定した後、
次の画面で IdP メタデータをダウンロードできます。これはあとで使います。

なお、SAML アプリケーションに対するシングル サインオン(SSO)の設定 からもダウンロードできます。

続いて、サービスプロバイダの詳細を設定する画面に進みます。
ACS の URL」および「エンティティ ID」の入力を求められますが、
これは AWS 側の OpenSearch Service のドメイン作成が終わっている必要があるので、それを待ちます。

3. AWS OpenSearch Service の設定更新

AWS 側の OpenSearch Service のドメイン作成が終わっていたら、
ドメインの「セキュリティ設定の編集」に進みます。

f:id:nekonenene:20211112222608p:plain

再び「SAML 認証を有効化」のチェックをONにして、設定していきます。

ここの「サービスプロバイダーエンティティ ID」と「SP によって開始された SSO URL」は、このあとの 4. の工程で使います。

f:id:nekonenene:20211112223402p:plain
IdP メタデータをインポート

さて、「XMLファイルからインポート」のボタンから
2. の工程のときにダウンロードした IdP メタデータをアップロードします。

その後、その下の「SAML マスターユーザーネーム」の箇所に、
管理者として使いたい Google Workspace のメールアドレスを指定してあげてください。

アクセスポリシー」については、最初の作成時に誰もアクセスできないような設定で作っていたので、
誰でもアクセスできるように今度は変更します。

f:id:nekonenene:20211112224331p:plain
アクセスポリシーの変更

そうしたら「変更の保存」を押して完了です。

4. Google 側の設定 その2

ACS の URL」には、「SP によって開始された SSO URL」を設定します。
これが認証後のリダイレクト先です。 (例: https://search-opensearch-test-hogehoge.ap-northeast-1.es.amazonaws.com/dashboards/opendistro/_security/saml/acs

「エンティティID」には「サービスプロバイダーエンティティ ID」を設定します。
(例: https://search-opensearch-test-hogehoge.ap-northeast-1.es.amazonaws.com/dashboards/opendistro/_security/saml/acs

結果として、以下のようになります。

f:id:nekonenene:20211112233132p:plain
サービスプロバイダの詳細の設定

属性のマッピングは特に設定せず完了させます。

完了すると、以下のような画面になります。

f:id:nekonenene:20211112223835p:plain

この状態のままだと、まだユーザーアクセスが「オフ」になっていて誰もログインできないので、
ユーザーアクセス」の箇所をクリックして、
このアカウントのすべてのユーザー、もしくはユーザーグループ単位でアクセスを許可します。(「オン」にします)

5. ダッシュボードへのアクセス

ダッシュボード(OpenSearch Dashboards の URL)にアクセスしてみましょう。 (例: https://search-opensearch-test-hogehoge.ap-northeast-1.es.amazonaws.com/_dashboards

どの Google アカウントでログインするか選択する画面になるので、
3. の「SAML マスターユーザーネーム」で設定したメールアドレスを選択して、次の画面に進みます。

認証が許可されていない場合は以下のような 403 ページが表示されます。

もし、2. の「ユーザーアクセス」の設定を変更しているはずなのに表示される場合、
もう少し待ってから再度アクセスしてみてください。(GoogleSAML 設定が反映されるまでは数分かかるため。最長24時間かかると書かれていますが、さすがにそんなにはかからないはず)
それでもダメなら、4. の「ユーザーアクセス」の設定や「エンティティID」の設定が失敗していないか再度確認してみてください。

f:id:nekonenene:20211112224637p:plain

無事成功すると、Dashboard のトップ画面に進みます! おめでとうございます!

f:id:nekonenene:20211112233422p:plain
OpenSearch Dashboards へのログインが成功しました

6. ユーザーの招待

4. でユーザーアクセスを許可した人たちが Google ログインできるようになりましたが、
OpenSearch Dashboards のアカウントはまだ作られていないので、
3. で設定した「SAML マスターユーザーネーム」のメールアドレス以外でログインすると
Missing Role のエラーが表示されます。

f:id:nekonenene:20211112234437p:plain
OpenSearch Missing Role

SAML マスターユーザーネーム」のメールアドレスでログインした
管理者が、他のユーザーの登録をおこなっておく必要があります。

Amazon OpenSearch Service のきめ細かなアクセスコントロール - Amazon OpenSearch Service
のページを参照してください。

メニューから Security > Roles に進んで、その画面から例えば「all_access」のロールに対してユーザーをアサインします。

f:id:nekonenene:20211112235622p:plain
Security > Roles

ロールを選んで「Manage mapping」ボタンを押します。

f:id:nekonenene:20211112235758p:plain
Manage mapping

「Map user」の画面に進んだら、
権限を与えたいユーザーのメールアドレスを入力し、「Map」ボタンを押して保存します。

f:id:nekonenene:20211113000023p:plain
Map user の画面でメールアドレスを登録

なお、 Missing Role の画面からは Cookie などをいじらない限りログアウトできないという罠があるので、
もし他の Google アカウントでのログインを自身が試す場合は、
ログアウトせずに別の Web ブラウザから、他のアカウントを使ったログインを試すと良いです。

7. おわりに

公式ドキュメントには Okta を用いた SAML認証しか解説しておらず、
情報がなくてとってもとっても苦労したので、この記事を作成しました。

手順としてはそこまで複雑でないことが伝わったかと思います。
お役に立てましたら幸いです。

Slack のメッセージにチャンネル名やユーザーへのメンションを埋め込みたいとき

Slack App (Slack Bot) を書いているときに、毎度やり方わからなくなるのでここに置いておく。

https://api.slack.com/reference/surfaces/formatting にすべてが書いてある。

チャンネル名を入れ込む

https://api.slack.com/reference/surfaces/formatting#linking-channels に書いてある。
<#C024BE7LR> の形。

<# の後ろに Channel ID を入れて > で終わらせる形。

メンションを入れ込む

https://api.slack.com/reference/surfaces/formatting#mentioning-users に書いてある。
<@U024BE7LH> の形。

<@ の後ろに User ID を入れて > で終わらせる形。