AWS Lambdaで自動化

AWSクラウドでコマンダーを実行

概説

コマンダーは、さまざまな問題を解決し、Keeper Security環境に関する貴重な情報が得られる強力なツールです。ローカルのデスクトップやサーバーで使用するだけでなく、AWSのようなクラウド環境でコマンダーを実行して、スケジュールされたまたはオンデマンドの要件を実行することも可能です。

この例では、コマンダーをAWS Lambdaと連携させ、ユーザーおよび使用状況のレポートを定期的に実行する方法を解説します。

要件

  • コマンダー

  • マスターパスワードログイン方式を使用するKeeperユーザーアカウント (SSOログインとMFAはユーザー操作なしでは利用できません)。

  • AWSでLambda関数および関連するレイヤーを作成する権限、ならびにAWS CloudShellへのアクセス権限が必要です。

手順

Cloud 9を使用してLambdaレイヤーを作成

セットアップ

コマンダーは、AWS Lambdaで実行する環境に一致するマシンでパッケージ化する必要があります。そのためにCloudShellでコマンダーパッケージを作成することができます。

AWS CloudShellにはPython 3.7があらかじめインストールされていますが、Lambdaレイヤーを構築する際にサポートされているPythonのバージョン (3.6~3.11) を使用していることを確認するために、CloudShellコンソールでインストールされているPythonインタープリタのバージョンを確認してください。

$ python3 --version
Python 3.9.16

使用中のPythonのバージョンがコマンダーでサポートされていない場合は、上記のサポートされているバージョンのいずれかをインストールしてから作業をお進めください。

レイヤーコンテンツの構築

次の段階では、CloudShell環境内で実行できる便利なシェルスクリプトをご用意しました。このスクリプトは、Lambdaレイヤー用に必要な keepercommander パッケージを含むZIPファイルを作成します。

このスクリプトは、さまざまなコマンド呼び出しをまとめるだけでなく、keepercommander パッケージとその依存関係に特有のビルドプロセスの細かな問題を抽象化することで、レイヤーコンテンツのパッケージングを簡略化し、効率化することを目的としています。エラーが発生しにくいため、この方法を使用することを強くお勧めします。

スクリプトを見る
package_layer_content.sh
#!/usr/bin/env bash

# AWS Lambda 関数用の `keepercommander` 依存関係レイヤーを作成する
# 
# 1. このスクリプトを CloudShell 環境内の任意のフォルダにアップロードします。
# 2. (オプション) プロジェクトの `requirements.txt` ファイルを同じフォルダにアップロードします。
# 3. そのフォルダ内で次のコマンドを実行します:
#    source ./package_layer_content.sh
# 4. 実行後、同じフォルダ内に `commander-layer.zip` という名前のファイルが作成されます。
#    この ZIP ファイルを S3 バケットにアップロードし、Lambda レイヤーの作成に使用します。

MAX_LIB_SIZE=262144000
LAYER_FILENAME='commander-layer.zip'
LAYER_PATH=$(pwd)/$LAYER_FILENAME
LIB_DIR='python'
VENV='commander-venv'
OTHER_DEPS='requirements.txt'

# 過去のアーティファクトをクリーンアップ
test -f $LAYER_FILENAME && rm $LAYER_FILENAME
test -d $LIB_DIR && rm -rf $LIB_DIR
test -d $VENV && rm -rf $VENV

# ZIPファイル用のパッケージフォルダを作成
mkdir $LIB_DIR

# 仮想環境を作成して実行
python -m venv $VENV
source ./$VENV/bin/activate

# 依存関係をインストールしてパッケージ化
pip install cryptography --platform manylinux2014_x86_64 --only-binary=:all: -t $LIB_DIR
pip install keepercommander -t $LIB_DIR

if test -f $OTHER_DEPS; then
  pip install -r $OTHER_DEPS -t $LIB_DIR
fi

deactivate

# 解凍後のライブラリサイズを確認
LIB_SIZE=$(du -sb $LIB_DIR | cut -f 1)
LIB_SIZE_MB=$(du -sm $LIB_DIR | cut -f 1)

if [ "$LIB_SIZE" -ge $MAX_LIB_SIZE ]; then
  echo "*****************************************************************************************************************"
  echo 'Operation was aborted'
  echo "The resulting layer has too many dependencies and its size ($LIB_SIZE_MB MB) exceeds the maximum allowed (~262 MB)."
  echo 'Try breaking up your dependencies into smaller groups and package them as separate layers.'
  echo "*****************************************************************************************************************"
