はじめに
CircleCIからセキュリティグループでアクセスが制限されているEC2上で何かしらのコマンド(ChefやAnsibleたたくなど)を実行したいということがあり、Systems Manager Run Commandを使って実現しました。
Systems Manager Run Commandは初めてさわりましたが手軽で便利だったのでおすすめです。
アクセス制限の問題
多くの場合はEC2へのアクセスはセキュリティグループ等で制限されているため、CircleCIからsshで接続しようとしてもそのままでは接続できない。
また、CircleCIのインスタンスのIPアドレスは動的に設定されるためIPアドレスの制限を許可するのも手間がかかります。(こちらの記事であるような方法で実現は可能)
Systems Manager Run Commandを使った方法
こういった場合にSystems Manager Run Commandを使えば、IAMで適切なアクセス権を設定することでSSHを使用せずに(セキュリティグループ問題を気にせずに)EC2上でコマンドを実行できます。
やること
- EC2にSSMにエージェントのインストール(使用するAMIによってはデフォルトでインストールされている)
- EC2のIAMロール設定
- コマンドを実行するIAMユーザー作成
- CircliCI上の設定・処理の追加
EC2にSSMエージェントのインストール
Systems Manager Run Commandを使うためにEC2にSSMエージェントをインストールする必要があります。
SSMエージェントは使用するAMIによってはデフォルトでインストールされており、今回使用した Ubuntu Server 18.04
にはデフォルトでインストールされていためインストールは割愛します。
インストールが必要な場合はこちらを参照ください。
EC2のIAMロール(インスタンスプロファイル)設定
AmazonEC2RoleforSSM
のポリシーをアタッチしたIAMロールを作成し割り当てます。
インスタンスの設定 > IAMロールの割り当て/置換 からさきほど作成したロールを割り当てます。
CircleCIからコマンドを実行するユーザーのポリシーの設定
テスト用にAmazonSSMFullAccess
のポリシーがアタッチされたtest_ssm_user
というIAMユーザーを作成します。
CircleCI上の設定・処理の追加
ここまででコマンドを実行する準備ができたので、CIで実行する処理を追加していきます。
今回はRubyのaws-sdk
を使ってスクリプトを書いていきます。
require 'aws-sdk'
Aws.config.update(
access_key_id: ENV['SSM_ACCESS_KEY_ID'],
secret_access_key: ENV['SSM_SECRET_ACCESS_KEY'],
region: 'ap-northeast-1'
)
Aws::SSM::Client.new.send_command(
document_name: "AWS-RunShellScript",
instance_ids: [ENV['EC2_INSTANCE_ID']],
parameters: {
commands: ["echo Hello > /tmp/hello.txt"], # この部分がEC2上で実行するコマンド
executionTimeout:["3600"]
},
timeout_seconds: 600,
)
環境変数の設定
コマンドを実行するユーザー(test_ssm_user)のcredentialの情報とコマンドを実行するインスタンスの情報を環境変数に追加
config.yml
CircleCIのworkflowを定義します。
version: 2.1
executors:
default:
working_directory: ~/ec2_sample
docker:
- image: ruby:2.6.3-stretch
environment:
BUNDLE_GEMFILE: /root/ec2_sample/Gemfile
BUNDLE_PATH: /root/ec2_sample/vendor/bundle/ruby/2.6.0
jobs:
run-command:
executor:
name: default
steps:
- attach_workspace:
at: ~/ec2_sample
- checkout
- restore_cache:
keys:
- gf-bundle-1-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
- gf-bundle-1-{{ .Branch }}-
- gf-bundle-1-
- run:
name: bundler install
command: gem install bundler:2.0.1
- run:
name: bundle install
command: bundle install --path=./vendor/bundle
- run:
name: deploy
command: bundle exec ruby ec2_run_command.rb # scriptを実行
workflows:
ec2-ci:
jobs:
- run-command
scriptをrubyで書いたのでrubyのDockerイメージを使ったり色々書いてますが、bundle exec ruby ec2_run_command.rb
でさきほど書いたscriptを実行しているだけのjobです。
動作確認
さきほどコマンドに書いたecho Hello > /tmp/hello.txt
がec2上で実行され、hello.txtが作成されていることが確認できました。
$ cat /tmp/hello.txt
Hello
まとめ
以上、CircleCIからSystems Manager Run Commandを使ってEC2上でコマンドを実行する方法でした。
今回はCircleCIから実行するという使い方をしましたが、他の場面でもちょっとしたことをやるのにRun Commandは使えそうだなという印象です。
参考
チュートリアル: Run Command で AWS CLI を使用する
SSM エージェント の使用
Amazon EC2 Linux インスタンスに SSM エージェント を手動でインストールする
CircleCI2.0からEC2にアクセスするときだけ特定のIPを許可したい