ShellScript
centos7
firewalld

CentOS7 firewall の設定を一括でしたい

CentOS7になってから結構経ちましたが
Firewallの設定が未だにめんどくさいと思っていたので
思い切って必要最低限勝手にできるやつ作りました。

という個人的メモ的な

やりたいこと

・publicゾーンは、サービスとポートで制限をかける
・ssh用のゾーンを1つ作成し、SSHに対してIP制限をかける
・できれば、長ったらしいコマンドは書かないようにしたい
・こうしたいって思ったら修正変えやすい形がいい

必要そうなコマンドを流れに合わせて書いてみる

流れ

firewallが動いているかを確認する

現在のアクティブのゾーンは何かを確認する

アクティブのゾーンに追加したいサービスを追加する

アクティブのゾーンに追加したいポートを追加する

SSH用のゾーンを作成する

SSH用のゾーンをACCEPTのゾーンとして登録する

SSH用のゾーンにSSHサービスを追加する

SSH用のゾーンに接続を許可するIPを追加する

アクティブのゾーンからSSHを削除する

設定をリロードする

(必要ないけど)サービスを再起動する

コマンド

長いのでおりこみ

そもそも動いているかを確認する

]# systemctl status firewalld

※動いていなかった場合

]# systemctl start firewalld

現在のアクティブのゾーンを確認する

]# firewall-cmd --get-active-zone
public
 interfaces: enp0s3

出てきたゾーン名(public)が現在firewallでアクティブになっているゾーン

アクティブのゾーンに設定されている状態を確認する

]# firewall-cmd --list-all
public (active)
   target: default
   icmp-block....

ここに出てくるのが、現在アクティブのゾーンに設定されている内容

publicゾーンにhttpサービスを追加する

]# firewall-cmd --add-service=HTTP --zone=public --permanent

--add-service : 追加を行うサービス名
--zone= : サービスを追加するゾーン、このオプションがない場合デフォルトのゾーンが指定される(大体は追加するゾーンは決まっているので、書いてあったほうがいい)
--permanent : このオプションが付くと、firewallが再起動されても有効な状態になる

publicゾーンに8080/tcpポートを追加する(TCPポート)

]# firewall-cmd --add-port=8080/tcp --zone=public --permanent

publicゾーンに8080/udpポートを追加する(UDPポート)

]# firewall-cmd --add-port=8080/udp --zone=public --permanent

この様に、ポート番号/ポートタイプ を「--add-port=」に指定する

SSH用のゾーンを作成する

]# firewall-cmd --new-zone=ssh --permanent

念のため、追加した時点で一度リロードを行う

]# firewall-cmd --reload

作成したゾーンをACCEPTとして登録する

]# firewall-cmd --zone=ssh --set-target=ACCEPT --permanent

--set-target : SSHゾーンの登録をどのような形でするのかを設定する

ACCEPT : 接続の許可
REJECT : 接続の拒否

sshゾーンにサービスとしてSSHを登録する

]# firewall-cmd --add-service=ssh --zone=ssh --permanent

SSH接続を許可するIPを登録する

]# firewall-cmd --add-source=192.168.1.123/32 --zone=ssh --permanent

--add-source : 今回の場合は、接続を許可するIPアドレス
         192.168.1.123/32 という形で登録する

登録が終わったら再度リロードを行う

]# firewall-cmd --reload

publicゾーンからSSHを削除する

]# firewall-cmd remove-service=ssh --zone=public --permanent

SSHのゾーンを削除する前に行っても大丈夫ですが、ミスったときにSSH接続ができなくなるのである程度問題なくなってから削除するのをおすすめします

リロードをしてから、サービスを再起動する

]# firewall-cmd --reload
]# systemctl restart firewalld

長い

iptableのときよりやることが増えた感がすごい
あるものを使いたい精神なので、そう行ってもこれから離れられないんです…

そこでシェルスクリプト

書いたようなコマンドを全て内包して、ある程度自動でやってくれるように書いてしまおう!

あれもこれもと欲張った結果がこちらです

firewall_settngs.sh
# !/bin/sh
## ==============================================================
## firewall setting
## ==============================================================
LINE="============================================================"
O_LINE="------------------------------------------------------------"

# public zone setting
PUBLIC_SERVICE=("ssh false" "http true" "https true" "dhcpv6-client true")
PUBLIC_PORT=("8080/tcp true" "8080/ucp true")
PUBLIC_SOURCE=("")

# ssh zone setting
SSH_SERIVECE=("ssh true")
SSH_PORT=("")
SSH_SOURCE=("127.0.0.1/32 true" "192.168.59.111/32 true")

# * when adding a new zone
#


## ==============================================================
## result
## ==============================================================
result_success () {
  echo -e "${1} : [\e[34m success \e[m]"
}
# result_success "aaaa"
result_warning () {
  echo -e "${1} : [\e[31m failure \e[m]";
}
result_q () {
  if [ "${2}" = "success" ]; then
    result_success "${1}"
  elif [ "${2}" = "failure" ]; then
    result_warning "${1}"
  else
    echo -e "${1} : [\e[35m ${2} \e[m]"
  fi
}
cmd () {
  result=`${2}`
  result_q "${1}" "${result}"
}


## ==============================================================
## firewall cmd
## ==============================================================
firewall_service () {
    service=`firewall-cmd --list-service --zone=${1} | grep "${2} "`
    if [ "${?}" -eq 0 ]; then
        result1=`firewall-cmd --remove-service=${2} --zone=${1} --permanent`
        result_q "delete service ${2}" ${result1}
    fi

    if [ "${3}" = "true" ]; then
        result2=`firewall-cmd --add-service=${2} --zone=${1} --permanent`
        result_q "add service ${2}" ${result2}
    fi
}

firewall_port () {
    port=`firewall-cmd --list-port --zone=${1} | grep "${2} "`
    if [ "${?}" -eq 0 ]; then
        result1=`firewall-cmd --remove-port=${2} --zone=${1} --permanent`
        result_q "delete port ${2}" ${result1}
    fi

    if [ "${3}" = "true" ]; then
        result2=`firewall-cmd --add-port=${2} --zone=${1} --permanent`
        result_q "add port ${2}" ${result2}
    fi
}

firewall_ip () {
    ip=`firewall-cmd --list-sources --zone=${1} | grep "${2} "`
    if [ "${?}" -eq 0 ]; then
        result1=`firewall-cmd --remove-source=${2} --zone=${1} --permanent`
        result_q "remove ip ${2}" ${result1}
    fi

    if [ "${3}" = "true" ]; then
        result2=`firewall-cmd --add-source=${2} --zone=${1} --permanent`
        result_q "add ip ${2}" ${result2}
    fi
}

zone_accept () {
  echo ""
  echo "${O_LINE}"
  echo "${1} settings"
  echo "${O_LINE}"
  cmd "delete zone ${1}" "firewall-cmd --permanent --delete-zone=${1}"
  cmd "new zone ${1}" "firewall-cmd --permanent --new-zone=${1}"
  cmd "firewall reload" "firewall-cmd --reload"
  cmd "ACCEPT zone" "firewall-cmd --permanent --zone=${1} --set-target=ACCEPT"
}

