継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

【2024年版】RDS と Aurora の SSL/TLS 証明書のローテーションで再起動が発生するかと作業対象のデータベースの一覧を確認した

タダです.

数年ぶりに迫ってきた RDS と Aurora の SSL/TLS 接続で使用する証明書の入れ替えが東京リージョンは 2024/08/22 期限となっています.今回の証明書の入れ替えにあたって利用している Aurora で証明書入れ替え時に再起動が発生するのか,どの証明書のバージョンを使用しているのかを確認したのでこの記事にまとめてきます.

aws.amazon.com

証明書の入れ替え時に再起動が発生する DB エンジンとバージョンの確認

まず,証明書の入れ替え時に再起動が発生する DB エンジンとバージョンの確認を行いました.確認結果からDBエンジンバージョンが 5.7.mysql_aurora.2.11.1 以下は再起動が入るが,5.7.mysql_aurora.2.11.1 以降 8.0 系は再起動が入らないことがわかりました( SupportsCertificateRotationWithoutRestart の結果が true なら再起動が発生せず, false なら再起動が発生する)。

$ aws rds describe-db-engine-versions --engine aurora-mysql --include-all --region ap-northeast-1 | jq -r '.DBEngineVersions[] | (.EngineVersion,.SupportsCertificateRotationWithoutRestart,.SupportedCACertificateIdentifiers)'

5.7.12
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.02.3
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.03.2
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.03.3
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.03.4
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.1
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.2
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.3
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.4
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.5
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.6
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.7
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.8
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.04.9
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.05.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.06.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.1
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.2
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.3
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.4
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.5
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.6
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.7
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.8
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.9
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.07.10
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.08.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.08.1
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.08.2
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.08.3
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.08.3
false
[]
5.7.mysql_aurora.2.08.4
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.09.0
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.09.1
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.09.2
false
[
  "rds-ca-2019",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.09.3
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.10.0
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.10.1
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.10.2
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.10.3
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.0
false
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.3
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.4
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.11.4
false
[]
5.7.mysql_aurora.2.11.5
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.12.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.12.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
5.7.mysql_aurora.2.12.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.01.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.01.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.02.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.02.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.02.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.02.3
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.03.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.03.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.03.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.03.3
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.04.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.04.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.04.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.05.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.05.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.05.2
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.06.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.06.1
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]
8.0.mysql_aurora.3.07.0
true
[
  "rds-ca-2019",
  "rds-ca-ecc384-g1",
  "rds-ca-rsa4096-g1",
  "rds-ca-rsa2048-g1"
]

次に,利用している DB エンジンバージョンが 5.7系で 5.7.mysql_aurora.2.11.1 以降になっているかを確認してみました.幸いにして利用しているバージョンは 5.7.mysql_aurora.2.11.5 になっていたので証明書入れ替え時に再起動が発生しない状況でした.

$ aws rds describe-db-clusters --query "DBClusters[?starts_with(EngineVersion, '5.7')].[DBClusterIdentifier, EngineVersion]" --output json

[
    [
        "hoge",
        "5.7.mysql_aurora.2.11.5"
    ],
    [
        "fuga",
        "5.7.mysql_aurora.2.11.5"
    ]
]

利用している Aurora がどの証明書のバージョンを使用しているのかの確認

最後に,Aurora の中でどのクラスターで証明書入れ替えを行う rds-ca-2019 を利用しているかを確認をしました.Aurora クラスターとインスタンス,DB エンジンバージョン,証明書のバージョンを一覧で確認できるようにしています.

$ aws rds describe-db-instances --query 'DBInstances[?CACertificateIdentifier==`rds-ca-2019`].[DBInstanceIdentifier, DBClusterIdentifier, EngineVersion, CACertificateIdentifier]' --output table
--------------------------------------------------------------------------------------------------------------------
|                                                DescribeDBInstances                                               |
+------------------------------------+-----------------------------------+--------------------------+--------------+
|  hoge-writer-instances             |  hoge                     |  5.7.mysql_aurora.2.11.5 |  rds-ca-2019 |
|  hoge-reader-instances             |  hoge                     |  5.7.mysql_aurora.2.11.5 |  rds-ca-2019 |
|  fuga-writer-instances             |  fuga                     |  5.7.mysql_aurora.2.11.5 |  rds-ca-2019 |
|  fuga-reader-instances             |  fuga                     |  5.7.mysql_aurora.2.11.5 |  rds-ca-2019 |
+------------------------------------+-----------------------------------+--------------------------+--------------+

