ユーザーデータを使ってCloudFormationのヘルパースクリプトをインストールしてみた

ユーザーデータを使ってCloudFormationのヘルパースクリプトをインストールしてみた

Amazon LinuxとWindowsインスタンスでCloudFormationヘルパースクリプトを使いたい場合はひと準備が必要
Clock Icon2024.07.14

cfn-signal が実行されない

こんにちは、のんピ(@non____97)です。

皆さんはユーザーデータを使ってCloudFormationのヘルパースクリプトをインストールしたいなと思ったことはありますか? 私はあります。

CloudFormationのヘルパースクリプトの説明は以下記事をご覧ください。

https://dev.classmethod.jp/articles/cfn-helper-scripts/

Amazon Linux 2やAmazon Linux 2023、Windows Server 2022などでは正常に実行できましたが、Ubuntu 22.04やRed Hat Enterprise Linux 9(以降RHEL 9)では正常に実行できませんでした。

AWS公式ドキュメントを確認すると、Amazon LinuxにはCloudFormationヘルパースクリプトがプリインストールと言及がありましたが、その他のイメージにインストールされているかの言及はありませんでした。

Amazon Linux AMI イメージ

CloudFormation ヘルパースクリプトは、ブートストラップスクリプトがインストールされた Amazon Linux AMI イメージにプレインストールされています。

Amazon Linux AMI の最新バージョンでは、スクリプトは /opt/aws/bin にプレインストールされています。

以前の Amazon Linux AMI バージョンでは、スクリプトを含む aws-cfn-bootstrap パッケージは、Yum リポジトリにあります。

注記
ヘルパースクリプトは、Amazon Linux AMI の最新バージョンにプリインストールされており、Amazon Linux をベースとして使用する ECS に最適化されたイメージなど、最適化された AMI は対象外です。

その他のプラットフォーム用パッケージのダウンロード

Amazon Linux AMI イメージと Microsoft Windows (2008 以降) を除く Linux/Unix ディストリビューション用に、aws-cfn-bootstrap パッケージをダウンロードできます。

注記
ヘルパースクリプトのバージョン 2.0–1 以上は、Python 3.4 以上をサポートしています。以前のバージョンの Python をサポートするヘルパースクリプトが必要な場合は、「CloudFormation ヘルパースクリプト 1.4 のリリース履歴」を参照してください。

CloudFormation ヘルパースクリプトリファレンス - AWS CloudFormation

具体的なインストール方法についてもドキュメント内で言及されていなかったので実際にやってみます。

やってみた

CloudFormationヘルパースクリプトをインストールしない場合

CloudFormationヘルパースクリプトをインストールしない場合の挙動を確認します。

以下のEC2インスタンスをAWS CDKを用いてデプロイします。

  • Amazon Linux 2
  • Amazon Linux 2023
  • Ubuntu 22.04
  • RHEL 9.3
  • Windows Server 2022

AWS CDKのコードは以下記事で使用したものをベースに用意します。

https://dev.classmethod.jp/articles/aws-cdk-ec2-instance-os-conditional-branching/

以下記事を参考にユーザーデータにcfn-signalコマンドを追加します。

https://dev.classmethod.jp/articles/using-cfn-signal-to-wait-for-user-data-execution-in-aws-cdk-ec2-instance-setup/

変更箇所は以下です。

lib/construct/ec2-construct.ts
      // Instance
      const instance = new cdk.aws_ec2.Instance(
        this,
        `Instance${instanceSuffix}`,
        {
          machineImage: instanceProps.machineImage,
          instanceType: instanceProps.instanceType,
          vpc: props.networkConstruct.vpc,
          vpcSubnets: props.networkConstruct.vpc.selectSubnets(
            instanceProps.subnetSelection
          ),
          blockDevices: instanceProps.blockDevices,
          propagateTagsToVolumeOnCreation: true,
          role,
          requireImdsv2: true,
          userData: userDataOsNameMappings.find((userDataOsNameMapping) => {
            return (
              userDataOsNameMapping.osName ===
              this.isSupportedOs(instanceProps.machineImage)
            );
          })?.userData,
          securityGroup,
          instanceName: `${props.systemPrefix}-${props.envName}-ec2${instanceSuffix}`,
+          resourceSignalTimeout: cdk.Duration.minutes(10),
        }
      );

