AWS Transfer Family が認可の要素として接続元 IP を指定できるようになりました

記事タイトルとURLをコピーする

はじめに

こんにちは、技術1課の山中です。 雨が多いと思ったらいつの間にか梅雨に入っていたみたいですね。 これからは晴れの日が貴重になってくるので、計画的に洗濯していこうと思っています。 というのはさておき! 今回はこのアップデートについて見ていきます!

AWS Transfer Family が認可の要素としてソース IP を有効に

AWS Transfer Family が認可の要素として接続元 IP を指定できるようになったとのことなので、試していこうと思います。

AWS Transfer Family とは

Amazon Transfer Family とは、以下サービスの集合的な名称でフルマネージド型のサービスです。

  • AWS Transfer for SFTP
  • AWS Transfer for FTPS
  • AWS Transfer for FTP

AWS Transfer Family | アマゾン ウェブ サービス

SFTP、FTPS、FTP 経由で Amazon S3 と直接ファイルのやり取りができます。

料金

AWS Transfer Family では、それぞれのエンドポイントが有効になっている時間及びデータアップロード/ダウンロード量に対する従量課金となっています。 各プロトコルのエンドポイントごとに料金が発生しますので、ご注意ください。 詳しくは以下を参照ください。 AWS Transfer Family の料金 | アマゾン ウェブ サービス

アップデート内容の確認

今回は接続元 IP が認可の要素として利用できるようになったということで、接続元 IP によってユーザに異なる権限を与えることを試していきます。

S3 バケットのセットアップ

まずは、 SFTP 経由で接続するための S3 バケットを作成します。 今回は、 20200615-demo-bucket というバケットを作成しました。 適当にファイルを作成し、配置しておきました。

IAM ロールのセットアップ

今回は以下のようなアクセスコントロールを行ってみたいと思います。

  • 特定 IP アドレスからのアクセス バケット内ファイルの参照及び操作が可能
  • 上記 IP アドレス以外からのアクセス バケット内ファイルの参照のみ可能