まとめ

RDS と Aurora の SSL/TLS 接続で使用する証明書の入れ替え作業にあたって,証明書入れ替え時に再起動が発生する化どうかの確認と作業対象の確認を行った際に使った AWS CLI コマンドをまとめました.

関連記事

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

Bytebase API を実行するワークフロー を Step Functions で構築する

タダです.

前回の記事で Bytebase の API を実行するコマンドを紹介しました.この記事ではローカルから curl で実行していたのですが,自動化して実行できるように Step Functions のサードパーティ API 実行を試してみます.

sadayoshi-tada.hatenablog.com

Step Functions から Bytebase API を実行する準備

API を実行する時に必要な準備を行います.以下,3つを行います.

  • サービスアカウント及びキーの発行
  • サービスアカウントキーの Secrets Manager への格納
  • EventBridge Connection の追加

サービスアカウントキーの発行

事前準備としてサービスアカウントのユーザーを作ります.Workspace Admin か DBA のロールを付与する必要があるため,DBAを設定して作成しました.作成後にサービスアカウントキーをコピーしておきます.

サービスアカウントキーの Secrets Manager への格納

発行したサービスアカウントキーを Secrets Manager に入れていきます.加えて,Step Functions の IAM ロールに読み取りアクセス許可を付与します.

EventBridge Connection の追加

Step Functions から API を叩く時に Authorization ヘッダーを付ける必要があるのですが,Step Functions の API 実行する時に Authorization は設定できない仕様になっているため EventBridge Connection を用意します.

curl で実行したときの例

# List projects
curl --request GET ${bytebase_url}/v1/projects \
  --header 'Authorization: Bearer '${bytebase_token}

www.bytebase.com

以下のような感じで設定します.値は Bearer dummy を初期設定として入れています.

Step Functions でワークフローを構築する

準備が完了したら,ワークフローを構築していきます.まずは結論ですが,以下の ASL を作りました.

{
  "Comment": "Bytebase API exec test",
  "StartAt": "GetBytebaseServiceAPIUserCredential",
  "States": {
    "GetBytebaseServiceAPIUserCredential": {
      "Type": "Task",
      "Parameters": {
        "SecretId": "[サービスアカウントキーを格納した Secrets Manager 名]"
      },
      "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
      "Next": "Call Bytebase Authrization API"
    },
    "Call Bytebase Authrization API": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/auth/login",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        },
        "Method": "POST",
        "RequestBody": {
          "email": "[サービスアカウントのアドレス]",
          "password.$": "$.SecretString",
          "web": true
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "JitterStrategy": "FULL"
        }
      ],
      "ResultSelector": {
        "token.$": "States.StringSplit($.ResponseBody.token, ':')"
      },
      "OutputPath": "$.token[0]",
      "Next": "UpdateConnection"
    },
    "UpdateConnection": {
      "Type": "Task",
      "Parameters": {
        "Name": "[EventBridge Connection 名]",
        "AuthorizationType": "API_KEY",
        "AuthParameters": {
          "ApiKeyAuthParameters": {
            "ApiKeyName": "Authorization",
            "ApiKeyValue.$": "States.Format('Bearer {}',$)"
          }
        }
      },
      "Resource": "arn:aws:states:::aws-sdk:eventbridge:updateConnection",
      "Next": "Call Bytebase Get Instances API"
    },
    "Call Bytebase Get Projects API": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/projects",
        "Method": "GET",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "JitterStrategy": "FULL"
        }
      ],
      "End": true
    }
  }
}

詳細の説明をしていきます.

認証のエンドポイントを叩く処理

下記の部分が該当します.まずはサービスアカウントキーを Secrets Manager から取得し,認証エンドポイントを叩きます.レスポンスで認証トークンが返ってくるので,それを EventBridge Connection の値に入れます.認証トークンは当然ずっと固定ではないため,更新できるようにしています.UpdateConnection API を実行すれば更新ができたので,この処理をステートに入れています.

