こんにちは、Aireです。
今回はSystems Managerの一機能であるパラメータストアについて、自分で作成したパラメータの値をLambda関数を用いて定期的に更新する方法を紹介します。
本記事では、RHEL 9のAMI IDを格納するSSMパラメータを運用・管理するケースを例として実装方法を説明します。実装方法の概要ですが、SSMパラメータの作成や更新を行うLambda関数をデプロイし、EventBridgeのスケジュール機能を用いてLambda関数の定期実行を行います。作業時間の目安は約30分です。
パラメータストアにマイパラメータを作成する(所要時間:約5分)
はじめにパラメータストア上で、RHEL 9.xのAMI IDが格納されるパラメータを作成します。(後述のLambda関数を実行するとパラメータが自動的に作成または更新されるので実際の手順としては不要ですが、ここではパラメータの説明も兼ねて手動で作成する手順を記載します)
- [AWS Systems Managerコンソール] > [パラメータストア]に移動し、[パラメータの作成]をクリックします。
- パラメータの入力項目を設定し、[パラメータを作成]をクリックします。(任意の入力項目は省略)
- 名前:パラメータの意味が分かるような名前を入力します。本記事では
/cloudformation/ami-latest/rhel9uX
とします。(X
の部分はマイナーバージョン) - 利用枠:本記事では[標準]を選択します。パラメータポリシー(パラメータの有効期限)や他のAWSアカウントとの共有が必要であれば、[詳細]を選択してください。
- タイプ:[文字列]を選択します。
- データ型:[aws:ec2:image]を選択します。[text]でも良いですが、[aws:ec2:image]を選択すると、パラメータの値が有効なAMI IDかチェックしてくれるため、不正な値のパラメータを使用するリスクを減らしたりできます。
- 値:有効なAMI IDを確認して入力します(存在しないAMI IDやAMI ID以外の文字列を入力するとパラメータの作成に失敗します)。
- マイパラメータの一覧に表示されていることを確認します。
Lambda関数の実行ロールを作成する(所要時間:約5分)
ここでは、パラメータストアの値を更新するLambda関数を実行する上で必要なIAMロールを作成します。
次の章で作成するLambda関数では、以下の処理を行う予定です。
- RHEL AMIの情報を取得する
- Systems Managerのパラメータストアの値を更新する
これらの処理ができるように、以降の手順ではAmazonEC2ReadOnlyAccess
とAmazonSSMFullAccess
をアタッチしたIAMロールを作成します。
- [IAM]コンソール > [ロール]に移動し、[ロールを作成]をクリックします。
- [信頼されたエンティティタイプ]で[AWSのサービス]を選択後、[ユースケース]から[Lambda]を選択し、[次へ]をクリックします。
AmazonEC2ReadOnlyAccess
とAmazonSSMFullAccess
にチェックマークを入れて、[次へ]をクリックします。
- IAMロールの名前(本記事では
RoleForLambdaToUpdateSsmParameterForRHEL9Ami
とします)を入力し、[ロールを作成]をクリックすると本手順は完了です。
Lambda関数を作成する(所要時間:約10分)
本章では、実際にLambda関数を作成していきます。
- [Lambda]コンソールに移動し、[関数の作成]をクリックします。
- [一から作成]を選択し、以下の情報を入力した後、[関数の作成]をクリックします。
- 関数名:実行する内容が分かるように本記事では
updateRHEL9Ami
としています。 - ランタイム:本記事ではPython(バージョンは執筆時の最新のもの)を選択し、関数を作成します。
- アーキテクチャ:デフォルトのx86_64にします。
- 実行ロール:[既存のロールを使用する]を選択します。
- 既存のロール:作成したIAMロール(本記事では
RoleForLambdaToUpdateSsmParameterForRHEL9Ami
)を選択します。
Lambda関数のタイムアウト時間を変更する
少しはまったポイントになるのですが、Lambda関数をデプロイした後に動作確認テストをしてもパラメータストアの値が更新されませんでした。
調べてみた結果、Lambda関数のデフォルトのタイムアウト値(3秒)に対して、Lambda関数の実行時間(約5秒)が超過していたことが原因でした。そのため、本節ではタイムアウト値の変更を行います。
- 関数の画面にある[設定]タブに移動し、[編集]をクリックします。
- タイムアウト設定を変更します。今回作成するLambda関数の実行時間は約5秒だったので、本記事では2倍の猶予を持たせるということで10秒に変更しています。
Lambda関数のデプロイと動作確認を行う
ここではLambda関数のコードを貼り付けて動作確認を行います。
はじめに上図の①の箇所に、以下のコードを貼り付けます。その後、②の[Deploy]をクリックし、デプロイの完了メッセージが表示されたら、③の[Test]をクリックします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
import boto3 def lambda_handler(event, context): ec2 = boto3.client('ec2') ssm = boto3.client("ssm") versions = ['9.0', '9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '9.7', '9.8', '9.9', '9.10'] warnings = [] errors = [] for version in versions: try: response = ec2.describe_images( Filters=[ {'Name': 'name', 'Values': [f'RHEL-{version}.0_HVM-*']}, {'Name': 'state', 'Values': ['available']}, {'Name': 'architecture', 'Values': ['x86_64']}, {'Name': 'is-public', 'Values': ['true']} ], Owners=['309956199498'] ) parameter_name = f'/cloudformation/ami-latest/rhel{version.replace(".", "u")}' # `CreationDate`を基準に降順でソートして最新のAMIを取得 if response['Images']: latest_ami = sorted(response['Images'], key=lambda x: x['CreationDate'], reverse=True)[0] latest_ami_id = latest_ami['ImageId'] latest_ami_name = latest_ami['Name'] ssm.put_parameter( Name = parameter_name, Description = latest_ami_name, Value = latest_ami_id, Type = 'String', DataType = 'aws:ec2:image', Overwrite = True ) print(f'SSM parameter for RHEL {version} has been updated with AMI ID: {latest_ami_id} ({latest_ami_name})') else: try: ssm.get_parameter(Name=parameter_name) ssm.delete_parameter(Name = parameter_name) print(f"Deleted an existing SSM paramater for RHEL {version} because there is no public AMI for launching RHEL {version}") except ssm.exceptions.ParameterNotFound: print(f"There is no public AMI for launching RHEL {version}") warnings.append(f'There is no public AMI for launching RHEL {version}') except Exception as e: print(f'An unexpected error occurred while updating RHEL {version}: {str(e)}') errors.append(f'An unexpected error occurred while updating RHEL {version}: {str(e)}') if errors: return { 'statusCode': 500, 'message': 'Unexpected errors occurred while updating SSM parameters for RHEL versions' } elif warnings: return { 'statusCode': 404, 'message': 'Some SSM parameters were not updated due to missing available AMIs' } else: return { 'statusCode': 200, 'message': 'All SSM parameters have been updated' } |
③の[Test]をクリックすると、以下のようにテストイベントの設定画面が表示されます。[イベント名]を入力後、[保存]または[呼び出す]をクリックします。
前のステップで[保存]をクリックした場合は、下図の[Test]をクリックしLambda関数のテストをしてみます([呼び出す]をクリックした場合は、そのままLambda関数のテストが行われます)。先ほどのコードをそのまま貼り付けた場合は、実行結果として、下図の赤枠内のような結果が表示されると思います(AMI IDはその時々の最新のものが出力されるため、下図の結果とは異なる場合があります)。
パラメータストアに移動すると、先ほど作成したパラメータの値が更新されていることを確認できます。
EventBridgeで定期実行を設定する(所要時間:約10分)
最後にAmazon EventBridgeのスケジュール機能を使用して、デプロイしたLambda関数が定期的に自動実行されるように設定します。EventBridgeのスケジュール機能により、Lambda関数を特定の時刻もしくは一定の間隔(3時間ごとや2日ごとなど)で実行されるように指定できます。
スケジュールグループを作成する
次のステップで作成するEventBridgeのスケジュールは、スケジュールグループと呼ばれる入れ物に配置する必要があります。スケジュールグループの設定項目は名前とタグのみであり、配置するスケジュールグループによってスケジュールの動作が変わるわけではないため、特にこだわりがなければデフォルトのスケジュールグループdefault
をそのまま使用して良いと思いますが、ここではせっかくなのでAMI更新用のスケジュールグループを個別に作成します。
- [EventBridge]コンソール > [スケジュールグループ]に移動し、[スケジュールグループを作成]をクリックします。
- スケジュールグループの名前(本記事では
ScheduleGroupForLambdaToUpdateAmiId
)を入力し、[スケジュールグループを作成]をクリックします。
スケジュールを作成する
- [EventBridge]コンソール > [スケジュール]に移動し、[スケジュールを作成]をクリックします。
- スケジュール名(本記事では
ScheduleForLambdaToUpdateRHEL9Ami
)を入力します。 - 前のステップで作成したスケジュールグループ(本記事では
ScheduleGroupForLambdaToUpdateAmiId
)を選択します。
- スケジュールのパターンを設定します。本記事では、特定の時刻にLambda関数が実行されるようにcronベースのスケジュール設定をしてみます。以下の入力例では毎週土曜日の18:00にLambda関数が実行されるように設定しています。
- タイムゾーンを意識する必要がある場合は以下の時間枠も設定した方が良さそうですが、本記事ではスキップして[次へ]をクリックします。
- スケジュールのターゲットとして呼び出すAPIを選択します。今回はLambdaを選択します。
- 先ほど作成したLambda関数(本記事では
updateRHEL9Ami
)を選択し、[次へ]をクリックします。
- スケジュールの状態:[有効化]を選択します。
- スケジュール完了後のアクション:本記事では[NONE]を選択します。今後呼び出されることがないスケジュールを自動的に削除したい場合は[削除]を選択します。
- 再試行ポリシー:本記事では無効にします。Lambda関数が実行できなかった場合やLambda関数の実行に失敗した場合に本設定が有効にしてあると、ユーザが指定した回数分の再試行が行われます。
- デッドレターキュー(DLQ):本記事では無効にします。Lambda関数の実行に失敗したイベント情報を保存することができます。
- 暗号化:EventBridgeスケジューラが保存するデータは、デフォルトでAWSマネージドKMSキーによって暗号化されます。カスタマーマネージドKMSキーを使用したい場合は、チェック欄にチェックを入れて、KMSキーを選択します。
- アクセス許可:EventBridgeスケジュールがLambda関数を実行するためのIAMロールを作成します。[このスケジュールの新しいロールを作成]を選択すれば、適切なIAMロールを作成してくれます。
- [次へ]をクリックします。
- [スケジュールを作成]をクリックします。
スケジュールで指定した時刻以降にパラメータストアを確認すると値が更新されたことを確認できます。(UTC表記でタイムゾーンがずれていますが18:00に更新されています)
以上、ここまで。