+      instance.userData.addSignalOnExitCommand(instance);

npx cdk deployでデプロイします。

すると、以下のようにUbuntu 22.04とRHEL 9.3のEC2インスタンスのみ処理が完了しません。

cicd-non-97-sandbox: deploying... [1/1]
cicd-non-97-sandbox: creating CloudFormation changeset...
[██████████████████████████████████████████████▍···········] (16/20)

18:32:33 | UPDATE_IN_PROGRESS   | AWS::CloudFormation::Stack            | cicd-non-97-sandbox
18:35:12 | CREATE_IN_PROGRESS   | AWS::EC2::Instance                    | Ec2Construct/Instance-ubuntu
18:35:13 | CREATE_IN_PROGRESS   | AWS::EC2::Instance                    | Ec2Construct/Instance-rhel

Ubuntu 22.04のEC2インスタンスのユーザーデータは以下のとおりです。exitTrap()関数がAWS CDKのaddSignalOnExitCommand()によって作成された箇所です。

#!/bin/bash
function exitTrap(){
exitCode=$?
/opt/aws/bin/cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstanceubuntu58EC8C59 --region us-east-1 -e $exitCode || echo 'Failed to send Cloudformation Signal'
}
trap exitTrap EXIT
#!/bin/bash

# -x to display the command to be executed
set -xe

# Redirect /var/log/user-data.log and /dev/console
exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>&1

declare -r SYSTEM_PREFIX=non-97
declare -r ENV_NAME=sandbox

echo "$SYSTEM_PREFIX $ENV_NAME Ubuntu Instance"

Ubuntu 22.04のEC2インスタンスに接続してユーザーデータの実行ログを確認します。

$ cat /var/log/user-data.log
+ declare -r SYSTEM_PREFIX=non-97
+ declare -r ENV_NAME=sandbox
+ echo 'non-97 sandbox Ubuntu Instance'
non-97 sandbox Ubuntu Instance
+ exitTrap
+ exitCode=0
+ /opt/aws/bin/cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstanceubuntu58EC8C59 --region us-east-1 -e 0
/var/lib/cloud/instance/scripts/part-001: line 4: /opt/aws/bin/cfn-signal: No such file or directory
+ echo 'Failed to send Cloudformation Signal'
Failed to send Cloudformation Signal

/opt/aws/bin/cfn-signalが存在しないようです。

/opt/awsを確認すると、確かに存在しません。

$ ls -lRh /opt/aws
/opt/aws:
total 4.0K
drwxr-xr-x 4 root root 4.0K Jul 11 09:36 inspector

/opt/aws/inspector:
total 8.0K
drwxr-xr-x 2 root root 4.0K Jul 11 09:36 bin
drwxr-xr-x 4 root root 4.0K Jul 11 09:36 var

/opt/aws/inspector/bin:
total 35M
-rwxr-xr-x 1 root root 35M Jul  8 14:26 inspectorssmplugin

/opt/aws/inspector/var:
total 8.0K
drwxr-xr-x 2 root root 4.0K Jul  8 14:26 input
drwxr-xr-x 2 root root 4.0K Jul 11 09:36 output

/opt/aws/inspector/var/input:
total 0

/opt/aws/inspector/var/output:
total 4.0K
-rwxr-xr-x 1 root root 1.3K Jul 11 09:36 packages.txt

RHEL 9.3についても同様に/opt/aws/bin/cfn-signalが存在しないため、異常終了しています。

$ cat /var/log/user-data.log
+ declare -r SYSTEM_PREFIX=non-97
+ declare -r ENV_NAME=sandbox
++ curl -s -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600' http://169.254.169.254/latest/api/token
+ token=AQAEAB0XQXYdOu2a34CpHl0wOI0TPqiNOknylQfolmwk442Hr1wRlA==
++ sed -e 's/.$//'
++ curl -s -H 'X-aws-ec2-metadata-token: AQAEAB0XQXYdOu2a34CpHl0wOI0TPqiNOknylQfolmwk442Hr1wRlA==' http://169.254.169.254/latest/meta-data/placement/availability-zone
+ region_name=us-east-1
+ dnf install -y https://s3.us-east-1.amazonaws.com/amazon-ssm-us-east-1/latest/linux_amd64/amazon-ssm-agent.rpm
Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered with an entitlement server. You can use subscription-manager to register.

