[アップデート] AWS Transfer Family のカスタム ID プロバイダーで複数の認証方法が利用出来るようになってました

2023.06.13

いわさです。

AWS Transfer Family では様々な認証方法を採用することが出来ます。
オプションのひとつにカスタム ID プロバイダー認証という機能があります。

この機能は Lambda 関数などで認証リクエストごとにポリシーを生成することで自由に認証結果をカスタマイズすることが出来ます。

今回別件で Transfer Family のカスタム ID プロバイダーを構成していたところ、見覚えのないオプションが追加されていることに気が付きました。

What's New at AWS を確認したところアップデートアナウンスが確認出来なかったのですが Transfer Family 公式ドキュメントの変更履歴によると 2023 年 5 月 17 日よりこの機能が使えるようになったようです。

UI に表示されているままですが、パスワードとパブリックキーを組み合わせたカスタム認証を使うことが出来ます。
この記事では使い方を調べてみましたので紹介します。

2023.08.31 追記

2023.08.29 付で次のアップデートアナウンスがありました。おそらく同じ内容だと思います。こんなにアナウンスまでのタイムラグあるの珍しい。

パスワードのみ

まずは基本的なところから確認です。
こちらは従来よく使っていたパターンだと思いますが、受け取ったパスワードを Lambda で検査しポリシーを返却することで認証成功となる仕組みです。

次の関数は受け取ったパスワードの検証すらしてないですが、ストレージへのアクセス許可がされている IAM ロールを指定することで許可されたとみなされます。

lambda_function.py

import json

def lambda_handler(event, context):
    print(event)
    return { 
        'Role': 'arn:aws:iam::123456789012:role/IwasaHogeAllowSpecifyS3forTransfer' 
    }

認証方法に「パスワードのみ」を指定したことで接続時にパスワードが要求されるようになります。

% sftp hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com                
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com's password: 
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

なお、秘密鍵を指定しても無視されてパスワードが要求されます。

% sftp -i hoge0613-key hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com's password: 
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

パブリックキーのみ

続いてパブリックキーを使う場合です。
この場合は先程の IAM ロールに加えて Lambda のレスポンスで許可する公開鍵の一覧を設定します。
SFTP 接続時に指定した秘密鍵のペアとなる公開鍵がこのリストに指定されていない場合は接続に失敗します。

カスタム ID プロバイダーなのでマネージドユーザーのように鍵の登録やダウンロードなどありませんが、使い方としては event からユーザーなどの情報を判断し、外部で管理する公開鍵のリストを Lambda でレスポンスような形になると思います。

lambda_function.py

import json

def lambda_handler(event, context):
    print(event)
    return { 
        'Role': 'arn:aws:iam::123456789012:role/IwasaHogeAllowSpecifyS3forTransfer',
        'PublicKeys': [
            'ssh-rsa hogehogepub'
            ]
    }

認証方法に「パブリックキーのみ」を指定しているので、パスワードは要求されません。
秘密鍵が指定されていない、あるいは指定した秘密鍵のペアとなる公開鍵が Lambda 関数のレスポンスにリストされていない場合は次のように拒否されます。

% sftp hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com                
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com: Permission denied (publickey).
Connection closed.

公開鍵がリストされている場合は次のように許可されます。

% sftp -i hoge0613-key hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

ちなみにPublicKeysについてですが、「パスワードのみ」認証で指定してしまうと正しいパスワードを入力したとしても次のようにエラーとなります。

% sftp hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com   
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com's password: 
Permission denied, please try again.

パスワードまたはパブリックキー

ここまでで「パスワードのみ」と「パブリックキーのみ」を紹介しましたが、ここからはその 2 つを組み合わせたものになります。
まずは「パスワードまたはパブリックキー」です。

こちらはパスワードかパブリックキーのどちらか 1 つで認証を成功させるものになります。
認証時に秘密鍵が指定されている場合は鍵の検証を行い、秘密鍵が指定されていない場合はパスワードが要求されます。

注意点として、パスワード認証になった場合にカスタムレスポンスで公開鍵リストが指定されてしまうと先程のようにエラーとなってしまいます。
カスタム ID プロバイダーの処理については次のようにパスワードの設定有無に応じてレスポンスを動的に組み立てる必要があります。

lambda_function.py

import json

def lambda_handler(event, context):
    print(event)
    if event.get('password', '') == '':
        return { 
            'Role': 'arn:aws:iam::123456789012:role/IwasaHogeAllowSpecifyS3forTransfer',
            'PublicKeys': [
                'ssh-rsa hogehogepub'
            ]
        }
    elif event['password'] == 'hoge':
        return { 'Role': 'arn:aws:iam::123456789012:role/IwasaHogeAllowSpecifyS3forTransfer' }
    else:
        return {}

秘密鍵を指定しなかった場合と、指定した場合の動作は次のようになります。

% sftp -i hoge0613-key hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

% sftp hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com                
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com's password: 
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

パスワードおよびパブリックキー

最後は「パスワードおよびパブリックキー」です。
こちらは先程とちょっと違って、どちらも要求されるものになります。

カスタム処理の内容は先程と同じもので良いので省略します。
実行すると Lambda でリストされる公開鍵と対になる秘密鍵の指定が必須で、かつ正しいパスワードの入力も必要になります。

% sftp -i hoge0613-key hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com
hoge@s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com's password: 
Connected to s-a94e4cf130a241869.server.transfer.ap-northeast-1.amazonaws.com.
sftp>

一点注意点というか挙動として知っておいたほうが良い点がありまして、パスワード認証とパブリックキー認証でそれぞれ Lambda が実行されます。
つまり 1 回の認証で Lambda が 2 回実行されます。
Lambda の実行ログを確認してみると、次のように 1 回目はパブリックキー認証用で、2 回目はパスワード認証用でした。

さいごに

本日は AWS Transfer Family のカスタム ID プロバイダーで複数の認証方法が利用出来るようになっていたので使ってみました。

クライアント側の仕様あるいはセキュリティの要件などからカスタム ID プロバイダーが必要になるケースは多いと思いますが、より柔軟な設定が出来るオプションが登場しました。
これまで認証周りで仕様を満たせずに Transfer Family が採用出来なかった方など、是非チェックしてみてください。