SSMセッションマネージャでサーバ運用

弊社では以前からAWS環境のEC2(LinuxWindows問わず)にリモートアクセスする際は、コンソールサーバ経由でブラウザ接続していました。ただ、現行のコンソールサーバからSSMセッションマネージャを経由するよう、Linuxサーバへのリモートアクセス運用を現在進行形で移行中です。 言わずと知れた機能ですが、ついでにSlack通知もできるようにしたため、ご紹介します。

SSMセッションマネージャの動作環境

Session Manager の使用開始 に色々と書いてありますが、本記事では準備が完了したEC2(CentOS 7.6)を使います。

  • 対象サーバにSSMエージェントがインストール済み
  • SSMセッションマネージャに対応するIAMポリシーが付与されていること
  • 各サーバからはインターネット接続が可能であること

大雑把に言ってしまえば、上記の3つでしょうか。
IAMポリシーによる制御については、Session Manager の使用開始のステップ2に記載されています。
3点目を補足するなら、パブリックサブネットのサーバはもちろん、NATGW経由やPrivateLink経由でも、SSM機能は動作します。
SSMエージェントを導入しておけば、オンプレ機器に対してもセッションマネージャからログイン可能な点もメリットですね。

 

SSMセッションマネージャの設定

SSMセッションマネージャの設定

SSMセッションマネージャの数少ない設定内容は、ログデータの扱いだけです。 今回はS3にセッションログを出力しています。

Lambda関数の作成

SSMセッションの開始を検知してSlack通知するLambda関数です。 本記事では、CloudWatch Eventの「AWS API Call via CloudTrail」をトリガーに使用しました。

CloudWatch Event設定

検知したいイベント名は「StartSession」になります。 CloudWatch Event設定後のイベントパターン定義は次の通りです。

{
  "source": [
    "aws.ssm"
  ],
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "ssm.amazonaws.com"
    ],
    "eventName": [
      "StartSession"
    ]
  }
}

Lambda関数のコード

詳細は省略しますが、今回は下記情報を通知しています。

  • Start Time: CloudTrailログのUTC時刻。メッセージではJSTに変換。

  • User: SSMセッションマネージャを使用したIAMユーザ。
    SSMのセッションID自体にユーザ名が含まれているため、そこから抽出。

  • Server: ログイン先のインスタンスID。

  • Session ID: 一意のSSMセッションID。

 

Slackへの通知内容は、以下のようになります。

Slackへの通知内容 今回作成したLambda関数のコードは、次の通りです。 下記コードの send_data ではemojiも指定できるので、癒されたい絵文字をお持ちの方は是非使ってください。

import json
import urllib.request
from datetime import datetime, date, timedelta


def notice_slack(start,user,target,id):

    msg = '''
Start Time: %s
User: %s
Server: %s
Session ID: %s
''' % (start,user,target,id)

    send_data = {
        "username": "ssm-session_start",
        "text": msg,
    }
    send_text = "payload=" + json.dumps(send_data)

    request = urllib.request.Request(
        "https://hooks.slack.com/services/~~~", 
        data=send_text.encode("utf-8"), 
        method="POST"
    )
    
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")
    

def lambda_handler(event, context):
    start_s = event['time']
    start_t = datetime.strptime(start_s, '%Y-%m-%dT%H:%M:%SZ') + timedelta(hours=9)
    print(start_t)
    start = datetime.strftime(start_t, '%Y-%m-%dT%H:%M:%SJST')
    target = event['detail']['requestParameters']['target']
    id = event['detail']['responseElements']['sessionId']
    user = id[0:(len(id) - 18)]
    
    print(start)
    print(user)
    print(target)
    print(id)
    
    notice_slack(start,user,target,id)

 

SSMセッションマネージャ経由のログイン

「ターゲットインスタンス」を選択後、「セッションの開始」をクリックすると、ターミナルがブラウザの新規画面(タブorウィンドウ)で開かれます。ログインユーザは「ssm-user」で、ログインシェルは sh のようです。

ちなみに、Githubでわりに紛糾しているissueで、
Custom Shell for aws ssm start-sessionがあります。
現在、コメント数は第2位。。ssm-userのログインシェルなんてどーでもいい、とは思えないギークな人が多いのです。
なお、コメント数が一番多いのは、「コピペするとセッションマネージャが遅い」というissueです。

 

最後に

SSMセッションマネージャはブラウザベースですが、SSH接続であることに変わりはありません。
ただ、セキュリティグループ等のインバウンド通信要件が不要であり、リモートアクセスの監査ログも楽できます。弊社では以前から、EC2へのリモートアクセスにApache Guacamoleを使ってきましたが、Linuxサーバに関しては順次、SSMセッションマネージャ方式に移行しています。
Windows OS等のGUI環境への接続では、今後もApache Guacamoleで構築したコンソールサーバに頼っています

ただ、ブラウザベースでサーバにログインできる分、それなりの考慮点はでてきます。 例えば次の点などがあります。

  • AWSコンソールの認証方式が重要 →弊社ではOneloginでカバーしています。 →IAMポリシーでは、必要に応じてSSMセッション先を制限することも可能です。
  • SSMセッションの「ssm-user」が制限なしのsudo権限を持っている →「1つのサーバを複数OSユーザで運用を使い分けたい」という要望など、実運用に合わないケースもあります。 →/etc/sudoers.d/ssm-agent-users が自動生成されている影響です。例として、以下のように変更すればOSユーザを運用で使い分け可能になります。
##差分のみ表示
#ssm-user ALL=(ALL) NOPASSWD:ALL
ssm-user ALL=(ALL) NOPASSWD:/usr/bin/su - test01
ssm-user ALL=(ALL) NOPASSWD:/usr/bin/su - test02

 

 

このブログの著者

 

 

アプリケーション開発バナー