TravisCIが成功したらテストサーバにGithubからクローンしてVAddyを動かす
はじめに
やりたいこと
GithubにPushされたものがTravisCIのテストで成功したら、テストサーバでクローンしてVaddyでセキュリティテストして通知を自動化したい!
TravisCIの設定メインです。
色々と書いていますが、最終的にはVaddyのクライアントを使い公開鍵通信でSSHをする結果になりましたので、他は気にしなくても大丈夫です。参考にしたこちらと全く同じものとなりました。そちらの方が簡潔でわかりやすいです。
gdgdしていますが、色々調べたことを忘れたくなかったのでかきました。
やらなきゃいけないこと
Vaddy
1.テスト設定をする
TravisCI
1.今回テストサーバがTravisのdeployに対応していないため、自分でdeployを設定する
2.テストを走らせる条件を指定できるようにする
3.Vaddyの準備など
その他
1.テスト後の通知など
Vaddy
自動でXSSやSQLインジェクションなどのセキュリティテストをしてくれるもの
アカウントの登録等は、テストが実行できる形(クロールの登録まで)割愛。
テストを実行するには3つやり方がある。
1.ダッシュボードより「Scan」ボタンを押す
2.githubよりクライアントをDLしてコマンドで実行
3.VaddyAPIをコマンドで実行
ダッシュボードよりKEYを発行しておく。
APIを使ってテストをしてみます。下記のようにすると実行できます。変数はTravis上での暗号化を想定しています。
$ curl https://api.vaddy.net/v1/scan -X POST -d "action=start" -d "user=$VADDY_USER" -d "auth_key=$VADDY_AUTH_KEY" -d "fqdn=$VADDY_FQDN"
TravisCI
https://travis-ci.org/
アカウント登録等は割愛。
今回sshする際のパスワードやVaddyAPIのキーなど知られたくない情報がたくさんありますので暗号化していきます。
自前で暗号化しなくてもTravisが用意してくれた暗号で楽々に実現できるのでそちらを使っていきます。
travis encrypt
コマンドで暗号化して環境変数を定義できますが、今回はコマンドではなくホームページで追加していきます。
1.travisダッシュボードより右上のMore Option
よりSetting
を選択。
2.Environment Variables
欄のAdd
を押して環境変数を追加
SSHのサーバとPW、APIKey、テストサーバのVaddy用FQDN、ユーザ名を暗号化して追加しました。
これで環境変数として色々使えるようになります。お手軽ですね。
強いて言うならコマンドで一度に変えれないため、設定を変えたときに面倒くさいかな・・・?
sshpassを使う
コマンドでsshする際にパスワードも一緒に入力できるコマンドです。
.travis.yml
にsshpassをインストールするように追記
addons:
apt:
packages:
- sshpass
実行してみます。
オプションは接続の際にでるAre you sure you want to continue connecting (yes/no)?
を防ぐため付けました。
$ sshpass -p XXXXXX(password) ssh -o “StrictHostKeyChecking no” -o “PreferredAuthentications=password” XXXXXX@XXXXXX(SSH先)
エラーにより、詰まったので断念
Warning: Permanently added 'XXXXXX(SSH先)' (ECDSA) to the list of known hosts.
Permission denied, please try again.
.ssh/known_hostsのせいかなとか、.ssh/configのせいかなとか、いろいろ頑張ったのですが、解決できませんでした・・・。オプションで“StrictHostKeyChecking no”にしているが、サーバ側が一般ユーザーのため.ssh/configが変更できないのかな?と考えてます。
多分サーバ側をいじることができる環境なら.ssh/configをいじれば解決できると思いますが、今回はいじれない環境なので、sshpassを諦めsshで接続する方向へ
sshを使う
expectコマンドを使いAre you sure you want to continue connecting (yes/no)?
やXXXXXX(SSH先)'s password:
に対応させます。
expectコマンドについてはこちらを参考にしました。
after_success:
- expect -c "
spawn ssh $TEST_SERVER
expect \"Are you sure you want to continue connecting (yes/no)?\"
send \"yes\n\"
expect \":\"
send \"$SSH_KEY\n\"
expect \"%\"
send \"git pull XXXXXX(github)\n\"
expect \"%\"
send \"exit\n\"
interact
"
こんな感じになりました。
yes/no?が聞かれたらyes、password:を聞かれたらSSH_KEYを入れます。ログインしたらgit pullしてexitです。ですが、戻り値の出し方がわからなかったり、成功してるか失敗しているかもわからなかった...断念...
ssh-askpassを使う
stdinからpasswordを読み込ませるらしい。
参考はこちら
できる未来が見えなかったので、パスワードを諦め、鍵で接続してみる。
公開鍵を使う
ローカルでキーを作り、Travis上で
# 鍵を作る
$ ssh-keygen -f deploy_key
# 秘密鍵を暗号化する為のベースとなる文字列を作成
$ cat /dev/urandom | head -c 10000 | openssl sha1
XXX
# 秘密鍵を暗号化
$ openssl aes-256-cbc -k "XXX" -in deploy_key -out deploy_key.enc -a
# deploy_key.enc を、レポジトリ直下に配置
# deploy_key.pub を、テストサーバーの ~/.ssh/authorized_keys に追記
# Travis 用のコマンドをインストール
$ sudo gem install travis
# 復号化用の文字列を作成 (.travis.ymlに自動的に記述される)
# ここはコマンドではなくダッシュボードで追加してもok
$ travis encrypt -r XXXX(github) "SERVER_KEY=XXX" -a
# .travis.yml 編集(最終的に、テストサーバー上で、script.sh 実行される)
- openssl aes-256-cbc -k "$SERVER_KEY" -in deploy_key.enc -d -a -out deploy.key
- cp deploy.key ~/.ssh/
- chmod 600 ~/.ssh/deploy.key
- ssh -i ~/.ssh/deploy.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TEST_SERVER 'bash -s' < script.sh
script.sh
git pull origin dev-4
touch vaddy_test.txt
公開鍵暗号通信で楽に接続できました。今までの努力が....w
あとは.shの中に処理を書けば色々なことができます。
条件分岐
テストの数だけ毎回Vaddyテストが動いたり、プルリクのたびにテストサーバが汚されたりすると困るので、masterブランチがpushされたときだけ、sshしてテストを動かすようにします。
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then
openssl aes-256-cbc -k "$SERVER_KEY" -in deploy_key.enc -d -a -out deploy.key;
cp deploy.key ~/.ssh/;
chmod 600 ~/.ssh/deploy.key;
ssh -i ~/.ssh/deploy.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TEST_SERVER 'bash -s' < script.sh;
fi;
自動取得
apiを使っているのですが、終了判定が用意されていないため自分で作成する必要があります。
apiの返り値でスキャンidが帰ってくるのでスキャンidを元に結果をリクエストし続けます。
$ curl ($api) | echo $?
0
とすることで curlの出力結果を表示してみたい..のですが、結果は0
idを取得できないと結果がとってこれません。
##スキャン実行
$ RES=$(curl -Ss https://api.vaddy.net/v1/scan -X POST -d "action=start" -d "user=$VADDY_USER" -d "auth_key=$VADDY_AUTH_KEY" -d "fqdn=$VADDY_FQDN")
echo "$RES"
##結果取得
$ RES=$(curl -G -d "user=$VADDY_USER&auth_key=$VADDY_AUTH_KEY&fqdn=$VADDY_FQDN&scan_id=$VADDY_ID" https://api.vaddy.net/v1/scan/result)
echo "$RES"
変数に代入して結果を取得してみました。とりあえず表示はできました。
表示されたものを利用するためには一旦中間ファイルに書き出したりする必要があるみたいです。
あとはこれをbashでwhileして10分起きくらいにおわったか確認したらいいしたらいいのかな?
・・ここでVaddyのクライアントツールの方がコマンド実行後、進行度がわかり、終了されたら結果がかえってくることが判明。
APIを捨ててクライアントを使おうかとおもいます。
APIからCLIツールへ
Travis上で下記のコマンドでインストールし実行します。travisはlinuxなのでlinux-64bitを実行
仕様書
git clone https://github.com/vaddy/go-vaddy.git
cd go-vaddy/bin/vaddy-linux-64bit $VADDY_AUTH_KEY $VADDY_USER $VADDY_FQDN
最初はshに書いてたのですが、正常に動作しなかったため、travisのbefore_scriptに git cloneを加えました。
実行すると
No output has been received in the last 10m0s
となり、30分くらいかかるテストの10分ほどでエラーがでて強制終了されてしまいます。
進捗が出力されてるはずなのになー・・と思いながら、エラーがでないように。
travisが10分間出力がない場合強制終了するみたい。
travis側で時間を変更するコマンドが用意されていました。
参考こちら
#30分までタイムアウトしない
travis_wait 30 XXX(コマンド)
しかしこちらもエラー・・・
Terminated travis_jigger $! $timeout $cmd
このエラーが解消できなかったため、別の方法を模索
とりあえず何かアウトプットすればいいので、何分おきかにechoで適当に表示させてみます。
参考2こちら
しかしうまくいかず、リアルタイムで何か表示させれないかと色々調べました。
とりあえず今の状態は
#travis
./vaddy.sh | ./slack.sh
とパイプで通知を実装しようとしていたのですが、これではログが標準出力されないらしく、
./vaddy.sh
としたら出力される感じ。
どうにか変数に結果をいれることができないと何もできない!
またまたぐぐったり人にきいたり。すると、teeコマンドで結果を保存できることが判明!
teeはログを標準出力しつつ、ファイルにも出力してくれるコマンドなので、今の状況にぴったりです!
./vaddy.sh | tee result.txt
$msg = 'cat result.txt'
echo "$msg"
これで解決しました!
何度もリクエストさせる
TravisCIでは並列でテストが進むことがあるが、Vaddyは並列のテストにはエラーの原因になるため、対応していません。なので、テストリクエストが失敗してもテストリクエストが成功するまで、リクエストし続ける処理を書かなければいけません。
さっき用意した変数を使い、正規表現で判断します。
vaddy.shに、[[ ]]を使う正規表現の判別を追加してみます。
msg=`cat result.txt`
if [[ $msg =~ "Scan has already been running" ]]; then
while :
do
echo "テスト中のため5分後にもう一度テストリクエストします。"
sleep 300
go-vaddy/bin/vaddy-linux-64bit $VADDY_AUTH_KEY $VADDY_USER $VADDY_FQDN | tee result.txt
msg=`cat result.txt`
if [[ ! $msg =~ "Scan has already been running" ]]; then
break
fi
done
fi
すごく汚い気がしますが、とりあえず動くように。しかし、ローカルでは成功するのですが、どうもtravis上では[[ ]]が使えない様子・・・なぜ?
#!/bin/sh
から下記に変更
#!/bin/bash
どうやらshではだめみたいです。
とりあえず動くようになったやつ
travis.yml
after_success:
#Vaddyテスト
- cd ../secure_test/
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "dev-4" ]; then
./vaddy.sh;
fi;
vaddy.sh
#!/bin/bash
git clone https://github.com/vaddy/go-vaddy.git;
while :
do
timeout 5 go-vaddy/bin/vaddy-linux-64bit $VADDY_AUTH_KEY $VADDY_USER $VADDY_FQDN | tee result.txt
msg=`cat result.txt`
if [[ $msg =~ "Scan has already been running" ]]; then
echo "既に他のテスト実行中のため5分後にもう一度テストリクエストします。"
sleep 300
fi
if [[ ! $msg =~ "Scan has already been running" ]]; then
break
fi
done
openssl aes-256-cbc -k "$SERVER_KEY" -in deploy_key.enc -d -a -out deploy.key
cp deploy.key ~/.ssh/
chmod 600 ~/.ssh/deploy.key
ssh -i ~/.ssh/deploy.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TEST_SERVER 'bash -s' < script.sh
並列でテストしているときのために、一度テストを動かして、動けばデプロイしてもう一度動かす、という風にしたいと思い書きましたが、これではテスト結果がとってこれず、timeoutコマンドで強制終了したらもうテストをコマンドではキャンセルする術がないです。困りました。
ここでAPIだけがスキャンIDをとってこれ中止や結果取得ができることに気づきます!
前述のAPIで詰まっていた出力問題はもう解決しているので、このコードを書き直しました。
#確認
while :
do
curl -Ss https://api.vaddy.net/v1/scan -X POST -d "action=start" -d "user=$VADDY_USER" -d "auth_key=$VADDY_AUTH_KEY" -d "fqdn=$VADDY_FQDN" | tee result.txt
msg=`cat result.txt`
if [[ $msg =~ "Scan has already been running" ]]; then
echo "既に他のテスト実行中のため5分後にもう一度テストリクエストします。"
sleep 300
fi
if [[ $msg =~ scan_id\":\"(.*)\" ]]; then
SCAN_ID=${BASH_REMATCH[1]}
curl -Ss https://api.vaddy.net/v1/scan -X POST -d "action=cancel" -d "user=$VADDY_USER" -d "auth_key=$VADDY_AUTH_KEY" -d "scan_id=$SCAN_ID" -d "fqdn=$VADDY_FQDN"
break
fi
done
# デプロイ
openssl aes-256-cbc -k "$SERVER_KEY" -in deploy_key.enc -d -a -out deploy.key
cp deploy.key ~/.ssh/
chmod 600 ~/.ssh/deploy.key
ssh -i ~/.ssh/deploy.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TEST_SERVER 'bash -s' < deploy.sh
#Vaddy実行
curl -Ss https://api.vaddy.net/v1/scan -X POST -d "action=start" -d "user=$VADDY_USER" -d "auth_key=$VADDY_AUTH_KEY" -d "fqdn=$VADDY_FQDN" | tee result.txt
msg=`cat result.txt`
echo "$msg"
if [[ $msg =~ scan_id\":\"(.*)\" ]]; then
SCAN_ID=${BASH_REMATCH[1]}
fi;
#結果取得
while :
do
echo "$SCAN_ID"
curl -G -d "user=$VADDY_USER&auth_key=$VADDY_AUTH_KEY&fqdn=$VADDY_FQDN&scan_id=$SCAN_ID" https://api.vaddy.net/v1/scan/result | tee result.txt
msg=`cat result.txt`
if [[ $msg =~ status\":\"scanning ]]; then
echo "テストが完了していないため、5分後にもう一度確認します。"
sleep 300
fi
if [[ ! $msg =~ status\":\"scanning ]]; then
break;
fi
done
あとはこのresult.txtの中身をslack通知するだけ!
長かったができてよかった!
あとがき。
scanidがとってこれなかったり、キャンセルが強制終了したらできなくなったり。まだまだ増えてほしい機能が多いですね。shとかsshとかコマンドとか、色々勉強できました。
--追記(2017/08/25)
https://github.com/vaddy/WebAPI-document/commit/fac22ae0750e1f4885cc481a25092968911be0c2
APIが追加されたので、実行可能かどうか状況を確認するための実行リクエストを出しているwhile部分を
while :
do
curl -G -d "user=$VADDY_USER&auth_key=$VADDY_AUTH_KEY&fqdn=$VADDY_FQDN" https://api.vaddy.net/v1/scan/runcheck | tee result.txt
msg=`cat result.txt`
if [[ $msg =~ {\"running_process\":0} ]]; then
break
fi
if [[ $msg =~ {\"running_process\":.*} ]]; then
echo "既に他のテスト実行中のため5分後にもう一度テストリクエストします。"
sleep 300
fi
done
に変更しました。これにより実行が2度行われないのでキャンセルする必要もなくなりました。
Author And Source
この問題について(TravisCIが成功したらテストサーバにGithubからクローンしてVAddyを動かす), 我々は、より多くの情報をここで見つけました https://qiita.com/kinzi0828/items/9d060a32252aa7e5346d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .