本記事は 夏休みクラウド自由研究2026 8/25付の記事です。 |
この記事は前編・中編・後編の3部構成です。
– 前編 (この記事) : VPC Private subnet 上の Ubuntu 24.04 EC2 デスクトップ環境に Amazon DCV でセキュアに接続する(前編)
– 中編 (作成中) : VPC Private subnet 上の Ubuntu 24.04 EC2 デスクトップ環境に Amazon DCV でセキュアに接続する(中編)
– 後編 (作成中) : VPC Private subnet 上の Ubuntu 24.04 EC2 デスクトップ環境に Amazon DCV でセキュアに接続する(後編)
こんにちは、SCSKで テクニカルエスコートサービス を担当してる兒玉です。
Linux の開発環境を用意したいのですが、会社より支給される PC は Windows が標準で、しかもストレージなどが手狭で Linux の開発には向かないなぁ、と思っている方はいらっしゃいませんか?
そんなあなたにピッタリの企画です。
- EC2 を VPC Private subnet 上に作成したい
- リモートデスクトップのような口を外に開けるのはちょっと怖いので
- Linuxのデスクトップ環境も使用したい
- コンソールや Kiro / VSCode などからのSSH接続だけでなく、デスクトップ環境も使用したい
です
構成概要
本記事の全体像は下記のようになります。

構成する要素がたくさんあるように見えますが、最終目的は中央下の EC2 になります。
右下のWindows PC から AWS Systems Manager Sessions Manager 経由で Amazon DCV を使って EC2 上のLinux デスクトップにセキュアにアクセスします。
まず、前編では、EC2 のイメージを作成するところから始めます。
イメージパイプラインの構築
- EventBridge または 手動でイメージレシピを元にイメージパイプラインを実行。以降はすべて EC2 Image Builder が実行してくれます。
- ベースイメージ AMI から EC2 インスタンスを作成して VPC にデプロイ
- レシピを元にコンポーネントや設定をインストール
- インストール完了後、出力イメージAMI を作成
- Inspector を使用して 脆弱性検査を実施
- テストのために出力イメージをVPCに再デプロイ
- テストを実行
- 完了したら Amazon SNS から結果を知らせる
Amazon SNS を利用した結果通知ですが、パイプラインの実行は長時間かかるため、パイプライン実行中は別のこととしていて、実行完了時にメールなど結果を知らせてもらうような使い方や、定期的にゴールデンイメージを作成するようなケースでは FAILED となった場合には対応が必要なのでメールで通知するような運用ケースが考えられます。
パイプライン作成方針
パイプラインの CloudFormation 作成方針としては以下を考慮しました。
-
- EC2 Image Builder のパイプラインはモジュールの追加や、エラー対応などのトライアンドエラーを行うので CloudFormation で修正を繰り返すことになる(前提条件)
- CloudFormationスタックの updateや create-change-set もやってみたのですが、うまく適用できず結局削除となるケースが多々あった
- パイプラインの実行環境である VPC は EC2 Image Builder の CloudFormation テンプレートで一緒に作ってしまうと毎回作成/削除時に余計な時間がかかってしまう
- イメージ作成の際に、インターネットからのダウンロードが必要なので、外向きの出口が必要で、NAT Gateway などを作成する必要がある
- イメージ作成時しか使わないので何本もパイプラインを作成する運用を考えるとそのパイプライン専用のAWSリソースとして作成するのは費用的にもったいない
- CloudFormationテンプレートにVPC、サブネット、NAT Gatewayなどの情報も記載すると煩雑になる
- SNS トピックについては、作成後にサブスクリプションが必要で、何度も作り直すとなると毎回サブスクリプションの承認が必要になるのは面倒
- EC2 Image Builder のパイプラインはモジュールの追加や、エラー対応などのトライアンドエラーを行うので CloudFormation で修正を繰り返すことになる(前提条件)
という点から、VPC 、Subnet、セキュリティグループ、SNS トピックなどのリソースは作成済みのIDをパラメータで渡すことにしました。
Ubuntu 24.04 EC2 Image Builder pipeline の構築
準備その1 : 必要なファイルの準備
それでは構築を始めましょう。
必要なファイルをまとめた zip ファイルをダウンロードして、CloudShellにアップロードします。
SHA256: a20bb1d5bfbf44121497e757a6a4ab82524b1dc568b02c66cb240972c582611a
zip ファイルの中身を展開してフォルダを移動します。
~ $ unzip ubuntu24-pipeline.zip -d ./ubuntu24-pipeline Archive: ubuntu24-pipeline.zip inflating: ./ubuntu24-pipeline/ubuntu2404-pipeline.yaml inflating: ./ubuntu24-pipeline/shared-resources.yaml inflating: ./ubuntu24-pipeline/deploy-imagebuilder-pipelines.sh inflating: ./ubuntu24-pipeline/ubuntu2404-pipeline-deployment-guide.md inflating: ./ubuntu24-pipeline/vpc-infrastructure.yaml inflating: ./ubuntu24-pipeline/deploy-vpc-resources.sh ~ $ cd ubuntu24-pipeline ubuntu24-pipeline $
デプロイ用の環境変数( PROJECT_NAME と COST_TAG_VALUE ) を設定します。
PROJECT_NAME は作成するリソースの prefix(接頭語) となります。英小文字、数字、ハイフン、11文字まで 例: yourproject
英小文字、数字、記号はハイフンのみとしているのは この PROJECT_NAME が S3バケットの prefix として使用される場合にS3のバケットの命名規則により作成できなくなるからです。
COST_TAG_VALUE は コスト配分タグとして利用するタグ( タグ名 “Cost” ) 例: yourdivision
ubuntu24-pipeline $ export PROJECT_NAME=kodama-th ubuntu24-pipeline $ export COST_TAG_VALUE=j.kodama ubuntu24-pipeline $
準備その2 : VPC、Private Subnet、Security Group、NAT Gateway、VPC Endpoint (SSM、SSM Messages、EC2 Messages) の作成
EC2をデプロイするために、VPC、Private Subnet、Security Group が必要になります。
EC2は Private Subnet に配置します。 しかし、EC2へのインストールに必要なファイル群はインターネットからダウンロードしてくるので、インターネットへのアクセスのために Public Subnet に NAT Gateway の配置と適切なルーティングテーブル設定が必要です。
このNAT Gateway を経由して Private Subnet の Image Builder が使用する ビルド用EC2インスタンス がインターネットに出られるようにしておきます。
VPC Endpoint(SSM、SSM Messages、EC2 Messages) 3つは EC2 が Systems Manager とプライベートに通信するのに必要です。
既に作成済みのリソースを割り当てる場合は準備その3 に進んでください。
deploy-vpc-resources.sh を実行して VPCなどのリソースをデプロイします。
ubuntu24-pipeline $ ./deploy-vpc-resources.sh
=== Configuration ===
PROJECT_NAME: kodama-th
COST_TAG_VALUE: j.kodama
CREATE_DATE: 2026/01/28
STACK_NAME: kodama-th-vpc-infrastructure
TEMPLATE_FILE: vpc-infrastructure.yaml
=== Deploying VPC Infrastructure Stack ===
Stack does not exist, creating new stack...
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/kodama-th-vpc-infrastructure/abcd1234-de56-ab12-cd34-abdce12345",
"OperationId": "1234bcde-ab01-cd12-ef34-abcdef012345"
}
Waiting for stack creation to complete...
VPC infrastructure created successfully
=== Deployment completed ===
Stack Outputs:
-------------------------------------------------
| DescribeStacks |
+------------------+----------------------------+
| Key | Value |
+------------------+----------------------------+
| VPCId | vpc-01234567890abcdef |
| SecurityGroupId | sg-567890abcdef01234 |
| PrivateSubnetId | subnet-90abcdef012345678 |
+------------------+----------------------------+
ubuntu24-pipeline $
正常に完了すると、VPCId、SecurityGroupId、PrivateSubnetId が表示されるのでメモしておきます。
準備その3 : SNS トピックの作成
EC2 Image Builder のパイプラインの実行の完了を通知してもらう際の通知先として定義します。
完了するまでマネジメントコンソールを眺めていてもよいのですが、レシピの内容によっては実行に長時間かかる場合があるのでずっと待っているのは無駄だからです。
すでに通知用として機能するSNSのトピックに通知してもらうように設定する場合は、トピックARNをメモして 次の EC2 Image Builder パイプラインの作成に進んでください。
トピックの作成には create-topic コマンドを使用します。
$ aws sns create-topic --name my-image-builder-result-topic
{
"TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:my-image-builder-result-topic"
}
$
応答の TopicArn をメモしておいて、そこに通知先のメールアドレスを追加します。
$ aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:my-image-builder-result-topic \
--protocol email \
--notification-endpoint user@example.com
{
"SubscriptionArn": "pending confirmation"
}
$
“pending confirmation” と表示されればOKです。
メールが届いているはずなので、Confirm subscription リンクをクリックしてサブスクリプションします。
Topicにサブスクリプションされたかどうかは以下のコマンドで確認できます。
$ aws sns list-subscriptions-by-topic \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:my-image-builder-result-topic \
--query 'Subscriptions[*].{Email:Endpoint,Protocol:Protocol,Status:SubscriptionArn}' \
--output table
---------------------------------------------------------------------------------------------------------------------------------------------------
| ListSubscriptionsByTopic |
+------------------+-----------+------------------------------------------------------------------------------------------------------------------+
| Email | Protocol | Status |
+------------------+-----------+------------------------------------------------------------------------------------------------------------------+
| user@example.com| email | arn:aws:sns:ap-northeast-1:123456789012:my-imagebuilder-result-topic:defg1234-ab56-cd78-ef90-45678abcdef |
+------------------+-----------+------------------------------------------------------------------------------------------------------------------+
$
サブスクリプションが完了している場合には、Status欄にサブスクリプションARNが表示され、サブスクリプションが完了していない場合には、Status欄が pending confirmation となります。
EC2 Image Builderパイプラインのデプロイ
次はパイプラインのデプロイです。
必要な情報は
- Security Group ID
- Private Subnet ID
- SNS Topic 名(メモしたTopic ARN の一番最後コロンより後の部分 例: my-image-builder-result-topic )
- プロジェクト名 (他のリソースと競合しないように付与するリソースの prifix(接頭語))
- コスト配分タグの値
です。
パラメータ無しで、 `deploy-imagebuilder-pipelines.sh` を実行すると、必要な環境変数名と設定例を出力してくれますので、これを参考に値を設定します。
$ ./deploy-imagebuilder-pipelines.sh Error: The following environment variables are not set: - PROJECT_NAME - COST_TAG_VALUE - SECURITY_GROUP_ID - PRIVATE_SUBNET_ID - SNS_TOPIC_NAME Please set them using the following commands: export PROJECT_NAME="<your-project-name>" export COST_TAG_VALUE="<your-cost-allocation-department-name>" export SECURITY_GROUP_ID="sg-<your-sg-id>" like sg-01234567890abcdef export PRIVATE_SUBNET_ID="subnet-<your-subnet-id>" like subnet-01234567890abcdef export SNS_TOPIC_NAME="<your-sns-topic-name>" like imagebuilder-notifications $
PROJECT_NAME と COST_TAG_VALUE は設定済みと思いますが PROJECT_NAME については 11 文字以内で 小文字のみ記号はハイフンのみ有効なことに注意してください。
パラメータを環境変数に設定して、 `deploy-imagebuilder-pipelines.sh` を実行します。
ubuntu24-pipeline $ export PROJECT_NAME=kodama-th ubuntu24-pipeline $ export COST_TAG_VALUE=j.kodama ubuntu24-pipeline $ export SECURITY_GROUP_ID=sg-567890abcdef01234 ubuntu24-pipeline $ export PRIVATE_SUBNET_ID=subnet-90abcdef012345678 ubuntu24-pipeline $ export SNS_TOPIC_NAME=my-imagebuilder-result-topic ubuntu24-pipeline $ ./deploy-imagebuilder-pipelines.sh === Validating AWS resources === Checking SNS Topic: my-imagebuilder-result-topic ✓ SNS Topic exists Checking Security Group: sg-567890abcdef01234 ✓ Security Group exists Checking Subnet: subnet-90abcdef012345678 ✓ Subnet exists === All AWS resources validated successfully === === DEBUG: Tag values === PROJECT_NAME: kodama-th COST_TAG_VALUE: j.kodama CREATE_DATE: 2026-01-29 COMMON_TAGS: Cost=j.kodama Project=kodama-th CreateDate=2026-01-29 Press Enter to continue...
パラメータとして渡したリソースが実際に存在するかを確認して、タグ値の出力をしてくれます。
何度も間違ったパラメータを渡してデプロイして CREATE_FAILED となりやり直すのに時間がかかってしまった苦い経験からチェックを入れています。
問題なければ Enter キーで先に進めます。
Press Enter to continue...
=== Step 1: Create ChangeSet for shared resources ===
Stack does not exist, creating new stack...
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/kodama-th-shared-resources/12345678-1234-1234-1234-123456789abc",
"OperationId": "23456789-2345-2345-2345-23456789abcd"
}
Waiting for stack creation to complete...
Shared resources created successfully
=== Step 2: Deploy Ubuntu2404 pipeline ===
Stack kodama-th-ubuntu2404-pipeline does not exist, creating new stack...
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/kodama-th-ubuntu2404-pipeline/34567890-3456-3456-3456-34567890abcd",
"OperationId": "45678901-4567-4567-4567-45678901abcd"
}
kodama-th-ubuntu2404-pipeline created successfully
=== Deployment completed ===
ubuntu24-pipeline $
構築完了後、 SNS から EC2 Image Builder の作成時に発行される SNS発行権限確認メールが来ます。

イメージパイプラインの実行
作成されたイメージパイプラインからEC2 のイメージ (AMI) を作成します。
作成されたCloudFormation スタックのリソースタブから 作成された <プロジェクト名>-ubuntu2404-pipeline のスタックの、リソース ImagePipeline に表示されているリンクをクリックして EC2 Image Builder のイメージパイプラインの画面を表示します。
EC2 Image Builder のイメージパイプラインの画面から、アクション→パイプラインを実行 を選択し、パイプラインが動作させて AMI の作成を開始します。

AMIイメージの作成にはかなり時間がかかりますので、完了のメールが届くまで気長に待ちましょう。
パイプラインの実行結果の確認
完了メールが来ました!

メールに json で実行時された内容が詳しく記載されています。
“arn” が実行されたレシピの ARN、”state” の “status” が作成された AMI のステータスです。
SNS の完了通知は AVAILABLE か FAILEDの場合のみ来るので、 AVAILABLE なら成功、FAILED なら失敗ですね。
メール内の outputResources に 作成された AMI の ID が入ってます。
...
"outputResources": {
"amis": [
{
"region": "ap-northeast-1",
"accountId": "123456789012",
"image": "ami-01234567890abcdef",
"name": "kodama-th-ubuntu2404-ami-2026-01-29T10-56-12.206Z"
}
]
},
...
SNS からメールですが、定期実行するなどのユースケースで、EC2 Image Builder からのメッセージは FAILED の場合だけ原因究明の必要があるので確認したいという場合、SNSサブスクリプションに サブスクリプションフィルタポリシーを設定することで実現できます。
SNSのサブスクリプションから、サブスクリプションフィルターポリシーの編集を選択し、
サブスクリプションフィルターポリシーのチェックをON
フィルターポリシーのスコープで、メッセージ属性を選択し、JSONエディタにサブスクリプションフィルターポリシーを貼り付けて変更を保存します。
設定するフィルタポリシは、以下のようになります。
{
"$or": [
{
"sourcePipelineArn": [
{"prefix": "arn:aws:imagebuilder:"}
],
"state": {
"status": ["FAILED"]
}
},
{
"sourcePipelineArn": {
"exists": false
}
}
]
}
このフィルターの意味ですが、
“$or” は「以下のいずれかの条件に一致するメッセージを受信する」という意味です
条件1(OR の最初の要素)
{
"sourcePipelineArn": [{"prefix": "arn:aws:imagebuilder:"}],
"state": {"status": ["FAILED"]}
}
意味:
sourcePipelineArnフィールドが存在し、かつ
その値がarn:aws:imagebuilder:で始まり(Image Builderのメッセージ)、かつ
state.statusがFAILEDである
→ 該当するメッセージ: Image Builderのパイプライン実行が失敗した通知
条件2(OR の2番目の要素)
{
"sourcePipelineArn": {"exists": false}
}
意味:
sourcePipelineArnフィールドが存在しない
→ 該当するメッセージ: Image Builder以外の全てのメッセージ(CodePipeline、CloudWatch Alarms、Lambda通知など)
となるので、SNSトピックを他のサービスの通知と共有している場合でも他のメッセージは引き続き受信することができます。
実行時のログをみると、今回は40分弱かかったようです。
次回は作成されたAMIからEC2を起動します。