Red Hat Enterprise Linux 9 for x86_64 - AppStre  44 MB/s |  37 MB     00:00
Red Hat Enterprise Linux 9 for x86_64 - BaseOS   50 MB/s |  26 MB     00:00
Red Hat Enterprise Linux 9 Client Configuration  25 kB/s | 3.2 kB     00:00
amazon-ssm-agent.rpm                             79 MB/s |  26 MB     00:00
Dependencies resolved.
================================================================================
 Package                Architecture Version           Repository          Size
================================================================================
Installing:
 amazon-ssm-agent       x86_64       3.3.551.0-1       @commandline        26 M

Transaction Summary
================================================================================
Install  1 Package

Total size: 26 M
Installed size: 114 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Running scriptlet: amazon-ssm-agent-3.3.551.0-1.x86_64                    1/1
  Preparing        :                                                        1/1
  Running scriptlet: amazon-ssm-agent-3.3.551.0-1.x86_64                    1/1
  Installing       : amazon-ssm-agent-3.3.551.0-1.x86_64                    1/1
  Running scriptlet: amazon-ssm-agent-3.3.551.0-1.x86_64                    1/1
Created symlink /etc/systemd/system/multi-user.target.wants/amazon-ssm-agent.service → /etc/systemd/system/amazon-ssm-agent.service.

  Verifying        : amazon-ssm-agent-3.3.551.0-1.x86_64                    1/1
Installed products updated.

Installed:
  amazon-ssm-agent-3.3.551.0-1.x86_64

Complete!
+ systemctl enable amazon-ssm-agent --now
+ echo 'non-97 sandbox RHEL Instance'
non-97 sandbox RHEL Instance
+ exitTrap
+ exitCode=0
+ /opt/aws/bin/cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstancerhel88A430F6 --region us-east-1 -e 0
/var/lib/cloud/instance/scripts/part-001: line 4: /opt/aws/bin/cfn-signal: No such file or directory
+ echo 'Failed to send Cloudformation Signal'
Failed to send Cloudformation Signal

$ ls -l /opt/aws/bin/
ls: cannot access '/opt/aws/bin/': No such file or directory

$ ls -l /opt/aws/
total 0
drwxr-xr-x. 4 root root 28 Jul 11 09:36 inspector

正常終了したAmazon Linux 2023も確認します。確かにCloudFormationのヘルパースクリプトがインストールされていますね。/opt/aws/bin/内の各種スクリプトから/apitools/cfn-init/bin/への各種スクリプトへのシンボリックリンクが張られていますね。

$ cat /var/log/user-data.log
+ declare -r SYSTEM_PREFIX=non-97
+ declare -r ENV_NAME=sandbox
+ echo 'non-97 sandbox AL2023 Instance'
non-97 sandbox AL2023 Instance
+ exitTrap
+ exitCode=0
+ /opt/aws/bin/cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstanceweb903197A6 --region us-east-1 -e 0

$ ls -lRh /opt/aws/
/opt/aws/:
total 0
drwxr-xr-x. 3 root root  45 Jun 28 01:05 apitools
drwxr-xr-x. 2 root root 256 Jun 28 01:05 bin
drwxr-xr-x. 4 root root  28 Jul 11 09:35 inspector

/opt/aws/apitools:
total 0
lrwxrwxrwx. 1 root root 17 Apr 30 20:01 cfn-init -> ./cfn-init-2.0-30
drwxr-xr-x. 5 root root 42 Jun 28 01:05 cfn-init-2.0-30

/opt/aws/apitools/cfn-init-2.0-30:
total 0
drwxr-xr-x. 2 root root 160 Jun 28 01:05 bin
drwxr-xr-x. 5 root root  49 Jun 28 01:05 init
drwxr-xr-x. 3 root root  17 Jun 28 01:05 share

/opt/aws/apitools/cfn-init-2.0-30/bin:
total 52K
-rwxr-xr-x. 1 root root 3.5K Apr 30 20:01 cfn-elect-cmd-leader
-rwxr-xr-x. 1 root root 3.7K Apr 30 20:01 cfn-get-metadata
-rwxr-xr-x. 1 root root 8.6K Apr 30 20:01 cfn-hup
-rwxr-xr-x. 1 root root 7.7K Apr 30 20:01 cfn-init
-rwxr-xr-x. 1 root root 4.2K Apr 30 20:01 cfn-send-cmd-event
-rwxr-xr-x. 1 root root 4.5K Apr 30 20:01 cfn-send-cmd-result
-rwxr-xr-x. 1 root root 6.2K Apr 30 20:01 cfn-signal

