やりたいこと
外部ネットワークへのルートがなく、従ってAWSのAPIエンドポイントへの疎通ができないサブネット(以降、Secured Subnet)に存在する踏み台EC2がある。
ここから、同じくSecured Subnet内にVPCアクセスとして構成したAmazon ESドメインに対し、手動スナップショットレポジトリの登録を行いたい。
ここに手順が書いてあるが、SigV4認証が必要とあり、インスタンスプロファイルから認証情報取ってくるから大丈夫だろうとは思いつつも一抹の不安がある。
環境
Amazon ES
- 7.10
- VPCアクセス(Secured Subnetに配置)
- VPC外とは疎通できない
- IAM認証なし、Fine Grained Access Control(FGAC)なし
- Secured Subnet内の通信のみ許可
踏み台EC2
- Amazon Linux 2
- あらかじめpip3で以下をインストール済み
- boto3
- requests
- requests_aws4auth
- Secured Subnetに配置
- VPC外とは疎通できない
手順
1. S3バケットを作成する
今回はmy-bucket-4-es
として作成。
% aws s3 mb s3://my-bucket-4-es --region ap-northeast-1
2. S3バケットに読み書きできるポリシーを作成する
いくつかポリシーを作成していくのだが、これはESが使う用のポリシー。
手動スナップショットのデータをS3にPutするのに使用する。
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-bucket-4-es"
]
},
{
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-bucket-4-es/*"
]
}
]
}
3. ESに渡すロールを作成し、上記ポリシーをアタッチする
ポリシーをESに渡すために、es.amazonaws.comをプリンシパルに指定したロールを作る。
ここではTestRoleForESManualSnapshot
として作成する。
ちなみに、マネジメントコンソールのIAMポリシージェネレーターから作るとESを指定できないので、EC2とかで適当に作成して後で修正する。もちろんCLIで作ってもよい。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "es.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
なおこのロールは、マネジメントコンソールやCLIからはESには渡せない。
後続のPythonスクリプトでESドメインに手動スナップショットレポジトリを登録する際に、一緒に渡す建て付けとなっている。
4. iam:passRoleとes:ESHttpPut権限を付与したポリシーを作成する
上記で作成したロールをESに渡すには、iam:passRole
という「ロールを渡すための権限」が必要になる。
今回、渡す側はEC2上のPythonスクリプトで、PythonスクリプトはEC2インスタンスプロファイルから一時認証情報を取ってくるので、iam:passRole
を持たせる相手はこのインスタンスプロファイルに指定するロール、ということになる。
また、ESドメインに手動スナップショットレポジトリを登録するためにPUTを使うので、es:ESHttpPut
も併せて付与する。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::123456789012:role/TestRoleForESManualSnapshot"
},
{
"Effect": "Allow",
"Action": "es:ESHttpPut",
"Resource": "arn:aws:es:ap-northeast-1:123456789012:domain/<ESドメイン名>/*"
}
]
}
5. EC2インスタンスプロファイルとして使うロールを作成し、上記ポリシーをアタッチする
上記ポリシーをEC2インスタンスプロファイルで使えるようにするために、プリンシパルをec2.amazonaws.comとしたロールを作成する。
ここではEC2RoleForESSnapshot
として作成し、マネジメントコンソールで踏み台EC2にアタッチする。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
6. 踏み台に接続
準備が整ったので、手動スナップショットレポジトリの作成に入る。
目指す踏み台には直接入れないので、IGWのいるサブネット(Public Subnet)上の踏み台を経由して入る。他にも手段はあるが今回はそこ主眼でないので、古の方法で。
% ssh -A ec2-user@"<Public Subnet上のEC2 FQDN>".ap-northeast-1.compute.amazonaws.com
Last login: Fri Jun 4 07:17:53 2021 from 27.0.3.146
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-XXX-XXX-XXX-XXX ~]$ ssh "<Secure Subnet上のEC2 FQDN>".ap-northeast-1.compute.internal
Last login: Fri Jun 4 07:22:30 2021 from ip-XXX-XXX-XXX-XXX.ap-northeast-1.compute.internal
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-YYY-YYY-YYY-YYY ~]$
7. 手動スナップショットレポジトリ登録用のPythonスクリプトを用意する
公式ドキュメントのサンプルを改修して作成。
import boto3
import requests
from requests_aws4auth import AWS4Auth
host = 'https://<ESエンドポイント>.ap-northeast-1.es.amazonaws.com/'
region = 'ap-northeast-1'
s3bucket = 'my-bucket-4-es'
snapshotrole = 'arn:aws:iam::123456789012:role/TestRoleForESManualSnapshot'
service = 'es'
credentials = boto3.Session().get_credentials()
awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)
# Register repository
path = '_snapshot/my-snapshot-repo' # the Elasticsearch API endpoint
url = host + path
payload = {
"type": "s3",
"settings": {
"bucket": s3bucket,
"region": region,
"role_arn": snapshotrole
}
}
headers = {"Content-Type": "application/json"}
r = requests.put(url, auth=awsauth, json=payload, headers=headers)
print(r.status_code)
print(r.text)
8. レポジトリの登録を実行
[ec2-user@ip-YYY-YYY-YYY-YYY ~]$ python3 ./manual-ss.py
200
{"acknowledged":true}
問題なく実行できた。
AWSのAPIエンドポイントへのアクセスは不要であるようだ。
9. レポジトリの確認
[ec2-user@ip-YYY-YYY-YYY-YYY ~]$ curl -XGET https://"<ESエンドポイント>".ap-northeast-1.es.amazonaws.com/_snapshot/my-snapshot-repo-name/my-first-snapshot?pretty
{
"snapshots" : [ {
"snapshot" : "my-first-snapshot",
"uuid" : "lw31y3buT1iJyV-09Gy85Q",
"version_id" : 7090199,
"version" : "7.9.1",
"indices" : [ "movies", ".kibana_1" ],
"data_streams" : [ ],
"include_global_state" : true,
"state" : "SUCCESS",
"start_time" : "2021-06-04T07:43:34.170Z",
"start_time_in_millis" : 1622792614170,
"end_time" : "2021-06-04T07:43:34.770Z",
"end_time_in_millis" : 1622792614770,
"duration_in_millis" : 600,
"failures" : [ ],
"shards" : {
"total" : 6,
"failed" : 0,
"successful" : 6
}
} ]
}
10. 手動スナップショットの作成
% curl -XPUT https://<ESエンドポイント>.ap-northeast-1.es.amazonaws.com/_snapshot/my-snapshot-repo/my-first-snapshot
{"accepted":true}
11. 手動スナップショットの確認
% curl -XGET https://<ESエンドポイント>.ap-northeast-1.es.amazonaws.com/_snapshot/my-snapshot-repo/my-first-snapshot
S3上ではこんな感じで作られる。
通常の自動スナップショットはユーザーのS3側には現れないが、こちらはユーザー所有の(1.で作成した)バケット上に格納され、自由に扱える。
まとめ
AWSのAPIエンドポイントへのアクセスが一切ない環境でも、手動スナップショットレポジトリの登録とスナップショットの作成ができることが確認できた。
リストアについてはまたいずれ。