Moderniser.repo
  • 日本語✔️
  • English
  • 日本語✔️
  • English
[AWS]
設計ガイドラインとは?
AWS における標準化ガイドラインとは?
AWS Organizations AWS Control Tower
AWS lAM / AWS lAM Identity Center
AWS CloudTrail AWS Config Amazon GuardDuty
SSM オートメーションの aws:executeScript アクション
AWS Control Towerに関する備忘録 Prowler でカスタムチェックを作成する方法 Security Hub コントロールのリファレンスをスクレイピングしてデータ化する方法 CIS AWS Foundations Benchmark v3.0.0 に対応しているセキュリティチェックツールを調査 SSM オートメーション(もしくは Lambda)で最新の boto3 を利用する方法 samconfig.yml で CommaDelimitedList を List (配列)形式で記述する方法 AWS::SSM::Document の Script プロパティでローカルファイルを指定する方法 Terraform の Data Source で複数の AWS リソースの情報を取得する方法まとめ
CloudFormation テンプレート / SAM テンプレートのコーディングルール
Amazon S3
Amazon Athena (Glue Database)
[GCP]
Cloud RunをデプロイするCloud Buildを構築する際に考慮したことのまとめ
Cloud RunとFirebase Hostingで静的サイトを公開した際のランニングコストを比較
無料の Google アカウントで Cloud Build の 成功通知 を Google Chat へ投稿する方法
[Visual Studio Code]
Visual Studio Code の Draw.io で最新の AWS のアイコンを利用する方法
クラウドエンジニア向け Visual Studio Code のおすすめプラグインまとめ
[iPhone]
ほぼ無償で YouTube 動画を音声ファイル化して iPhone で聴く方法 iPhone から Gmail のフィルタ設定にアクセスするアイコンを作成
[その他]
ブログ作成時に検討したこと ブログURLのパーマリンクをアルファベットに変更しました
GitHub CLIコマンドのアカウントをコマンドで切り替える方法
ChatGPTでアクセス可能なURLを検証
プライバシーポリシー
Profile
...

Kanji

・クラウドエンジニア / フリーランス
・1993年生まれ
・愛媛県出身 / 東京都渋谷区在住
・AWS歴5年

プロフィールの詳細

Contact
Twitter(@kanji_aws_fl) Instagram(kanji_aws_freelance) Mail(kanji@cont-aid.com)


【Python】AWS::SSM::Document の Script プロパティでローカルファイルを指定する方法


作成日: 2025/04/13, 更新日: 2025/04/13


aws cloudformation package コマンドでは、AWS::SSM::Document で SSM オートメーションで利用するランブックを定義する際に利用する、aws:executeScript ステップの Script プロパティで指定するファイルを S3 にアップロードすることができません。
この処理にしばらく AWS の機能アップデート対応されていない理由として、AWS::SSM::Document に S3 バケットへ配置したスクリプトを指定するためには
格納した S3 バケットの名前、ファイル名だけでなく、チェックサムとしてハッシュ値を AWS::SSM::Document で指定する必要がある仕様になっているからだと推測します。
本記事では、AWS::SSM::Document の Script プロパティでローカルファイルをパスで指定してもデプロイできるよう
変換処理を Python で実装しましたので、その方法を紹介いたします。

目次


  1. 注意事項
  2. コーディングルール・前提条件
  3. AWS::SSM::Document の Script プロパティで指定したファイル内容を CloudFormatio テンプレートへ書き込む処理



注意事項

  • 本記事に記載の Python スクリプトを実行することで、CloudFormation テンプレートの AWS::SSM::Document リソースの Script プロパティで指定したファイルの内容を CloudFormation テンプレートに書き込むことができます。
  • Python スクリプトの場合、実行するスクリプトで利用できるモジュールは Lambda の標準のモジュールと同等のものとなります。Lambda の標準モジュール以外を利用する場合はこの Python スクリプトでは対応できません。
    • os, argparse, boto3, json, logging, time, datetime などの標準モジュールは利用可能です。
  • Lambda の標準モジュール以外を利用する場合は、手動で S3 バケットに Python スクリプトとパッケージを含めた ZIP ファイルをアップロード後、CloudFormation テンプレートをデプロイする必要があります。

コーディングルール・前提条件

  • 本記事に記載の Python スクリプトでは、PEP8 に準拠しています。
    • flake 8 による構文チェックと、 black による自動フォーマットを実施しています。
    • 処理の都合上チェックを無視する必要があるコードには、 # noqa を記載しています。
    • 1行当たりの最大文字数( max-line-length )は 200 に設定しています。
  • Python のランタイムバージョンは 3.12.1 を利用して動作確認を行っています。