/opt/aws/apitools/cfn-init-2.0-30/init:
total 0
drwxr-xr-x. 2 root root 21 Jun 28 01:05 redhat
drwxr-xr-x. 2 root root 29 Jun 28 01:05 systemd
drwxr-xr-x. 2 root root 21 Jun 28 01:05 ubuntu

/opt/aws/apitools/cfn-init-2.0-30/init/redhat:
total 4.0K
-rwxr-xr-x. 1 root root 1.2K Feb 29 22:28 cfn-hup

/opt/aws/apitools/cfn-init-2.0-30/init/systemd:
total 4.0K
-rw-r--r--. 1 root root 141 Feb 29 22:28 cfn-hup.service

/opt/aws/apitools/cfn-init-2.0-30/init/ubuntu:
total 4.0K
-rwxr-xr-x. 1 root root 1.2K Feb 29 22:28 cfn-hup

/opt/aws/apitools/cfn-init-2.0-30/share:
total 0
drwxr-xr-x. 3 root root 35 Jun 28 01:05 doc

/opt/aws/apitools/cfn-init-2.0-30/share/doc:
total 0
drwxr-xr-x. 2 root root 64 Jun 28 01:05 aws-cfn-bootstrap-2.0

/opt/aws/apitools/cfn-init-2.0-30/share/doc/aws-cfn-bootstrap-2.0:
total 24K
-rw-r--r--. 1 root root 3.2K Feb 29 22:28 CHANGELOG.txt
-rw-r--r--. 1 root root  10K Feb 29 22:28 LICENSE.txt
-rw-r--r--. 1 root root 4.7K Feb 29 22:28 NOTICE.txt

/opt/aws/bin:
total 28K
lrwxrwxrwx. 1 root root   45 Apr 30 20:01 cfn-elect-cmd-leader -> ../apitools/cfn-init/bin/cfn-elect-cmd-leader
lrwxrwxrwx. 1 root root   41 Apr 30 20:01 cfn-get-metadata -> ../apitools/cfn-init/bin/cfn-get-metadata
lrwxrwxrwx. 1 root root   32 Apr 30 20:01 cfn-hup -> ../apitools/cfn-init/bin/cfn-hup
lrwxrwxrwx. 1 root root   33 Apr 30 20:01 cfn-init -> ../apitools/cfn-init/bin/cfn-init
lrwxrwxrwx. 1 root root   43 Apr 30 20:01 cfn-send-cmd-event -> ../apitools/cfn-init/bin/cfn-send-cmd-event
lrwxrwxrwx. 1 root root   44 Apr 30 20:01 cfn-send-cmd-result -> ../apitools/cfn-init/bin/cfn-send-cmd-result
lrwxrwxrwx. 1 root root   35 Apr 30 20:01 cfn-signal -> ../apitools/cfn-init/bin/cfn-signal
-rwxr-xr-x. 1 root root 6.7K Feb  2  2023 eic_curl_authorized_keys
-rwxr-xr-x. 1 root root  16K Feb  2  2023 eic_parse_authorized_keys
-rwxr-xr-x. 1 root root  823 Feb  2  2023 eic_run_authorized_keys

/opt/aws/inspector:
total 0
drwxr-xr-x. 2 root root 32 Jul 11 09:35 bin
drwxr-xr-x. 4 root root 33 Jul 11 09:35 var

/opt/aws/inspector/bin:
total 35M
-rwxr-xr-x. 1 root root 35M Jul  8 14:22 inspectorssmplugin

/opt/aws/inspector/var:
total 0
drwxr-xr-x. 2 root root  6 Jul  8 14:22 input
drwxr-xr-x. 2 root root 26 Jul 11 09:36 output

/opt/aws/inspector/var/input:
total 0

/opt/aws/inspector/var/output:
total 4.0K
-rwxr-xr-x. 1 root root 2.0K Jul 11 09:36 packages.txt

Windowsの場合はヘルパースクリプトはC:\Program Files\Amazon\cfn-bootstrapに配置されているようです。

> .\where.exe cfn-signal
C:\Program Files\Amazon\cfn-bootstrap\cfn-signal.exe

> ls "C:\Program Files\Amazon\cfn-bootstrap\"

    ディレクトリ: C:\Program Files\Amazon\cfn-bootstrap

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/02/06     12:56         441891 cacert.pem
-a----        2024/02/08     17:58          55992 cfn-elect-cmd-leader.exe
-a----        2024/02/08     17:58          55992 cfn-get-metadata.exe
-a----        2024/02/08     17:58          64696 cfn-hup.exe
-a----        2024/02/08     17:58          63160 cfn-init.exe
-a----        2024/02/08     17:58          57528 cfn-send-cmd-event.exe
-a----        2024/02/08     17:58          57528 cfn-send-cmd-result.exe
-a----        2024/02/08     17:58          60088 cfn-signal.exe
-a----        2024/02/06     12:56           2654 endpoints.json
-a----        2024/02/06     22:41        5191960 libcrypto-3.dll
-a----        2024/02/06     22:41          39696 libffi-8.dll
-a----        2024/02/08     17:56        8873032 library.zip
-a----        2024/02/06     22:41         787224 libssl-3.dll
-a----        2024/02/06     12:56          11423 LICENSE.rtf
-a----        2024/02/06     12:56          15502 notice.txt
-a----        2024/02/08     17:56          28672 perfmon.pyd
-a----        2024/02/06     22:41         198424 pyexpat.pyd
-a----        2024/02/06     22:41        5789464 python311.dll
-a----        2024/02/08     17:56         689664 pythoncom311.dll
-a----        2024/02/08     17:56         146944 pywintypes311.dll
-a----        2024/02/06     22:41          30488 select.pyd
-a----        2024/02/08     17:56          41984 servicemanager.pyd
-a----        2024/02/06     22:41        1141016 unicodedata.pyd
-a----        2024/02/08     17:56         139776 win32api.pyd
-a----        2024/02/08     17:56         603136 win32com.shell.shell.pyd
-a----        2024/02/08     17:56          28160 win32event.pyd
-a----        2024/02/08     17:56          78336 win32evtlog.pyd
-a----        2024/02/08     17:56          60416 win32service.pyd
-a----        2024/02/08     17:56        1612288 win32ui.pyd
-a----        2024/02/08     17:58          56504 winhup.exe
-a----        2024/02/06     22:41          84760 _bz2.pyd
-a----        2024/02/06     22:41         124696 _ctypes.pyd
-a----        2024/02/06     22:41         253720 _decimal.pyd
-a----        2024/02/06     22:41         128280 _elementtree.pyd
-a----        2024/02/06     22:41          65304 _hashlib.pyd
-a----        2024/02/06     22:41         159512 _lzma.pyd
-a----        2024/02/06     22:41          32536 _queue.pyd
-a----        2024/02/06     22:41          79640 _socket.pyd
-a----        2024/02/06     22:41         176920 _ssl.pyd
-a----        2024/02/06     22:41          25368 _uuid.pyd
-a----        2024/02/08     17:56          14336 _win32sysloader.pyd

ユーザーデータの実行ログは以下のとおりです。Successをthrowしていますね。

> ls C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618\

    ディレクトリ: C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/07/11      9:56            291 err.tmp
-a----        2024/07/11      9:56             33 output.tmp
-a----        2024/07/11      9:55            403 UserScript.ps1

> cat C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618\err.tmp
Success
発生場所 C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618\UserScript.ps1:10 文字:1
+ throw "Success"
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Success:String) [], RuntimeException
    + FullyQualifiedErrorId : Success

> cat C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618\output.tmp
non-97 sandbox Windows Instance

> cat C:\Windows\system32\config\systemprofile\AppData\Local\Temp\EC2Launch1861941618\UserScript.ps1
trap {
$success=($PSItem.Exception.Message -eq "Success")
cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstancewindows1F2FDC2F --region us-east-1 --success ($success.ToString().ToLower())
break
}
Set-Variable -name SYSTEM_PREFIX -value non-97 -Option Constant
Set-Variable -name ENV_NAME -value sandbox -Option Constant

echo "$SYSTEM_PREFIX $ENV_NAME Windows Instance"
throw "Success"

ということでAmazon LinuxとWindows Serverの公式AMI以外のAMIにはCloudFormationのヘルパースクリプトはインストールされていなさそうです。

CloudFormationヘルパースクリプトをインストールする処理を追加した場合

ユーザーデータにloudFormationヘルパースクリプトをインストールする処理を追加します。

具体的には以下です。

# tar.gz形式の aws-cfn-bootstrap パッケージをダウンロード
curl https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz \
  -s \
  -o aws-cfn-bootstrap-py3-latest.tar.gz

# tar.gzの解凍
tar zxvf aws-cfn-bootstrap-py3-latest.tar.gz

# セットアップスクリプトの実行
cd aws-cfn-bootstrap-2.0/
python3 setup.py install

# tar.gz および 解凍されたディレクトリを削除
cd ../
rm -rf aws-cfn-bootstrap-*

# インストールされたスクリプトのシンボリックリンクを /opt/aws/bin/ に作成
mkdir -p /opt/aws/bin/
ln -s /usr/local/bin/cfn-* /opt/aws/bin/

実行しているsetup.pyの中身は以下のとおりです。

setup.py
#!/usr/bin/env python3

# ==============================================================================
# Copyright 2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

from distutils.core import setup, Distribution
import sys

name = 'aws-cfn-bootstrap'
version = '2.0'

if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 4):
    print("Error: Python 3.4+ is required, but found:\n" + sys.version)
    sys.exit(1)

if sys.version_info >= (3,6):
    dependencies = ['python-daemon>=2.2.4,<2.3', 'chevron', 'docutils', 'setuptools']
else:
    dependencies = ['python-daemon>=2.1,<2.2', 'pystache<=0.5.4', 'docutils', 'setuptools<=57.5.0']

rpm_requires = ['python >= 3.4', 'python-daemon', 'pystache', 'python-setuptools']

_distclass = Distribution
_opts = {'bdist_rpm': {'requires': rpm_requires}}
_data_files = [('share/doc/%s-%s' % (name, version), ['license/NOTICE.txt', 'license/LICENSE.txt', 'CHANGELOG.txt']),
               ('init/redhat', ['init/redhat/cfn-hup']),
               ('init/ubuntu', ['init/ubuntu/cfn-hup']),
               ('init/systemd', ['init/systemd/cfn-hup.service'])]
