【入門編】Pulumiのパッチ(Patch)とアノテーション機能を使った既存リソースの強制的カスタマイズ術 – インフラ構成管理(IaC)活用バイブル

こんにちは!クラウドインフラの世界へようこそ。
日々、AWSやKubernetes、あるいはその他のクラウドサービスを触っていると、「あぁ、このプロバイダ(PulumiやTerraformなどの管理モジュール)のバージョンが古くて、新しくリリースされたあのパラメータが設定できない…!」とか、「サードパーティ製のモジュールが内部で作るリソースに、どうしてもセキュリティタグを強制付与したいのに!」といった、歯痒い壁にぶつからridden(直面)することはありませんか?

一般的なマニュアルには「プロバイダのアップデートを待ちましょう」なんて書かれていますが、現場のスケジュールはそんなことを待ってくれませんよね。

今回は、そんな絶望的な状況を鮮やかに打破し、「プロバイダがサポートしていない属性すら、俺たちの手でねじ伏せて強制書き換えする」ための禁断の奥義――Pulumiの「パッチ(Patch)」と「トランスフォーメーション(Transformations)機能」について、実務で即座に使えるレベルまで徹底的に解説していきます。

これをマスターすれば、日々のインフラ管理で「もう仕様のせいで諦める必要はないんだ」と、胸が熱くなるはずです。一緒にその深淵を覗いてみましょう!

—

1. はじめてのPulumi:その役割と基礎セットアップ

まず、「そもそもPulumiって何だっけ?」という方のために、ほんの少しだけ基礎に触れておきます。

Terraformが「HCLという独自言語」でインフラを書くのに対し、Pulumiは「TypeScript, Python, Go, C#といった使い慣れた一般プログラミング言語」でインフラを構築できる次世代のIaC(Infrastructure as Code)ツールです。条件分岐やループ、関数化を「本物のプログラミング言語のパワー」で書けるため、複雑なインフラ構成管理においては無類の強さを誇ります。

インストールとプロジェクトの初期化

まずは手元の環境にPulumi CLIをインストールしましょう(MacならHomebrewが最速です)。

Pulumi CLIのインストール
brew install pulumi

バージョン確認
pulumi version

次に、適当なディレクトリを作成し、TypeScriptを使ってプロジェクトを初期化してみましょう。ここでは一番直感的なTypeScriptを選びます。

mkdir pulumi-patch-demo
cd pulumi-patch-demo
pulumi new aws-typescript –dir . –force

(※途中でAWSのリージョンなどを聞かれますが、デフォルトのままで進めて構いません)

たったこれだけで、TypeScriptのプロジェクト構造が自動生成されます。`index.ts`を開くと、そこにはすでにインフラを定義するためのキャンバスが用意されています。

—

2. サードパーティ製プロバイダの限界を超える:パッチ(Patch)機能の正体

さて、ここからが本題です。
Pulumiは内部的にクラウドのAPIを叩いてリソースを作りますが、時々こんな問題が起きます。

  • 「AWSの新しい機能がリリースされたのに、PulumiのAWSプロバイダがまだ追従していない」
  • 「サードパーティ製モジュールが勝手に作るS3バケットに、特定のライフサイクルルールをねじ込みたいが、プロバイダの型定義にそのフィールドが存在しない」

TypeScriptの型チェック(TypeScript Compiler)が、「そんなプロパティは存在しません」と怒ってビルドを落としてしまうわけです。

ここで登場するのが、パッチ機能(Transformationsにおける`registerTransformations`や、リソースオプションのカスタマイズ)です。
これを使うと、「型定義の目を盗んで(あるいは型アサーションで無理やり)、APIリクエストのペイロード直前でJSONを書き換える」という、SRE的裏技が使えます。

実践:型定義にない属性を強制的にねじ込むコード