{
  "Comment": "Bytebase API exec test",
  "StartAt": "GetBytebaseServiceAPIUserCredential",
  "States": {
    "GetBytebaseServiceAPIUserCredential": {
      "Type": "Task",
      "Parameters": {
        "SecretId": "[サービスアカウントキーを格納した Secrets Manager 名]"
      },
      "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
      "Next": "Call Bytebase Authrization API"
    },
    "Call Bytebase Authrization API": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/auth/login",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        },
        "Method": "POST",
        "RequestBody": {
          "email": "[サービスアカウントのアドレス]",
          "password.$": "$.SecretString",
          "web": true
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "JitterStrategy": "FULL"
        }
      ],
      "ResultSelector": {
        "token.$": "States.StringSplit($.ResponseBody.token, ':')"
      },
      "OutputPath": "$.token[0]",
      "Next": "UpdateConnection"
    },
   "UpdateConnection": {
      "Type": "Task",
      "Parameters": {
        "Name": "[EventBridge Connection 名]",
        "AuthorizationType": "API_KEY",
        "AuthParameters": {
          "ApiKeyAuthParameters": {
            "ApiKeyName": "Authorization",
            "ApiKeyValue.$": "States.Format('Bearer {}',$)"
          }
        }
      },
      "Resource": "arn:aws:states:::aws-sdk:eventbridge:updateConnection",
      "Next": "Call Bytebase Get Instances API"
    }

認証トークンを取得後にプロジェクトの一覧を取得する API を叩く

そして,本命の API 実行部分ですが,以下が該当します.GET メソッドで /v1/projects で叩くと取得ができます.

    "Call Bytebase Get Projects API": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/projects",
        "Method": "GET",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "JitterStrategy": "FULL"
        }
      ],
      "End": true
    }
  }
}

認証トークンが更新していてリクエストが成功すると以下のようなレスポンスが出力されます.

{
  "Headers": {
    "date": [
      "Wed, 19 Jun 2024 10:12:07 GMT"
    ],
    "content-length": [
      "641"
    ],
    "grpc-metadata-content-type": [
      "application/grpc"
    ],
    "content-type": [
      "application/json"
    ]
  },
  "ResponseBody": {
    "projects": [
      {
        "name": "projects/default",
        "uid": "1",
        "state": "ACTIVE",
        "title": "Default",
        "key": "DEFAULT",
        "workflow": "UI",
        "tenantMode": "TENANT_MODE_DISABLED",
        "webhooks": [],
        "dataClassificationConfigId": ""
      },
      {
        "name": "projects/project-sample",
        "uid": "101",
        "state": "ACTIVE",
        "title": "Sample Project",
        "key": "SAM",
        "workflow": "UI",
        "tenantMode": "TENANT_MODE_DISABLED",
        "webhooks": [],
        "dataClassificationConfigId": ""
      },
      {
        "name": "projects/hoge",
        "uid": "102",
        "state": "ACTIVE",
        "title": "hoge",
        "key": "HOGE",
        "workflow": "UI",
        "tenantMode": "TENANT_MODE_DISABLED",
        "webhooks": [],
        "dataClassificationConfigId": ""
      }
    ],
    "nextPageToken": ""
  },
  "StatusCode": 200,
  "StatusText": "OK"
}

Step Functions の IAM ポリシー

最後に API 実行のために必要だった IAM ポリシーをまとめます.まずは states:InvokeHTTPEndpoint 関連ですが,それぞれのエンドポイントメソッドを定義しました.

{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Sid": "InvokeHttpEndpoint1",
          "Action": [
              "states:InvokeHTTPEndpoint"
          ],
          "Resource": [
              "arn:aws:states:ap-northeast-1:1234567891011:stateMachine:*"
          ],
          "Condition": {
              "StringEquals": {
                  "states:HTTPEndpoint": [
                      "https://[Bytebaseの外部アクセス URL]/v1/auth/login",
                      "https://[Bytebaseの外部アクセス URL]/v1/instances"
                  ],
                  "states:HTTPMethod": [
                      "POST",
                      "GET"
                  ]
              }
          }
      }
  ]
}

