外部のサーバからGCP/AWSのサーバにAPI連携する際の認証にIAMやService accountを使う

by

@wapa5pow

課題

サービスを運営しているとGCPやAWSで開発しているサーバに外部のパートナーから接続したいという要求があるときがあります。

今回、少数のパートナー(100以下など)のみに上記の要求を満たす方法を考えます。
(不特定多数のパートナーがいる場合はSlackアプリのようにクライアントを作成してもらってIDとシークレットを利用してアクセスしたりします。)

連携と言っても大きく分けて「ファイル」と「API」の2つがあります。ファイルは、売上の連携など定期的に大きなファイルを置きたい場合です。「API」は、ポイント消費など同期的に行いたい場合です。

実現する方法として各種あり、AWSの場合はApproaches for authenticating external applications in a machine-to-machine scenarioでAWSを使った場合のサーバ間通信の様々な方法が書いてあります。
AWSに関しては、この中で複雑性が低く非常に便利に実装できるとあるIAMアクセスを使ったAWS Signature v4の方法を紹介します。
GCPの場合はClouod EndpointsにあるChoosing an Authentication Methodを参考にAWSと同じようにService accountsを使った方法を紹介します。

AWSの場合

以下のように構築します。

/assets/2022-09-17--machine-to-machine-communication/aws.png

外部パートナーでIAMの用意

連携に接続する側の外部パートナーのAWSアカウントで、IAMを発行します。このIAMに対して認証を設定します。

S3の連携

ファイル連携はS3を使います。

連携を提供する方のS3はBucket policiesを通して認証します。以下のようなポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{*account-id}:user/{*iam-name}"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::{*bucket-name}"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::${*account-id}:user/{*iam-name}"
            },
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::{*bucket-name}/*"
        }
    ]
}

連携に接続する側のIAMにも以下のような権限のIAM policyを設定する必要があります。連携を提供する側のBucket policyと、連携に接続する側のIAMのIAM Policyの両者に権限を設定する必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
            ],
            "Resource": [
                "arn:aws:s3:::{*bucket-name}"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::{*bucket-name}/*"
        }
    ]
}

設定後、AWS CLIを使って接続できます。

API Gatewayの連携

API連携はAPI Gatewayを通して行います。

API GatewayにはIAMを通して認証できる仕組みがあるのでそれを利用します。
API GatewayのResource Policyに以下のように権限を設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{*account-id}:user/{*iam-name}"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:{*region}:{*provider-account-id}:{api-id}/*/*/*"
        }
    ]
}

連携に接続するIAM policyは以下のように設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "execute-api:Invoke",
            ],
            "Resource": [
               "arn:aws:execute-api:{*region}:{*provider-account-id}:{api-id}/*/*/*",
            ]
        }
    ]
}

設定後、Signature Version 4(SigV4)で署名することによりアクセスできます。

GCPの場合

/assets/2022-09-17--machine-to-machine-communication/gcp.png

外部パートナーでService accountの用意

連携に接続する側の外部パートナーのGCPアカウントで、Service accountを発行します。このService accountに対して認証を設定します。

GCSの連携

ファイル連携はGCSを使います。連携を提供する側のGCSでIAM権限を設定します。連携に接続する側の設定は不要です。

設定後、gsutilを使いService accountを設定してアクセスできます。

Cloud Endpointsの連携

API連携はCloud Ednpoitns通して行います。

API Gatewayの設定ファイルで設定します。サービス間認証を参考に設定します。こちらも同じく連携に接続する側の設定は不要です。

設定後、Service accountで署名されたJWTを送信することによりAPIを呼び出すことができます。

まとめ

AWSではIAMで、GCPではService accountでどのように安全に外部パートナーへのアクセスを提供するかの方法を紹介しました。アクセス権を設定する手間はありますがそれ以外は簡単に行えます。
APIごとにアクセス権を細かく設定したりパートナー自身に各種設定して自己完結して行ってもらうにはクライアントIDとシークレットでアクセスする方法を構築する必要があります。
これらは規模や提供する側の負荷など様々な状況に応じてとる選択肢がかわるかなと思います。