AWS AppSyncでCognito User Pools認証を利用する
「AppSyncでGraphQL簡単に使える」ってことだったので、最近仲良くなろうと頑張ってます。 SaaSとかだとAPIキーではなくCognito User PoolsでAPIの認証かけたいよねってなるので、トライした […]
目次
「AppSyncでGraphQL簡単に使える」ってことだったので、最近仲良くなろうと頑張ってます。
SaaSとかだとAPIキーではなくCognito User PoolsでAPIの認証かけたいよねってなるので、トライした覚書です。
まとめ
- GraphQL APIのSettingsで
Authorization type
をCognito UserPoolsに変えればOK - defaultActionをDENYにするとスキーマ毎に制御できる
- マネコンでテストするときにCognito User PoolsのClient IDいるから要注意
AWS CDKでさっさと作る
最近AWS CDKが型定義ファイルとIDEの入力補完でパラメーター書けるので、新しいサービス立ち上げるときによく使ってます。
スタック作ってFailしてRollbackして・・・のループに入る前に、TypeScriptがガンガンバリデートしてくれるので割と助かってます。
ということで簡単なサンプルコード(lib/aws-cdk-stack.ts
)
import cdk = require('@aws-cdk/cdk');
import Appsync = require('@aws-cdk/aws-appsync')
export class AwsCdkStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// APIを作る
const api = new Appsync.CfnGraphQLApi(this, 'GraphQLAPI', {
authenticationType: 'AMAZON_COGNITO_USER_POOLS',
name: id,
userPoolConfig: {
appIdClientRegex: 'XXXXXXXXX',
awsRegion: 'us-east-1',
defaultAction: 'DENY',
userPoolId: 'us-east-1_XXXXXXx'
}
})
// schemaを定義する(今回は省略)
const schema = AppSyncSchema.create(this, api)
// datasourceを定義する(今回は省略)
const dataSource = AppSyncDatasourcess.create(this, id, api)
// resolverを定義する(今回は省略)
const resolvers = AppSyncResolvers.create(this, api)
// CFNの依存を組む
resolvers.map((resolver: Appsync.CfnResolver) => {
resolver.node.addDependency(dataSource);
resolver.node.addDependency(schema);
})
}
}
schema / datasource / resolverも定義しないとですが、そこを書き出すと長いので省略しました。
設定のポイント
設定時のポイントとしては、以下の点があります。
- 認証方式は1API 1タイプなので、API tokenなどとの併用はできない。
- schema / resolverとかのコードを共有にして、もう1つAPIつくると良さそう。
defaultAction
をDENYにした場合、schema毎に許可する設定が必要- アプリクライアントも決め打ちしたいなら、
appIdClientRegex
で指定
複数の認証方式に対応させる
CDKやCloudFormationで複数のAPIを作るのがよいでしょう。
import cdk = require('@aws-cdk/cdk');
import Appsync = require('@aws-cdk/aws-appsync')
export class AwsCdkStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// APIを作る
const api = new Appsync.CfnGraphQLApi(this, 'GraphQLAPI', {
authenticationType: 'AMAZON_COGNITO_USER_POOLS',
name: id,
userPoolConfig: {
appIdClientRegex: 'XXXXXXXXX',
awsRegion: 'us-east-1',
defaultAction: 'DENY',
userPoolId: 'us-east-1_XXXXXXx'
}
})
const apiWithKey = new Appsync.CfnGraphQLApi(this, 'GraphQLAPI', {
authenticationType: 'API_KEY',
name: id,
})
new Appsync.CfnApiKey(this, 'apiKey', {
apiId: apiWithKey.graphQlApiApiId,
})
// schemaを定義する(今回は省略)
const schema = AppSyncSchema.create(this, api)
const schema1 = AppSyncSchema.create(this, apiWithKey)
// datasourceを定義する(今回は省略)
const dataSource = AppSyncDatasourcess.create(this, id, api)
const dataSource1 = AppSyncDatasourcess.create(this, id, apiWithKey)
// resolverを定義する(今回は省略)
const resolvers = AppSyncResolvers.create(this, api)
const resolvers1 = AppSyncResolvers.create(this, apiWithKey)
// CFNの依存を組む
resolvers.map((resolver: Appsync.CfnResolver) => {
resolver.node.addDependency(dataSource);
resolver.node.addDependency(schema);
})
resolvers1.map((resolver: Appsync.CfnResolver) => {
resolver.node.addDependency(dataSource1);
resolver.node.addDependency(schema1);
})
}
}
schema単位での制御
@aws_auth
を使うことでschema別に制御できます。ドキュメントをざっと見た範囲では、Cognito User Poolsのgroupで割り振りできる様子です。
type Query {
getItem(UUID: String!, track_month: Int!): Item
@aws_auth(cognito_groups: ["admin", "editor", "reader"])
queryStatistics(
user_name: String!,
track_month: Int!,
): StatisticsConnection
@aws_auth(cognito_groups: ["admin"])
}
上のサンプルだと、getItem
はadmin / editor / readerのいずれかに所属するユーザーがアクセス可能で、queryStatistics
はadminのみアクセスできます。
これとdefaultAction
をDENYにする設定を入れることで、ホワイトリスト的に制御できます。ただしすべてのschemaに明示的に設定する必要がありますので、トレードオフであることは要注意です。