【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

AWS SSM の Run Command で Ansible の Playbook を実行する手順について解説します。

AWS で Ansible を使って OS やミドルウェア周りの管理をコード化して実施したい場合があります。

コード化のメリットとしてはドキュメントが不要になるという点が挙げられます。

昔はExcelファイルやWordを使って基本設計書や詳細設計書(パラメータシート)を書いていたと思います。

そして上長にレビューを依頼して何度も繰り返して数か月、ようやくレビューが通ったと思ったら、運用をしていく中でどんどん仕様が変わっていき、数か月かけて作成したドキュメントは使い物にならずに結局リモートログインをしてコマンドを叩いてみるか、他の人に確認するなりしてドキュメントを全く見ない(もしくはそもそもドキュメントを信用してはいけない)ようになります。

しかしコード化ならコードを見れば一発で把握できます。

(仮にTerraformとGUIでの手動という2つの方法で管理をしていたらコードは全く信用できなくなりますが)

 

他にもコード化することにより繰り返しインスタンスを構築・設定する必要がある場合はミスなく正確に短時間で構築・設定ができるようになります。

また、人の手が入らないのでヒューマンエラー(開発環境だと思ってたら実は本番環境だった等)が発生しないというメリットもあります。

 

このようにコード化にはメリットがあります。

 

 

設計

まずは簡単に設計します。

  • Ansible を利用する。
  • AWS SSM を利用する。
  • Ansible Playbook の実行は SSM Run Command を利用する。
  • Ansible Playbook は S3 バケットに保存する。Playbook のコードは GitHub で管理するが Planbook の zip ファイルは S3 バケットに保存する)
  • Ansible 管理対象は EC2 インスタンスで試す。
  • Linux サーバ は Amazon Linux2 にする。(別途 SSM エージェントをインストールする必要なし)
  • Linux サーバはパブリックサブネットに構築する。

 

 

作業概要

以下、作業概要です。

  1. Terraform で管理対象の Linux サーバを構築する。
  2. SSM へのアクセスを許可するため、IAM ロールを作成する。
  3. AWS 管理コンソールより(GUI より)Run Command で実施する。

 

※Run Command の他にもステートマネージャからも実行できます。イメージとしては Run Command は単発の処理で利用し、ステートマネージャは運用に乗せて定期的に処理を回す場合に利用するので、今回は Run Command を利用します。

 

 

事前準備

Ansible コード管理用に GitHub にリポジトリを作成します。

 

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

環境構築用の Terraform の tf ファイル

Ansible 検証用の環境(EC2 インスタンス、S3 バケット)は Terraform で作成します。

 

 

■Ec2.tfファイル

cat Ec2.tf  
resource “aws_instance” “ansible-test-ec2” { 
  ami           = “ami-0f36dcfcc94112ea1” 
  instance_type = “t2.micro” 
  subnet_id     = “subnet-xxxxxxxxxx” 
  iam_instance_profile = aws_iam_instance_profile.ssm-agent-for-ec2.name 
 
  tags = { 
    Name = “ansible-test-ec2” 
  } 
}

 

 

■Iam.tfファイル

