AQ Tech Blog

OpenSearchのIAM認証によるcurlリクエストの注意点

作成者: tsuyoshi.watanabe|2023年11月28日

はじめに

クラウドインテグレーション部の渡邊です。
今回はAmazon OpenSearch Service (以降、OpenSearchと呼ぶ)の認証について説明します。
OpenSearchの接続時の認証はSAML、Cognito、IAM、Basicなどがありますが、今回はIAM認証を中心に取り上げます。
IAM認証で接続する際に、実行環境がEC2とECSで異なる点があるため、そちらについて触れます。
本記事の事前作業でロールマッピングを行って、その情報に基づいて制御します。

 

ロールマッピングについて補足

Elasticsearchディストリビューションである、Open Distroには独自の権限管理モデルがあります。
そのモデルには、ロールというOpenSearchへの権限をまとめた単位があります。
そのロールとAWSのIAMロールを結びつけることを、ロールマッピングといいます。
こちらを利用することで、IAMロールに基づいて、OpenSearchへの細かい権限制御を行うことができます。
よって、今回IAMロールで細かい権限制御を行うために、このロールマッピングというものを行う必要があります。

環境情報

  • OpenSearch 2.7
  • Amazon Linux 2023
  • AWS Fargate プラットフォームバージョン 1.4.0
  • php:8.1.9-fpm-bullseye
  • jq-1.6
  • curl 8.2.1 (ECS)
  • curl 8.0.1 (EC2)
    curlコマンドで--aws-sigv4フラグを使えるようにするために、7.75以上のバージョンが必要です。

事前準備

  • ECS

    • ロールマッピング用のECSのタスクロール(IAMロール)を用意
    • 公式ドキュメントを参考にECS Execができる環境を用意
      • 本筋ではないため設定の詳細は割愛しますが、動作環境を確認するためにAmazon ECS Exec Checkerが有用
  • EC2

    • ロールマッピング用のEC2インスタンスのIAMロールを用意
  • OpenSearch

    • きめ細かなアクセスコントロールを有効にしたOpenSearchを作成
      • ドメインアクセスポリシーの設定はきめ細かなアクセスコントロールのみを使用 
    • OpenSearchでロールマッピング設定
      • この時点ではIAMにより認証できないので、パスワード認証でロールマッピングを行います。
      • 以下にロールマッピングのコマンドを示します。

※事前に以下の環境変数を設定してください。

USERNAME=<マスターユーザ名>
PASSWORD=<マスターユーザパスワード>
ENDPOINT=<opensearchエンドポイント>
EC2_ROLE=<ec2にアタッチしたiamロールarn>
ECS_TASK_ROLE=<ECSにアタッチしたタスクロールARN>

ロールall_accessと、EC2のIAMロールおよびECSのタスクロールをロールマッピングします。
all_accessは、OpenSearchのクラスターに対するフルアクセス権限のあるロールです。

※補足 all_accessというロールがフルアクセス権限に対応するロールと説明しましたが、マスターユーザと同等の権限を得るためには不十分です。
マスターユーザと同等の権限を得るためには、ロールsecurity_managerall_accessを別途アタッチする必要があります。
以下のリクエスト例では、all_accessのみ権限を持つユーザによってリクエストした場合、ロールマッピング情報の取得に失敗しております。

$ curl -XGET -u "<all_access権限を持つユーザ>:<all_access権限を持つユーザのパスワード>" -H "Content-Type: application/json" "https://${ENDPOINT}:443/_plugins/_security/api/rolesmapping/all_access?pretty"

{
 "status" : "FORBIDDEN",
 "message" : "No permission to access REST API: User <新規作成ユーザ名> with Security roles [all_access] does not have any role privileged for admin access. No ssl info found in request."
}

マスターユーザ名もロールマッピングのフィールドusersに含めることに注意して、以下のようにロールマッピングしてください。

