【AWS CDK】 AWS Lake FormationのHybrid Access modeで権限管理

【AWS CDK】 AWS Lake FormationのHybrid Access modeで権限管理

Clock Icon2025.03.13

はじめに

データ事業本部ビッグデータチームのkasamaです。
今回はAWS Lake FormationのHybrid Access modeで、LF tagを用いたアクセス権の管理をCDKで実装したいと思います。

前提

今回実現したい構成は以下の通りです。

AWS_Lake_Formation_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側では既存リソースを参照する実装としました。
https://dev.classmethod.jp/articles/managing-existing-resources-after-lake-formation-activation/#%25E4%25BA%258B%25E5%2589%258D%25E6%25BA%2596%25E5%2582%2599

今回の実装コードについては、Github上に格納してあるのでご確認いただければと思います。

https://github.com/cm-yoshikikasama/blog_code/tree/main/51_lakeformation_with_cdk

@ 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

実装

bin/app.ts
#!/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ではスタックを定義しています。

lakeformation.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 administratorscdk-hnb659fds-cfn-exec-role-00000000000-ap-northeast-1を登録する必要があります。これはCDKでLake Formation資産をCreateするのが実際にはこのIAM Roleになるためです。この設定が無いとデプロイで失敗します。

Screenshot 2025-03-13 at 20.44.00

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が登録されています。
Screenshot 2025-03-13 at 20.48.50

Data lake locationsにS3 BucketがHybrid access modeで登録されています。
Screenshot 2025-03-13 at 20.51.26

table全体に対してvalueをOpenとして、特定のカラムのみvalueをRestrictedとしてタグが付与されています。
Screenshot 2025-03-13 at 20.53.53
Screenshot 2025-03-13 at 20.54.17

Lake FormationでアクセスをしたいIAM Role、valueOpenタグの条件に対して、参照権限をGrantしています。
Screenshot 2025-03-13 at 20.56.22

これでAthenaで確認といきたいところですが、Hybrid access modeにGlue DBとIAM Roleを紐づける設定だけ手動で行う必要があります。
Screenshot 2025-03-13 at 20.59.54

CloudFormationのユーザーガイドで上記設定をできる記載を見つけられなかったので、現状は対応していないと想定しています。(私が見つけられてないだけであればすみません..)
AWS CLIコマンドでできるか確認しましたが、こちらも特に見当たらなかったため、手動設定しています。
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_LakeFormation.html
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lakeformation/index.html#cli-aws-lakeformation

Athenaで参照

最後にAthenaで参照したところ、参照できるカラムは全て参照でき、制限されたカラムは参照できないことを確認しました。
Screenshot 2025-03-13 at 21.05.56

最後に

LakeformationをCDKで実装するときの一つの参考になれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.