【AWS CDK】 AWS Lake FormationのHybrid Access modeで権限管理
はじめに
データ事業本部ビッグデータチームのkasamaです。
今回はAWS Lake FormationのHybrid Access modeで、LF tagを用いたアクセス権の管理をCDKで実装したいと思います。
前提
今回実現したい構成は以下の通りです。
- LF TagをGlue tableに一括で、
AccessLevel = Open
で付与します。 - tableに付与すると下位のカラムにも伝播されるので、参照をしたい制限カラムについては、
AccessLevel = Restricted
に設定します。 - LF tagが
AccessLevel = Open
なリソースは該当IAM Roleが参照できるように権限をGrantします。 - 最後はAthenaで想定通り参照できることを確認します。
前提として、IAM Role、S3 Bucket、Glue DB、 Glue tableは以下のブログ記事の事前準備のものを使用しています。そのため、今回新規で作成するということはしておりません。CDK側では既存リソースを参照する実装としました。
今回の実装コードについては、Github上に格納してあるのでご確認いただければと思います。
@ 51_lakeformation_with_cdk % tree
.
├── README.md
└── cdk
├── bin
│ └── app.ts
├── cdk.json
├── jest.config.js
├── lib
│ └── lakeformation.ts
├── package-lock.json
├── package.json
└── tsconfig.json
4 directories, 8 files
実装
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib";
import { LakeFormationHybridStack } from "../lib/lakeformation";
const app = new cdk.App();
new LakeFormationHybridStack(app, "CMKasamaLakeFormation", {
description: "ETL (tag:kasama-test-tag)",
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
tags: {
Repository: "kasama-test-tag",
},
projectName: "project",
envName: "dev",
});
app.ts
ではスタックを定義しています。
import * as cdk from "aws-cdk-lib";
import * as lakeformation from "aws-cdk-lib/aws-lakeformation";
import type { Construct } from "constructs";
export interface LakeFormationHybridStackProps extends cdk.StackProps {
envName: string;
projectName: string;
}
export class LakeFormationHybridStack extends cdk.Stack {
constructor(
scope: Construct,
id: string,
props: LakeFormationHybridStackProps,
) {
super(scope, id, props);
// 既存リソースを定数として定義
const existingResources = {
dataBucketNameArn: `arn:aws:s3:::${props.projectName}-lakeformation-tests`,
lakeFormationAdminRoleArn: `arn:aws:iam::${this.account}:role/${props.projectName}-lakeformation-admin`,
lakeFormationAccessRoleArn: `arn:aws:iam::${this.account}:role/${props.projectName}-data-access-role`,
databaseName: "cm_kasama_hr_employee",
tableName: "personal_info",
sensitiveColumns: ["salary"], // 機密情報を含む列
};
// Lake Formation 管理ロール設定
new lakeformation.CfnDataLakeSettings(this, "DataLakeSettings", {
admins: [
{
dataLakePrincipalIdentifier:
existingResources.lakeFormationAdminRoleArn,
},
],
allowExternalDataFiltering: false, // 外部データフィルタリング
});
// Data lake locationsにS3バケットを登録
new lakeformation.CfnResource(this, "RegisterS3Location", {
resourceArn: existingResources.dataBucketNameArn,
useServiceLinkedRole: true, // サービスリンクロールを使用
hybridAccessEnabled: true,
});
// LFタグの作成
new lakeformation.CfnTag(this, "AccessLevelTag", {
catalogId: this.account,
tagKey: "AccessLevel",
tagValues: ["Open", "Restricted"],
});
// LFタグの付与
// table全体にOpenタグを割り当てる
new lakeformation.CfnTagAssociation(this, "TableOpenTagAssociation", {
lfTags: [
{
catalogId: this.account,
tagKey: "AccessLevel",
tagValues: ["Open"],
},
],
resource: {
table: {
catalogId: this.account,
databaseName: existingResources.databaseName,
name: existingResources.tableName,
},
},
});
// LFタグの付与
// 機密列のみにRestrictedタグを割り当てる
new lakeformation.CfnTagAssociation(
this,
"RestrictedColumnsTagAssociation",
{
lfTags: [
{
catalogId: this.account,
tagKey: "AccessLevel",
tagValues: ["Restricted"],
},
],
resource: {
tableWithColumns: {
catalogId: this.account,
databaseName: existingResources.databaseName,
name: existingResources.tableName,
columnNames: existingResources.sensitiveColumns, // 機密列のみ指定
},
},
},
);
// LF-Tagに基づいたアクセス権限の付与
new lakeformation.CfnPrincipalPermissions(this, "TagBasedPermissions", {
catalog: this.account,
principal: {
dataLakePrincipalIdentifier:
existingResources.lakeFormationAccessRoleArn,
},
resource: {
lfTagPolicy: {
catalogId: this.account,
resourceType: "TABLE",
expression: [
{
tagKey: "AccessLevel",
tagValues: ["Open"],
},
],
},
},
permissions: ["SELECT", "DESCRIBE"],
permissionsWithGrantOption: [],
});
}
}
lakeformation.ts
では、Lake Formationの設定を定義しています。
CfnDataLakeSettings
では、Data lake administrators
に管理者Roleを登録しています。CfnResource
では、Data lake locations
にS3 BucketをHybrid access modeで登録しています。CfnTag
では、KeyがAccessLevel
、valueがOpen
,Restricted
のタグを作成しています。CfnTagAssociation
では、table全体に対してvalueをOpen
として、特定のカラムのみvalueをRestricted
としてタグを付与しています。database全体に付与する設定も可能ですが、今回はtableとしています。CfnPrincipalPermissions
では、Lake FormationでアクセスをしたいIAM Roleに対し、value Open タグの条件で参照権限をGrantしています。
デプロイ
Data lake administratorsにCDK実行Role登録
それではCDK Deployといきたいところですが、CDKでLake Formationリソースをデプロイする際は、事前にData lake administrators
にcdk-hnb659fds-cfn-exec-role-00000000000-ap-northeast-1
を登録する必要があります。これはCDKでLake Formation資産をCreateするのが実際にはこのIAM Roleになるためです。この設定が無いとデプロイで失敗します。
CDK Deploy
まずpackage.jsonがあるディレクトリで依存関係をインストールします。
npm install
同じくcdk.jsonがあるディレクトリでデプロイコマンドを実行します。--all
はCDKアプリケーションに含まれる全てのスタックをデプロイするためのオプション、--require-approval never
はセキュリティ的に敏感な変更やIAMリソースの変更を含むデプロイメント時の承認を求めるダイアログ表示を完全にスキップします。never
は、どんな変更でも事前確認なしにデプロイすることを意味します。今回は検証用なので指定していますが、慎重にデプロイする場合は必要のないオプションになるかもしれません。
npx cdk deploy --all --require-approval never --profile <YOUR_AWS_PROFILE>
デプロイ後確認
Lake Formation設定確認
設定値が正しく設定されているかを確認します。
Data lake administrators
に管理者Roleが登録されています。
Data lake locations
にS3 BucketがHybrid access modeで登録されています。
table全体に対してvalueをOpen
として、特定のカラムのみvalueをRestricted
としてタグが付与されています。
Lake FormationでアクセスをしたいIAM Role、valueOpen
タグの条件に対して、参照権限をGrantしています。
これでAthenaで確認といきたいところですが、Hybrid access mode
にGlue DBとIAM Roleを紐づける設定だけ手動で行う必要があります。
CloudFormationのユーザーガイドで上記設定をできる記載を見つけられなかったので、現状は対応していないと想定しています。(私が見つけられてないだけであればすみません..)
AWS CLIコマンドでできるか確認しましたが、こちらも特に見当たらなかったため、手動設定しています。
Athenaで参照
最後にAthenaで参照したところ、参照できるカラムは全て参照でき、制限されたカラムは参照できないことを確認しました。
最後に
LakeformationをCDKで実装するときの一つの参考になれば幸いです。