$ curl -XPUT -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}:443/_plugins/_security/api/rolesmapping/all_access" -d "{\"backend_roles\" : [ \"${EC2_ROLE}\" , \"${ECS_TASK_ROLE}\"],\"users\" : [ \"${USERNAME}\"]}"

{"status":"OK","message":"'all_access' updated."}

ロールマッピングの情報を確認します。

$ curl -XGET -u "${USERNAME}:${PASSWORD}" -H "Content-Type: application/json" "https://${ENDPOINT}:443/_plugins/_security/api/rolesmapping/all_access?pretty"


{
  "all_access" : {
    "hosts" : [ ],
    "users" : [
      "<マスターユーザ名>"
    ],
    "reserved" : false,
    "hidden" : false,
    "backend_roles" : [
      "<ec2にアタッチしたiamロールarn>",
      "<ecsにアタッチしたタスクロールarn>"
    ],
    "and_backend_roles" : [ ]
  }
}

backend_rolesの値としてIAMロールのARN、usersの値としてマスターユーザ名が含まれているため、想定通りです。

パターン1:EC2の場合

後にIAM認証情報を利用したリクエストを実施するために、環境変数を設定します。

TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
ROLE_NAME=`curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/iam/security-credentials/`
CRED=`curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/${ROLE_NAME}/`
AWS_ACCESS_KEY_ID=`echo $CRED | jq -r ".AccessKeyId"`
AWS_SECRET_ACCESS_KEY=`echo $CRED | jq -r ".SecretAccessKey"`
AWS_SESSION_TOKEN=`echo $CRED | jq -r ".Token"`
REGION="ap-northeast-1"
SERVICE="es"

動作確認するために、インデックスの一覧を取得します。
こちらのリクエストでは、パスワードではなく取得したIAMロールの認証情報を利用しています。

$ curl -k -XGET "https://${ENDPOINT}:443/_cat/indices" -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" --aws-sigv4 "aws:amz:${REGION}:${SERVICE}" --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"

green open .opensearch-observability 4BaVs933R-iUPlDojYx5SQ 1 0  0 0   208b   208b
green open .kibana_1                 IaEGo5pvSp-m5efRTLR-EA 1 0  0 0   208b   208b
green open .opendistro_security      N9V2uNSXRNGVI-doFhkqag 1 0 10 3 74.7kb 74.7kb

インデックスの一覧が取得できていますね。

パターン2:ECS(Fargate)の場合

コンテナに直接入ってコマンドを実行するために、ECS Execを使っています。

以下コマンドでコンテナにログインします。

$ aws ecs execute-command --region ap-northeast-1 --cluster <クラスター名> --task <タスクID> --container <コンテナ名> --command "/bin/bash" --interactive

以下の環境変数を設定します。
Fargate環境の場合、メタデータの取得するパスやアドレスがEC2とは異なるため、注意する必要があります。

CRED=`curl 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI`
AWS_ACCESS_KEY_ID=`echo $CRED | jq -r ".AccessKeyId"`
AWS_SECRET_ACCESS_KEY=`echo $CRED | jq -r ".SecretAccessKey"`
AWS_SESSION_TOKEN=`echo $CRED | jq -r ".Token"`
REGION="ap-northeast-1"
SERVICE="es"

EC2で実施した場合と同様に、動作確認をします。

$ curl -k -XGET "https://${ENDPOINT}:443/_cat/indices" -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" --aws-sigv4 "aws:amz:${REGION}:${SERVICE}" --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"

green open .opensearch-observability 4BaVs933R-iUPlDojYx5SQ 1 0  0 0   208b   208b
green open .kibana_1                 IaEGo5pvSp-m5efRTLR-EA 1 0  0 0   208b   208b
green open .opendistro_security      N9V2uNSXRNGVI-doFhkqag 1 0 10 3 74.7kb 74.7kb

EC2のときと同じ結果でした!

まとめ

  • IAM認証を行うためには、ロールマッピングする必要がある。
    • ロールマッピングは、Open DistroのロールとAWSのIAMロールを結びつけること。
  • リクエスト実施時の注意点
    • メタデータの取得するパスやアドレスが、EC2とは異なる。
    • curlコマンドで--aws-sigv4フラグを使えるようにするため、7.75以上のバージョンが必要

【参考】

CURL 7.75.0 IS SMALLER

Amazon ES の権限モデル

追加のマスターユーザー

Open Distro Documentation

Security

curlの–aws-sigv4を使って、IAMロールでアクセス制限したOpenSearch(旧: ElasticSearch)にリクエストする

Users and roles

ECS Fargate で 169.254.169.254 が含まれるエラーが発生するときの対処法

きめ細かなアクセスコントロール