AWS::SSM::Document の Script プロパティで指定したファイル内容を CloudFormatio テンプレートへ書き込む処理

  • 実行に必要なモジュールは以下の通りです。 argparse、os は標準ライブラリのため、追加のインストールは不要です。
ruamel.yaml

  • 以下の Python スクリプトが、 AWS::SSM::Document の Script プロパティで指定したファイルの内容を CloudFormation テンプレートへ書き込みます。適当 Python ファイルの名前(例: package-ssm-document.py )で保存してください。
    • aws cloudformation package コマンドと同様、Cloud Formation テンプレートをデプロイする前に実行する必要があります。実行手順や CI/CD に組み込んでご利用ください。
import argparse
import os
from ruamel.yaml import YAML
from ruamel.yaml.scalarstring import LiteralScalarString

yaml = YAML()
yaml.default_flow_style = False
yaml.sort_keys = False

def replace_script_with_inline_code(input_file, output_file):
    base_dir = os.path.dirname(input_file)

    with open(input_file, "r") as file:
        yaml_content = yaml.load(file)

    def process_main_steps(main_steps):
        for step in main_steps:
            if step.get("action") == "aws:executeScript" and "Script" in step["inputs"]:
                script_path = step["inputs"]["Script"]
                full_script_path = os.path.normpath(os.path.join(base_dir, script_path))
                if os.path.exists(full_script_path):
                    with open(full_script_path, "r") as script_file:
                        script_content = script_file.read()
                    step["inputs"]["Script"] = apply_literal_block_style(script_content)
                else:
                    print(f"Warning: Script file not found at {full_script_path}")
            elif step.get("action") == "aws:loop" and "Steps" in step["inputs"]:
                process_main_steps(step["inputs"]["Steps"])
            if "nextStep" in step:
                process_main_steps(step.get("nextStep", []))

    def apply_literal_block_style(script_content):
        return LiteralScalarString(script_content)

    for resource in yaml_content.get("Resources", {}).values():
        if resource.get("Type") == "AWS::SSM::Document":
            content = resource.get("Properties", {}).get("Content", {})
            if "mainSteps" in content:
                process_main_steps(content["mainSteps"])

    output_dir = os.path.dirname(output_file)
    if output_dir and not os.path.exists(output_dir):
        os.makedirs(output_dir)

    with open(output_file, "w") as file:
        yaml.dump(yaml_content, file)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Transform parameter overrides in a YAML file.")
    parser.add_argument("--input-file", help="Path to the input YAML file.", default="template.original.yml")
    parser.add_argument("--output-file", help="Path to the output YAML file.", default="template.yml")
    args = parser.parse_args()
    replace_script_with_inline_code(args.input_file, args.output_file)

  • 以下は実行例となります。
    • template.original.yml を template.yml に変換する場合のオプションを指定しています。
    • 要件に応じて、引数でファイルパスを指定して実行してください。
python package-ssm-document.py \
--input-file tests/template1.original.yml \
--output-file .alcache/template.yml

  • template.original.yml の内容は以下の通りです。 Script プロパティで指定したファイルは src/sample1.py です。
AWSTemplateFormatVersion: 2010-09-09
Description: template.yml
Resources:
  TestRunbook:
    Type: AWS::SSM::Document
    Properties:
      Name: Sample-TestRunbook
      DocumentType: Automation
      DocumentFormat: YAML
      UpdateMethod: NewVersion
      Content:
        schemaVersion: '0.3'
        mainSteps:
          - name: SampleStep
            action: aws:executeScript
            isEnd: true
            inputs:
              Runtime: python3.11
              Handler: main
              Script: src/sample1.py

  • 以下は、変換後の template.yml の内容です。 Script プロパティで指定したファイルの内容が Script プロパティの値に置き換わっていることが確認できます。
AWSTemplateFormatVersion: 2010-09-09
Description: template.yml
Resources:
  TestRunbook:
    Type: AWS::SSM::Document
    Properties:
      Name: Sample-TestRunbook
      DocumentType: Automation
      DocumentFormat: YAML
      UpdateMethod: NewVersion
      Content:
        schemaVersion: '0.3'
        mainSteps:
        - name: SampleStep
          action: aws:executeScript
          isEnd: true
          inputs:
            Runtime: python3.11
            Handler: main
            Script: |
              def main(event, context):
                  print("[sample1] Hello, World!")

              if __name__ == "__main__":
                  main(None, None)



©2025 ContAID