CodeBuild から EC2 に SSH して Jenkins の息の根を止める


背景

SSHして何かやる定形/不定形業務を廃止するのは、なかなか困難が伴います。

  • SSH接続を許可するか許可しないか、くらいしかできない
    • いやまあ、Linux側でがんばってユーザー/グループを組めばいいんですけど
  • 極少数のメンバーしか、保安上の理由から、許可できない
  • 極少数のメンバーは、能力高しで多忙なのに、たいしたことないSSH作業に忙殺される

以前は、SSH定形業務をJenkinsジョブとして形式知化していましたが、

  • JenkinsのEC2インスタンスが
    • SPOFとなる。単純に台数を増やせばいいものでもない。
    • 闇のダンジョンとなりがち
  • だからといって、今からJenkinsfileとかすごく頑張るのは、あまりに低い山の頂上を目指しているのではないか
  • Jenkinsおじさんの雇用が生まれてしまう

など問題がありました。このうち一部の問題について、CodeBuildジョブにすることで上手く扱えそうな感触が得られたので、まとめます。

ちなみに、ユニットテストやデプロイの類は、CircleCIやCodeBuildに移植済みで、Jenkinsには本当に「ポチるとSSHして何かするジョブ」だけが残っています。

作る

CodeBuildからEC2にSSHで何かさせてみます。

EC2 SSH Keypair、EC2インスタンスを作り、SSHできることを確認する

これは何も躓くところ無いですね。Keypair名は「hoge」で作ります。hoge.pemがダウンロードできてるものとして記述します。お手元から接続できることまで確認してください。

EC2 SSH KeypairのSSH秘密鍵をSSMパラメータストアに保管する

先程のSSH秘密鍵をSSMパラメータストアに暗号化保管します。

https://console.aws.amazon.com/systems-manager/parameters でパラメータの作成して、

先程のSSH秘密鍵をまるっとコピーして、

cat hoge.pem | pbcopy

AWS System Managerのパラメータストアの「値」にベタッとして、暗号化保管するので「安全な文字列」で、パラメータの作成。

AWSのEC2 SSH Keypairで作成した鍵なら1700文字くらいなので大丈夫ですが、手元のsshコマンドで生成した場合は、SSH秘密鍵の文字数に注意してください。4096文字までです。

CodeBuildジョブを作る

ジョブの組み立ては以下を参考に。ところかまわずSSHできるのはマズいでしょうから、VPC内でCodeBuildが起動するよう組むのが望ましいかと思います。

ポイントは以下。

  • CodeBuildの環境変数で、プレーンテキストではなくパラメータとして、SSMパラメータストアから読むようにする
    • 作例では、CodeBuildの環境変数「SSH_PRIV_KEY」に、SSMパラメータストアの「ssh_private_key」を読み込ませています
  • CodeBuildジョブに付けるIAMロールに、SSMパラメータストアを読む権限を付けてあげる
  • sshコマンドをインストール済みのコンテナを使うと面倒が少ないです。たとえば https://hub.docker.com/r/ansible/ansible-runner とか。

buildspec.yaml は以下のように。sshコマンドで、初回アクセス時の(yes/no?)に答えようがないので抑止したりしてます。

version: 0.2
phases:
  pre_build:
    commands:
      - mkdir ~/.ssh
      - echo "${SSH_PRIV_KEY}" > ~/.ssh/id_rsa
      - chmod 0700 ~/.ssh
      - chmod 0600 ~/.ssh/id_rsa
  build:
    commands:
      - ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected] -p 22 "pwd;ls -alF;hostname"

見てのとおりで、buildspec.yaml でシェル芸を極めたコマンドラインをsshに流し込むのはまあまあ大変です。

接続先のEC2内にシェルスクリプトの類を設置して、CodeBuildはそれを呼ぶだけにするのが良いんじゃないかと思っています。

そのシェルスクリプトは、AnsibleのGitHubリポジトリか、アプリケーションコードのGitHubリポジトリのどちらかで管理して。など。

CodeBuildの権限制御をどうするか

SSHに比べると、いくらか制御しやすいんじゃないでしょうか。

Jenkinsなら Jenkinsでユーザーに権限を付与してアクションを制限する - Qiita の手法で権限制御できました。

AWS なら、

  • IAMで権限制御する
    • IAMグループを作成し、どのIAMグループは、CodeBuildジョブ定義を作成/編集/削除できる、実行/中断できる、などを構成する
  • 誰が、いつ、どのジョブに、何をしたか、の
    • 雑なトラッキングは、CodeBuildのジョブのログで見る
    • 詳細なトラッキングは、AWS CloudTrailでやる

SSHの不定形業務はどうすんの

不定形だと思ってる業務も、Excel手順書(w)に書き出して、何度かやれば、これが定形業務で、ここは人間による条件分岐判断があって、その先は定形業務で、などと見えてくるはずなので、定形業務の部分をCodeBuildに切り出していくといいんじゃないですかね。

SSMセッションマネージャーもあるじゃん

これとかですね。非常に良いと思っていて、技術指針に従って、どちらでも使ったらいいのではないかと。