else
  zip -r $LAYER_FILENAME $LIB_DIR
  echo "***************************************************************************"
  echo "***************************************************************************"
  echo 'Lambda layer file has been created'
  printf "To download, copy the following file path: %s\n%s\n$LAYER_PATH%s\n%s\n"
  echo 'and click on "Actions" in the upper-right corner of your CloudShell console'
  echo "***************************************************************************"
fi

# クリーンアップ
rm -rf $LIB_DIR
rm -rf $VENV
2KB
開く
keepercommander Lambda Layerコンテンツのパッケージング用 Bash スクリプト

上記のスクリプトを使用するには、以下を実行します。

  1. スクリプトをCloudShell環境内の任意のフォルダ(できれば空のフォルダ)にアップロードします。

    • (オプション) プロジェクトに依存関係のリストが含まれているrequirements.txt ファイルがある場合、そのファイルを同じフォルダにアップロードし、keepercommanderパッケージに加えて依存関係も結果のレイヤーに含めることができます。

  2. 同じフォルダ内で、ターミナルで以下のコマンドを実行します。

source ./package_layer_content.sh
  1. 現在のフォルダにcommander-layer.zipというZIPファイルが作成されているはずです。このファイルが、Lambdaレイヤーのコンテンツを表しています。

Lambdaレイヤーのコンテンツにはサイズ制限があります (S3に保存されている場合でも)。上記のスクリプトでrequirements.txtファイルで追加の依存関係を含めようとしてその結果コンテンツの総サイズが制限を超えると、作成されたZIPファイルが使用できなくなります。この状況が検出された場合、スクリプトはレイヤーコンテンツを出力せず、代わりにメッセージが表示されます。

比較的簡単な解決策としては、依存関係を小さなグループに分割し、それぞれを個別のレイヤーにパッケージ化します。requirements.txtからいくつか (またはすべて) の依存関係を削除し、再度スクリプトを実行することができます。その結果、パッケージに含まれなかった依存関係は、標準のパッケージングプロセスを使用して別のレイヤーとしてパッケージ化できます。

コンテンツZipファイルからのレイヤーの作成と更新

結果として生成されるZIPファイルは50MB以上 (Lambdaレイヤーに直接アップロードできる最大サイズ) になるため、最初にAWS S3バケットにアップロードし、その後、生成されたS3アイテムをLambdaレイヤーにリンクする必要があります。

残りの手順を完了する方法はいくつかありますが、GUIベースの方法を好まれる場合はAWSコンソールをご使用ください。ただし、すでにCloudShell環境内にいるため、組み込みのAWS CLIコマンドラインツールを使用するのが最も簡単ですので、ここではその方法をご紹介します。

  1. まず、ZIPファイルをAWS S3にアップロードする必要があります。このタスク用にS3バケットをまだ作成していない場合は、CloudShellで以下のコマンドを実行して作成できます。

$ aws s3 mb <bucket-name>

ここで、 <bucket-name>はグローバルで固有の名前である必要があります。

  1. 新しくパッケージしたZipファイルをCloudShellからS3バケットへアップロードします。

$ aws s3 cp ./commander-layer.zip 's3://<bucket-name>'
  1. アップロードしたコンテンツでLambdaレイヤーを公開します。

$ aws lambda publish-layer-version --layer-name <layer-name> \
--description <layer-description> \
--content "S3Bucket=<bucket-name>,S3Key=commander-layer.zip" \
--compatible-runtimes python<your-version>

Lambdaの作成

AWS Lambdaで、Lambdaエディタを使用してPython関数を作成します。

lambda_handler 関数は、処理される際にLambdaによって呼び出されます。

以下は、コマンダーLambda関数の完全な例となります。

#  _  __
# | |/ /___ ___ _ __  ___ _ _ ®
# | ' </ -_) -_) '_ \/ -_) '_|
# |_|\_\___\___| .__/\___|_|
#              |_|
#
# Keeper Commander
# Copyright 2024 Keeper Security Inc.
# Contact: [email protected]

import os

# マウントされたボリュームがない場合、Lambdaは /tmp にのみ書き込み可能です。 
# 次の環境変数は、Pythonのインポートキャッシュがユーザーフォルダではなく 
# /tmp に書き込まれるようにするために必要です。
os.environ['HOME'] = '/tmp'
os.environ['TMPDIR'] = '/tmp'
os.environ['TEMP'] = '/tmp'

from keepercommander import api
from keepercommander.__main__ import get_params_from_config

# 既定では、Keeper CommanderはJSON構成を保存するために 
# ユーザーフォルダに .keeper ディレクトリを作成しようとします。
# このケースでは /tmp に .keeper ディレクトリを作成し、 
# JSON構成(get_params_from_config() を使用)を保存します。
keeper_tmp = '/tmp/.keeper'
os.makedirs(keeper_tmp, exist_ok=True)

