こんにちは。SREの井上です
Teamsからセキュリティグループの設定を一括変更できるようにしてみました。
ざっくりと構成図
仕組みとしては
1.TeamsでAWS Systems Managerコマンドを実行する
2.Amazon Q Developer in chat applicationsが走る
3.Amazon Q Developer in chat applicationsがAWS Systems ManagerのDocument(※1)を基にRunCommandを走らせる
※1 AWS Systems ManagerのDocumentには、「指定したEC2インスタンスに置いてある.shファイル(※2)を実行する」という設定がされている。
※2 .shファイルにはセキュリティグループ変更関連のスクリプトが記載されている。
という感じです。
主に使用しているツール
AWS
●Amazon Q Developer in chat applications (旧称: AWS Chatbot)
⇒名称が長いのでこの先はChatbotと記述します。
●EC2インスタンス
●AWS Systems Manager:Document、RunCommand
⇒名称が長いのでこの先はSSMと記述します。
●IAMロール、ポリシー
AWS外
●Teams(Slackでもできると思います)
できること
セキュリティグループに設定されている特定のIPアドレスを一括変更
使用例:1.1.1.1というIPアドレスを2.2.2.2に上書きしたい場合
※変更前のIPアドレス(上記だと1.1.1.1)を失念した場合、このツールは使えない
できないこと
既存セキュリティグループへのIPアドレス新規追加
理由:セキュリティグループのIDを指定する必要があるため、SRE以外には管理が難しい
ALBリスナールールで設定されているIPアドレスの変更
理由:なんとなく実装はできそうだが管理が煩雑になる気がする
セキュリティグループに設定されている特定のIPアドレスを0.0.0.0/0へ変更、及び0.0.0.0/0からの変更、もしくは会社IP関連の変更
理由:一歩間違えると重大インシデントになりかねないため
作ってみよう
1.事前準備
AWS CLI v2入りのEC2インスタンスを用意し、SSMが使えるようにしておく必要があります。
SSMの設定に関しては公式ドキュメントを参考にしてください。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-setting-up-ec2.html
同じEC2インスタンスの適当な場所に、以下リポジトリにある.shファイルをアップしてください。実行権限はec2-userを想定して進めます。
https://github.com/sp-inoue/shellscript-sg
.shファイルについてちょっと説明
SSMコマンド実行時に引数として変更前のIPを入力します(使用方法は後述します)。その変更前のIPが設定上あるかどうか、をまずは確認しています。
あったら当該のセキュリティグループに設定されている変更前のIPを変更後のIPに変更、なかったらエラーを返すようにしています。
Port、Descriptionの設定内容は引き継がれます。
2.IAMポリシーの作成
ポリシーは4つ作成します。それぞれのポリシーに設定しているjsonの中身を以下に記載します。
ポリシー①:Chatbotチャネルのガイドラインに付与するポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*",
"logs:PutLogEvents",
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssm:SendCommand",
"ssm:GetCommandInvocation",
"ssm:ListCommandInvocations"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "arn:aws:iam::アカウントID:role/後述する「ロール①」
}
]
}
ポリシー②:後述する「ロール①」に付与するためのポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:SendCommand",
"ssm:GetCommandInvocation",
"ssm:ListCommandInvocations"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": [
"arn:aws:iam::アカウントID:role/後述する「ロール①」",
]
}
]
}
ポリシー③:Chatbotのチャネルロールとユーザーロールに設定するためのポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::アカウントID:role/後述する「ロール①」",
]
}
]
}
ポリシー④:後述するIAMロール①とロール②共通設定
※アカウント内全てのEC2インスタンスに対する許可設定が入っていますが、必要に応じてインスタンスIDを指定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:SendCommand",
"ssm:GetCommandInvocation",
"ssm:ListCommandInvocations",
"ssm:DescribeDocument",
"ssm:ListDocuments",
"ssm:DescribeInstanceInformation"
],
"Resource": [
"arn:aws:ssm:ap-northeast-1:アカウントID:document/この後作成するSSMドキュメント名",
"arn:aws:ec2:ap-northeast-1:アカウントID:instance/*"
]
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::アカウントID:role/後述する「ロール①」",
]
},
{
"Effect": "Allow",
"Action": [
"ec2:Describe*"
],
"Resource": "*"
}
]
}
3.IAMロールの作成
IAMロールは2つ作成します。
ロール①:Teamsからssmコマンドを実行する為のロール
先程作成した「ポリシー②」と「ポリシー④」と、AWS管理の以下ポリシーをアタッチ
AmazonSSMFullAccess
AmazonSSMManagedInstanceCore
AWSResourceExplorerReadOnlyAccess
ロール②:AmazonQを使用する為のロール、Chatbotのチャネルロールとユーザーロールに設定する
先程作成した「ポリシー③」と「ポリシー④」をアタッチ
4.Chatbot(Amazon Q Developer in chat applications)とTeamsの紐づけ
AWSコンソールにてAmazon Q Developer in chat applicationsを開き、チャットクライアントをTeamsに設定します。
使用したいTeamsのチャネルアドレスを貼付します。
設定すると左メニューにチャネル名が表示されるので、そこから詳細画面へ移り、新しいチャネルを設定に移ります。
設定名やチャネルURLは適切なものを入力してください。
ロール設定のチャネルロールにて「既存のIAMロールを使用する」を選択し、先程作成した「ロール②」を指定します。
チャネルガードレールポリシーには先程作成した「ポリシー①」を指定して、ここでの設定は終わりです。
5.SSMドキュメントの作成
AWSコンソールにてSystemsManager>ドキュメントに移ります。
ドキュメントの作成>コマンドまたはセッションを選択します。
ターゲットタイプを「/AWS::EC2::Instance」とし、コンテンツはJSONを指定して以下のJSONを入力します。
{
"schemaVersion": "2.2",
"description": "Command Document Example JSON Template",
"parameters": {
"OLDIP": {
"type": "String",
"description": "Previous IP address",
"default": "hoge"
},
"NEWIP": {
"type": "String",
"description": "New IP address",
"default": "hoge"
}
},
"mainSteps": [
{
"action": "aws:runShellScript",
"name": "example",
"inputs": {
"runCommand": [
"cd /home/ec2-user", #.shファイルををアップロードしたファイルパス
"./ip_address_change.sh {{OLDIP}}/32 {{NEWIP}}/32"
]
}
}
]
}
今回はCIDRを/32で固定していますが、必要に応じて修正してください。
使ってみよう
設定ができたので動作確認します。
Chatbotと紐づけをしたTeamsのチャネルにて、@Amazon Qにメンションを付け、以下のコマンドを実行します。
変数の値は適宜ご変更ください。
ssm send-command --targets Key=InstanceIds,Values=インスタンスID --document-name 作成したドキュメント名 --cloud-watch-output-config CloudWatchOutputEnabled=true,CloudWatchLogGroupName="ログを出力するファイル" --parameters OLDIP=変更前IP,NEWIP=変更後IP --region ap-northeast-1
実際に使ってみるとこんな感じ
ログが不要の場合は以下の部分を除いて実行してください。
-cloud-watch-output-config CloudWatchOutputEnabled=true,CloudWatchLogGroupName="ログを出力するファイル"
コマンドの実行に成功したか失敗したかはSSMのRunCommandから確認できます。先程のキャプチャ赤枠部分にあるコマンドIDを控えておくと探しやすいです。
成功するとこんな感じ
上記のインスタンスIDを選択すると詳細を見ることができます。
成功した場合、変更されたセキュリティグループのIDがOutputに表示されます。
ちなみに失敗するとこんな感じ
インスタンスIDから出力先の詳細にいくと、Outputに失敗した理由が出力されています。
今回は変更前IPが設定上存在しなかったため、失敗となりました。
以下のパターンに該当すると失敗します。
●変更前IPが設定上存在しない場合
●0.0.0.0を変更前、変更後IPとして設定した場合
●会社の固定IPを変更前、変更後IPとして設定した場合
今後の課題
実はコマンドが成功したか失敗したかの確認が現状だとSSMのRunCommandでしかできません…。
CloudWatchLogsと紐づけるとSNS通知ができるっぽいので絶賛実装中です。できたら追記したいと思います。