例えば、AWSのS3バケットを作る際、最新の(しかしプロバイダの型定義がまだ追いついていないと仮定した)特殊なログ設定プロパティを無理やりリクエストに乗せる例を見てみましょう。

import as pulumi from “@pulumi/ pulumi”;
import as aws from “@pulumi/aws”;

// 通常のS3バケット作成
const bucket = new aws.s3.Bucket(“my-secret-bucket”, {
bucket: “my-ultra-secure-bucket-2024”,
acl: “private”,
});

// 【極秘テクニック】プロバイダの型を無視して、作成される直前のリソース定義(Props)を改造する!
// リソースのオプションに transformation を仕込みます。
const patchedBucket = new aws.s3.Bucket(“my-patched-bucket”, {
bucket: “my-force-patched-bucket-2024”,
acl: “private”,
}, {
transformations: [
(args) => {
// リソースの種類が S3 Bucket の場合のみ介入する
if (args.type === “aws:s3/bucket:Bucket”) {
// 型定義(TypeScriptのインターフェース)に縛られず、自由なJSONプロパティを追加・上書きする
args.props[“experimentalFeatureFlag”] = {
enabled: true,
forceOverride: “extreme-mode”
};
}
return { props: args.props, opts: args.opts };
}
]
});

この `transformations` オプションは、Pulumiがクラウドへリクエストを飛ばす「直前」にフックをかけ、送出されるパラメータ(`args.props`)を直接書き換える魔法の機能です。
TypeScriptのコンパイルエラーを華麗に回避しつつ、プロバイダが未対応の最新APIパラメータすら完全手動でねじ込むことが可能になります。

—

3. Transformationsを用いたグローバルなセキュリティ設定の強制適用

「パッチ」の概念をさらに発展させたのが、プロジェクト全体、あるいはスタック全体に影響を与えるグローバル・トランスフォーメーションです。

現場でよくある要望:

  • 「社内コンプライアンスとして、作成されるすべてのリソースに `CostCenter: “Engineering”`, `Owner: “SRE-Team”` というタグを絶対につけさせろ」
  • 「すべてのS3バケットに対して、パブリックアクセスブロックを強制的に有効化させろ」

これを一つひとつのリソース定義に手で書いていたら、開発者がタグを付け忘れた瞬間に監査で怒られてしまいます。
Pulumiのプロジェクトルート(`index.ts` や別ファイルの初期化時)でグローバルにトランスフォーメーションを登録すれば、開発者がどれだけサボっても、自動的にすべてのリソースが強制矯正されます。

グローバルタグ付与 & セキュリティ強制アプライのコード

import as pulumi from “@pulumi/pulumi”;

// プルミのランタイム全体に「トランスフォーメーション」をフックする
pulumi.runtime.registerStackTransformation((args) => {
// 1. すべてのリソースに強制的にタグを付与する(もしリソースがtagsプロパティを持っていれば)
if (args.props.tags && typeof args.props.tags === “object”) {
args.props.tags = {
…args.props.tags,
“CostCenter”: “Engineering-Dept”,
“ManagedBy”: “Pulumi-Enforcer”,
“ComplianceStatus”: “Strict”
};
} else if (args.props.tags === undefined) {
// tagsを持っていないリソースであっても、必要なら強制追加
// (※リソースの種類によってtagsを受け付けないものもあるため、型チェックを入れるのがプロの技です)
}

// 2. もしS3バケットなら、特定の暗号化設定を強制的にデフォルト注入する
if (args.type === “aws:s3/bucket:Bucket”) {
// サーバサイド暗号化の設定が未指定であっても、強制的にAES256を義務付ける
if (!args.props.serverSideEncryptionConfiguration) {
args.props.serverSideEncryptionConfiguration = {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: “AES256”,
},
},
};
}
}

return { props: args.props, opts: args.opts };
});

// — ここから下は、開発者が普通に書いたリソース定義 —
import as aws from “@pulumi/aws”;

