AWS CodeシリーズでAnsible自動実行環境を構築する

AWS

2024.2.26

Topics

はじめに

こんにちは!
第一SAチームのshikaです。
先日EC2のLinuxサーバーの運用を効率化するため、AWSのCodeシリーズ(AWS CodePipeline+AWS CodeBuild)を使ってAnsibleの自動実行を行うCICDパイプラインを構築しました。
Ansibleのコントロールノードを用意する必要がなく、便利に使えそうだったので、構築方法をまとめてみます。

仕組み

構成図

AWS CodeCommit、AWS CodeBuild、AWS CodePipleine、AWS Secrets Managerを次の用途で使用しています。
・CodeCommit・・・Ansible関連ソース、buildspec.ymlの格納リポジトリ
・CodeBuild・・・Ansible実行環境
・CodePipeline・・・CICDパイプラインの構築
・Secrets Manager・・・EC2のssh接続ユーザの秘密鍵を格納場所

フロー

パイプラインを実行した際のフローは以下のようになります。

① CodePipelineを開始
② CodeBuild上で次の処理を実行

  • Ansibleインストール
  • Secrets Managerから秘密鍵を取得

③ CodeBuildからEC2に対しCodeCommitに格納されているAnsibleプレイブックを実行

上記フローのうち、本記事では以下の部分を重点的に解説します。

  • Secrets Managerへの秘密鍵登録
  • buildspec.ymlの内容
  • CodeBuild設定内容

※CodeCommitやCodePipelineに関しては特筆する設定等はないため説明を割愛します

<Ansibleの実行にRunCommandを使用しない理由>

AWSでAnsibleを使う場合、Systems Managerという運用系サービスの1機能である「RunCommand」を使うことで、簡単にAnsibleプレイブックを実行できます。 しかし、今回は以下の理由からRunCommandは使わず、CodeシリーズでAnsible実行環境を構築しました。

  • RunCommandを利用する場合、実行対象インスタンスにAnsibleやその他パッケージのインストールが必要であるため

RunCommandは、Ansibleをリモートで実行するものではなく、実行対象のインスタンスにAnsibleをインストールし、ローカル実行するという仕様です。
そのため、RunCommandを実行するとAnsible実行対象のインスタンスにAnsibleやその他のパッケージが自動でインストールされます。
アプリケーションに必要のないパッケージのインストールは避けたかったため、RunCommandは使いませんでした。

  • CodePipelineの承認フェーズを利用したかったため

CodePipelineを利用しCICDパイプラインを組めば、承認フェーズを組み込むことができます。承認フェーズをパイプラインの任意の段階に組み込むことで、レビュー担当者の承認が得られるまでパイプラインの進行を一時停止させることが可能です。
実行対象のホストや実行する処理が想定通りか、メンバーによるレビューを経てから実行したかったためRunCommandではなくCodeシリーズを検討しました。

構築してみる

1. 実行対象インスタンスのSSH秘密鍵をSecrets Managerに登録する

まずはCodeBuildがAnsible実行対象のインスタンスにSSHでアクセスできるように、EC2内のSSHユーザの秘密鍵をSecrets Managerに登録します。

<AWS Secrets Managerとは>

データベース認証情報やアクセストークンといったアプリケーションが利用する機密情報を安全に管理してくれるマネージドサービスです。
AWS Secrets Manager 公式ドキュメント

秘密鍵はこのSecrets Managerに安全に保管しておき、CodeBuildがAnsibleを実行する際に取得できるようにしておきます。

秘密鍵はEC2構築時に指定したキーペアを利用しても、新しくキーペアを作成しても問題ありません。
秘密鍵を用意できたら、AWS CLIの実行が可能な環境で、以下のコマンドを実行しSecrets Managerに秘密鍵を登録します。

aws secretsmanager create-secret –name 「Secrets Managerの名前」 –secret-binary file://「秘密鍵のパス」

また登録した秘密鍵を取り出す際のコマンドは以下の通りです。

aws secretsmanager get-secret-value –secret-id 「Secrets Managerの名前」 –query ‘SecretBinary’ –output text

実行例

「ec2-user」ユーザの秘密鍵をSecrets Managerに登録します。

	
[ec2-user@ip-11-1-1-167 ~]$ ll	
total 4	
-rw------- 1 ec2-user ec2-user 1675 Dec 21 10:54 id_rsa  #ec2-userの秘密鍵	
[ec2-user@ip-11-1-1-167 ~]$	
	
[ec2-user@ip-11-1-1-167 ~]$ aws secretsmanager create-secret --name ec2-privatekey --secret-binary file://~/id_rsa     #秘密鍵をec2-privatekeyという名前でsecretsmanagerに登録	
[ec2-user@ip-11-1-1-167 ~]$	
[ec2-user@ip-11-1-1-167 ~]$ aws secretsmanager get-secret-value --secret-id ec2-privatekey --query 'SecretBinary' --output text | base64 -d check-key #登録した秘密鍵を取得しcheck-keyというファイルに出力 	
[ec2-user@ip-11-1-1-167 ~]$view check-key #登録した秘密鍵の内容が正常に出力されているか確認	
[ec2-user@ip-11-1-1-167 ~]$	

[注意点]

・秘密鍵がエンコードされている場合、コマンドは以下になります。
aws secretsmanager create-secret –name 「Secrets Managerの名前」 –secret-binary fileb://「ファイルパス」

・秘密鍵にパスフレーズを設定している場合、解除してからSecrets Managerに登録します。
(パスフレーズが設定されているとAnsible実行時にパスフレーズの入力が求められるため自動実行ができなくなります)

・EC2のIAMロールにはSercrets Managerのアクセス権限を持つポリシーを付与しておく必要があります。

Secrets Managerのコンソールを見ると、「ec2-privatekey」が作成されていることを確認できます。

2. ソースの用意

次にansible関連ファイル、buildspec.yml等をCodeCommitにプッシュします。
(ソースリポジトリは別のgitツールやS3を使っても構築可能です。)

以下のようなディレクトリ構造にしました。

	
[ec2-user@ip-11-1-1-167 ansible-test-repo]$ tree	
.	
├── ansible	
│ ├── inventory.ini	
│ ├── roles	
│ │ └── common	
│ │ └── tasks	
│ │ └── main.yml	
│ └── site.yml	
└── buildspec.yml	
4 directories, 5 files	

Ansible関連ソース

/testディレクトリを作成する簡単なプレイブックを格納しています。

buildspec.yml

buildspec.ymlは以下の通りです。

version: 0.2
phases:
install: 
commands:
- sed -i 's/# StrictHostKeyChecking ask/StrictHostKeyChecking no/' /etc/ssh/ssh_config # SSH接続時のホストキーチェックを無効にする
- aws secretsmanager get-secret-value --secret-id ec2-privatekey --query 'SecretBinary' --output text | base64 -d &gt; ~/.ssh/id_rsa # EC2の秘密鍵をAWS Secrets Managerから取得し、.sshディレクトリに保存
- chmod 400 ~/.ssh/id_rsa # 秘密鍵のパーミッションを設定
pre_build: 
commands:
- cd ${CODEBUILD_SRC_DIR}/ansible
build: 
commands:
- ansible-playbook -i inventory.ini site.yml -u ec2-user -v # Ansibleプレイブックを実行

3. CodeBuild作成

CodeBuildのコンソールより、以下の通りビルドプロジェクトを新規作成します。



→ CodeBuildに付与するIAMロールはCodeCommitへの読み取りが可能なポリシーを付与します。


→特権付与にチェックを入れroot権限を使えるようにします。


→ CodeBuildはAnsible実行対象のEC2が所属するVPC上に作ります。
またCodeBuildがインターネットに出るためにNAT Gatewayを経由する必要があります。
「VPC設定の確認」を押下することでNAT Gateway経由でインターネットに出れることを確認できます。

※NAT Gatewayがない場合、以下のエラーが表示されます。

4. CodePipelineでパイプラインを構築し実行

構築したCodeCommitをソースステージ、CodeBuildをビルドステージに設定してCodePipelineを構築・実行します。

5. Ansibleが想定通り実行されたか確認

EC2にログインし、ディレクトリが作成されたか確認します。

	
[root@ip-11-1-0-140 ~]# ll /	
total 16	
lrwxrwxrwx 1 root root 7 Jan 24 00:28 bin -&amp;gt; usr/bin	
dr-xr-xr-x 4 root root 4096 Jan 24 00:29 boot	
drwxr-xr-x 15 root root 2900 Jan 29 08:23 dev	
drwxr-xr-x 81 root root 8192 Jan 29 09:31 etc	
drwxr-xr-x 4 root root 38 Jan 29 09:31 home	
lrwxrwxrwx 1 root root 7 Jan 24 00:28 lib -&amp;gt; usr/lib	
lrwxrwxrwx 1 root root 9 Jan 24 00:28 lib64 -&amp;gt; usr/lib64	
drwxr-xr-x 2 root root 6 Jan 24 00:28 local	
drwxr-xr-x 2 root root 6 Apr 9 2019 media	
drwxr-xr-x 2 root root 6 Apr 9 2019 mnt	
drwxr-xr-x 4 root root 27 Jan 24 00:29 opt	
dr-xr-xr-x 162 root root 0 Jan 29 08:23 proc	
dr-xr-x--- 3 root root 103 Jan 29 08:23 root	
drwxr-xr-x 28 root root 980 Jan 29 08:23 run	
lrwxrwxrwx 1 root root 8 Jan 24 00:28 sbin -&amp;gt; usr/sbin	
drwxr-xr-x 2 root root 6 Apr 9 2019 srv	
dr-xr-xr-x 13 root root 0 Jan 29 08:23 sys	
drwxr-xr-x 2 root root 6 Jan 29 09:18 test	
drwxrwxrwt 8 root root 172 Jan 29 09:25 tmp	
drwxr-xr-x 13 root root 155 Jan 24 00:28 usr	
drwxr-xr-x 19 root root 269 Jan 29 08:23 var	
[root@ip-11-1-0-140 ~]#	

⇒ /testが作成されていました。

まとめ

本ブログでは必要最小限の構成で試してみましたが、実運用では以下のようなフローにしてます。

CodeCommit→CodeBuild(チェック)→Approve(承認)→CodeBuild(Ansible実行)
⇒1つ目のCodeBuildで実行対象ホストやAnsibleチェックコマンドで実行内容が想定通りか確認し、承認後に2つ目のCodeBuildで実行する

工夫次第で色々とカスタムすることが可能かと思います。

サーバレスで安全にAnsible実行環境が構築できるのでぜひ試してみてください!

テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら