AWS Systems Manager(SSM)のAutomation機能でDB特権ユーザーの利用を承認制にする
- yeda1343
- 9月5日
- 読了時間: 8分

目次
はじめに
私の参画しているプロジェクトでは、AWS上にデータを集約管理する「データ管理基盤」の構築を行っています。
DBの特権ユーザーについて、利用された場合に管理者に通知する仕組みはあるものの、パスワードを知っている人であればいつでも利用可能となっており、特権ユーザーを申請に基づいて一時的に有効化する仕組みがありませんでした。
AWS Systems ManagerのAutomationを用いて、DB特権ユーザーの利用を承認制にし、特権ユーザーのログイン有効化/無効化を自動化する承認フローを実装したので、紹介していきます。
AWS Systems Manager(SSM)とは
AWS Systems Manager(SSM)は、AWSクラウド、オンプレミス、マルチクラウド環境にまたがるサーバーや仮想マシン(ノード)を一元的に管理・運用できるマネージドサービスです。
SSMの主な機能
SSMは多機能な運用管理サービスであり、その主な機能は大きく以下の4つのカテゴリに分類されます。
アプリケーション管理
ノード管理
運用管理
変更管理
具体的にはこのような構成になっています。
AWS Systems Manager(SSM)
├── アプリケーション管理
│ ├── Parameter Store(パラメータ管理)
│ ├── AppConfig(アプリケーション設定管理)
│ └── Application Manager(アプリケーションリソース管理)
├── ノード管理
│ ├── Fleet Manager(ノード一元管理)
│ ├── Session Manager(リモート接続)
│ ├── Run Command(リモートコマンド実行)
│ ├── Patch Manager(パッチ管理)
│ ├── Inventory(インベントリ収集)
│ ├── State Manager(状態管理)
│ ├── Compliance(コンプライアンス管理)
│ ├── Distributor(ソフトウェア配布)
│ └── Hybrid Activations(オンプレミス連携)
├── 運用管理
│ ├── Incident Manager(インシデント管理)
│ ├── Explorer(運用ダッシュボード)
│ ├── OpsCenter(運用課題管理)
│ └── CloudWatch Dashboards(運用可視化)
└── 変更管理
├── Automation(自動化ワークフロー)
├── Document(SSMドキュメント)
├── Quick Setup(初期セットアップ自動化)
├── Maintenance Windows(メンテナンススケジューリング)
├── Change Manager(変更管理)
└── Change Calendar(変更カレンダー)
SSMのAutomationとは
これらの機能の中で、今回の承認フロー構築において大きな役割を果たすのがAutomationです。これは、AWSリソースの運用・管理タスクを自動化するための機能を指します。
Automationでは「Runbook」と呼ばれるワークフロー定義(JSON/YAML)を利用し、複数のAWSリソースに対して一連の操作を自動的に実行できます。
実行方法は以下の4つから選択できます。
シンプルな実行(Simple execution) 1回の実行、単一または少数リソース向け
レート制御(Rate control) 複数リソースに対し同時実行数・エラー閾値を制御
マルチアカウント・リージョン(Multi-account and Region) 複数AWSアカウント・リージョンをまたぐ一括実行
手動実行(Manual execution) ステップごとに進行を手動で制御、確認しながら実行
SSMのRunbookとは
RunbookはDocumentの一種であり、AWS Systems Manager(SSM)の「Automation」機能で利用される自動化手順書のことです。
Automation Runbookとも呼ばれ、AWSリソースやマネージドインスタンスに対して実行する一連のアクション(手順)を定義します。
Runbookには以下の2種類があります。
AWSが提供する事前定義済みRunbook
独自のカスタムRunbook
Runbookの主な構成要素は以下の通りです。
Runbook
├── description: Runbookの説明文
├── schemaVersion: Runbookのスキーマバージョン(例: 0.3)
├── parameters: Runbook実行時に入力するパラメータ群
│ ├── パラメータ名
│ │ ├── type: パラメータの型(例: String, StringList, Map)
│ │ ├── required: 必須かどうか(true/false)
│ │ ├── default: デフォルト値(省略可)
│ │ └── description: パラメータの説明
│ └── ...(複数パラメータを定義可能)
├── mainSteps: Runbookのメイン処理ステップ群
│ ├── ステップ名
│ │ ├── action: 実行するアクション(例: aws:runCommand等)
│ │ ├── name: ステップの名前
│ │ ├── inputs: ステップで使用する入力値
│ │ └── onFailure: 失敗時の挙動(オプション)
│ └── ...(複数ステップを定義可能)
└── outputs: Runbook実行後に返す出力値の定義(オプション)【例】AWS-StopEC2Instanceの事前定義済みRunbook

