はじめに
前回は、実際にマルチステージ環境のStackを構築して、Stackの概要や活用のメリットについて解説していきました。今回は、第1回でも少し触れたPulumiのArchitectureをおさらいしつつ、PulumiにおけるSecurityについて解説していきます。
なお記事後半のハンズオンでは、Securityに関連してAWS RDS(MySQL)接続のための認証情報についてPulumiによる暗号化処理を行い、AWS SecretManagerを利用してセキュアにRDS接続する流れを実践していきます。
PulumiのArchitecture
Pulumiは大まかに2種類のArchitectureに分類されます。1つは前回のハンズオンまで利用してきた、Pulumi ServerがSaaSとして提供/管理される「Pulumi Service Architecture」と、もう1つはPulumi Serverを自前のインフラ環境に構築する「Self-Hosted Architecture」です。Pulumi Service Architectureは個人利用が無料のプラン(Individual)を含め全てのプランで選択できますが、Self-Hosted Architectureは「BusinessCritical」プランでのみ選択できます。Pulumiの利用プランについてはこちらを参照ください。
Pulumi Service(SaaS) Architecture
「Pulumi Service Architecture(Pulumi Cloud)」は、Pulumiで作成したリソースの情報(state)やsecretの管理、監査ログ、CI/CDインテグレーションやアクセスコントロールなどの設定が可能で、SaaSとしてクラウド上で提供されます。個人利用が無料のプラン(Individual)を含め、全てのプランでPulumi Service Architectureを選択できます。「Pulumi Service」は2つのエンドポイント「api.pulumi.com」または「app.pulumi.com」にインターネット経由でアクセスでき、「pulumi up」コマンドなどのPulumi CLIによるアクセスとWebコンソール画面からのアクセスが可能です。
Pulumi Service Webコンソール画面
Pulumi Serviceの実体はAWSで管理されており、以下のArchitectureが組まれているので、世界各国からのアクセスに高可用性が維持されています。
- Pulumi Serviceの静的コンテンツはcross-regionレプリケーションが有効化されたS3に保存されており、AWS CloudFront CDNにより配信される
- Pulumi Serviceへのリクエスト処理はオートスケーリングされたAWS Elastic Compute Cloud(EC2)とElastic Container Service(ECS)の組み合わせにより処理される
- Pulumi ServiceのデータベースはAmazon Relational Database Service(RDS)が利用され、automatic HA/automaticマルチゾーンスケール/インクリメンタルバックアップが実施されている
Pulumi Self-Hosted Architecture
「Self-Hosted Architecture」は、Pulumi Serviceが提供する同等の機能(Pulumi Server)を自前のインフラ環境に構築するArchitectureです。Self-Hosted ArchitectureでPulumi実行環境を構築する場合は、ユーザ自身でPulumi Serviceが実装しているデータバックアップや可用性の確保について検討する必要がありますが、Pulumiで発生する通信をすべて自前の環境内で完結(Intranet-Only)させることが可能なので、Pulumi Service Architectureよりも、よりセキュアなPulumi実行環境を実現できます。もちろん、インターネット経由でアクセスできるような独自のPulumi実行環境(Internet-Accessible)も構築可能です。ただし、Self-Hosted Architectureは「BusinessCritical」プランでのみ選択可能なので、インターネット通信が制限されるような、より厳格なセキュリティ要件を求められるシステムにおいて利用を検討すると良いでしょう(まずは30日間のトライアルライセンスでお試しいただくと良いかもしれません)。
自前のインフラ環境に構築するためのPulumiの機能(Frontend UIとBackend API)は、Dockerコンテナイメージとして提供されるので、以下のようなOCI互換性のある様々なサービスにホストできます。詳細は公式HPを参照ください。
- クイックスタート用Docker Compose(Pulumiが提供するdocker-composeとbashスクリプトを利用したテスト用Pulumi環境の構築)
- Amazon ECS(Elastic Container Service)
- Amazon EKS(Elastic Kubernetes Service)
- AKS(Azure Kubernetes Service)
- GKE(Google Kubernetes Engine)
- 自前のKubernetes
- ローカルのDocker
PulumiのSecurity
PulumiではどのようなSecurityが考慮されているのか、またユーザ自身でどのようなSecurity対策を実施できるのかなど、公式が発表している「Pulumi Cloud Security Whitepaper」をベースに紹介します。
Pulumi側で実施されるSecurity対策
・Pulumi Service(SaaS) Security
前述したPulumiのArchitectureのうち、Pulumiの全プランで利用可能なPulumi Service Architecture(Pulumi Cloud)では、下図のようなSecurity対策が施されています。図の左側「Client」が「pulumi up」コマンドなどの「Pulumi CLI」を実行するユーザを指します。認証、通信の暗号化、データの暗号化、不要な通信の制限など、ひと通りのSecurity対策が実施されていることが分かります。
Pulumi Service ArchitectureのSecurity対策
- 全てのインターネット経由の通信(PulumiCLI↔Pulumi Service、Pulumi CLI↔管理対象のクラウドインフラ(Cloud APIs))はTLSで暗号化される
- Pulumi CLIを実行するPC(マシン)でPulumi Serviceとの認証と管理対象のクラウドインフラとの認証が実行される。管理対象のクラウドインフラとの認証情報はPulumi Serviceに共有されない
- Pulumi Serviceと管理対象のクラウドインフラとで直接通信は発生しない
- 顧客情報が含まれるデータは全て暗号化
- 外部からのアクセスを無効化。NIST(アメリカ国立標準技術研究所)制定の暗号化方式AES256を採用
その他のSecurity対策としては「Pulumi Serviceのサービスやアプリケーションに対する年1回のペネトレーションテスト」「SOC 2 Type 2フレームワークに準拠したセキュリティ活動」などが挙げられます。Pulumi ServiceはAWSにホストされているので、AWSが管理するITインフラストラクチャは、AWSの厳格なSecurity対策に基づき「SOC 1/SSAE16/ISAE 3402(formerly SAS 70)、SOC 2、SOC 3…」など(キリがないのですが)、数多くのITセキュリティスタンダードに準拠しています。
ユーザで実施可能なSecurity対策
Pulumiでは以下の機能が提供されており、ユーザの要件次第でSecurityを強化できます。
・Role Based Access Control
「PulumiTeam」「Enterprise」「BusinessCritical」プランで利用可能な「RoleBasedAccessControl(RBAC)」は、Pulumi Serviceを利用するチームにStackへのアクセス権限をコントロールする機能です。権限は以下の4種類に分類されます。
- None→Stackに対するアクセス権限(read/write)を付与しない
- Read-only→Stackに対するアクセス権限(read)を付与する
- Read-write→Stackに対するアクセス権限(read/write)を付与する
- Administrator→Stackに対する管理者権限を付与する
Pulumi Serviceのデフォルト設定では(2023年5月現在)、組織(Organization)レベルで全てのStackに対するRead-write権限が付与されており、組織に所属する全てのチームにそのRead-write権限が継承されています。さらに細かい単位(Stack単位)でチームに権限を設定することで組織レベルの権限設定をオーバーライドさせることもできます。
組織レベルでStackに対するRead-write権限がデフォルトで付与されている
チームレベルで個々のStackに対する権限を設定できる
・Secrets Management
前回でも紹介したように、Pulumiでデプロイするリソースの設定をStackで保持させたいケースがあります(AWS EC2のサイズやStack毎に異なる変数の値など)。その中でも、センシティブなデータ(DatabaseのパスワードやSaaSサービスのトークンなど)もStackで保持させたい場合、Stackの設定コマンド「pulumi config set」に「--secret」フラグを付与することでStack設定ファイルで保持するデータが暗号化されます。
1 | $ pulumi config set my-password 123456 |
4 | test-project:my-password: "123456" |
【Stack設定ファイルの暗号化されていないKey(my-password)】
1 | $ pulumi config set my-password 123456 --secret |
4 | test-project:my-password: |
5 | secure: AAABAKPkoCCr1b2mP3S34TC7mj7ElYd2MixU8yYzs1+gQwwt0qg= |
【Stack設定ファイルの暗号化されたKey(my-password)】
また、リソースデプロイ後はリソースの状態がStateファイルとして記録されますが、このStateファイルに記録されるセンシティブデータもPulumi Programで暗号化できます。
04 | config = pulumi.Config() |
05 | pulumi.export('my-password', config.get("my-password")) |
12 | "urn": "urn:pulumi:dev::4-pulumi-security::pulumi:pulumi:Stack::4-pulumi-security-dev", |
14 | "type": "pulumi:pulumi:Stack", |
16 | "my-password": "123456" |
【Stack設定ファイルから取得したKeyをplaintextでデプロイ】
04 | config = pulumi.Config() |
05 | pulumi.export('my-password', config.require_secret("my-password")) |
12 | "urn": "urn:pulumi:dev::4-pulumi-security::pulumi:pulumi:Stack::4-pulumi-security-dev", |
14 | "type": "pulumi:pulumi:Stack", |
17 | "4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1eb44270", |
18 | "ciphertext": "AAABAKJxhTMcSzu7bH0/UqYgHb+FeXN0ERpVbuY/Tt9QQ0IlBGGwGQ==" |
【Stack設定ファイルから取得したKeyをsecretとしてデプロイ】
暗号化の際に利用されるキーは、デフォルトでPulumi ServiceがホストされているAWSのKMS-basedの暗号化キー(AES256GCM)が利用されます。また、オプションとして暗号化の際に利用されるsecret providerもユーザ自身で以下より選択できます。
- AWS KMS
- Google Cloud KMS
- Azure Key Vault
- HashiCorp Vault
- ユーザ自身が入力するパスフレーズを利用したPBKDF2によるsecret provider
1 | $ pulumi stack init stg --secrets-provider passphrase |
2 | Enter your passphrase to protect config/secrets: |
3 | Re-enter your passphrase to confirm: |
【ユーザ自身が入力するパスフレーズを利用したPBKDF2によるsecret provider】
・Pulumi CrossGuard
「Policy as Code」サービスとしてPulumiが提供する「Pulumi CrossGuard」を利用してPulumiでデプロイするリソースのコンプライアンスを強化し、結果的にSecurityを確保できます。また「Pulumi CrossGuard」を利用してユーザが所属する組織や会社のセキュリティコンプライアンスに沿ったポリシーを事前に定義することで、例えばSecurity要件に厳しい環境でPulumiによる「インターネット上で誰でも読み取り可能なAWS S3の作成」を事前にブロックできます。Pulumi CrossGuardの詳細は次回以降で紹介します。
01 | $ pulumi preview --policy-pack ../policypack |
02 | Previewing update (dev) |
07 | + pulumi:pulumi:Stack test-program-dev create 1 error |
08 | + └─ aws:s3:Bucket my-bucket create |
12 | pulumi:pulumi:Stack (test-program-dev): |
16 | [mandatory] aws-python v0.0.1 s3-no-public-read (aws:s3/bucket:Bucket: my-bucket) |
17 | Prohibits setting the publicRead or publicReadWrite permission on AWS S3 buckets. |
【ポリシーによりインターネット公開でread-write可能なS3の作成がブロックされた様子】