// 開発者はタグを細かく意識しなくてもよい(勝手にグローバル側で付与されるため)
const normalBucket = new aws.s3.Bucket(“developer-friendly-bucket”, {
bucket: “app-data-storage-2024”,
});

このコードを実行すると、開発者が `tags` を一切書かなくても、Pulumiが裏側で検知してすべてのリソースに `CostCenter` や `ManagedBy` をねじ込んでクラウドへ送信します。
これを導入した瞬間から、あなたの組織のインフラガバナンスは劇的に向上します。

—

4. トラブルシューティング:パッチ活用で現場の修羅場を乗り切るユースケース

最後に、実際の現場で私が遭遇した「パッチ機能に命を救われた修羅場」のユースケースを一つご紹介します。

ユースケース:サードパーティ製モジュールが引き起こす「意図しないプロパティの競合」

ある時、社内の共通チームが作った「セキュアVPC構築用Pulumiパッケージ(サードパーティ製)」を導入しました。しかし、そのモジュール内部で作成される特定のルートテーブルの仕様が古く、AWS側の仕様変更(プレビュー機能の追加など)によって、デプロイ時に以下のようなエラーを吐いて沈黙するようになったのです。

> Error: error creating EC2 Route Table: unexpected attribute ‘foo_bar_legacy_opt’ specified

モジュールのソースコードを修正して再リリースしてもらうには、何日もの社内調整が必要です。しかし、本番環境のリリース期限は明日に迫っている……。

ここでパッチの出番です。

サードパーティ製モジュールを呼び出す側のメインコードで、以下のようなトランスフォーメーション(パッチ)を急遽挟み込みました。

// サードパーティ製モジュールが暴走して古い属性を送ろうとするのを、直前で「削除」するパッチ
const emergencyPatchTransformation: pulumi.ResourceTransformation = (args) => {
// 問題を起こしているルートテーブルリソースをピンポイントで狙い撃ち
if (args.type === “aws:ec2/routeTable:RouteTable”) {
// クラウドへ送る直前のプロパティから、エラーの原因になるゴミ属性を強制削除!
if (args.props[“foo_bar_legacy_opt”]) {
delete args.props[“foo_bar_legacy_opt”];
console.warn(“⚠️ 警告: レガシー属性 ‘foo_bar_legacy_opt’ をパッチによって削除しました。”);
}
}
return { props: args.props, opts: args.opts };
};

// パッチを適用したスコープ内でモジュールを呼び出す
// (これにより、モジュールのコード自体を一切いじらずにエラーを回避!)

このパッチを適用して `pulumi up` を実行した瞬間、先ほどまで赤く燃え盛っていたエラーログが嘘のように消え、無事にインフラのデプロイが完了しました。
夜遅くのオフィスで、思わずガッツポーズが出た瞬間です。

—

まとめ:仕様の壁にぶつかったら「パッチとトランスフォーメーション」を思い出せ

いかがでしたでしょうか?
今回は、Pulumiのパッチ(Patch)とアノテーション(Transformations)機能を使って、既存リソースやサードパーティ製モジュールを強制的かつ優雅にカスタマイズするテクニックをご紹介しました。

  • プロバイダの型定義に縛られず、未対応の最新パラメータをねじ込む
  • グローバル・トランスフォーメーションで、全リソースにセキュリティ・タグを強制適用する
  • サードパーティ製モジュールの不具合やレガシーな設定を、コード修正なしでその場で外科手術的にパッチする

これらをマスターすれば、もう「ツールやプロバイダの仕様が足りないからできない」という言い訳は通用しなくなります(笑)。
あなたのインフラストラクチャの主導権は、常にあなた(エンジニア)の手の中にあります。

これを武器に、毎日のインフラ運用を劇的に楽にし、よりクリエイティブな開発に時間を投資していきましょう。それでは、次回の極限の知見でお会いしましょう!

タイトルとURLをコピーしました