【AWS】lambdaでparamikoを使ってSFTP通信する


環境


手順

他サーバーよりSFTPでファイルを取得する処理を作るためにparamikoを利用します。
AWS lambdaでparamikoを利用するためにレイヤーを利用します。

lambdaのレイヤーはDockerなどを使って構築する方法もありますが
簡易に作成したかったのでAWS SAMを利用してレイヤーの作成をしました。

①AWS SAMをインストールする

Macにて以下コマンドを実行してAWS SAMをインストールします。

$ brew tap aws/tap
$ brew install aws-sam-cli

この記事を書いている時点でインストールできたのはバージョン1.99.0でした。

$ sam --version
SAM CLI, version 1.99.0

②AWS SAM用のファイルを作成する。

以下構成でファイルを作成します。
paramiko-layerディレクトリは変えても良いです。

(current dir)
    ├── paramiko-layer
    │   └── requirements.txt
    └── template.yaml

各ファイルの中身は以下です。

【requirements.txt】
インストールするライブラリを記載します

paramiko

【template.yaml】
ここで記載するContentUriはrequirements.txtを配置しているディレクトリにします。
またpython3.9x86_64の部分は作成するlambdaに合わせて読み替えてください。

Resources:
  ParamikoLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      ContentUri: 'paramiko-layer/'
      CompatibleRuntimes:
        - python3.9
      CompatibleArchitectures:
        - x86_64
    Metadata:
      BuildMethod: python3.9

③レイヤーをビルドする

template.yamlがあるディレクトリにて以下コマンドを実行します。
ParamikoLayerは変えても良いです。

sam build ParamikoLayer

これにより現在のディレクトリ配下に.aws-samディレクトリが作成され、ビルドされたファイルができあがります。
これをCLI上のコマンドでlambdaのレイヤーにデプロイすることもできますが、今回はZIPをアップする方法でデプロイしてみます。

生成されたpythonディレクトリ配下にあるファイルを以下コマンドで圧縮します。

cd .aws-sam/build/ParamikoLayer/
zip -r paramiko-layer.zip python/*

作成したparamiko-layer.zipをAWSマネジメントコンソールでアップロードします。
lambdaのレイヤーページを開き、『レイヤーの作成』をクリックします。

以下入力して『作成』をクリックする。

項目 内容
名前 任意のレイヤーの名前
説明 空で良いです。必要ならレイヤーの説明を記載してください。
アップロード ラジオで『.zipファイルをアップロード』を選択し、『アップロード』よりさきほど生成したzipを選択する。
互換性のあるアーキテクチャ template.yamlに記載したものと合わせてください。
互換性のあるランタイム template.yamlに記載したものと合わせてください。
ライセンス 空で良いです。何かしらレイヤーにライセンスをつける場合は記載してください。

あとはlambda関数で上記レイヤーを設定し、paramikoを利用するだけです。
実装サンプルとしては以下のようになります。

import paramiko

def lambda_handler(event, context):
    sshClinet = paramiko.SSHClient()
    policy = paramiko.client.MissingHostKeyPolicy()
    sshClinet.set_missing_host_key_policy(policy)
    sshClinet.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    sshClinet.connect('接続先ホスト名', '接続先ポート', '接続先ユーザー名', '接続先パスワード')

    sftpClient = sshClinet.open_sftp()
    sftpClient.get('取得するファイルのパスとファイル名', '接続元(lambda)の配置先パスとファイル名')

    〜後続処理を記載〜

参考