# ------------------------------------------------------
# Keeper初期化関数
# ------------------------------------------------------
def get_params():
    # 既定のJSON構成の場所を /tmp に変更
    params = get_params_from_config(keeper_tmp + '/config.json') 

    # Keeper Commanderログイン用のユーザー名とパスワードを設定
    #params.config = {'sso_master_password': True} # SSOユーザーにマスターパスワードログインを強制
    #params.server = os.environ.get('KEEPER_SERVER') # https://keepersecurity.com
    params.user = os.environ.get('KEEPER_USER')
    params.password = os.environ.get('KEEPER_PASSWORD')
    return params

# ------------------------------------------------------
# Keeper JSONレポート関数
# ------------------------------------------------------
def get_keeper_report(params, kwargs):
    from keepercommander.commands.aram import AuditReportCommand
    from json import loads
    
    report_class = AuditReportCommand()
    report = report_class.execute(params, **kwargs)
    return loads(report)
    
# ------------------------------------------------------
# Keeper CLI関数
# ------------------------------------------------------
def run_keeper_cli(params, command):
    from keepercommander import cli
    
    cli.do_command(params, command)
    # 戻り値はありません。この関数はCLIコマンドを実行するだけで、 
    # Pythonでは何も返しません。
    
# ------------------------------------------------------
# Lambdaハンドラー
# ------------------------------------------------------
def lambda_handler(event, context):
    # Keeper Commanderのパラメータを初期化
    params = get_params()

    # Keeperにログインして同期
    api.login(params)
    api.sync_down(params)
    # エンタープライズ同期(エンタープライズコマンド用)
    api.query_enterprise(params)

    run_keeper_cli(
        params, 
        'device-approve -a'
    )
    
    run_keeper_cli(
        params, 
        'action-report --target locked --apply-action delete --dry-run'
    )

    return get_keeper_report(
        params,
        {
            'report_type':'raw', 
            'format':'json',
            'limit':100,
            'event_type':['login']
        }
    )

このプログラムは以下の要素で構成されています。

lambda_handler 関数

この関数は、lambdaが実行されたときに呼び出されます。他のすべての関数は、この関数から呼び出す必要があります。

get_params() 関数

環境変数に設定されたユーザー名とパスワード (US以外の環境ではサーバー情報も含む) を使用して、Keeperのログイン構成を初期化します。api.login() を呼び出すと、この構成は config.json ファイルとして作成されます。Lambdaハンドラーにマウントされたストレージがない場合は、このファイルを /tmp に書き込む必要があります。get_params_from_config() 関数はその処理を行います。

コマンダー関数

ログインして同期が完了すると、コマンダーSDKから関数を実行したりクラスを作成したりできます。上記のプログラムには2つの関数が含まれています。get_keeper_report() はJSON形式のレポートを取得します (audit-report コマンドと同等)。run_keeper_cli() はCLIコマンドを実行します (Python内でデータを返さずに実行のみ行います)。

Lambdaの構成

タイムアウトの設定

Lambdaの設定にある一般構成セクションでは、タイムアウト値を変更することを推奨します。コマンダーの一部の関数は実行に時間がかかるため、スクリプトの処理時間がこの値を超えると、Lambdaは完了前に自動的に終了してしまいます。

タイムアウト値は任意の値に設定できますが、ほとんどの処理に対しては300秒 (5分) に設定しておけば十分です。

レイヤーの選択

Lambdaエディタで、上記で作成したレイヤーを選択して、Lambdaビルドにコマンダーパッケージを追加します。

実行スケジュールの作成

Lambdaを呼び出すEventCloudトリガーを作成し、適切な頻度 (たとえば、1日に1回や30日に1回) で動作するように設定します。

AWSでは、メールやSMSによるトリガーなど、他のいくつかのソースからLambdaを呼び出すように設定することもできます。その他のオプションについては、Lambdaの呼び出しに関するAmazonのドキュメントをご参照ください。

次の手順

コマンダーの他の機能、Lambdaの呼び出し方法、またSNSなどのAWSサービス (SMSメッセージを含むさまざまなプッシュ通知の手法に活用可能) を組み合わせて、Keeperの処理を自動化してみましょう。

コマンダーSDKコードの使用例については、コマンダーのGitHubリポジトリにあるサンプルスクリプトをご参照ください。

コマンダーのさまざまなメソッドの詳細については、コマンドリファレンスのページをご参照ください。

コマンドリファレンス

最終更新