以前投稿した記事で作成したAPI GatewayにIAM認証の設定を追加してみました。
IAM認証とは
HTTP API ルートに対して IAM 認証を有効にできます。IAM 認証が有効な場合、クライアントは署名バージョン 4 を使用して、AWS 認証情報でリクエストに署名する必要があります。API Gateway は、クライアントがルートに対する execute-api アクセス許可を持っている場合にのみ、API ルートを呼び出します。
https://docs.aws.amazon.com/ja_jp/ja_jp/apigateway/latest/developerguide/http-api-access-control-iam.html
とのことです。
IAM認証を有効にすると、署名バージョン4(SigV4)を使用してリクエストに署名をする必要がある、ということですね。
署名バージョン 4 (SigV4) は、HTTP で送信される AWS API リクエストに認証情報を追加するプロセスです。セキュリティのため、AWS へのほとんどのリクエストはアクセスキーで署名する必要があります。アクセスキーは、アクセスキー ID とシークレットアクセスキーで構成されます。
https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-4.html
SigV4で署名するには、アクセスキー ID とシークレットアクセスキーを用いるようです。
今回は、IAMユーザーを作成しアクセスキーとシークレットアクセスキーを用意します。
作るもの
以前作成したAPI Gatewayは認証などを何もかけていないため、誰でも好きに実行できてしまいます。
そのため、今回はIAM認証を利用して制限をかけようと思います。
API GatewayにIAM認証の設定を行い、APIを実行できる権限を持つIAMユーザーを作成していきます。
環境
cdk --version
2.44.0 (build bf32cb1)
tsc --v
Version 3.9.10
curl -V
curl 7.83.1
API GatewayにIAM認証をかける設定
以前投稿した記事のコードをベースに、記述を追加します。
// titleを指定してitemを1件取得するapi
bookResource.addMethod('GET', new apigateway.AwsIntegration({
service: 'dynamodb',
action: 'GetItem',
options: {
credentialsRole: credentialRole,
requestTemplates: {
'application/json': `{
"Key": {
"title": {
"S": "$input.params('title')"
}
},
"TableName": "Book"
}`
},
integrationResponses: [
{
statusCode: '200',
responseTemplates: {
'application/json': `{
"title": "$input.path('$').Item.title.S",
"price": $input.path('$').Item.price.N,
}`
}
}
]
}
}),
{
authorizationType: apigateway.AuthorizationType.IAM, // この記述を追加
methodResponses: [
{
statusCode: '200',
}
]
});
デプロイしてコンソールで確認してみると確かに設定されています。
この状態でcurlしてみると、認証で弾かれていることがわかります。
{restapi_id}と{region}は作成したもので適宜置き換えてください。
$ curl -X GET https://{restapi_id}.execute-api.{region}.amazonaws.com/dev/books/how_to_book
{"message":"Missing Authentication Token"}%
IAMユーザー
bookApiを実行できるinvoke-user
というユーザーを作成します。
// invoke用 IAM Role
const invokeUser = new iam.User(this, 'User', {
userName: `invoke-user`,
});
invokeUser.attachInlinePolicy(
new iam.Policy(this, 'Policy', {
statements: [
new iam.PolicyStatement({
actions: ['execute-api:Invoke'],
effect: iam.Effect.ALLOW,
resources: [api.arnForExecuteApi()],
}),
],
}),
);
なお、api.arnForExecuteApi()
のapiは以下を指しています。
// API Gateway
const api = new apigateway.RestApi(this, "bookApi", {
deployOptions: {
stageName: "dev",
metricsEnabled: true,
dataTraceEnabled: true,
}
});
デプロイしてユーザーを作成し、コンソールなどからアクセスキーとシークレットキーを発行します。
このアクセスキーとシークレットキーはAPI実行に必要な情報となるので忘れずにメモなどしておきます。
動作確認
準備が整ったので、API実行を試してみます。
まずは認証情報なしでcurlします。
$ curl -X GET https://{restapi_id}.execute-api.{region}.amazonaws.com/dev/books/how_to_book
{"message":"Missing Authentication Token"}%
想定通り弾かれます。
次に認証情報ありでcurlします。
{アクセスキー}と{シークレットアクセスキー}はそれぞれ先ほど発行したものに置き換えて実行します。
$ curl -X GET https://{restapi_id}.execute-api.{region}.amazonaws.com/dev/books/how_to_book --aws-sigv4 aws:amz:{region}:execute-api --user {アクセスキー}:{シークレットアクセスキー}
{
"title": "how_to_book",
"price": 1000,
}%
認証が通り、how_to_bookの情報が返ってきました。
なお、--aws-sigv4
はcurlのオプションです。
https://curl.se/docs/manpage.html#--aws-sigv4
最後に
今回は、API GatewayにIAM認証の設定を追加してみました。
この設定を行うことで、API実行権限のあるIAMユーザーのアクセスキーとシークレットアクセスキーを知っている人しか実行できない制限をかけることができました。