承認フローの構築
それでは、これらの知識を踏まえて実際に承認フローを構築してみましょう。
今回は、ユーザーが申請した使用開始・終了時刻に基づき、一時的にDB特権ユーザーを利用可能にする承認フローを作成します。
構築イメージ(Runbookの全体像)
以下はデザインモード(GUI)で表示した場合のRunbookです。今回はコードで作成しますが、Runbookの全体像の理解にご利用ください。

Step1:承認/否認 Step2:待機秒数計算 Step3:待機処理(利用開始) Step4:特権ユーザー有効化 Step5:待機処理(利用終了) Step6:特権ユーザー無効化 |
Step4及び6では、踏み台サーバーからpsqlコマンドでDB特権ユーザーの利用可否(LOGIN/NOLOGIN)を制御します。
※psqlはPostgreSQL に接続するクライアントコマンドです。コマンドラインからデータベースに接続し、SQLコマンドやpsql独自のメタコマンドを実行できます
Runbookの作成 ①Parametersセクション
まずは、申請に必要なパラメータをコードで定義します。
デフォルト値を設定することでユーザーの申請負荷を減らすことができます。
parameters:
Approvers:
type: StringList
description: 承認者(IAMユーザーもしくはIAMロール)
default:
- arn:aws:iam::<アカウントID>:role/aws-reserved/sso.amazonaws.com/<リージョン>/<ロール名>
SnsTopicArn:
type: String
description: SNS通知先
default: arn:aws:sns:<リージョン>:<アカウントID>:<トピック名>
EC2InstanceId:
type: String
description: psql実行用EC2インスタンスID
DBUser:
type: String
description: 特権DBユーザー名
DBName:
type: String
description: データベース名
StartTime:
type: String
description: '利用開始時刻(ISO8601、例: 2025-05-29T09:00:00Z)'
EndTime:
type: String
description: '利用終了時刻(ISO8601、例: 2025-05-29T10:00:00Z)'※承認者のパラメータはIAMユーザーの直接指定(リスト形式)もしくはIAMロールとなります
Runbookの作成 ②mainStepsセクション
続いて、各処理ステップをコードで定義します。
mainSteps:
#1.承認/否認
- name: approve
action: aws:approve
nextStep: calcSleepSeconds
isEnd: false
onFailure: Abort
inputs:
NotificationArn: '{{SnsTopicArn}}'
Message: 特権ユーザー利用の承認依頼
Approvers: '{{Approvers}}'
MinRequiredApprovals: 1
#2.待機秒数計算
- name: calcSleepSeconds
action: aws:executeScript
nextStep: sleepUntilStart
isEnd: false
inputs:
Runtime: python3.10
Handler: main
Script: |
import datetime
def parse_iso8601(s):
return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ")
def main(events, context):
start = parse_iso8601(events['StartTime'])
end = parse_iso8601(events['EndTime'])
now = datetime.datetime.utcnow()
sleep_to_start = int((start - now).total_seconds())
sleep_to_end = int((end - now).total_seconds())
if sleep_to_start < 0:
sleep_to_start = 0
if sleep_to_end < 0:
sleep_to_end = 0
return {
"SleepToStart": str(sleep_to_start),
"SleepToEnd": str(sleep_to_end)
}
InputPayload:
StartTime: '{{StartTime}}'
EndTime: '{{EndTime}}'
outputs:
- Name: SleepToStart
Selector: $.Payload.SleepToStart
Type: String
- Name: SleepToEnd
Selector: $.Payload.SleepToEnd
Type: String
#3.待機処理(利用開始)
- name: sleepUntilStart
action: aws:sleep
nextStep: enableLogin
isEnd: false
inputs:
Duration: PT{{calcSleepSeconds.SleepToStart}}S
#4.特権ユーザー有効化
- name: enableLogin
action: aws:runCommand
nextStep: sleepUntilEnd
isEnd: false
inputs:
DocumentName: AWS-RunShellScript
InstanceIds:
- '{{EC2InstanceId}}'
Parameters:
commands:
- |
# Parameter StoreからDB接続情報を取得
export PGPASSWORD=$(aws ssm get-parameter --name '/db/password' --with-decryption --query 'Parameter.Value' --output text)
export PGHOST=$(aws ssm get-parameter --name '/db/endpoint' --query 'Parameter.Value' --output text)
# 特権ユーザーのログイン権限を付与
psql -h $PGHOST -U usr_dbmgr -d {{DBName}} -c "ALTER ROLE {{DBUser}} LOGIN;"
#5.待機処理(利用終了)
- name: sleepUntilEnd
action: aws:sleep
nextStep: disableLogin
isEnd: false
inputs:
Duration: PT{{calcSleepSeconds.SleepToEnd}}S
#6.特権ユーザー無効化
- name: disableLogin
action: aws:runCommand
isEnd: true
inputs:
DocumentName: AWS-RunShellScript
InstanceIds:
- '{{EC2InstanceId}}'
Parameters:
commands:
- |
# Parameter StoreからDB接続情報を取得
export PGPASSWORD=$(aws ssm get-parameter --name '/db/password' --with-decryption --query 'Parameter.Value' --output text)
export PGHOST=$(aws ssm get-parameter --name '/db/endpoint' --query 'Parameter.Value' --output text)
# 特権ユーザーのログイン権限を剥奪
psql -h $PGHOST -U usr_dbmgr -d {{DBName}} -c "ALTER ROLE {{DBUser}} NOLOGIN;"これで承認フローの作成は完了です。続いて動作確認にうつりましょう。
※実環境実装時の留意点
DBパスワード管理 今回はDBパスワード管理にSSM Parameter StoreのSecureStringsを採用しています。 より厳密に管理したい場合はSecrets Manager等の利用を検討してください。
各ステップのエラー処理 今回はコード簡略化のため、各ステップのエラー処理を組み込んでいません。 実環境で実装する際は、各ステップのエラーハンドリングを適切に処理してください。
エラー処理を組み込んだ例(GUI)

