
メリークリスマス! なのまる です。
NTPの脆弱性(英語)の対応しよーと思って、手作業はツラすぎるのである程度の自動化をしようと思いました。
もくじ
Fabricが楽しかった理由
そもそもCapistrano (Ruby) を使っていたんですがなんとなく、一度だけ勉強会で使わせてもらったFabricの勉強をしてみたいと思って使いました!Fabricを使ってみて、楽しいなぁ~って思った理由を自分なりにまとめてみたので書いておきます。
- Capistranoでは、そのままでは煩わしい部分が簡単に解決できた!(認証関連)
- 出来上がった、コードが短くて済んだ!
- 出来上がった、コードがわかりやすい!
- 上記もあって、使っていて楽しい!w
Fabric を使ってみる!
前提条件
- OSシステム環境のPythonに影響を及ぼさない
- pyenv + virtualenv
- Linux (CentOS 6)
- fabric
そのため「pyenv + virtualenv」で実装した。
「pyenv + virtualenv」 インストール・設定
ここの部分長いので、わかる人は飛ばしていいと思います!pyenv インストール
pyenvはinstallerがあって、インストールが簡単です!以下を実行するだけ!
1 | curl -L https: //raw .githubusercontent.com /yyuu/pyenv-installer/master/bin/pyenv-installer | bash |
インストール状況
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [snickerjp@localhost ~]$ curl -L https: //raw .githubusercontent.com /yyuu/pyenv-installer/master/bin/pyenv-installer | bash % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 101 2126 101 2126 0 0 6321 0 --:--:-- --:--:-- --:--:-- 6858 Initialized empty Git repository in /home/snickerjp/ .pyenv/.git/ remote: Counting objects: 8056, done . remote: Total 8056 (delta 0), reused 0 (delta 0) Receiving objects: 100% (8056 /8056 ), 1.44 MiB | 374 KiB /s , done . Resolving deltas: 100% (5898 /5898 ), done . Initialized empty Git repository in /home/snickerjp/ .pyenv /plugins/pyenv-doctor/ .git/ remote: Counting objects: 26, done . ~中略~ Resolving deltas: 100% (8 /8 ), done . WARNING: seems you still have not added 'pyenv' to the load path. # Load pyenv automatically by adding # the following to ~/.bash_profile: export PATH= "$HOME/.pyenv/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" |
~/.bash_profileに以下を追記
1 2 3 | export PATH= "$HOME/.pyenv/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" |
かっこよく編集してみたりw
1 2 3 4 5 6 | cat << 'EOF' >> ~/.bash_profile # for pyenv export PATH= "$HOME/.pyenv/bin:$PATH" eval "$(pyenv init -)" eval "$(pyenv virtualenv-init -)" EOF |
localにPythonのインストール
なんとなく2.x系をインストールしました。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Pythonの現在のバージョンを確認 [snickerjp@localhost ~]$ python --version Python 2.6.6 [snickerjp@localhost ~]$ pyenv install 2.7.8 Downloading Python-2.7.8.tgz... ~略~ Installed Python-2.7.8 to /home/snickerjp/ .pyenv /versions/2 .7.8 [snickerjp@localhost ~]$ pyenv versions * system ( set by /home/snickerjp/ .pyenv /version ) 2.7.8 [snickerjp@localhost ~]$ pyenv install 2.7.9 Downloading Python-2.7.9.tgz... ~略~ [snickerjp@localhost ~]$ pyenv versions * system ( set by /home/snickerjp/ .pyenv /version ) 2.7.8 2.7.9 |
Pythonのインストールでエラーが出たので、追加でdevelパッケージを入れました。
1 2 3 4 | WARNING: The Python readline extension was not compiled. Missing the GNU readline lib? WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib? WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib? ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib? |
yumでインストール!
1 | sudo yum install readline-devel bzip2 -devel openssl-devel sqlite-devel |
virtualenvのインストール
virtualenvのインストール~1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [snickerjp@localhost fabric-bin]$ pyenv virtualenv 2.7.9 fabric Collecting virtualenv Downloading virtualenv-12.0.3-py2.py3-none-any.whl (1.8MB) 100% | ################################| 1.8MB 6.2MB/s Installing collected packages: virtualenv Successfully installed virtualenv-12.0.3 New python executable in /home/snickerjp/ .pyenv /versions/fabric/bin/python2 .7 Also creating executable in /home/snickerjp/ .pyenv /versions/fabric/bin/python Installing setuptools, pip... done . Ignoring indexes: https: //pypi .python.org /simple/ Requirement already satisfied (use --upgrade to upgrade): setuptools in /home/snickerjp/ .pyenv /versions/fabric/lib/python2 .7 /site-packages Requirement already satisfied (use --upgrade to upgrade): pip in /home/snickerjp/ .pyenv /versions/fabric/lib/python2 .7 /site-packages Cleaning up... [snickerjp@localhost fabric-bin]$ [snickerjp@localhost fabric-bin]$ pyenv versions * system ( set by /home/snickerjp/ .pyenv /version ) 2.7.8 2.7.9 fabric |
localのPythonを使う場所を作る
localバージョンのPythonを使う場所を作ります!1 2 3 4 5 6 7 8 9 10 11 | [snickerjp@localhost ~]$ mkdir fabric-bin [snickerjp@localhost fabric-bin]$ cd fabric-bin/ [snickerjp@localhost fabric-bin]$ pyenv local fabric pyenv-virtualenv: activate fabric (fabric)[snickerjp@localhost fabric-bin]$ (fabric)[snickerjp@localhost fabric-bin]$ pyenv rehash (fabric)[snickerjp@localhost fabric-bin]$ python --version Python 2.7.9 (fabric)[snickerjp@localhost fabric-bin]$ pip list pip (6.0.3) setuptools (8.2.1) |
fabric インストール
やっと、ここでfabricのインストール!もうvirtualenvでlocal環境にインストールできる状態です!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | (fabric)[snickerjp@localhost fabric-bin]$ pip install fabric Collecting fabric Downloading Fabric-1.10.1. tar .gz (209kB) 100% | ################################| 212kB 9.3MB/s Collecting paramiko>=1.10 (from fabric) Downloading paramiko-1.15.2-py2.py3-none-any.whl (165kB) 100% | ################################| 167kB 10.8MB/s Collecting ecdsa>=0.11 (from paramiko>=1.10->fabric) Downloading ecdsa-0.11. tar .gz (45kB) 100% | ################################| 49kB 10.3MB/s Collecting pycrypto!=2.4,>=2.1 (from paramiko>=1.10->fabric) Downloading pycrypto-2.6.1. tar .gz (446kB) 100% | ################################| 446kB 8.1MB/s Installing collected packages: pycrypto, ecdsa, paramiko, fabric Running setup.py install for pycrypto checking for gcc ... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out ~略~ gcc -pthread -shared -L /home/snickerjp/ .pyenv /versions/2 .7.9 /lib build /temp .linux-x86_64-2.7 /src/_counter .o -o build /lib .linux-x86_64-2. 7 /Crypto/Util/_counter .so Running setup.py install for ecdsa Running setup.py install for fabric Installing fab script to /home/snickerjp/ .pyenv /versions/fabric/bin Successfully installed ecdsa-0.11 fabric-1.10.1 paramiko-1.15.2 pycrypto-2.6.1 |
参考
ntp をアップデートしてみる
いよいよ本題ですね!wntpup.py
こちらを参考に以下のコードを書いてみました!
(コメント部分は消してください)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #coding:utf-8 from fabric.api import env, run, sudo from fabric.contrib.console import confirm env.use_ssh_config = True env.key_filename = [ '~/.ssh/id_rsa' ] def yum_update_ntp(): sudo( 'cat /etc/∗-release' ,user = 'root' , pty = True ) # Linuxのディストリビューションの確認 sudo( 'yum -q -y update ntp' ,user = 'root' , pty = True ) # sudo で yum update def run_su(command, user = "root" ): # sudo が無いサーバーなどの対応 return run( 'su %s -c "%s"' % (user, command), pty = True ) def su_update_ntp(): run_su( 'cat /etc/∗-release' ,user = 'root' ) run_su( 'yum -y update ntp' ,user = 'root' ) # sudo がないサーバーで yum update |
実行例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | [192.168.82.xxx] Executing task 'yum_update_ntp' [192.168.82.xxx] sudo : cat /etc/ *-release [192.168.82.xxx] Login password for 'snickerjp' : [192.168.82.xxx] out: [192.168.82.xxx] out: We trust you have received the usual lecture from the local System [192.168.82.xxx] out: Administrator. It usually boils down to these three things: [192.168.82.xxx] out: [192.168.82.xxx] out: #1) Respect the privacy of others. [192.168.82.xxx] out: #2) Think before you type. [192.168.82.xxx] out: #3) With great power comes great responsibility. [192.168.82.xxx] out: [192.168.82.xxx] out: sudo password: [192.168.82.xxx] out: Sorry, try again. [192.168.82.xxx] out: sudo password: ← 公開鍵とPAMで違うパスワードの時は聞いてきてくれる! [192.168.82.xxx] out: NAME= "Amazon Linux AMI" [192.168.82.xxx] out: VERSION= "2014.09" [192.168.82.xxx] out: ID= "amzn" [192.168.82.xxx] out: ID_LIKE= "rhel fedora" [192.168.82.xxx] out: VERSION_ID= "2014.09" [192.168.82.xxx] out: PRETTY_NAME= "Amazon Linux AMI 2014.09" [192.168.82.xxx] out: ANSI_COLOR= "0;33" [192.168.82.xxx] out: CPE_NAME= "cpe:/o:amazon:linux:2014.09:ga" [192.168.82.xxx] out: HOME_URL= "http://aws.amazon.com/amazon-linux-ami/" [192.168.82.xxx] out: Amazon Linux AMI release 2014.09 [192.168.82.xxx] out: [192.168.82.xxx] sudo : yum --releasever=2014.09 --disablerepo=epel update ntp [192.168.82.xxx] out: sudo password: [192.168.82.xxx] out: Loaded plugins: priorities, update-motd, upgrade-helper [192.168.82.xxx] out: [192.168.82.xxx] out: amzn-main /2014 .09 | 2.1 kB 00:00 [192.168.82.xxx] out: [192.168.82.xxx] out: amzn-updates /2014 .09 | 2.3 kB 00:00 [192.168.82.xxx] out: 181 packages excluded due to repository priority protections [192.168.82.xxx] out: No packages marked for update [192.168.82.xxx] out: |
Capistranoでやろうとすると、このあたりが比較的にめんどくさい!
- 公開鍵とPAMで違うパスワードでも対話で入力できる!
- rootパスワードも対話で入力できる!
- サーバーごとにパスワード違っても対話で入力できる!
- 前の処理で入れたパスワードは記憶しておいてくれる!
fabricだと、楽だった!のでした!
参考
まとめ
- Capistranoで不便と思っていた部分が解決できる!(認証関連)
- コードが短くて、さらに読みやすい!
- pyenv + virtualenv + fabric でポータビリティもあるんじゃないかと!w
参考サイト
- Welcome to Fabric! — Fabric documentation
- virtualenv 12.0.4 : Python Package Index
- NTPに複数の脆弱性 - US-CERTが注意喚起 | マイナビニュース
- 時刻同期のNTPに極めて深刻な脆弱性--「パケット1つで悪用が可能」 - ZDNet Japan
- Network Time Protocol Vulnerabilities (Update A) | ICS-CERT
- (capistrano) A remote server automation and deployment tool written in Ruby.