cat Iam.tf 
# ———————————————— 
# SSM 用ロール作成 
# ———————————————— 
resource “aws_iam_role” “ssm-agent-for-ec2-role” { 
  name               = “ssm-agent-test-role” 
  assume_role_policy = data.aws_iam_policy_document.ec2-assume-policy-document.json 

 
# ———————————————— 
# Assume Role ポリシードキュメント 
# ———————————————— 
data “aws_iam_policy_document” “ec2-assume-policy-document” { 
  statement { 
    effect = “Allow” 
    actions = [ 
      “sts:AssumeRole” 
    ] 
    principals { 
      type        = “Service” 
      identifiers = [“ec2.amazonaws.com”] 
    } 
  } 

 
# ———————————————— 
# ポリシーを IAM ロールにアタッチする 
# ———————————————— 
resource “aws_iam_role_policy_attachment” “ssm-agent-for-ec2-attachment” { 
  role       = aws_iam_role.ssm-agent-for-ec2-role.name 
  policy_arn = “arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM” 

 
# ———————————————— 
# インスタンスプロファイルの設定 
# ———————————————— 
resource “aws_iam_instance_profile” “ssm-agent-for-ec2” { 
  name = “ec2-instance-profile” 
  role = aws_iam_role.ssm-agent-for-ec2-role.name 

 

 

■S3.tfファイル

cat S3.tf  
#—————————————– 
# ALB Access Log 用の S3 バケットの作成 
#—————————————– 
resource “aws_s3_bucket” “ansible_dev_zip_bucket” { 
  bucket = “ansible-dev-zip-bucket-xxxxxxxxxx” 
  # バケットの削除設定(バケットの中にオブジェクトが入っているとdestroyでエラーになるのでtrueにする) 
  force_destroy = true 

 
#—————————————– 
# S3 バケットの ACL の設定 
#—————————————– 
resource “aws_s3_bucket_acl” “bucket_acl” { 
  bucket = aws_s3_bucket.ansible_dev_zip_bucket.id 
  acl    = “private” 

 
# S3バケットのオブジェクト所有者(ACL設定) 
resource “aws_s3_bucket_ownership_controls” “bucket_acl_owner” { 
  bucket = aws_s3_bucket.ansible_dev_zip_bucket.id 
  rule { object_ownership = “BucketOwnerEnforced” } 

 
# ブロック パブリック アクセス 
resource “aws_s3_bucket_public_access_block” “private” { 
  bucket                  = aws_s3_bucket.ansible_dev_zip_bucket.id 
  block_public_acls       = true 
  block_public_policy     = true 
  ignore_public_acls      = true 
  restrict_public_buckets = true 
}

 

 

 

■terraform.tfファイル

※tfstate ファイルは S3 バケットに配置します。(複数人での Terraform 管理を想定しています) 

cat terraform.tf  
terraform { 
  backend “s3” { 
    bucket = “terraform-tfstate-xxxxxxxxxxxx” 
    key    = “terraform.tfstate” 
    region = “ap-northeast-1” 
  } 
 
  // Terraform本体に対するバージョン制約 
  required_version = “~> 1.2.0” 
 
  required_providers { 
    aws = { 
      source  = “hashicorp/aws” 
      version = “~> 4.0” 
    } 
  } 
}

 

 

 

Terraformで環境を構築する 

tfファイルを作成したら terraform plan、terraform apply コマンドを実行して Ansible のテスト環境を構築します。

 

■terraform plan コマンド

$ terraform plan

 

 

■terraform apply コマンド

$ terraform apply

 

 

Ansible テスト用の EC2 インスタンスが作成されていることを確認します。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

 

ssm コマンドをログイン確認

Amazon Linux2 で構築した場合は、セキュリティグループの設定不要で ssm コマンドで EC2 インスタンスにログインが可能です。

ポートを全部閉じていても aws cli でログインが可能です。

 

■ssm コマンドで EC2 インスタンスにアクセスをする

aws ssm start-session –target i-0xxxxxxxxxxx 
 
Starting session with SessionId: i-0xxxxxxxx-0xxxxxxxxxxx 
sh-4.2$ hostname 
ip-172-xxxxxx.ap-northeast-1.compute.internal 
sh-4.2$ 

sh-4.2$ whoami
ssm-user ← ssm-user でログインしている。
sh-4.2$

sh-4.2$ sudo su - ← ssm-user は sudo 権限を持っている。
[root@ip-172-xxxxxxx ~]#

 

権限さえあれば、ssm-user でログインができます。

しかも ssm-user は EC2 インスタンスに対して sudo 権限を持っているので sudo su – で root にスイッチできます。

 

 

Ansible Playboot を作成する

環境ができたら Ansible Playbook を作成します。

 

■ディレクトリ&ファイル構成

tree 

└── test_yum_update 
    ├── roles 
    │   └── common 
    │       └── tasks 
    │           └── main.yml 
    └── server.yml 
 
4 directories, 2 files

 

トップディレクトリを「test_yum_update」にしました。

Playbook の内容は単純に yum update を実行するだけです。

テスト段階なのでシンプルな構成にしました。

 

 

 

■server.ymlファイル

cat server.yml  
– name: yum update 
  hosts: all 
  become: true 
  become_method: sudo 
  roles: 
    – common

 

 

 

■main.ymlファイル

cat main.yml  
– name: gather ec2 facts 
  ec2_metadata_facts: 
  
– name: upgrade all packages (Red Hat) 
  yum: 
    name: ‘*’ 
    state: latest 
  # Amazon Linux2でもos_familyは「RedHat」になる。 
  when: ansible_os_family == “RedHat”

 

「when: ansible_os_family == “RedHat”」で RedHat の場合 yum update コマンドを実行します。

ちなみに今回の管理対象の OS は Amazon Linux2 ですが、ansible_os_family は「RedHat」になります。

 

 

 

Playbook を ZIP で圧縮して S3 バケットに保存する

Playbook ファイルを作成したら zip コマンドで圧縮して S3 バケットに保存します。

 

まずは再帰的にディレクトリ配下のファイルを全部圧縮します。

ただし .git ディレクトリ配下は Ansible と関係がないので zip コマンドで除外します。

 

 

■zip コマンドで圧縮する(.git ディレクトリ配下は除外する)

zip -r test_yum_update.zip test_yum_update -x ‘*.git*’ 
  adding: test_yum_update/ (stored 0%) 
  adding: test_yum_update/server.yml (deflated 23%) 
  adding: test_yum_update/roles/ (stored 0%) 
  adding: test_yum_update/roles/common/ (stored 0%) 
  adding: test_yum_update/roles/common/tasks/ (stored 0%) 
  adding: test_yum_update/roles/common/tasks/main.yml (deflated 20%)

 

-x オプションで指定のディレクトリやファイルを除外できます。

 

 

■zipファイルを確認する

$ ls -l test_yum_update.zip
-rw-rw-r– 1 ec2-user ec2-user 1389 Dec 3 18:12 test_yum_update.zip

 

 

 

S3バケットにアップロードします。

 

■S3バケットにアップロードする

 $ aws s3 cp test_yum_update.zip s3://ansible-dev-zip-bucket-xxxxxxxxxxx/
upload: ./test_yum_update.zip to s3://ansible-dev-zip-bucket-xxxxxxxxxxx/test_yum_update.zip

 

 

 

■S3バケットにアップロードしたオブジェクトを確認する

$ aws s3 ls s3://ansible-dev-zip-bucket-xxxxxxxx/
2022-12-03 18:19:06 1389 test_yum_update.zip

 

 

 

SSM ダッシュボードより Run Command を実行する

Playbook を S3 にアップロードしたら SSM ダッシュボードより Run Command を実行します。

 

以下のように Run Command を設定します。

  • 名前 ← AWS-ApplyAnsiblePlaybooks
  • ドキュメントのバージョン ← 1(デフォルト)

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

以下のように Run Command を設定します。

  • Source Type ← S3
  • Source Info ← S3 バケットに配置した ZIP ファイルを URL で指定します。【例:https://[S3バケット名.s3.ap-northeast-1.amazonaws.com/test_yum_update.zip】
  • Playbook File ← xxxx.zip ファイルを展開した場合のパスを入力します。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

Ansible で管理する対象の EC2 インスタンスを指定します。

タグでもリソースグループでも指定できます。これは非常に便利ですね。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

出力オプションで以下のように設定します。

  • S3 バケットへの書き込みを有効化する ← チェック

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

Run Command の設定が問題なければ「実行」ボタンをクリックします。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

 

 

 

 

Run Command が成功すると下図のように「成功」と表示されます。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

 

動作確認

次に本当に EC2 インスタンス上で yum update が実施されたのか確認します。

ssm コマンドで管理対象の EC2 インスタンスにアクセスをします。

 

 

■実際に EC2 インスタンスにログインして yum 履歴を確認

$ aws ssm start-session –target i-0xxxxxxxxxxxx
Starting session with SessionId: i-0xxxxxxxxxxxxxxx 
sh-4.2$ sudo su – 
[root@ip-172-xxxxxxxx ~]# yum history list all 
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd 
ID     | Command line             | Date and time    | Action(s)      | Altered 
——————————————————————————- 
     4 | -d 2 -y update           | 2022-12-04 04:01 | I, O, U        |   40    
     3 | install -y ansible       | 2022-12-04 04:01 | Install        |    4    
     2 | install -y https://dl.fe | 2022-12-04 04:01 | Install        |    1    
     1 | -t -y –exclude=kernel – | 2022-12-04 03:47 | Update         |    9    
history list 
[root@ip-172-xxxxxxxx ~]# 

 

yum update が実行されたことが確認できました。

ちなみに、ansible のインストールも確認できます。

 

 

 

 

 

 

 

 

エラーになった場合

今回は一発で全てうまく行ったわけではなく何度か失敗してエラーになりました。

Run Command を実行してエラーになった場合の原因と対応方法について記載します。

 

 

 

S3 バケットにアップロードした ZIP ファイルのパスが間違っている場合

S3 バケットにアップロードした ZIP ファイルのパスが間違っている場合は以下のエラーが出力されます。

 

Error内容は

「Installing and or updating required tools: Ansible, wget unzip ….
Error: Nothing to do
The specified Playbook file doesn’t exist in the downloaded bundle. Please review the relative path and file name.
failed to run commands: exit status 2」

と出力されます。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

原因はファイルのパスが間違っているためです。

再度ファイルのパスを確認します。

下図のように ZIP ファイルを解凍した時の Playbook のパスを入力します。

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

 

 

S3 バケットへのアクセス権がない場合

S3 バケットへのアクセス権がない場合は以下のエラーになります。

 

「http request failed. status:403 Forbidden statuscode:403」

【Ansible】AWS SSM の Run Command で Ansible の Playbook を実行する手順

 

原因は S3 バケットへのアクセス権限がないからとなります。

Ansible での管理対象の EC2 インスタンスのロールから S3 バケットへアクセスをして ZIP ファイルをダウンロードする必要がありますが、対象の S3 バケットにアクセスして ZIP ファイルを取得する権限がない場合に上記のエラーになります。

正しい権限(ポリシー)を割り当てればエラーはなくなります。

ポリシーは上記でも記載してありますが、AWS管理ポリシーの「AmazonEC2RoleforSSM」を割り当てればエラーはなくなります。

 

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

AlphaOmega Captcha Medica  –  What Do You See?
     
 

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください