【AWS】AWS Glue ~ Boto3 / Glue connection編 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/10/14/000000

で、Glue の Workflows/Jobs/trigger について扱った。

今回は、Glue の 接続(connection)について扱う。

目次

【1】Glue connection
【2】関連する主なBoto3 API一覧
【3】使用上の注意
【4】サンプル
 例1:コネクション削除/作成 (delete/create_connection)
 例2:コネクション取得 (get_connection)
【5】補足
 補足1:DB Host/port/DB nameについて
 補足2:JDBC の フォーマット

【1】Glue connection

Glue の 接続(connection)について

公式サイト
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/console-connections.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-glue-connection.html

【2】関連する主なBoto3 API一覧

以下のAPIを参照しながら、実装していく

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html

主なAPI

# API 説明
1 get_connection() コネクションの取得
2 get_connections() コネクション群の取得
3 create_connection() コネクションの作成
4 update_connection() コネクションの更新
5 delete_connection() コネクションの削除
6 batch_delete_connection() コネクション群の削除

[1] GetConnection / [2] GetConnections
https://docs.aws.amazon.com/glue/latest/webapi/API_GetConnection.html
https://docs.aws.amazon.com/glue/latest/webapi/API_GetConnections.html

Name(Type: String/Required: Yes)
 ... Connection名
HidePassword(Type: Boolean/Required: No) 
 ... パスワードを隠すかどうか(特にパスワードが不要ならTrueを指定)

[3] CreateConnection
https://docs.aws.amazon.com/glue/latest/webapi/API_CreateConnection.html

Parameters
CatalogId (string)
  ... カタログオブジェクトを作成するデータカタログの ID
ConnectionInput (ConnectionInput object) [REQUIRED]
 ... 作成する接続

[4] UpdateConnection
https://docs.aws.amazon.com/glue/latest/webapi/API_UpdateConnection.html

ConnectionInput(Required: Yes) ... 更新したい認証情報
Name(Required: Yes) ... 接続名

!! 個人的なメモ !!
更新する前に「GetConnection」でConnection情報を取得し、
その後、そのオブジェクトに対して、更新したユーザ情報(例:パスワード)を
上書き。

その更新したConnection情報をインプットとして、
UpdateConnection を実行させてあげればよさそう。

[5] DeleteConnection / [6] BatchDeleteConnection
https://docs.aws.amazon.com/glue/latest/webapi/API_DeleteConnection.html
https://docs.aws.amazon.com/glue/latest/webapi/API_BatchDeleteConnection.html

Parameters
CatalogId (string)
  ... カタログオブジェクトを作成するデータカタログの ID
ConnectionName (string) [REQUIRED]
  ... 削除する接続名

[関連オブジェクト] ConnectionInput object
https://docs.aws.amazon.com/glue/latest/webapi/API_ConnectionInput.html
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-glue-connection-connectioninput.html

 HOST | PORT | USERNAME | PASSWORD | ENCRYPTED_PASSWORD |
 JDBC_DRIVER_JAR_URI | JDBC_DRIVER_CLASS_NAME | JDBC_ENGINE |
 JDBC_ENGINE_VERSION | CONFIG_FILES | INSTANCE_ID | JDBC_CONNECTION_URL |
 JDBC_ENFORCE_SSL | CUSTOM_JDBC_CERT | SKIP_CUSTOM_JDBC_CERT_VALIDATION |
 CUSTOM_JDBC_CERT_STRING | CONNECTION_URL |
 KAFKA_BOOTSTRAP_SERVERS | KAFKA_SSL_ENABLED | KAFKA_CUSTOM_CERT |
 KAFKA_SKIP_CUSTOM_CERT_VALIDATION | KAFKA_CLIENT_KEYSTORE |
 KAFKA_CLIENT_KEYSTORE_PASSWORD | KAFKA_CLIENT_KEY_PASSWORD |
 ENCRYPTED_KAFKA_CLIENT_KEYSTORE_PASSWORD |
 ENCRYPTED_KAFKA_CLIENT_KEY_PASSWORD |
 SECRET_ID | CONNECTOR_URL | CONNECTOR_TYPE | CONNECTOR_CLASS_NAME

【3】使用上の注意

1)接続パスワードを暗号化した場合、boto3 API / get_connection() からは
  暗号化した値が返ってくる(以下のサンプル・例2を参照)

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_connection

より抜粋

ENCRYPTED_PASSWORD - 
When you enable connection password protection by setting ConnectionPasswordEncryption in the Data Catalog encryption settings,
this field stores the encrypted password.

※ 接続パスワードの暗号化 については、以下の公式サイトを参照。

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/encrypt-connection-passwords.html

2)boto3 API が実行して成功(エラーがかえってこない)しても、
  不備がある可能性がある

 => 完了後にAWS Management Console上でGlueのページまで飛び
     「Test Connection」を実行した方がいい
 (ここで、引数不備などで、よくエラーになる)
  以下の公式サイトにも
  「ベストプラクティスとして、ETL ジョブのデータストア接続を使用する前に、
  [Test connection (接続のテスト)] を選択します」って記載されている

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/console-connections.html
【実例】

+ 「SecurityGroupIdList」「SubnetId」を設定しているが、
   「AvailabilityZone」は設定しない又は値に不備がある場合
+ 「"JDBC_ENFORCE_SSL": "true"」を設定した場合

AWS Glue で失敗したテスト接続のトラブルシューティング

https://aws.amazon.com/jp/premiumsupport/knowledge-center/glue-test-connection-failed/

より抜粋

SSL 設定を確認する:
 データストアが指定されたユーザーの SSL 接続を必要とする場合は、
コンソールで接続を作成するときに [Require SSL connection] を必ず選択してください。
データストアが SSL をサポートしていない場合は、このオプションを選択しないでください。

Aurora Postgre SQL / SSL
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Security.html#AuroraPostgreSQL.Security.SSL.Requiring

【4】サンプル

例1:コネクション削除/作成 (delete/create_connection)

import boto3
try:
    from botocore.exceptions import BotoCoreError, ClientError
except ImportError:
    pass

# ここから実装
aws_region = 'ap-northeast-1'
glue_client = boto3.client('glue', region_name=aws_region)

target_connection = 'target-db-connection'

# 一旦 connection の削除を試みる
try:
  delete_response = glue_client.delete_connection(ConnectionName=target_connection)
  print(delete_response)
except(BotoCoreError, ClientError) as ex:
  if ex.response['Error']['Code'] == 'EntityNotFoundException':
    print('対象[{}]見当たらず、削除不要'.format(target_connection))
  else:
    raise ex

# connection の作成
try:
  create_response = glue_client.create_connection(
    ConnectionInput={
        "Name": target_connection,
        "Description": "This is just a demo",
        "ConnectionType": "JDBC",
        "ConnectionProperties": {
            "JDBC_CONNECTION_URL": "jdbc:postgresql://postgresql-instance1.xxxxxxx.us-east-1.rds.amazonaws.com/myDatabase",
            "JDBC_ENFORCE_SSL": "false",
            "USERNAME": "postgre",
            "PASSWORD": "password"
        },
        "PhysicalConnectionRequirements": { 
           "AvailabilityZone": "ap-northeast-1a",
           "SecurityGroupIdList": [
              "security-sample-group001",
              "security-sample-group002"
           ],
           "SubnetId": "vpc-subnet001"
        }
      })
  print(create_response)
except(BotoCoreError, ClientError) as ex:
  print('Error [{}]'.format(ex))
  raise ex

例2:コネクション取得 (get_connection)

import boto3
import base64
import re

# ここから実装
aws_region = 'ap-northeast-1'
glue_client = boto3.client('glue', region_name=aws_region)
target_connection_name = 'target-db-connection'

# connection の作成
try:
  response = glue_client.get_connection(
      Name=target_connection_name)
  print(response)

   properties = response['Connection']['ConnectionProperties']
   user_name = properties['USERNAME']
   password = properties.get('PASSWORD')
   if not password:
      # 以下を参考に...
      # https://gist.github.com/nmarley/99cec84a0b1b9fd87d3ae51c88d68fbb
      kms_client = boto3.client('kms', region_name=aws_region)
      encrypted_password = properties['ENCRYPTED_PASSWORD']
      binary_data = base64.b64decode(encrypted_password)
      meta = kms_client.decrypt(CiphertextBlob=binary_data)
      plaintext = meta[u'Plaintext']
      password = plaintext.decode()
   print('user_name = {}, password = {}'.format(user_name, password))

   # 補足1を参照
   # e.g. jdbc:redshift://endpoint:port/database
   connection_url = properties['JDBC_CONNECTION_URL']
   results = re.findall(r'://(\S+):(\d+)/(\S+)$', connection_url)
   db_host = results[0][0]
   db_port = results[0][1]
   db_name = results[0][2]
   print('db_host = {}, db_port = {}, db_name = {}'.format(db_host, db_port, db_name))
except(Exception) as ex:
  print('Error [{}]'.format(ex))
  raise ex

【5】補足

補足1:DB Host/port/DB nameについて

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/glue.html#Glue.Client.get_connection

から分かるように、DB Host/port だけであれば、
properties['HOST'], properties['PORT'] で取得できる。

 しかし、DB名は(何故か)ないので、
properties['JDBC_CONNECTION_URL'] から正規表現を使って抽出する。
(以下の関連記事を参照のこと)

https://dk521123.hatenablog.com/entry/2019/09/01/000000

補足2:JDBC の フォーマット

* Redshift については、以下を参照。

https://docs.aws.amazon.com/ja_jp/redshift/latest/mgmt/configure-jdbc-connection.html

関連記事

AWS Glue ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/10/01/221926
AWS Glue ~ Boto3 / 入門編 ~
https://dk521123.hatenablog.com/entry/2019/10/14/000000
AWS Glue ~ Boto3 / クローラ編 ~
https://dk521123.hatenablog.com/entry/2021/04/16/135558
AWS Glue ~ Boto3 / セキュリティ設定編 ~
https://dk521123.hatenablog.com/entry/2020/04/08/171208
AWS Glue ~ Boto3 / Glue connection編 ~
https://dk521123.hatenablog.com/entry/2020/01/29/224525
b機密データの管理 ~ Secrets Manager / boto3 編 ~
https://dk521123.hatenablog.com/entry/2021/10/05/105550
Glue/Python から Redshift に接続することを考える
https://dk521123.hatenablog.com/entry/2020/08/26/193237
AWS Glue のトラブルシューティング
https://dk521123.hatenablog.com/entry/2019/10/25/232155
Python ~ 基本編 / 正規表現
https://dk521123.hatenablog.com/entry/2019/09/01/000000