これを実現するために 2 つの IAM ロールを事前に作成します。

  • AllowAccessToS3
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::20200615-demo-bucket"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["arn:aws:s3:::20200615-demo-bucket/*"]
    }
  ]
}
  • AllowReadOnlyAccessToS3
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::20200615-demo-bucket"]
    },
    {
      "Effect": "Allow",
      "Action": [
            "s3:GetObject"
        ],
      "Resource": ["arn:aws:s3:::20200615-demo-bucket/*"]
    }
  ]
}

上記 IAM ポリシーの信頼ポリシーは以下です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "transfer.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

CloudFormation で各リソースの作成

Working with identity providers - AWS Transfer Familyページの Basic stack template からテンプレートをダウンロードし、 AWS CloudFormation で新たにスタックを作成していきます。 SFTP サーバーは後ほど作成するので、 CreateServerfalse にします。 また、 UserPublicKey1 に公開鍵を指定し、 UserRoleArn には先ほど作成した IAM ロール (特定 IP からアクセスがあった際に利用する) の ARN を指定します。

Lambda 関数の修正

CloudFormation にて作成される Lambda 関数は以下です。

'use strict';

// GetUserConfig Lambda

exports.handler = (event, context, callback) => {
  console.log("Username:", event.username, "ServerId: ", event.serverId);

  var response;
  // Check if the username presented for authentication is correct. This doesn't check the value of the serverId, only that it is provided.
  if (event.serverId !== "" && event.username == 'myuser') {
    response = {
      Role: 'arn:aws:iam::000000000000:role/AllowAccessToS3', // The user will be authenticated if and only if the Role field is not blank
      Policy: '', // Optional JSON blob to further restrict this user's permissions
      HomeDirectory: '/' // Not required, defaults to '/'
    };

    // Check if password is provided
    if (event.password == "") {
      // If no password provided, return the user's SSH public key
      response['PublicKeys'] = [ "ssh-rsa AAAAB3NzaC1yc2EXXXXXXXXXXx" ];
    // Check if password is correct
    } else if (event.password !== 'MySuperSecretPassword') {
      // Return HTTP status 200 but with no role in the response to indicate authentication failure
      response = {};
    }
  } else {
    // Return HTTP status 200 but with no role in the response to indicate authentication failure
    response = {};
  }
  callback(null, response);
};

アクセス元 IP アドレスによって与える権限を変えたいので、該当箇所を以下のように変更します。 ※ Lambda の環境変数 allowIp に接続元 IP アドレスを設定しています

  if (event.serverId !== "" && event.username == 'myuser') {
    if (event.sourceIp == process.env.allowIp) {
      response = {
        Role: 'arn:aws:iam::000000000000:role/AllowAccessToS3', // sourceIp が指定した IP アドレスの場合
        Policy: '', // Optional JSON blob to further restrict this user's permissions
        HomeDirectory: '/' // Not required, defaults to '/'
      };
    } else {
      response = {
        Role: 'arn:aws:iam::000000000000:role/AllowReadOnlyAccessToS3', // sourceIp が指定した IP アドレスでない場合
        Policy: '', // Optional JSON blob to further restrict this user's permissions
        HomeDirectory: '/' // Not required, defaults to '/'
      };
    }

    // Check if password is provided
    if (event.password == "") {

API Gateway のセットアップ

続いて、 Lambda 関数のトリガとなっている API Gateway の該当 API を開き、 /servers/{serverId}/users/{username}/config - GET のメソッドリクエストを選択します。 まず、 リクエストの検証 から クエリ文字列パラメータおよびヘッダーの検証 を選択し、リクエスト時の検証を有効にします。 続いて URL クエリ文字列パラメータ を展開し sourceIp の必須にチェックを入れます。 これで API Gateway の設定は完了したので、 [アクション] - [API のデプロイ] をクリックし prod ステージにデプロイします。

Transfer Family のセットアップ

マネジメントコンソールから AWS Transfer Family にアクセスし、 Create server をクリックします。 今回は SFTP にてファイル転送を行うので、 SFTP を選択し Next ボタンをクリックします。 Identity provider type では Custom を選択します。 Custom provider には先ほどデプロイした API Gateway の URL、 Invocation role には CloudFormation で作成した [Stack 名]-TransferIdentityProviderRole-XXXXXXXX を指定します。 エンドポイントタイプは Publicly accessible を選びます。 あとの設定はデフォルトのまま進めて Create server をクリックし、作成してください。 しばらく経つとステータスが Online となるので、 [Actions] - [Test] をクリックしテストしてみます。

テスト

Lambda 関数のコードで指定したユーザ名とパスワード及び IP アドレスを入力しテストしてみます。 この場合はきちんと AllowAccessToS3 ロールが返ってきました。 次は、 IP アドレスを違うものに変更してテストしてみます。 接続元 IP が異なるので、今度はきちんと AllowReadOnlyAccessToS3 ロールが返ってきています。 テストはうまくいきましたね。

アクセスしてみる

実際に許可している IP アドレスから SFTP 接続してみます。

$ sftp -i ~/.ssh/private_key myuser@s-8c3b109e73f64257b.server.transfer.ap-northeast-1.amazonaws.com
Connected to s-8c3b109e73f64257b.server.transfer.ap-northeast-1.amazonaws.com.
sftp> cd /20200615-demo-bucket #該当バケットに移動
sftp> ls
samplefile01.txt  samplefile02.txt  samplefile03.txt
sftp> rm samplefile01.txt #ファイルを削除
Removing /20200615-demo-bucket/samplefile01.txt
sftp> ls
samplefile02.txt  samplefile03.txt
sftp>

想定通り、許可している IP アドレスではファイルの参照も削除も可能ということがわかりました。 続いて VPN を繋いで上記と異なる IP アドレスで SFTP 接続してみます。

$ sftp -i ~/.ssh/private_key  myuser@s-8c3b109e73f64257b.server.transfer.ap-northeast-1.amazonaws.com
Connected to s-8c3b109e73f64257b.server.transfer.ap-northeast-1.amazonaws.com.
sftp> cd /20200615-demo-bucket #該当バケットに移動
sftp> ls
samplefile02.txt  samplefile03.txt
sftp> rm samplefile02.txt #ファイルを削除
Removing /20200615-demo-bucket/samplefile02.txt
Couldn't delete file: Permission denied #削除に失敗
sftp> ls
samplefile02.txt  samplefile03.txt
sftp>

許可していない IP アドレスからアクセスがあった場合、オブジェクトの参照はできますが削除はできないことがわかりました。

おわりに

接続元 IP アドレスにて権限を制御できるようになったお陰で、社内にいるときはフルアクセス、社外のときは参照権限のみ、など柔軟にアクセスコントロールができるようになるのではないでしょうか。

また、この内容は 2020/6/17(水) 12:00 よりYouTube Liveで配信する「30分でわかる AWS UPDATE!」で取り上げますますので、是非ご覧ください!

参考