Terraform と OpenSearch CLI で OpenSearch Service に入門する
2022-07-04Terraform とOpenSearch CLI で OpenSearch Service に入門してみたので、そのメモです。
目次
やること
- Terraform で OpenSearch Service のドメインを定義する
- エンジンは OpenSearch v1.x
- ドメインポリシーで OpenSearch に対してのリクエストを制限する
- 構築した OpenSearch クラスタに OpenSearch CLI でリクエストを投げる
- 異なる IAM ロールで認証して、ドメインポリシーの挙動を確認する
とりあえず試したい
以降は↑の内容を順番に書いていくだけなので、もし実際に試したいという方は下記リポジトリを clone して試してみてください。 terraform/README.md
を読んでもらえれば諸々試せます。
michimani/get-started-opensearch: Hello OpenSearch.
Terraform で OpenSearch Service のドメインを定義する
下記ドキュメントを参考に、 OpenSearch Service のドメインを定義します。
aws_opensearch_domain | Resources | hashicorp/aws | Terraform Registry
ドメイン
最小構成だとこんな感じになります。
resource "aws_opensearch_domain" "first_opensearch" {
domain_name = "first-opensearch"
engine_version = "OpenSearch_1.2"
cluster_config {
instance_type = "t3.small.search"
}
ebs_options {
ebs_enabled = true
volume_size = 10
}
}
OpenSearch Service で指定できるエンジンは aws opensearch list-versions
で確認できます。2022/07/04 現在だと下記のエンジンが指定可能です。
{
"Versions": [
"OpenSearch_1.2",
"OpenSearch_1.1",
"OpenSearch_1.0",
"Elasticsearch_7.10",
"Elasticsearch_7.9",
"Elasticsearch_7.8",
"Elasticsearch_7.7",
"Elasticsearch_7.4",
"Elasticsearch_7.1",
"Elasticsearch_6.8",
"Elasticsearch_6.7",
"Elasticsearch_6.5",
"Elasticsearch_6.4",
"Elasticsearch_6.3",
"Elasticsearch_6.2",
"Elasticsearch_6.0",
"Elasticsearch_5.6",
"Elasticsearch_5.5",
"Elasticsearch_5.3",
"Elasticsearch_5.1",
"Elasticsearch_2.3",
"Elasticsearch_1.5"
]
}
ドメインポリシー
今回は、構築する OpenSearch クラスターに対して Read (GET
アクセス) のみ可能な IAM ロールと Write (POST
, PUT
, DELETE
アクセス) も可能な IAM ロールを作成し、それらによるアクセス制御を行うためのドメインポリシーを設定します。 Terraform での定義は下記のようになります。
resource "aws_opensearch_domain_policy" "first_domain_policy" {
domain_name = aws_opensearch_domain.first_opensearch.domain_name
access_policies = <<POLICIES
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessByAdministrator",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/demo/opensearch-admin"
]
},
"Action": [
"es:*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"${var.my_ip}"
]
}
},
"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/first-opensearch/*"
},
{
"Sid": "AccessByReadOnlyUser",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/demo/opensearch-read-only"
]
},
"Action": [
"es:ESHttpGet"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"${var.my_ip}"
]
}
},
"Resource": "arn:aws:es:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:domain/first-opensearch/*"
}
]
}
POLICIES
}
opensearch-admin
というロールには es:*
ですべてのアクションを許可し、 opensearch-read-only
ロールには es:ESHttpGet
で GET
アクセスのみ許可します。また、今回は Condition
で特定の IP からのアクセスのみ許可するようにしています。
IAM ロールの方の定義はこちら。
resource "aws_iam_role" "opensearch_ro_role" {
name = "opensearch-read-only"
path = "/demo/"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "${var.iam_user_arn}"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role" "opensearch_admin_role" {
name = "opensearch-admin"
path = "/demo/"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "${var.iam_user_arn}"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
特定の IAM ユーザーからスイッチロールして使うことを想定しています。 ${var.iam_user_arn}
には、実際にこれらのロールにスイッチする IAM ユーザーの ARN を variable で指定します。
variables.tf を作成して apply
variables.tf
は下記のような形で作成しておきます。
variable "my_ip" {
default = "203.0.113.0" // Your machine's global IP address.
}
variable "iam_user_arn" {
default = "arn:aws:iam::000000000000:user/hoge" // ARN of the IAM User for which AWS CLI credentials have been set up.
}
自身の IP アドレスの確認には、
curl -X GET 'https://checkip.amazonaws.com/'
がシンプルなのでおすすめです。
あとは terraform apply
でリソースを作成します。初回の apply には 15 分程度かかります。
OpenSearch CLI でリクエストを投げる
OpenSearch のクラスタが構築できたら、 OpenSearch CLI を使ってリクエストを投げてみます。
OpenSearch CLI のインストール
下記ページからダウンロードします。
macOS の場合はインストーラ (pkg) 形式なので、ダウンロードしてインストーラの指示に従ってインストールします。
プロファイルの設定
OpenSearch CLI はいくつかプロファイルを作成して使い分ける事ができます。 AWS CLI でいう --profile
オプションみたいなのがあります。
プロファイルの作成には OpenSearch クラスタの URL と、認証方法を指定する必要があります。
まず、 OpenSearch クラスタの URL を取得します。
今回は first-opensearch
という名前でドメインを作成したので、下記の AWS CLI コマンドで URL (エンドポイント) を取得します。
ENDPOINT=$(
aws opensearch describe-domain \
--domain-name 'first-opensearch' \
--query 'DomainStatus.join(``,[`https://`,Endpoint])' \
--output text
) && echo "${ENDPOINT}"
続いて認証方法についてですが、 OpenSearch CLI では下記の 3 の認証方法が指定できます。
disabled
basic
cert
aws-iam
今回は、 IAM ロールでの認証を行うので aws-iam
を認証方法として指定します。
プロファイルの作成には下記コマンドを実行します。
opensearch-cli profile create \
--auth-type aws-iam \
--endpoint "${ENDPOINT}" \
--name env-role
aws-iam
を指定した場合、認証に使用する AWS のプロファイルと AWS のサービス名を聞かれます。
プロファイルに関しては特定のプロファイルを指定する事もできますが、指定しない場合は実行環境の環境変数をもとに認証に使用するプロファイルが選択されます。今回は環境変数によって使用するプロファイルを使い分けることにします。
AWS のサービス名は、 es
または ec2
で指定します。今回は es
を指定します。 (OpenSearch Service ですが es
です)
Read Only なロールでリクエストを投げてみる
まずは Read Only なロール opensearch-read-only
にスイッチしてリクエストを投げてみます。
スイッチロールするには下記のコマンドを実行します。
SWITCH_CMD=$( \
aws sts assume-role \
--role-arn $(aws iam list-roles \
--path-prefix '/demo' \
--query 'Roles[?contains(to_string(RoleName), `opensearch-read-only`)].Arn' \
--output text) \
--role-session-name 'opensearch-read-only' \
--query 'Credentials.join(``,[`export AWS_ACCESS_KEY_ID=\"`,AccessKeyId,`\" AWS_SECRET_ACCESS_KEY=\"`,SecretAccessKey,`\" AWS_SESSION_TOKEN=\"`,SessionToken,`\"`])' \
--output text) \
&& eval ${SWITCH_CMD} \
&& aws sts get-caller-identity
ちなみに、このコマンドを AWS CLI のエイリアスとしていい感じに設定しておくことで、 AWS CLI でのスイッチロールがめちゃくちゃ簡単になるよ というのを別記事で書いているので参考にしてみてください。
AWS CLI のエイリアスを使ってメチャクチャ簡単にスイッチロールできるようにしてみた - michimani.net
opensearch-read-only
ロールにスイッチできたら、 GET
のリクエストを投げてみます。
$ opensearch-cli curl get \
--path '_cluster/health' \
--output-format yaml \
--profile env-role
---
cluster_name: "000000000000:first-opensearch"
status: "green"
timed_out: false
number_of_nodes: 1
number_of_data_nodes: 1
discovered_master: true
active_primary_shards: 1
active_shards: 1
relocating_shards: 0
initializing_shards: 0
unassigned_shards: 0
delayed_unassigned_shards: 0
number_of_pending_tasks: 0
number_of_in_flight_fetch: 0
task_max_waiting_in_queue_millis: 0
active_shards_percent_as_number: 100.0
続いて PUT
リクエストを投げてみます。
$ opensearch-cli curl put \
--path 'demoindex' \
--profile env-role
{
"Message": "User: arn:aws:sts::000000000000:assumed-role/opensearch-read-only/opensearch-read-only is not authorized to perform: es:ESHttpPut because no identity-based policy allows the es:ESHttpPut action"
}
こちらはエラーになりました。
ここまで終わったらスイッチロールを解除するために下記コマンドを実行します。
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
Write も許可されてたロールでリクエストを投げてみる
次に Write も許可されたロール opensearch-admin
にスイッチしてリクエストを投げてみます。
opensearch-admin
にスイッチするには下記コマンドを実行します。
SWITCH_CMD=$( \
aws sts assume-role \
--role-arn $(aws iam list-roles \
--path-prefix '/demo' \
--query 'Roles[?contains(to_string(RoleName), `opensearch-admin`)].Arn' \
--output text) \
--role-session-name 'opensearch-admin' \
--query 'Credentials.join(``,[`export AWS_ACCESS_KEY_ID=\"`,AccessKeyId,`\" AWS_SECRET_ACCESS_KEY=\"`,SecretAccessKey,`\" AWS_SESSION_TOKEN=\"`,SessionToken,`\"`])' \
--output text) \
&& eval ${SWITCH_CMD} \
&& aws sts get-caller-identity
Read Only のときに失敗した PUT
リクエストを投げてみます。
$ opensearch-cli curl put \
--path 'demoindex' \
--profile env-role
{"acknowledged":true,"shards_acknowledged":true,"index":"demoindex"}
今度は成功しました。続いて DELETE
リクエストも投げてみます。
$ opensearch-cli curl delete \
--path 'demoindex' \
--profile env-role
{"acknowledged":true}
こちらも成功しました。
ここまで終わったら、忘れずにスイッチロールを解除しておきます。
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
まとめ
- Terraform で OpenSearch Service のドメイン、ドメインポリシーを定義した
- OpenSearch CLI で OpenSearch のクラスタにリクエストを投げてみた
- 副作用として AWS CLI でスイッチロールするワンライナーが生まれた
comments powered by Disqus