firewall_zone () {
    # firewall public zone is default active zone
    echo "${O_LINE}"
    echo "public settings"
    echo "${O_LINE}"
    for (( I = 0; I < ${#PUBLIC_SERVICE[@]}; ++I )); do
        set -- ${PUBLIC_SERVICE[I]}
        firewall_service "public" ${1} ${2}
    done
    for (( I = 0; I < ${#PUBLIC_PORT[@]}; ++I )); do
        set -- ${PUBLIC_PORT[I]}
        firewall_port "public" ${1} ${2}
    done
    for (( I = 0; I < ${#PUBLIC_SOURCE[@]}; ++I )); do
        set -- ${PUBLIC_SOURCE[I]}
        firewall_ip "public" ${1} ${2}
    done

    # firewall ssh zone is add active zone
    ssh="ssh"
    zone_accept "${ssh}"
    for (( I = 0; I < ${#SSH_SERVICE[@]}; ++I )); do
        set -- ${SSH_SERVICE[I]}
        firewall_service "${ssh}" ${1} ${2}
    done
    for (( I = 0; I < ${#SSH_PORT[@]}; ++I )); do
        set -- ${SSH_PORT[I]}
        firewall_port "${ssh}" ${1} ${2}
    done
    for (( I = 0; I < ${#SSH_SOURCE[@]}; ++I )); do
        set -- ${SSH_SOURCE[I]}
        firewall_ip "${ssh}" ${1} ${2}
    done

    # new zone status added below


    # end a "zone" setting
    cmd "firewall reload" "firewall-cmd --reload"
}

firewall_status () {
  C_S="\e[37;41;1m"
  C_E="\e[m"
  cat << EOF
${O_LINE}
ZONE:${1}
service:
  `firewall-cmd --list-service --zone=${1}`
port:
  `firewall-cmd --list-port --zone=${1}`
sources:
  `firewall-cmd --list-sources --zone=${1}`
${O_LINE}
EOF
}

view_status () {
  echo ""
  echo "${LINE}"
  echo "setting firewall view"
  echo "${LINE}"
  firewall_status "public"
  firewall_status "ssh"
  # new zone status added below

}


## ==============================================================
## firewalld check
##
## return code
##   -1  : running iptables
## ==============================================================
firewalld_check () {
  echo "${LINE}"
  echo "firewall running check"
  echo "${LINE}"

  r01=`systemctl status firewalld | grep running`
  if [ -n "${r01}" ]; then
    result_success "firewalld"

    return 0
  else
    result_warning "firewalld"
    r02=`systemctl status iptables | grep running`
    if [ -n "${r02}" ]; then
      result_success "iptables"
      echo "# is running iptables system"

      return 1
    fi

    result_warning "iptables"
    echo "\e[31m*** No Resistance Tactice  ***\e[m"
  fi

  return 2
}


## ==============================================================
## update command
## ==============================================================
update_line () {
  r01=`firewalld_check`
  if [ "${?}" -eq 1]; then
    printf "${r01}\n"
    exit 1
  elif [ "${?}" -eq 2]; then
    printf "${r01}\n"
    echo "${O_LINE}"
    echo "start firewalld"
    echo "${O_LINE}"
    eval "systemctl start firewalld"
    if [ "${?}" -ne 0]; then
      exit 1
    fi
  else
    printf "${r01}\n"
  fi
  firewall_zone
  cmd "restart service" "systemctl restart firewalld"
  view_status
}


## ==============================================================
## check command
## ==============================================================
check_line () {
  r01=`firewalld_check`
  if [ "${?}" -eq 0 ]; then
    printf "${r01}\n"
    view_status
  else
    printf "${r01}\n"
  fi
}


## ==============================================================
## help command
## ==============================================================
help_line () {
  cat << EOF

this script was created to
automatically update the Firewalld of CentOS 7.

command.
    [-h]   : script help
    [-c]   : check firewall setting
    [-u]   : update firewall

EOF
}

usage_exit () {
  echo "Usage: ${0} [-h] [-c] [-u]"
  exit 1
}

while getopts hcu option
do
  case $option in
    h)
      help_line
      exit 0 ;;
    c)
      check_line
      exit 0 ;;
    u)
      update_line
      exit 0 ;;
    \?)
      usage_exit ;;
  esac
done
usage_exit

public ゾーンに登録したいサービス

PUBLIC_SERVICE=("ssh false" "http true" "https true" "dhcpv6-client true")

public ゾーンに登録したいポート

PUBLIC_PORT=("8080/tcp true" "8080/ucp true")

public ゾーンに登録したいIP(publicゾーンでは使用しないが念のため)

PUBLIC_SOURCE=("")

SSH用のゾーンに登録したいサービス

SSH_SERIVECE=("ssh true")

SSH用のゾーンに登録したいポート

SSH_PORT=("")

SSH用のゾーンに登録したいIP

SSH_SOURCE=("127.0.0.1/32 true" "192.168.59.111/32 true")

全ての入力内容に共通しているものとして、スペース区切りでtrueかfalseか入れるようにしてあります。

trueなら、登録
falseなら、削除はするが登録はしない(いらなくなったものとか)

呼び出し方は

]# ./firewall_settngs.sh [-h] [-c] [-u]

[-h] : よくあるコマンドのヘルプ
[-c] : 現在設定されている項目の出力(public, ssh)
[-u] : 設定されている内容で、Firewallを更新する

終わりに

このシェルスクリプトでは、activeになっているゾーンはpublicという決め打ちになっているので、そうじゃなかった時が修正めんどくさそうだけど、そうなっているのは基本的にいじっている後なので、これ使う必要あるのかなぁと思います。

これでサーバを適当に作ったときのめんどくさい作業が少しでも減れば…