try:
    import py2exe
    class WindowsDistribution(Distribution):
        def __init__(self, attrs):
            self.com_server = []
            self.ctypes_com_server = []
            self.service = ["cfnbootstrap.winhup"]
            self.isapi = []
            self.windows = []
            self.zipfile = 'library.zip'
            self.console = ['bin/cfn-init', 'bin/cfn-signal', 'bin/cfn-get-metadata', 'bin/cfn-hup', 'bin/cfn-elect-cmd-leader', 'bin/cfn-send-cmd-result', 'bin/cfn-send-cmd-event']
            Distribution.__init__(self, attrs)
    _distclass = WindowsDistribution
    _opts['py2exe'] = {
                        'typelibs': [('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0),
                                     ('{E34CB9F1-C7F7-424C-BE29-027DCC09363A}', 0, 1, 0)],
                        'excludes': ['pyreadline', 'difflib', 'distutils', 'doctest', 'pdb', 'unittest', 'adodbapi'],
                        'includes': ['dbm', 'win32com'],
                        'dll_excludes': ['msvcr71.dll', 'w9xpopen.exe', ''],
                        'skip_archive': True
                      }
    _data_files = [('', ['license/win/NOTICE.txt', 'license/win/LICENSE.rtf', 'cfnbootstrap/packages/requests/cacert.pem', 'cfnbootstrap/resources/documents/endpoints.json', 'CHANGELOG.txt'])]
except ImportError:
    pass

setup(
    distclass=_distclass,
    name='aws-cfn-bootstrap',
    version='2.0',
    description='An EC2 bootstrapper for CloudFormation',
    long_description="Bootstraps EC2 instances by retrieving and processing the Metadata block of a CloudFormation resource.",
    author='AWS CloudFormation',
    url='http://aws.amazon.com/cloudformation/',
    license='Apache 2.0',
    classifiers=['License :: OSI Approved :: Apache Software License'],
    packages=[
        'cfnbootstrap',
        'cfnbootstrap.packages',
        'cfnbootstrap.packages.requests',
        'cfnbootstrap.packages.requests.packages',
        'cfnbootstrap.packages.requests.packages.chardet',
        'cfnbootstrap.packages.requests.packages.urllib3',
        'cfnbootstrap.packages.requests.packages.urllib3.packages',
        'cfnbootstrap.packages.requests.packages.urllib3.contrib',
        'cfnbootstrap.packages.requests.packages.urllib3.util',
        'cfnbootstrap.packages.requests.packages.urllib3.packages.ssl_match_hostname',
        'cfnbootstrap.packages.requests.packages.urllib3.packages.backports',
        'cfnbootstrap.resources',
        'cfnbootstrap.resources.documents'
    ],
    excluded=['setup.cfg'],
    install_requires=dependencies,
    scripts=['bin/cfn-init', 'bin/cfn-signal', 'bin/cfn-get-metadata', 'bin/cfn-hup', 'bin/cfn-elect-cmd-leader', 'bin/cfn-send-cmd-result', 'bin/cfn-send-cmd-event'],
    data_files=_data_files,
    package_data={'cfnbootstrap': ['packages/requests/cacert.pem', 'resources/documents/endpoints.json']},
    options=_opts
)

なお、Ubuntuでcfn-hupを使用する場合は、別途シンボリックリンクを作成する必要があるようです。

Python の Pip を使用して tar.gz をインストールします。Ubuntu 用のインストールを完了するには、シンボリックリンクを作成する必要があります。

ln -s /<path-to-extracted-tar>/aws-cfn-bootstrap-2.0/init/ubuntu/cfn-hup /etc/init.d/cfn-hup

CloudFormation ヘルパースクリプトリファレンス - AWS CloudFormation

Ubuntu 22.04とRHEL 9.3のEC2インスタンスのユーザーデータに上述の処理を追加して再度AWS CDKでデプロイします。

すると、正常にデプロイが完了しました。

Ubuntu 22.04のEC2インスタンスのユーザーデータの実行ログは以下のとおりです。

$ cat /var/log/user-data.log
+ declare -r SYSTEM_PREFIX=non-97
+ declare -r ENV_NAME=sandbox
+ echo 'non-97 sandbox Ubuntu Instance'
non-97 sandbox Ubuntu Instance
+ curl https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz -s -o aws-cfn-bootstrap-py3-latest.tar.gz
+ tar zxvf aws-cfn-bootstrap-py3-latest.tar.gz
aws-cfn-bootstrap-2.0/
aws-cfn-bootstrap-2.0/bin/
.
.
(中略)
.
.
aws-cfn-bootstrap-2.0/license/
aws-cfn-bootstrap-2.0/license/NOTICE.txt
aws-cfn-bootstrap-2.0/license/LICENSE.txt
+ cd aws-cfn-bootstrap-2.0/
+ python3 setup.py install
/aws-cfn-bootstrap-2.0/setup.py:19: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
  from distutils.core import setup, Distribution
/usr/lib/python3.10/distutils/dist.py:274: UserWarning: Unknown distribution option: 'excluded'
  warnings.warn(msg)
/usr/lib/python3.10/distutils/dist.py:274: UserWarning: Unknown distribution option: 'install_requires'
  warnings.warn(msg)
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/cfnbootstrap
copying cfnbootstrap/cfn_client.py -> build/lib/cfnbootstrap
copying cfnbootstrap/systemd_tool.py -> build/lib/cfnbootstrap
copying cfnbootstrap/construction.py -> build/lib/cfnbootstrap
.
.
(中略)
.
.
copying cfnbootstrap/resources/documents/__init__.py -> build/lib/cfnbootstrap/resources/documents
copying cfnbootstrap/packages/requests/cacert.pem -> build/lib/cfnbootstrap/packages/requests
copying cfnbootstrap/resources/documents/endpoints.json -> build/lib/cfnbootstrap/resources/documents
running build_scripts
creating build/scripts-3.10
copying and adjusting bin/cfn-init -> build/scripts-3.10
.
.
(中略)
.
.
changing mode of build/scripts-3.10/cfn-send-cmd-result from 644 to 755
changing mode of build/scripts-3.10/cfn-send-cmd-event from 644 to 755
running install_lib
creating /usr/local/lib/python3.10/dist-packages/cfnbootstrap
copying build/lib/cfnbootstrap/cfn_client.py -> /usr/local/lib/python3.10/dist-packages/cfnbootstrap
copying build/lib/cfnbootstrap/systemd_tool.py -> /usr/local/lib/python3.10/dist-packages/cfnbootstrap
copying build/lib/cfnbootstrap/construction.py -> /usr/local/lib/python3.10/dist-packages/cfnbootstrap
.
.
(中略)
.
.
byte-compiling /usr/local/lib/python3.10/dist-packages/cfnbootstrap/posix_security.py to posix_security.cpython-310.pyc
byte-compiling /usr/local/lib/python3.10/dist-packages/cfnbootstrap/json_file_manager.py to json_file_manager.cpython-310.pyc
byte-compiling /usr/local/lib/python3.10/dist-packages/cfnbootstrap/lang_package_tools.py to lang_package_tools.cpython-310.pyc
byte-compiling /usr/local/lib/python3.10/dist-packages/cfnbootstrap/command_tool.py to command_tool.cpython-310.pyc
running install_scripts
copying build/scripts-3.10/cfn-send-cmd-result -> /usr/local/bin
copying build/scripts-3.10/cfn-send-cmd-event -> /usr/local/bin
copying build/scripts-3.10/cfn-get-metadata -> /usr/local/bin
copying build/scripts-3.10/cfn-init -> /usr/local/bin
copying build/scripts-3.10/cfn-signal -> /usr/local/bin
copying build/scripts-3.10/cfn-hup -> /usr/local/bin
copying build/scripts-3.10/cfn-elect-cmd-leader -> /usr/local/bin
changing mode of /usr/local/bin/cfn-send-cmd-result to 755
changing mode of /usr/local/bin/cfn-send-cmd-event to 755
changing mode of /usr/local/bin/cfn-get-metadata to 755
changing mode of /usr/local/bin/cfn-init to 755
changing mode of /usr/local/bin/cfn-signal to 755
changing mode of /usr/local/bin/cfn-hup to 755
changing mode of /usr/local/bin/cfn-elect-cmd-leader to 755
running install_data
creating /usr/local/share/doc
creating /usr/local/share/doc/aws-cfn-bootstrap-2.0
copying license/NOTICE.txt -> /usr/local/share/doc/aws-cfn-bootstrap-2.0
copying license/LICENSE.txt -> /usr/local/share/doc/aws-cfn-bootstrap-2.0
copying CHANGELOG.txt -> /usr/local/share/doc/aws-cfn-bootstrap-2.0
creating /usr/local/init
creating /usr/local/init/redhat
copying init/redhat/cfn-hup -> /usr/local/init/redhat
creating /usr/local/init/ubuntu
copying init/ubuntu/cfn-hup -> /usr/local/init/ubuntu
creating /usr/local/init/systemd
copying init/systemd/cfn-hup.service -> /usr/local/init/systemd
running install_egg_info
Writing /usr/local/lib/python3.10/dist-packages/aws_cfn_bootstrap-2.0.egg-info
+ cd ../
+ rm -rf aws-cfn-bootstrap-2.0 aws-cfn-bootstrap-py3-latest.tar.gz
+ mkdir -p /opt/aws/bin/
+ ln -s /usr/local/bin/cfn-elect-cmd-leader /usr/local/bin/cfn-get-metadata /usr/local/bin/cfn-hup /usr/local/bin/cfn-init /usr/local/bin/cfn-send-cmd-event /usr/local/bin/cfn-send-cmd-result /usr/local/bin/cfn-signal /opt/aws/bin/
+ exitTrap
+ exitCode=0
+ /opt/aws/bin/cfn-signal --stack cicd-non-97-sandbox --resource Ec2ConstructInstanceubuntu58EC8C59 --region us-east-1 -e 0

正常に実行が完了していますね。

RHEL 9.3についても同様に正常に終了していました。

Amazon LinuxとWindowsインスタンスでCloudFormationヘルパースクリプトを使いたい場合はひと準備が必要

ユーザーデータを使ってCloudFormationのヘルパースクリプトをインストールしてみました。

Amazon LinuxとWindowsインスタンスでCloudFormationヘルパースクリプトを使いたい場合はひと準備が必要です。

ぜひ参考にしてみてください。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.