継続は力なり

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

Aurora 削除時に Bytebase API を実行するよう Step Functions で自動化する

タダです.

以下の記事を書きました.今回はこれらの記事でやっていることを1つのワークフローで実現するために行ったことをまとめます.つまり,時限式で Aurora を削除する際に合わせて Bytebase API を叩いて普段手動で触っているオペレーションを自動化します.

sadayoshi-tada.hatenablog.com sadayoshi-tada.hatenablog.com sadayoshi-tada.hatenablog.com

自動化した概要

自動化したオペレーションも以前に記事を書いたものになるのですが, Bytebase のライセンスの割当て/剥奪処理です.毎回手動オペレーションが発生しており,削除する Aurora では不要になるためライセンスの剥奪を行う処理をワークフロー内に入れることにしました.

sadayoshi-tada.hatenablog.com

作成した Step Functions のワークフロー

作成したワークフローの ASL が以下になります.

{
  "Comment": "Delete Aurora Cluster and instance,Bytebase API exec",
  "StartAt": "InputVariableCheck",
  "States": {
    "InputVariableCheck": {
      "Choices": [
        {
          "Next": "Fail",
          "Not": {
            "StringMatches": "taddy-test-*-clone",
            "Variable": "$.DbInstanceIdentifier"
          }
        }
      ],
      "Default": "DescribeDBInstances",
      "Type": "Choice"
    },
    "DescribeDBInstances": {
      "Next": "GetBytebaseServiceAPIUserCredential",
      "Parameters": {
        "DbInstanceIdentifier.$": "$.DbInstanceIdentifier"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBInstances",
      "Type": "Task"
    },
    "Fail": {
      "Cause": "Invalid input variable provided.(e.g. taddy-test-*-clone)",
      "Error": "Invalid input variable provided.",
      "Type": "Fail"
    },
    "GetBytebaseServiceAPIUserCredential": {
      "Next": "Call Bytebase Authrization API",
      "Parameters": {
        "SecretId": "[Secrets Manager名]"
      },
      "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
      "ResultPath": "$.TaskResult",
      "Type": "Task"
    },
    "Call Bytebase Authrization API": {
      "InputPath": "$.TaskResult.SecretString",
      "Next": "UpdateConnection",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/auth/login",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        },
        "Method": "POST",
        "RequestBody": {
          "email": "[サービスアカウントのアドレス]",
          "password.$": "$",
          "web": true
        }
      },
      "Resource": "arn:aws:states:::http:invoke",
      "ResultPath": "$.TaskResult",
      "Retry": [
        {
          "BackoffRate": 2,
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 5,
          "MaxAttempts": 3
        }
      ],
      "Type": "Task"
    },
    "UpdateConnection": {
      "InputPath": "$.TaskResult.ResponseBody.token",
      "Next": "Call Bytebase Licese Deactivation API",
      "Parameters": {
        "AuthParameters": {
          "ApiKeyAuthParameters": {
            "ApiKeyName": "Authorization",
            "ApiKeyValue.$": "States.Format('Bearer {}',$)"
          }
        },
        "AuthorizationType": "API_KEY",
        "Name": "[EventBridge Connection名]"
      },
      "Resource": "arn:aws:states:::aws-sdk:eventbridge:updateConnection",
      "ResultPath": "$.TaskResult",
      "Type": "Task"
    },
    "Call Bytebase Licese Deactivation API": {
      "InputPath": "$.DbInstances[0].DbClusterIdentifier",
      "Next": "DeleteDBInstance",
      "Parameters": {
        "ApiEndpoint.$": "States.Format('https://[Bytebaseの外部アクセス URL]/v1/instances/{}', $)",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        },
        "Method": "PATCH",
        "QueryParameters": {
          "update_mask": "activation"
        },
        "RequestBody": {
          "activation": false
        }
      },
      "Resource": "arn:aws:states:::http:invoke",
      "ResultPath": "$.TaskResult",
      "Retry": [
        {
          "BackoffRate": 2,
          "ErrorEquals": [
            "States.ALL"
          ],
          "IntervalSeconds": 5,
          "MaxAttempts": 3
        }
      ],
      "Type": "Task"
    },
    "DeleteDBInstance": {
      "InputPath": "$.DbInstances[0].DbInstanceIdentifier",
      "Next": "DeleteDBCluster",
      "Parameters": {
        "DbInstanceIdentifier.$": "$",
        "SkipFinalSnapshot": true
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:deleteDBInstance",
      "Type": "Task"
    },
    "DeleteDBCluster": {
      "End": true,
      "Parameters": {
        "DbClusterIdentifier.$": "$.DbInstance.DbClusterIdentifier",
        "SkipFinalSnapshot": true
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:deleteDBCluster",
      "Type": "Task"
    }
  }
}

作成されるワークフローイメージ図

個別のステートは冒頭の過去記事に記載している内容なので割愛しますが,全体のワークフローで必要な設定を書きます.

最初の DescribeDBInstances の結果を DeleteDBInstance まで保持する

通常ですと Step Functions のステートの結果は次のステートまでしか保持できませんが, ResultPath を用いるとそれが実現できました.つまり DescribeDBInstances で得られた出力をそのまま後続のステートで保持しつつ,後続のステートの結果も保管するために $.TaskResult という ResultPath に出力します.この設定によって DescribeDBInstances の結果を使用しないステートで直前のステートの結果を使いたい場合に役立ちます.以下の定義だと, GetBytebaseServiceAPIUserCredential の結果を Call Bytebase Authrization APIInputPath として $.TaskResult.SecretString で扱えるようにしました.

TaskResult に直前の結果を保存する使いまわし例

    "GetBytebaseServiceAPIUserCredential": {
      "Next": "Call Bytebase Authrization API",
      "Parameters": {
        "SecretId": "[Secrets Manager名]"
      },
      "Resource": "arn:aws:states:::aws-sdk:secretsmanager:getSecretValue",
      "ResultPath": "$.TaskResult",
      "Type": "Task"
    },
    "Call Bytebase Authrization API": {
      "InputPath": "$.TaskResult.SecretString",
      "Next": "UpdateConnection",
      "Parameters": {
        "ApiEndpoint": "https://[Bytebaseの外部アクセス URL]/v1/auth/login",
        "Authentication": {
          "ConnectionArn": "[EventBridge Connection の ARN]"
        },
        "Method": "POST",
        "RequestBody": {
          "email": "[サービスアカウントのアドレス]",
          "password.$": "$",
          "web": true
        }
      }

docs.aws.amazon.com

まとめ

Aurora 削除時に Bytebase API を実行するよう Step Functions で自動化した例と設定で気にしたことをまとめました.