AWSプロジェクトの人手不足でお困りではありませんか?
高い技術力を持つAWSエンジニアが、貴社の課題を解決します。
承認フローの動作確認
Automationの実行(承認申請)
パラメータを指定して実行します。
GUI

CLI
aws ssm start-automation-execution `
--document-name "<Runbook名>" `
--parameters "DBUser=<特権ユーザー名>,DBName=<データベース名>,StartTime=<利用開始時刻>,EndTime=<利用終了時刻>"承認依頼メールの受信
SNSトピックに登録されているメール(メーリングリスト)宛に承認依頼メールが送信されます。

承認オペレーション
承認者として指定されているIAMユーザーもしくは承認者ロールを持つIAM Identity Centerのワークフォースユーザー等で承認します。
CLI
aws ssm send-automation-signal `
--automation-execution-id <Automation ID> `
--signal-type Approve `
--payload Comment=OKDB接続時の挙動確認
ポートフォワーディングでSQLクライアント(A5M2等)から繋いだ場合の挙動を確認します。
承認中

承認外

上の画像のように、
承認中はDB特権ユーザーでDBにアクセスできる
承認外はDB特権ユーザーでDBにアクセスできない(ログイン権限がない旨のエラーメッセージが表示される)
となれば、想定通りです!
まとめ
ご紹介した通り、SSM Automationで簡易的な承認フローを作成できます。自動化により運用ミスも回避できるため、一時的な特権付与・剥奪などの権限制御に有用です。
【SSM Automationを用いた承認フローの主なユースケース】
IAMユーザーへの一時的な特権付与 参考:IAMユーザーに特権を一時的に付与する簡易承認ワークフローをSystems Manager (Automation) で実装してみた | DevelopersIO
DBユーザーへの一時的な特権付与 psqlの-cオプションにて下記SQL文で制御
GRANT/REVOKE rds_superuser FROM <DBユーザー>;DB特権ユーザーの一時的な利用許可(ログイン権限付与) psqlの-cオプションにて下記SQL文で制御
ALTER ROLE <DB特権ユーザー> LOGIN/NOLOGIN;今回は3つ目の方法を解説しました。 皆さまの業務やアイデアにもご活用いただければと思います。
AWSプロジェクトの人手不足でお困りではありませんか?
高い技術力を持つAWSエンジニアが、貴社の課題を解決します。




