Edited at

CircleCI から AWS VPC の private subnet に private repo を git clone

More than 3 years have passed since last update.

この記事はCircleCI Advent Calendar 2015の7日目の為に考えていた記事です。

あまりに時間が立ってしまったので、元記事から切り離して再投稿。


やりたいこと



  1. AWS VPC上に組んだプライベートサブネット上に

  2. CircleCIからVagrantでインスタンスを生成して

  3. GitHubのプライベートリポジトリをクローンする

図にするとこう。

image


動機

インターネットむき出しじゃないインスタンスに対して、SSHの鍵をばら撒かずにデプロイしたい


前提知識


プライベートサブネット構成

以下の図のように、ユーザからのアクセスをELB経由に限定してアプリケーションサーバ自体は直接インターネットに接続できないプライベートサブネットに置く構成。

アプリケーションサーバを直接インターネットに晒したくない人向け。

ただ、全ての通信を遮断してしまうと、リリースもできない。時刻同期もできない。となってしまうので、そういった管理上必要な通信は別途用意するNATサーバ経由で行う。

image

プライベートサブネットに置かれたサーバからの通信は全てNAT経由になるので、

一枚目の画像についても正しくはこういうなる。

image

参考:classmethod - Amazon VPCでELBとNATを使ってよりセキュアな環境を作る【5日目】

2015年の年末にマネージドNATゲートウェイが新機能としてリリースされたので、今後NATサーバを別に立てる必要はないのかも。


本題

こちらのリポジトリにまとめました。内容そのままでプライベートリポジトリに変更してCircleCIでビルドすると動くと思います。

https://github.com/kotatsu360/private-repo-deploy-sample

サンプルでは、VagrantとChefを使っています。


その1:プライベートサブネットのインスタンスへアクセスするための記述

まず、プライベートサブネットに踏み台(NATサーバ)経由でアクセスしてやる必要があります。

重要なのは2箇所です。


pre.sh

echo "Host nat" >> ~/.ssh/config

echo " Hostname ${AWS_NAT_SERVER_IP_ADDRESS}" >> ~/.ssh/config
echo " User ec2-user" >> ~/.ssh/config


Vagrantfile

    override.ssh.username = "ubuntu"

override.ssh.proxy_command = "ssh -A nat -W %h:%p"

ここでは、NATサーバがAmazonLinux, アプリケーションサーバがUbuntuの想定です。

まずpre.shの中でCircleCIの.ssh/configにNATの情報を書き込んでやります。

Vagrantでアクセスするときは、そのHostを使ってプロキシします。

また、この記事の範囲からは外れますが、pre.shはデプロイ前後で自分自身からのSSHを許可して、また閉じています。これは「普段はSSHを不許可、デプロイ時のみ許可」という運用をしたいためです。

※環境変数は最後に設定します


その2:プライベートリポジトリにへアクセスするための記述


Vagrantfile

  config.ssh.forward_agent = true

# ...

override.ssh.private_key_path = [ENV['GITHUB_CLONE_SSH_KEY_PATH'], ENV['AWS_LOGIN_SSH_KEY_PATH']]



default.rb

file "/etc/sudoers.d/root_ssh_agent" do

mode 0440
owner 'root'
group 'root'
content "Defaults env_keep += \"SSH_AUTH_SOCK\"\n"
end

bash "add ssh_setting to .ssh/config" do
not_if %!grep Host github.com /root/.ssh/config!

code <<-EOC
echo -e "Host github.com
\n StrictHostKeyChecking no\n" >> /root/.ssh/config
EOC
end



override.ssh.private_key_path

VagrantでSSHのAgentForwardを有効にしています。

また、


  • GitHubへアクセスするための鍵

  • Chefがインスタンスへアクセスするための鍵

を指定しています。ここで指定した鍵がAgent Forwardで転送されます。


content "Defaults env_keep += \"SSH_AUTH_SOCK\"\n"

EC2インスタンスへSSHしているユーザはubuntu

Chefはrootで動作する。ここではrootへ引き継ぐ環境変数にssh-agentを追加


echo -e "Host github.com\n StrictHostKeyChecking no\n" >> /root/.ssh/config

GitHubからはsshでgit cloneする。git cloneするときにfingerprintの確認で止まるのを防ぐためにStrictHostKeyChecking noを追加


その3:CircleCI

最後にCircleCIの「Environment variables」で環境変数を設定してやります。

AWS_ACCESS_KEY_ID

AWS_SECRET_ACCESS_KEY
についてはCircleCIの「AWS Permission」から設定してもいいかも。

変数名
概要
サンプル

AWS_ACCESS_KEY_ID
AWSのアクセスキー
xxxxCIBA

AWS_DEFAULT_REGION
AWS EC2のデフォルトリージョン
xxxxst-2

AWS_DEPLOY_MACHINE_SECURITY_GROUP
EC2インスタンスに割り当てるセキュリティグループ
xxxx228c

AWS_DEPLOY_SUBNET
EC2インスタンスを立てるサブネット
xxxxbc2c

AWS_KEYPAIR
AWSで作成するEC2インスタンスにSSHする時用keypair名
xxxxpair

AWS_LOGIN_SSH_KEY_PATH
※1

AWS_NAT_SECURITY_GROUP
デプロイに使うNATのセキュリティグループ
xxxx11db

AWS_NAT_SERVER_IP_ADDRESS
デプロイに使うNATのEIP
xxxx9.71

AWS_SECRET_ACCESS_KEY
AWSのシークレットアクセスキー
xxxx1muU

GITHUB_CLONE_SSH_KEY_PATH
※2


AWS_LOGIN_SSH_KEY_PATH

AWS_KEYPAIRで設定したkeypairの秘密鍵をCircleCIの「SSH Permission」からHostnameを空にして登録する。

スクリーンショット 2016-01-30 15.56.27.png

スクリーンショット 2016-01-30 15.56.54.png

Hostnameが空の場合、CircleCIはfingerprintに従って鍵を作成するので、そのパスを指定する。

~/.ssh/id_xxxxxxxxxxxx3044


GITHUB_CLONE_SSH_KEY_PATH

CircleCIに一度SSHする。~/.ssh/id_github.comという鍵(CircleCIがリポジトリをCheckoutするための鍵, GitHubでいうDeployKey)があるのでこれの中身を「SSH Permission」にHostname=github.comで登録する。

スクリーンショット 2016-01-30 16.14.15.png

スクリーンショット 2016-01-30 16.14.59.png

Hostnameが空でない場合、CircleCIはHostnameに従って鍵を作成するので、そのパスを指定する。

~/.ssh/id_github.com


制約

https://github.com/kotatsu360/private-repo-deploy-sample

このリポジトリのやり方だと、毎回Vagrantで新しいインスタンスを立ててしまうので

古いインスタンスは削除されるようにdeploy.shで設定しています。

EC2インスタンスの中にデータを入れておくと漏れ無く消えます。


振り返ってみて

「GitHubからクローンしたいリポジトリ」 = 「CircleCIでテストしているリポジトリ」の場合、シンプルにSCPで送るという手段もあったような。。


参考

怠け者のためのVagrant+Chef入門 - Qiita

CircleCIからサーバへのSSH接続確立時間を高速化する