AWS Glue で 異なるアカウントの RDS から OpenSearch にデータを同期する
株式会社フクロウラボでインフラをメインに担当している満江です。
とある開発で RDS の 特定テーブルの特定データのみ を 日次 で 異なるアカウント にホスティングしている OpenSearch に同期したいなぁと思うことがありました。
ちょっと特殊なんですが、今回同期したいデータは後から更新されることはなく、いわゆるログデータに近いものになります。
実際に構築してみたんですが、これが思いのほかハマったのでその内容を共有したいと思います。
やりたいこと

構成

最終的には上記の構成になりました。
アカウントA にホスティングされている RDS からアカウントB にホスティングされている OpenSearch に Glue を使ってデータを同期します。
データを同期するアカウントB に Glue 等のリソースを配置し、アカウントA には余計なリソースが存在していない点が個人的に気に入ってます。
仮に同期元の RDS が アカウントC, アカウントD, ... と増えても、アカウントB の Glue のリソースを追加するだけで対応できるのが良いですね。
データ同期であれば Glue でなくても OpenSearch Ingestion や Database Migration Service(DMS) や Lambda を使う方法もありますが、下記の理由で見送りました。
- OpenSearch Ingestion
- (2025/12/24 時点で) cross-account の RDS に対応してなさそう
- https://docs.aws.amazon.com/ja_jp/opensearch-service/latest/developerguide/rds-mysql.html#rds-mysql-pipeline-limitations
- DMS
- 日次同期で十分であり、ニアリアルタイムでの同期は不要(コストを抑えたい)
- 差分同期も今回は不要
- アカウントA に replication instance といった余計なリソースを置きたくない
- Lambda
- 出来るけど、どうせなら Glue で ETL したいじゃん
実践
1. VPC Peering
VPC や Subnet は既に存在している前提で進めます。
1.1 アカウントB で VPC Peering を作成
まずは VPC 間の通信を可能にするため、VPC Peering を作成します。
どちらのアカウントをリクエスタにしても良いです。
今回はアカウントB をリクエスタ、アカウントA をアクセプタにします。
ピアリング先は アカウントA の VPC になるため、「別のアカウント」を選択し、接続したい「アカウントID」と「VPC ID」を入力します。

1.2 アカウントA で VPC Peering を承認
アカウントB で申請した VPC Peering の承認を行います。

VPC の ピアリング接続 を開くと、上記のようにアカウントB で申請した内容が表示されているので、右上のアクションから「リクエストを承諾」を選択しましょう。
確認画面が表示されるので、問題なければ「リクエストを承諾」します。
1.3 DNS 解決を有効化
VPC Peering を申請->承諾しただけでは、Private IP アドレスでの通信は行えません。
両アカウントで DNS 解決を有効化する必要があります。
承諾した直後のアカウントA の画面では下記のようになっているはずなので、右上の「DNS 設定を編集」を押下します。

チェック項目にチェックを入れて「変更を保存」しましょう。

1.4 ルートテーブルの設定
これでもまだ VPC 間の通信は行えません。
上記の有効化はあくまで別アカウントの VPC 内リソースに対して DNS での名前解決ができるようになっただけです。
ルートテーブルを設定し、名前解決で得た Private IP アドレスに向けた通信を正しくルーティングしましょう。
この設定も両方のアカウントで設定する必要があります。
まずはアカウントA から設定します。
アカウントB の VPC CIDR は 172.80.0.0/16 であるため、下記のようにルートテーブルを設定します。

アカウントB でも同様にアカウントA の VPC CIDR をルーティングするように設定します。
アカウントA の VPC CIDR は 172.31.0.0/16 であるため、下記のようにルートテーブルを設定します。

これでようやく、VPC Peering による通信が可能になりました。
2. OpenSearch
ここからはアカウントB での作業になります。
2.1 Security Group を作成
OpenSearch 用の Security Group を作成します。
インバウンドルールは後に設定するので、今はルール無しで OK です。

2.2 ドメインを作成
OpenSearch ドメインを作成します。
エンジンバージョンは OpenSearch 3.3 を選択し、 互換モードを必ずON にしてください。
(自分はこれを設定せず、超タイムロスしました。。。)
ネットワーク設定では任意の Private Subnet に配置し、2.1で作成した Security Group をアタッチします。
きめ細かなアクセスコントロールでは マスターユーザー を設定しました。

3. Glue(Data Source)
いよいよ本丸の Glue を作成します。
まずはアカウントA の RDS をデータソースとするための設定を行います。
この作業もアカウントB で行いましょう。
3.1 Security Group を作成
Glue Connection 用の Security Group を作成します。
インバウンドルールには自身からの通信を許可するために、すべてのTCPで自身のセキュリティグループを設定します。
アウトバウンドルールにも自身のセキュリティグループと、OpenSearch にアタッチした Security Group を設定させ、、、
るのが適切なんですが、4.3で後述する AWS Glue Connector for Elasticsearch の ECR Image Pull が少し特殊なため、今回はすべてのトラフィックを許可する設定にしました。


アカウントA の RDS にアタッチしている Security Group に、今回作成した Glue Connection 用の Security Group からのアクセスを許可する Ingress ルールの追加も忘れずに。

3.2 Glue Connection を作成
アカウントA の RDS に接続するための Glue Connection を作成します。
データソースを選択する際、「Amazon Aurora」や「MySQL」などを選択せず、「JDBC」を選択します。
Connection URL は JDBC の形式で入力しましょう。
jdbc:mysql://<DB_ENDPOINT>:<DB_PORT>/<DB_NAME>?enabledTLSProtocols=TLSv1.2
ネットワーク設定は OpenSearch と同じ Private Subnet に配置し、先ほど作成した Glue Connection 用の Security Group をアタッチします。
Credential type はお好みで。

3.3 Glue Crawler を作成
アカウントA の RDS のメタデータを Glue Data Catalog に登録するため、Glue Crawler を作成します。
ここに関しては同期したいデータの特性によって Crawler 無しでも良いと思います。
Crawler を使う場合は ETL ジョブのデータソースが Data Catalog となり、使わない場合は Glue Connection となります。
また Glue Database も事前に作成しておきましょう。

アタッチする IAM Role の信頼ポリシーは下記のように設定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "glue.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
ポリシーは下記のように設定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GlueAccess",
"Effect": "Allow",
"Action": [
"glue:Get*",
"glue:CreateTable"
],
"Resource": [
"arn:aws:glue:ap-northeast-1:000000000000:catalog",
"arn:aws:glue:ap-northeast-1:000000000000:connection/*",
"arn:aws:glue:ap-northeast-1:000000000000:database/*",
"arn:aws:glue:ap-northeast-1:000000000000:table/*"
]
},
{
"Sid": "VpcAccess",
"Effect": "Allow",
"Action": [
"ec2:DescribeSubnets",
"ec2:DescribeVpcEndpoints",
"ec2:DescribeSecurityGroups",
"ec2:DescribeRouteTables",
"ec2:DescribeNetworkInterfaces",
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:CreateTags"
],
"Resource": [
"*"
]
},
{
"Sid": "CloudWatchLogsAccess",
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-northeast-1:000000000000:log-group:*"
]
}
]
}
4. Glue(Data Target)
OpenSearch をデータターゲットとするための設定を行います。
4.1 Secrets Manager を作成
OpenSearch のマスターユーザーの「ユーザー名/パスワード」を Secrets Manager に登録します。
ユーザー名のキーは es.net.http.auth.user 、パスワードのキーは es.net.http.auth.pass としてください。

4.2 AWS Glue Connector for Elasticsearch をサブスクライブ
Glue から OpenSearch にデータを書き込むために AWS Glue Connector for Elasticsearch を利用します。
AWS Marketplace で glue connector for elasticsearch と検索すると一番上に出てくるので、詳細ページから「購入オプションを表示」を押下し、サブスクライブします。



4.3 Glue Connector を作成
AWS Glue Connector for Elasticsearch をサブスクライブすると、AWS Marketplace の「サブスクリプションを管理」に AWS Glue Connector for Elasticsearch が追加されます。

製品を選択すると「アクティブな契約」にレコードが表示されているので、契約ID を押下し詳細ページを表示します。

右上の「アクション」から「さらにソフトウェアを起動する」を選択します。

サービスは「ECS」を選択し、配信オプションは「Glue 3.0」を選択します。
そうすると「起動」の部分に AWS Glue StudioからGlueコネクタを有効にしてください とテキストリンクが表示されるので押下します。

Glue Connector の作成ページにリダイレクトするので、必要な情報を入力し作成します。
- 「Connection access」は 4.1 で作成した Secrets Manager を選択します
- 「Network options」は OpenSearch と同じ Private Subnet に配置し、3.1 で作成した Security Group を選択します

4.4 NAT Gateway を作成
4.3 で使用した AWS Glue Connector for Elasticsearch は「AWS Account ID: 709825985650」の us-east-1 リージョンの ECR Image を使用しているため、Private Subnet 内の Glue ジョブから別アカウント・別リージョンの ECR Image を Pull する必要があります。
そのため ECR 用の VPC Endpoint を作成しても、Private Subnet が ap-northeast-1 リージョンの場合はアクセス出来ません。
今回は NAT Gateway を Public Subnet に配置して、Image を Pull できるようにしました。
4.5 Glue ジョブ用 IAM Role を作成
Glue ジョブ用の IAM Role を作成します。
信頼ポリシーは下記のように設定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "glue.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
ポリシーは下記のように設定します。
ちょっと粗い部分もあるので、細かい部分はお好みで。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OpenSearchAccess",
"Effect": "Allow",
"Action": [
"es:*"
],
"Resource": [
"arn:aws:es:ap-northeast-1:000000000000:domain/zenn-opensearch"
]
},
{
"Sid": "GlueAccess",
"Effect": "Allow",
"Action": [
"glue:Get*"
],
"Resource": [
"arn:aws:glue:ap-northeast-1:000000000000:catalog",
"arn:aws:glue:ap-northeast-1:000000000000:connection/*",
"arn:aws:glue:ap-northeast-1:000000000000:database/*",
"arn:aws:glue:ap-northeast-1:000000000000:table/*"
]
},
{
"Sid": "EcrAccess",
"Effect": "Allow",
"Action": [
"ecr:*"
],
"Resource": [
"*"
]
},
{
"Sid": "S3Access",
"Effect": "Allow",
"Action": [
"s3:Get*"
],
"Resource": [
"arn:aws:s3:::*"
]
},
{
"Sid": "SecretsManagerAccess",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:ap-northeast-1:000000000000:secret:zenn-opensearch-credentials"
]
},
{
"Sid": "VpcAccess",
"Effect": "Allow",
"Action": [
"ec2:DescribeSubnets",
"ec2:DescribeVpcEndpoints",
"ec2:DescribeSecurityGroups",
"ec2:DescribeRouteTables",
"ec2:DescribeNetworkInterfaces",
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:CreateTags"
],
"Resource": [
"*"
]
}
]
}
4.6 VPC Endpoint for S3 を作成
Glue ジョブでは VPC内から S3 へのアクセスが発生するため、Gateway 型の VPC Endpoint を作成します。

4.7 Glue ジョブを作成(Data Source)
いよいよ Glue ジョブを作成します。
Crawler を用いて Glue Data Catalog にメタデータを登録している場合は「Data Catalog」をデータソースとして設定しましょう。
「Database」と「Table」を選択し、「IAM Role」には 4.5 で作成した IAM Role を選択します。
なお今回は最低限の設定で構築するため、諸々のパラメータは必要に応じて設定してください。

画面下部の「Start session」を押下すると、アカウントA の RDS のデータが確認できると思います。
4.8 Glue ジョブを作成(Transform)
せっかく Glue を使うのであれば ETL を最大限に活用したいですよね。
ということで適当に Transform を追加します。
今回は id, created_at, updated_at のみを抽出するようにしています。

4.9 Glue ジョブを作成(Data Target)
最後にデータターゲットを設定します。
今回のターゲットは OpenSearch になるので、Data Target は「Amazon OpenSearch Service」、、、とはなりません。
ここでは 4.3 で作成した Connector を使いたいので、「Elasticsearch Connector」を選択します。

OpenSearch へのアクセスでは「Connection options」の設定が重要になってきます。
最低限、下記の項目は必要です。
-
es.nodes.wan.only: true -
es.nodes: OpenSearch のドメインエンドポイント (VPC) -
es.port: 443 -
es.resource: <INDEX_NAME>

4.10 OpenSearch のセキュリティグループを更新
このまま Glue ジョブを実行しても network/Elasticsearch cluster is not accessible or ... というエラーが発生します。
はい、そうです、2.1 で作成した OpenSearch のセキュリティグループに Glue Connection にアタッチしたセキュリティグループからのアクセスを許可する必要があります。
ということでインバウンドルールに Glue 側のセキュリティグループを追加。

5. 動作確認
5.1 Glue ジョブの実行
時は来ました。 Glue ジョブを手動で実行しましょう。
Run Status が Succeeded になり、OpenSearch にデータが登録されていれば成功です。
あとは Glue Job Schedules で日次実行のスケジュールを設定すれば完了!!


最後に
中々遭遇しないケースかもしれませんが、Glue で cross-account な RDS -> OpenSearch のデータ同期方法をご紹介しました。
Glue Connector for Elasticsearch 周りでハマるポイントが多いので、同じような構成を検討されている方の参考になれば幸いです。
ちなみに本来は OpenSearch に収集したデータをアレコレ活用する内容を紹介しようと思っていたので、その記事はまた今度。
Discussion