あと EventBridge Connection 関連のポリシー定義で以下を設定しました.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Sid": "RetrieveConnectionCredentials1",
            "Action": [
                "events:RetrieveConnectionCredentials"
            ],
            "Resource": [
                "arn:aws:events:ap-northeast-1:1234567891011:connection/[EventBridge Connection 名]/*"
            ]
        },
        {
            "Effect": "Allow",
            "Sid": "GetAndDescribeSecretValue1",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret"
            ],
            "Resource": [
                "arn:aws:secretsmanager:ap-northeast-1:1234567891011:secret:events!connection/[EventBridge Connection 名]/*"
            ]
        },
        {
            "Resource": "arn:aws:events:ap-northeast-1:1234567891011:connection/[EventBridge Connection 名]",
            "Effect": "Allow",
            "Action": [
                "events:UpdateConnection"
            ]
        },
        {
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:1234567891011:secret:events!connection/[EventBridge Connection 名]/*",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:PutSecretValue"
            ]
        }
    ]
}

まとめ

Bytebase の API を Step Functions で叩くことをやったので,まとめました.

Bytebase の API を使って手動オペレーションの仕組み化を試みる【DB インスタンス編】

タダです.

Bytebase を使っていて手動オペレーションの中でいわゆるトイルになってしまって運用上負担になってしまう状況を改善したいと思い,API を使ってみることにしました.この記事では Bytebase の API を使用するための事前準備,認証,特定のエンドポイントを叩いてみた内容をまとめます.

事前準備

事前準備としてサービスアカウントのユーザーを作ります.Workspace Admin か DBA のロールを付与する必要があるため,DBAを設定して作成しました.作成後にサービスアカウントキーをコピーしておきます.

www.bytebase.com

API の認証

API の認証ために以下の環境変数を設定します.

export bytebase_url=[Bytebase の外部 URL]
export bytebase_account=[サービスアカウントのユーザーメールアドレス]
export bytebase_password=[サービスアカウントキー]

環境変数の設定後,認証のエンドポイントを叩いて, {"token": "API トークン"} が返ってくれば認証成功です.

bytebase_token=$(curl -X POST ${bytebase_url}/v1/auth/login \
    --data-raw '{"email":"'${bytebase_account}'","password":"'${bytebase_password}'","web":true}' \
    --compressed 2>&1 

{"token":"hoge"}

特定のエンドポイントを叩いて実行確認をしてみる

今回は Bytebase のライセンスの割当て/剥奪を実行してみます.Bytebase のライセンスを購入したら DB インスタンスの設定画面よりトグルで ON/OFF することでライセンスの割当て/剥奪を容易に実行できます.ただし,毎回手動オペレーションが発生しており,これを API で実行できるようにしたいというのが今回のモチベーションになっています.インスタンスの設定をいじることができるのは /v1/instances/{instance} のエンドポイントになります.

api.bytebase.com

コマンドで試した結果,以下の実行によりライセンスの割当てと剥奪を実行することができました.

curl --request PATCH \
  --url https://[Bytebaseのドメイン]/v1/instances/[Bytebaseに登録しているDBインスタンスID]?update_mask=activation' \
  --header 'Authorization: Bearer [取得した認証トークン]' \
  --data '{
  "activation": true(有効化)/false(無効化)
}'

まとめ

Bytebase の API を使って普段手動オペレーションしている作業を API で実行できないか試してみたので,試した内容をまとめました.今後もオペレーションが増えてきた場合は API からの実行を試みて行こうと思います.

関連記事

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

EventBridge ルールでワイルドカードのイベントを拾い Aurora クラスターとインスタンス作成を検知する

タダです.

Aurora を複製時に EventBridge ルールで特定 Aurora クラスターと DB インスタンスの作成タイミングを検知して Step Functions に処理させたいと思って,EventBridge ルールでワイルドカードを使ってみたので備忘録にまとめます.

EventBridge ルールのワイルドカード

EventBridge ルールのワイルドカードサポートは2023年10月に行われたもので,今回 Aurora を複製した時に特定の Aurora のイベントを拾って Step Functions で処理させたいと思ったのがきっかけで利用してみました.

aws.amazon.com

Aurora のイベントの中で拾えるもの

Aurora のイベントとして拾えるものはドキュメントに記載があります.この中から DB クラスター作成イベントと DB インスタンスの再起動イベントを拾うようにしました.DB クラスター作成イベントは疑問がないところだと思いますが,DB インスタンスはなぜ再起動イベントを拾ったかというと Aurora を複製イベントを見た際に①インスタンス作成 → ②インスタンスのシャットダウン → ③インスタンスの再起動 → ④(拡張モニタリングを有効化している場合)拡張モニタリングの有効化の順番で処理が走ったため,③のイベントを拾って最終的に DB 作成完了の通知を出そうと考えた次第です.

hoge から始まる Aurora クラスターの作成イベントを拾う場合

{
  "detail": {
    "EventID": ["RDS-EVENT-0170"],
    "SourceIdentifier": [{
      "wildcard": "hoge-*"
    }]
  },
  "detail-type": ["RDS DB Cluster Event"],
  "source": ["aws.rds"]
}

hoge から始まり clone という DB インスタンスの再起動イベントを拾う場合

{
  "detail": {
    "EventID": ["RDS-EVENT-0006"],
    "SourceIdentifier": [{
      "wildcard": "hoge-*-clone"
    }]
  },
  "detail-type": ["RDS DB Instance Event"],
  "source": ["aws.rds"]
}

これで特定のクラスターとインスタンスに関するイベントを拾えるようになるので,後はターゲットに Step Functions を指定すれば OK です.Step Functions からの通知部分は次の記事で書きます.

まとめ

EventBridge ルールのワイルドカードを使って特定 Aurora クラスターと DB インスタンスの作成タイミングを検知するルールを初めて使ったので記事にまとめました.

関連記事

sadayoshi-tada.hatenablog.com

sadayoshi-tada.hatenablog.com

Step Functions のパラメーターのバリデーションを設定する

タダです.

前回の記事で時限式の Aurora Clone の削除を Step Functions で試した記事を書きました.今回の記事ではその関連として Aurora を削除するときのパラメーターで渡す際に意図したインプットを次のステートに引き継げるようバリデーションを設けてみます.

sadayoshi-tada.hatenablog.com

Step Functions で行うバリデーション

削除する Aurora を意図したものだけ消して,関係ない Aurora を削除しないようにバリデーションを設けていくのですが,Step Functions のどういった設定を行うかを検討していきます.今回の要件としては削除する Aurora の DB インスタンス名をパラメーターとして渡す際に,関連するインスタンス名の文字列が渡ってきているかをチェックしたいです.そのために,Choice ステートを使います.文字列一致判定の演算子StringMatches があり,判定の値にはワイルドカードを使用することができます.この記事では taddy-test-*-clone という命名の DB インスタンスを削除するようにしたいという前提で,バリデーションを設定します.

設定例

{
 "Variable": "$.foo",
 "StringMatches": "log-*.txt"
}

関連記事 docs.aws.amazon.com

前回記事の ASL にバリデーションを足す

文字列のバリデーションを前回記事の ASL に足しました.InputVariableCheckek を足していています.taddy-test-*-clone という文字列でパラメーターが渡ってきたら Aurroa の削除のステートを実行できるようになります.逆にそれ以外のパラメーターが渡ってきたら失敗判定になるように Not 演算子を使っています.

{
  "Comment": "Delete Aurora Cluster and instance",
  "StartAt": "InputVariableCheckek",
  "States": {
    "InputVariableCheckek": {
      "Type": "Choice",
      "Choices": [
        {
          "Not": {
            "Variable": "$.DbInstanceIdentifier",
            "StringMatches": "taddy-test-*-clone"
          },
          "Next": "Fail"
        }
      ],
      "Default": "DeleteDBInstance"
    },
    "Fail": {
      "Type": "Fail"
    },
    "DeleteDBInstance": {
      "Type": "Task",
      "Parameters": {
        "DbInstanceIdentifier.$": "$.DbInstanceIdentifier",
        "SkipFinalSnapshot": true
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:deleteDBInstance",
      "Next": "DeleteDBCluster",
      "ResultSelector": {
        "DbClusterIdentifier.$": "$.DbInstance.DbClusterIdentifier"
      },
      "OutputPath": "$.DbClusterIdentifier"
    },
    "DeleteDBCluster": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier.$": "$",
        "SkipFinalSnapshot": true
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:deleteDBCluster",
      "End": true
    }
  }
}

試しに失敗のパラメーターを渡してみると期待通りに失敗判定になりました.

DbInstanceIdentifier として hoge を渡す

次に taddy-test-hoge-clone というバリデーションを通過するパラメーターを渡してみると DeleteDBInstance に進みました.

該当のクラスターがないためエラーが出ていますが,想定通りの分岐ができています

まとめ

Step Functions のパラメーターパリデーションを初めて設けてみたので,記事にしました.