NGINX App Protect on Hatoba
で実現するセキュアなサービス公開
構築⼿順書
NGINX INGRESS CONTROLLERとWAFによる本番環境での安全なアプリケーションの実現
F5ネットワークスジャパン合同会社
ソリューションエンジニアリング部
シニアソリューションエンジニア
⼩峰 洋⼀
| ©2020 F5
2
注意事項
• 本⼿順書は、ニフクラのKubernetes Service Hatoba(以下Hatoba)上に
て、簡易的にNGINX Ingress Controller(以下NIC)とApp Protect(以
下NAP)の機能を持つIngress Controllerを構築、動作させるための⼿順書
となります。
• 検証以外でご利⽤頂く際には、ネットワークやセキュリティの設定等考慮
して構築してください。
• ニフクラやHatobaの各種設定の詳細はヘルプページをご確認ください。
| ©2020 F5
3
検証構成
ニフクラ
Hatoba
ニフクラL4
LB
NIC
+
NAP
DVWA
Ingress Controller Pod
ELK
仮想サーバ
Kibana
ダッシュボード
で攻撃を監視
サービスを楽しむ
正規ユーザ
攻撃を⽌められて
悲しむハッカー
type: LoadBalancerで設定されるため、
ユーザには実体は⾒えない
攻撃のログを送信
| ©2020 F5
4
構築⼿順
(1) k8sクラスタの作成
(2) DVWAのデプロイ
(3) NGINX評価ライセンスの取得
(4) NIC/NAPのビルド
(5) NIC/NAPのデプロイ
(6) Ingressの設定と疎通確認
(7) ELKの構築
(8) NAPの設定
(9) NIC/NAPとELKの接続
(10) チューニングの実施
| ©2020 F5
5
(1)k8sクラスタの作成
k8sクラスタを構築します。下記HELPにあるクイックスタートから作成してください。
https://pfs.nifcloud.com/guide/kubernetes-service-hatoba/quickstart.htm
作成途中で上記の設定がありますが、今回は
NIC/NAPをk8s内でのHTTPロードバラン
サーとして構築しますので、ここでは「利⽤
しない」(=⾃動的に構築されない)を選択
してください。
| ©2020 F5
6
(2)DVWAのデプロイ
DVWAとは、セキュリティ⽬的の教育に使⽤されたり、様々な⽬的のための脆弱なWebアプリケーションです。
詳しくは検索してご確認ください。
https://hub.docker.com/r/vulnerables/web-dvwa apiVersion: apps/v1
kind: Deployment
metadata:
name: dvwa-deployment
labels:
app: dvwa
spec:
replicas: 1
selector:
matchLabels:
app: dvwa
template:
metadata:
labels:
app: dvwa
spec:
containers:
- name: dvwa
image: vulnerables/web-dvwa
ports:
- containerPort: 80
右記のDeploymentを使⽤し、DVWAを
デプロイしてください。
その後下記にて正常にデプロイされてい
ることを確認してください。
-----------------------
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dvwa-deployment 1/1 1 1 6h
-----------------------
このPod数は1にしてください。
DVWAはPod間でセッションを共有しませんので、
2以上の値にすると動作が不安定になります。
deployment-dvwa.yaml
| ©2020 F5
7
(3)NGINX評価ライセンスの取得
https://www.nginx.co.jp/free-trial-request-nginx-ingress-controller/
下記より評価ライセンスの申請をしてください。
メールをご確認ください。
数分後に左記メール
を受信し・・
さらに数分後に左記メー
ルを受信します。最初に
記載されているリンクに
アクセスしてください。
| ©2020 F5
8
(3)NGINX評価ライセンスの取得
評価ライセンスファイルを2つダウンロードしてください。後ほど使⽤します。
| ©2020 F5
9
(4)NIC/NAPのビルド
NGINXのサイトから必要なファイルをダウンロードし、ビルドしてコンテナイメージを作成後、⾃
分のDocker Hubプライベートリポジトリにアップします。
① 下記のビルド環境を準備してください。
参考ページ
https://docs.nginx.com/nginx-ingress-controller/app-protect/installation/
https://docs.nginx.com/nginx-ingress-controller/installation/building-ingress-controller-image/
https://www.nginx.co.jp/products/products-nginx/kubernetes-ingress-controller/
② Docker Hubの準備をしてください。
・無料アカウントの登録
・Private Repositoryの作成
名前は nginx-plus-ingress としてください。
後ほど指定します。
| ©2020 F5
10
(4)NIC/NAPのビルド
③ 必要なファイルをダウンロードしてビルドしてください。
● ダウンロード
$ git clone https://github.com/nginxinc/kubernetes-ingress/
任意の場所へダウンロードしてください。
● 評価ライセンスファイルの移動
ダウンロードした評価ライセンスファイル(nginx-repo.crt、nginx-repo.key)を、
<NGINX DIR>/kubernetes-ingress ディレクトリに移動してください。
● カレントディレクトリの移動
<NGINX DIR>/kubernetes-ingress ディレクトリに移動してください。
● dockerログイン
$ docker login
Docker Hubアカウントへログインしてください。
保存したディレクトリを<NGINX DIR>と
します。後ほどこの<NGINX DIR>に移動して頂く
事があります。
例︓
/root 直下で git clone を⾏った場合は、
<NGINX DIR> = /root
となります。
| ©2020 F5
11
(4)NIC/NAPのビルド
● NGINXバージョンを確認してcheck out
$ git tag
バージョンが表⽰されるので、最新版を確認してください。(例: v1.12.0)
$ git checkout v1.12.0 ← 最新版を指定
●ビルドの実⾏
$ make debian-image-nap-plus VERSION=<version> PREFIX=<docker hub ID>/nginx-plus-
ingress TARGET=container
<version>には最新版を指定し、<docker hub ID>には⾃分のIDを指定してください。
● Docker Hub プライベートリポジトリにアップ
$ make push PREFIX=<docker hub ID>/nginx-plus-ingress VERSION=<version>
● 確認
Docker Hubにアップされているか確認してください。
※ 本⼿順書執筆時点では最新バージョンがv1.12.0となっています。NGINX
v1.12.0はk8s v1.21までの対応となっており、k8s v1.22ではデプロイでき
ません。k8s v1.22以降をご利⽤の場合はNGIXNの対応バージョンがリリー
スされるのをお待ち下さい。
| ©2020 F5
12
(5)NIC/NAPのデプロイ
Docker Hubプライベートリポジトリにアップしたイメージをデプロイします。
① マニフェストファイルの確認
<NGINX DIR>/kubernetes-ingress/deployments に含まれているマニフェストファイルを適⽤し
ます。 <NGINX DIR>/kubernetes-ingress/deployments ディレクトリに移動してください。
$ pwd
<NGINX DIR>/kubernetes-ingress/deployments
$ ls
README.md common daemon-set deploymenthelm-chart rbac service
| ©2020 F5
13
(5)NIC/NAPのデプロイ
② マニフェストファイルの適⽤
下記順番で適⽤してください。
$ kubectl apply -f common/ns-and-sa.yaml
$ kubectl apply -f rbac/rbac.yaml
$ kubectl apply -f rbac/ap-rbac.yaml
$ kubectl apply -f common/default-server-secret.yaml
$ kubectl apply -f common/nginx-config.yaml
$ kubectl apply -f common/ingress-class.yaml
$ kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml
$ kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml
$ kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml
$ kubectl apply -f common/crds/k8s.nginx.org_policies.yaml
$ kubectl apply -f common/crds/k8s.nginx.org_globalconfigurations.yaml
$ kubectl apply -f common/crds/appprotect.f5.com_aplogconfs.yaml
$ kubectl apply -f common/crds/appprotect.f5.com_appolicies.yaml
$ kubectl apply -f common/crds/appprotect.f5.com_apusersigs.yaml
参考ページ
https://docs.nginx.com/nginx-ingress-controller/installation/installation-
with-manifests/#configure-rbac
| ©2020 F5
14
(5)NIC/NAPのデプロイ
③ イメージのデプロイ
● プライベートリポジトリアクセス⽤のSecretの作成
$ kubectl create secret docker-registry private-reg-cred --docker-username=<docker hub
ID> --docker-password=<docker hub password> --docker-email=<email address> --
namespace=nginx-ingress
● マニフェストファイルの修正と適⽤
<NGINX DIR>/kubernetes-ingress/deployments/deployment/nginx-plus-ingress.yaml
修正後適⽤してください。
⾃分のプライベートリポジトリを指定してください。
- image: <docker hub ID>/nginx-plus-ingress:1.20.0
ここに先程作成した下記を追加してください。
serviceAccountName: nginx-ingress
imagePullSecrets:
- name: private-reg-cred
containers:
| ©2020 F5
15
(6)Ingressの設定と疎通確認
起動したNICとNAPの設定を⾏い、外部に公開して疎通確認を⾏います。
● マニフェストファイルの修正と適⽤
<NGINX DIR>/kubernetes-ingress/deployments/service/loadbalancer.yaml
修正後適⽤してください。
Nameからハイフンを削除してください。
nginx-ingress → nginxingress
※ 命名規則について
kind: Service、type: LoadBalancer のマニフェストにて、nameのみを指定してそこにハイフ
ンを使⽤することができません(7⽉時点での制限)。
もしハイフン等をご利⽤になられたい場合、アノテーションを利⽤してロードバランサーの名前
を別途指定することでハイフン等を使⽤できるようになります。詳しくは下記をご確認ください。
https://pfs.nifcloud.com/spec/kubernetes-service-hatoba/load_balancer.htm
本件について、ご不明点があれば下記ニフクラのお問い合わせページよりお問い合わせください。
https://pfs.nifcloud.com/inquiry/support.htm
| ©2020 F5
16
(6)Ingressの設定と疎通確認
● 疎通確認
IPアドレスを確認し、ブラウザからアクセスしてください。NGINXの404ページが表⽰されば疎通は問題
ありません。
(まだVirtualServer(Ingress)の設定を⾏っていないため現段階では404となります。)
$ kubectl get service -n nginx-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginxingress LoadBalancer xx.xx.xx.xx yy.yy.yy.yy 80:32583/TCP,443:31942/TCP 4m
ブラウザから http://yy.yy.yy.yy/ にアクセスし
404ページを確認してください。
| ©2020 F5
17
(6)Ingressの設定と疎通確認
● DVWAアプリケーションを接続
NGINXのCRDである VirtualServer でDVWAと接続します。
右記マニフェストファイルでDVWA Serviceを作成してください。
参考ページ︓ VirtualServerとは・・
https://docs.nginx.com/nginx-ingress-
controller/configuration/virtualserver-and-virtualserverroute-resources/
apiVersion: v1
kind: Service
metadata:
name: dvwa-svc
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: dvwa
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: nginx-vs
spec:
host: <external IP>
upstreams:
- name: dvwa
service: dvwa-svc
port: 80
routes:
- path: /dvwa
action:
proxy:
upstream: dvwa
rewritePath: /
左記マニフェストファイルでNGINXのVirtualServerを作成してください。
<external IP>には前ページの yy.yy.yy.yy を設定してください。
ブラウザから http://yy.yy.yy.yy/dvwa/
にアクセスし、ログインページが表⽰される
ことを確認してください。
service-dvwa.yaml
virtualserver-nginx.yaml
| ©2020 F5
18
(6)Ingressの設定と疎通確認
● DVWAアプリケーションのセットアップ
最初は何も⼊⼒せずに Login
ボタンをクリックしてください。
Create / Reset Database ボタンを
クリックしてください。404ページが
表⽰されますが問題ありません。
初期設定がされていますので、念の為
30秒ほどそのままお待ち下さい。
再度 http://yy.yy.yy.yy/dvwa/ にア
クセスし、下記情報でログインしてく
ださい。
Username: admin
Password: password
| ©2020 F5
19
(7)ELKの構築 ELKを起動する仮想サーバを構築し、その上にELKを構築します。
① 仮想サーバを構築してください。
SSHキーを作成して保存しておいてください。
下記3つをINルールに設定してください。
(1) SSH(TCP port 22)でのアクセス
(2) KibanaへのHTTP(TCP port 5601)でのアクセス
(3) NIC/NAPからデータを送信(TCP port 5144)
(1)(2)については適切なアドレスを設定してください。
(3)については、Hatoba k8s内のPodからのアクセスとな
りますが、送信元アドレスがk8sノードのIPアドレスで
NATされるため、ノードのIPアドレスを指定することにな
ります。実際の環境ではノード数の増減も考えられるため、
適切な運⽤をご検討ください。
CentOSを選択してください。
ここでは1vCPU/1GBを選択していますが、
⼤きい分には問題ありません。
| ©2020 F5
20
(7)ELKの構築
② ELKを構築してください。
● SSHで接続
$ chmod 700 elkserverkey_private.pem
$ ssh root@<global IP> -i elkserverkey_private.pem
仮想サーバ作成時にダウンロードしたSSHキーを指定してください。
● モジュールインストール
下記コマンドにて、必要なモジュールをインストールしてください。
Update: [root@localhost ~]# yum update
Git: [root@localhost ~]# yum install git
Docker: [root@localhost ~]# yum install docker
jq: [root@localhost ~]# yum install jq
※ dockerインストールにてpodmanがインストールされることにより、後の⼿
順のdocker runコマンド実⾏時、ボリュームマウント関連でエラーとなる
ケースがあるようです。その場合は「Centos8 docker インストール」等で
検索して頂き、別の⼿順(wgetでdocker関連インストーラをダウンロード
等)をお試しください。
| ©2020 F5
21
(7)ELKの構築
● テンプレートダウンロード
[root@localhost ~]# git clone https://github.com/f5devcentral/f5-waf-elk-dashboards.git
場所は任意ですが、今回は root 直下にクローンしてください。
● チューニング
[root@localhost ~]# vi /etc/sysctl.d/99-sysctl.conf
vm.max_map_count = 262144 ← ファイルの⼀番下に左記を追加して保存してください。
● 再起動
[root@localhost ~]# reboot
諸々設定を⾏ったので、再起動をしてください。
再起動後、設定が反映されていることを確認してください。
確認︓ [root@localhost ~]# sysctl -p
vm.max_map_count = 262144
| ©2020 F5
22
(7)ELKの構築
● SELinuxの設定
ディレクトリマウントに失敗しないように、SELinuxを無効にしておきます。(本環境以外では適切に設定
してください)
# setenforce 0
● docker run でELKを起動
[root@localhost ~]# docker run -d -v /root/f5-waf-elk-
dashboards/logstash/conf.d:/etc/logstash/conf.d -p 5601:5601 -p 9200:9200 -p 5144:5144 -it -
e ES_CONNECT_RETRY=300 --name elk sebp/elk
起動するまでお待ち下さい。数分かかります。
http://<global IP>:5601 にアクセスして
正常に画⾯が表⽰されれば⼤丈夫です。
docker run実⾏時にイメージ選択
が必要となった場合、docker.ioの
イメージを選択してください。
| ©2020 F5
23
(7)ELKの構築
● テンプレートのインポート
[root@localhost ~]# KIBANA_URL=http://<global IP>:5601
<global IP>に、仮想サーバのIPを指定してください。
[root@localhost ~]# jq -s . /root/f5-waf-elk-dashboards/kibana/overview-dashboard.ndjson | jq
'{"objects": . }' | curl -k --location --request POST
"$KIBANA_URL/api/kibana/dashboards/import" --header 'kbn-xsrf: true' --header 'Content-Type:
text/plain' -d @- | jq
[root@localhost ~]# jq -s . /root/f5-waf-elk-dashboards/kibana/false-positives-
dashboards.ndjson | jq '{"objects": . }' | curl -k --location --request POST
"$KIBANA_URL/api/kibana/dashboards/import" --header 'kbn-xsrf: true' --header 'Content-Type:
text/plain' -d @- | jq
参考ページ https://github.com/f5devcentral/f5-waf-elk-dashboards
| ©2020 F5
24
(7)ELKの構築
● Kibanaにアクセスして確認(http://<global IP>:5601)
まだデータが無いので
エラー画⾯となります。
| ©2020 F5
25
(8)NAPの設定
まずはDVWAにアクセスして攻撃が通ってしまうことを確認します。
その後NAPを設定し、攻撃がブロックされることを確認します。
① 攻撃(SQL Injection)の実施
SQL Injectionを試します。
下記⽂字列を⼊⼒して Submit します。
1' or 'a'='a
データベース内のすべてのユーザ
情報が⾒えてしまいます。
| ©2020 F5
26
(8)NAPの設定
② NAPの設定
● App Protectの有効化
下記ファイルを修正してください。
<NGINX DIR>/kubernetes-ingress/deployments/deployment/nginx-plus-ingress.yaml
修正後適⽤してください。
コメントを外し、1⾏新たに追加してください。
参考ページ
https://docs.nginx.com/nginx-ingress-controller/app-protect/installation/
https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/
| ©2020 F5
27
(8)NAPの設定
● Policyの作成
下記マニフェストファイルを適⽤してください。
参考ページ
https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-
manifests/#create-common-resources
https://docs.nginx.com/nginx-ingress-controller/app-
protect/configuration/#app-protect-policies/
apiVersion: appprotect.f5.com/v1beta1
kind: APPolicy
metadata:
name: default-policy
spec:
policy:
name: default-policy
template:
name: POLICY_TEMPLATE_NGINX_BASE
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: waf-default-policy
spec:
waf:
enable: true
apPolicy: "default/default-policy"
$ kubectl get appolicy
NAME AGE
default-policy 4m9s
$ kubectl get policy
NAME STATE AGE
waf-default-policy Valid 55s
default-policy.yaml policy.yaml
| ©2020 F5
28
(8)NAPの設定
● VirtualServerにPolicyを設定
(6)で作成したVirtualServerリソースにポリシーの指定を追加し、適⽤してください。
参考ページ
https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-
manifests/#create-common-resources
https://docs.nginx.com/nginx-ingress-controller/app-
protect/configuration/#app-protect-policies/
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: nginx-vs
spec:
host: yy.yy.yy.yy
policies:
- name: waf-default-policy
upstreams:
- name: dvwa
service: dvwa-svc
port: 80
・・・
・・・
こちらを追加します。
その後、同じようにDVWAにアクセスして
SQL Injectionを実⾏してください。
NAPによって攻撃がブロックされました。
virtualserver-nginx.yaml
| ©2020 F5
29
(9)NIC/NAPとELKの接続
NIC/NAPのログ設定を⾏い、ELKへログを送信します。
下記マニフェストファイルを適⽤してください。
apiVersion: appprotect.f5.com/v1beta1
kind: APLogConf
metadata:
name: logconf
spec:
filter:
request_type: all
content:
format: default
max_request_size: any
max_message_size: 5k
aplogconf.yaml
参考ページ
https://docs.nginx.com/nginx-ingress-controller/app-
protect/configuration/#app-protect-logs
$ kubectl get aplogconf
NAME AGE
logconf 5s
(8)で作成した policy.yaml を下記のように修正して適⽤してください。
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: waf-default-policy
spec:
waf:
enable: true
apPolicy: "default/default-policy”
securityLog:
enable: true
apLogConf: "default/logconf"
logDest: "syslog:server=<global IP>:5144"
policy.yaml
こちらを追加します。
<global IP>には、Kibanaにアクセスする際の
アドレスと同じものを指定してください。
| ©2020 F5
30
(9)NIC/NAPとELKの接続
DVWAにアクセスして攻撃を⾏うと、Kibana上で確認することができます。
⼀番最初にKibanaで確認する際には、攻撃を⾏ってから表⽰され
るまで10分程かかります。
⼀度データが表⽰されれば、その後はリアルタイムで表⽰されます。
| ©2020 F5
31
(10)チューニングの実施
デフォルトで設定しているセキュリティポリシーを修正し、チューニングを⾏ってみます。
● デフォルトのポリシー
(8)で指定した右記のポリシーがデフォルトのポリシーとなります。
POLICY_TEMPLATE_NGINX_BASEというテンプレートを使⽤し、
OWASP TOP10への対応等、基本的な攻撃に対してのテンプレート
となります。
具体的なテンプレートの中⾝は参考ページと
NIC Pod内にある下記ファイルに記載されています。
/opt/app_protect/install/policy_templates/nginx_base.xml
apiVersion: appprotect.f5.com/v1beta1
kind: APPolicy
metadata:
name: default-policy
spec:
policy:
name: default-policy
template:
name: POLICY_TEMPLATE_NGINX_BASE
default-policy.yaml
参考ページ
https://docs.nginx.com/nginx-app-
protect/configuration/#signature-sets-in-default-policy
| ©2020 F5
32
(10)チューニングの実施
具体的には下記のシグネチャセットがデフォルトで適⽤されています。
参考ページ
https://docs.nginx.com/nginx-app-
protect/configuration/#signature-sets-in-default-policy
• Command Execution Signatures
• Cross Site Scripting Signatures
• Directory Indexing Signatures
• Information Leakage Signatures
• OS Command Injection Signatures
• Path Traversal Signatures
• Predictable Resource Location
Signatures
• Remote File Include Signatures
• SQL Injection Signatures
• Authentication/Authorization
Attack Signatures
• XML External Entity (XXE)
Signatures
• XPath Injection Signatures
• Buffer Overflow Signatures
• Denial of Service Signatures
• Vulnerability Scanner Signatures
• High Accuracy Signatures
• All CVE Signatures
| ©2020 F5
33
(10)チューニングの実施
● Botへの対応
現在の設定で curl でアクセスしてください。
# curl http://yy.yy.yy.yy/dvwa/login.php
正しくHTMLが返され、Kibanaには下記のように表⽰
されると思います。
デフォルトのテンプレートだと alerted となっていま
すがcurlを含むBotからのアクセスをブロックする
チューニングを⾏ってみます。
curlアクセスする度にCountが増加します。
| ©2020 F5
34
(10)チューニングの実施
デフォルトのポリシーでは、Bot Defenseがtrueになっています。curlは untrust Botに分類されます。
apiVersion: appprotect.f5.com/v1beta1
kind: APPolicy
metadata:
name: default-policy
spec:
policy:
name: default-policy
template:
name: POLICY_TEMPLATE_NGINX_BASE
現⾏default-policy.yaml
/opt/app_protect/install/policy_templates/nginx_base.xml
※NIC Pod内で確認
<?xml version="1.0" encoding="utf-8"?>
<policy bigip_version="15.1.0"
name="/Common/NGINX_BASE_TEMPLATE">
<type>Security</type>
<encoding>utf-8</encoding>
<description>Base Template for NGINX
Standalone</description>
---(略)---
<bot_defense>
<settings>
<enabled>true</enabled>
</settings>
</bot_defense>
</policy>
Base Templateではデフォルトで
Bot Defenseがtrueになっています。
Bot type Action
trusted detect
untrust alarm
malicious block
デフォルトのアクション
| ©2020 F5
35
(10)チューニングの実施
● チューニング
Untrust BotをBlockする設定を追加し、適⽤してください。
apiVersion: appprotect.f5.com/v1beta1
kind: APPolicy
metadata:
name: default-policy
spec:
policy:
name: default-policy
template:
name: POLICY_TEMPLATE_NGINX_BASE
bot-defense:
mitigations:
classes:
- name: untrusted-bot
action: block
こちらを追加します。
default-policy.yaml
適⽤後再度curlでアクセスし、ブロックされることを確認します。
# curl http://yy.yy.yy.yy/dvwa/login.php
<html><head><title>Request Rejected</title></head><body>The requested URL
was rejected. Please consult with your administrator.<br><br>Your support ID is:
17145546028604397486<br><br><a href='javascript:history.back();'>[Go
Back]</a></body></html>
Kibana上でもブロックとしてカウントされています。
blockをalermにするか、追加部分を
削除することでもとにもどります。
| ©2020 F5
36
お問い合わせ
本件でお問い合わせがありましたら、お気軽に下記までお問い合わせください。
メールアドレス
F5_FJcloud_Team@f5.com
F5ネットワークスジャパン合同会社 ニフクラ担当チーム
NGINX App Protect on Hatobaで実現するセキュリティサービス公開 構築手順書

NGINX App Protect on Hatobaで実現するセキュリティサービス公開 構築手順書

  • 1.
    NGINX App Protecton Hatoba で実現するセキュアなサービス公開 構築⼿順書 NGINX INGRESS CONTROLLERとWAFによる本番環境での安全なアプリケーションの実現 F5ネットワークスジャパン合同会社 ソリューションエンジニアリング部 シニアソリューションエンジニア ⼩峰 洋⼀
  • 2.
    | ©2020 F5 2 注意事項 •本⼿順書は、ニフクラのKubernetes Service Hatoba(以下Hatoba)上に て、簡易的にNGINX Ingress Controller(以下NIC)とApp Protect(以 下NAP)の機能を持つIngress Controllerを構築、動作させるための⼿順書 となります。 • 検証以外でご利⽤頂く際には、ネットワークやセキュリティの設定等考慮 して構築してください。 • ニフクラやHatobaの各種設定の詳細はヘルプページをご確認ください。
  • 3.
    | ©2020 F5 3 検証構成 ニフクラ Hatoba ニフクラL4 LB NIC + NAP DVWA IngressController Pod ELK 仮想サーバ Kibana ダッシュボード で攻撃を監視 サービスを楽しむ 正規ユーザ 攻撃を⽌められて 悲しむハッカー type: LoadBalancerで設定されるため、 ユーザには実体は⾒えない 攻撃のログを送信
  • 4.
    | ©2020 F5 4 構築⼿順 (1)k8sクラスタの作成 (2) DVWAのデプロイ (3) NGINX評価ライセンスの取得 (4) NIC/NAPのビルド (5) NIC/NAPのデプロイ (6) Ingressの設定と疎通確認 (7) ELKの構築 (8) NAPの設定 (9) NIC/NAPとELKの接続 (10) チューニングの実施
  • 5.
  • 6.
    | ©2020 F5 6 (2)DVWAのデプロイ DVWAとは、セキュリティ⽬的の教育に使⽤されたり、様々な⽬的のための脆弱なWebアプリケーションです。 詳しくは検索してご確認ください。 https://hub.docker.com/r/vulnerables/web-dvwaapiVersion: apps/v1 kind: Deployment metadata: name: dvwa-deployment labels: app: dvwa spec: replicas: 1 selector: matchLabels: app: dvwa template: metadata: labels: app: dvwa spec: containers: - name: dvwa image: vulnerables/web-dvwa ports: - containerPort: 80 右記のDeploymentを使⽤し、DVWAを デプロイしてください。 その後下記にて正常にデプロイされてい ることを確認してください。 ----------------------- $ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE dvwa-deployment 1/1 1 1 6h ----------------------- このPod数は1にしてください。 DVWAはPod間でセッションを共有しませんので、 2以上の値にすると動作が不安定になります。 deployment-dvwa.yaml
  • 7.
  • 8.
  • 9.
    | ©2020 F5 9 (4)NIC/NAPのビルド NGINXのサイトから必要なファイルをダウンロードし、ビルドしてコンテナイメージを作成後、⾃ 分のDockerHubプライベートリポジトリにアップします。 ① 下記のビルド環境を準備してください。 参考ページ https://docs.nginx.com/nginx-ingress-controller/app-protect/installation/ https://docs.nginx.com/nginx-ingress-controller/installation/building-ingress-controller-image/ https://www.nginx.co.jp/products/products-nginx/kubernetes-ingress-controller/ ② Docker Hubの準備をしてください。 ・無料アカウントの登録 ・Private Repositoryの作成 名前は nginx-plus-ingress としてください。 後ほど指定します。
  • 10.
    | ©2020 F5 10 (4)NIC/NAPのビルド ③必要なファイルをダウンロードしてビルドしてください。 ● ダウンロード $ git clone https://github.com/nginxinc/kubernetes-ingress/ 任意の場所へダウンロードしてください。 ● 評価ライセンスファイルの移動 ダウンロードした評価ライセンスファイル(nginx-repo.crt、nginx-repo.key)を、 <NGINX DIR>/kubernetes-ingress ディレクトリに移動してください。 ● カレントディレクトリの移動 <NGINX DIR>/kubernetes-ingress ディレクトリに移動してください。 ● dockerログイン $ docker login Docker Hubアカウントへログインしてください。 保存したディレクトリを<NGINX DIR>と します。後ほどこの<NGINX DIR>に移動して頂く 事があります。 例︓ /root 直下で git clone を⾏った場合は、 <NGINX DIR> = /root となります。
  • 11.
    | ©2020 F5 11 (4)NIC/NAPのビルド ●NGINXバージョンを確認してcheck out $ git tag バージョンが表⽰されるので、最新版を確認してください。(例: v1.12.0) $ git checkout v1.12.0 ← 最新版を指定 ●ビルドの実⾏ $ make debian-image-nap-plus VERSION=<version> PREFIX=<docker hub ID>/nginx-plus- ingress TARGET=container <version>には最新版を指定し、<docker hub ID>には⾃分のIDを指定してください。 ● Docker Hub プライベートリポジトリにアップ $ make push PREFIX=<docker hub ID>/nginx-plus-ingress VERSION=<version> ● 確認 Docker Hubにアップされているか確認してください。 ※ 本⼿順書執筆時点では最新バージョンがv1.12.0となっています。NGINX v1.12.0はk8s v1.21までの対応となっており、k8s v1.22ではデプロイでき ません。k8s v1.22以降をご利⽤の場合はNGIXNの対応バージョンがリリー スされるのをお待ち下さい。
  • 12.
    | ©2020 F5 12 (5)NIC/NAPのデプロイ DockerHubプライベートリポジトリにアップしたイメージをデプロイします。 ① マニフェストファイルの確認 <NGINX DIR>/kubernetes-ingress/deployments に含まれているマニフェストファイルを適⽤し ます。 <NGINX DIR>/kubernetes-ingress/deployments ディレクトリに移動してください。 $ pwd <NGINX DIR>/kubernetes-ingress/deployments $ ls README.md common daemon-set deploymenthelm-chart rbac service
  • 13.
    | ©2020 F5 13 (5)NIC/NAPのデプロイ ②マニフェストファイルの適⽤ 下記順番で適⽤してください。 $ kubectl apply -f common/ns-and-sa.yaml $ kubectl apply -f rbac/rbac.yaml $ kubectl apply -f rbac/ap-rbac.yaml $ kubectl apply -f common/default-server-secret.yaml $ kubectl apply -f common/nginx-config.yaml $ kubectl apply -f common/ingress-class.yaml $ kubectl apply -f common/crds/k8s.nginx.org_virtualservers.yaml $ kubectl apply -f common/crds/k8s.nginx.org_virtualserverroutes.yaml $ kubectl apply -f common/crds/k8s.nginx.org_transportservers.yaml $ kubectl apply -f common/crds/k8s.nginx.org_policies.yaml $ kubectl apply -f common/crds/k8s.nginx.org_globalconfigurations.yaml $ kubectl apply -f common/crds/appprotect.f5.com_aplogconfs.yaml $ kubectl apply -f common/crds/appprotect.f5.com_appolicies.yaml $ kubectl apply -f common/crds/appprotect.f5.com_apusersigs.yaml 参考ページ https://docs.nginx.com/nginx-ingress-controller/installation/installation- with-manifests/#configure-rbac
  • 14.
    | ©2020 F5 14 (5)NIC/NAPのデプロイ ③イメージのデプロイ ● プライベートリポジトリアクセス⽤のSecretの作成 $ kubectl create secret docker-registry private-reg-cred --docker-username=<docker hub ID> --docker-password=<docker hub password> --docker-email=<email address> -- namespace=nginx-ingress ● マニフェストファイルの修正と適⽤ <NGINX DIR>/kubernetes-ingress/deployments/deployment/nginx-plus-ingress.yaml 修正後適⽤してください。 ⾃分のプライベートリポジトリを指定してください。 - image: <docker hub ID>/nginx-plus-ingress:1.20.0 ここに先程作成した下記を追加してください。 serviceAccountName: nginx-ingress imagePullSecrets: - name: private-reg-cred containers:
  • 15.
    | ©2020 F5 15 (6)Ingressの設定と疎通確認 起動したNICとNAPの設定を⾏い、外部に公開して疎通確認を⾏います。 ●マニフェストファイルの修正と適⽤ <NGINX DIR>/kubernetes-ingress/deployments/service/loadbalancer.yaml 修正後適⽤してください。 Nameからハイフンを削除してください。 nginx-ingress → nginxingress ※ 命名規則について kind: Service、type: LoadBalancer のマニフェストにて、nameのみを指定してそこにハイフ ンを使⽤することができません(7⽉時点での制限)。 もしハイフン等をご利⽤になられたい場合、アノテーションを利⽤してロードバランサーの名前 を別途指定することでハイフン等を使⽤できるようになります。詳しくは下記をご確認ください。 https://pfs.nifcloud.com/spec/kubernetes-service-hatoba/load_balancer.htm 本件について、ご不明点があれば下記ニフクラのお問い合わせページよりお問い合わせください。 https://pfs.nifcloud.com/inquiry/support.htm
  • 16.
    | ©2020 F5 16 (6)Ingressの設定と疎通確認 ●疎通確認 IPアドレスを確認し、ブラウザからアクセスしてください。NGINXの404ページが表⽰されば疎通は問題 ありません。 (まだVirtualServer(Ingress)の設定を⾏っていないため現段階では404となります。) $ kubectl get service -n nginx-ingress NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginxingress LoadBalancer xx.xx.xx.xx yy.yy.yy.yy 80:32583/TCP,443:31942/TCP 4m ブラウザから http://yy.yy.yy.yy/ にアクセスし 404ページを確認してください。
  • 17.
    | ©2020 F5 17 (6)Ingressの設定と疎通確認 ●DVWAアプリケーションを接続 NGINXのCRDである VirtualServer でDVWAと接続します。 右記マニフェストファイルでDVWA Serviceを作成してください。 参考ページ︓ VirtualServerとは・・ https://docs.nginx.com/nginx-ingress- controller/configuration/virtualserver-and-virtualserverroute-resources/ apiVersion: v1 kind: Service metadata: name: dvwa-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP name: http selector: app: dvwa apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: nginx-vs spec: host: <external IP> upstreams: - name: dvwa service: dvwa-svc port: 80 routes: - path: /dvwa action: proxy: upstream: dvwa rewritePath: / 左記マニフェストファイルでNGINXのVirtualServerを作成してください。 <external IP>には前ページの yy.yy.yy.yy を設定してください。 ブラウザから http://yy.yy.yy.yy/dvwa/ にアクセスし、ログインページが表⽰される ことを確認してください。 service-dvwa.yaml virtualserver-nginx.yaml
  • 18.
    | ©2020 F5 18 (6)Ingressの設定と疎通確認 ●DVWAアプリケーションのセットアップ 最初は何も⼊⼒せずに Login ボタンをクリックしてください。 Create / Reset Database ボタンを クリックしてください。404ページが 表⽰されますが問題ありません。 初期設定がされていますので、念の為 30秒ほどそのままお待ち下さい。 再度 http://yy.yy.yy.yy/dvwa/ にア クセスし、下記情報でログインしてく ださい。 Username: admin Password: password
  • 19.
    | ©2020 F5 19 (7)ELKの構築ELKを起動する仮想サーバを構築し、その上にELKを構築します。 ① 仮想サーバを構築してください。 SSHキーを作成して保存しておいてください。 下記3つをINルールに設定してください。 (1) SSH(TCP port 22)でのアクセス (2) KibanaへのHTTP(TCP port 5601)でのアクセス (3) NIC/NAPからデータを送信(TCP port 5144) (1)(2)については適切なアドレスを設定してください。 (3)については、Hatoba k8s内のPodからのアクセスとな りますが、送信元アドレスがk8sノードのIPアドレスで NATされるため、ノードのIPアドレスを指定することにな ります。実際の環境ではノード数の増減も考えられるため、 適切な運⽤をご検討ください。 CentOSを選択してください。 ここでは1vCPU/1GBを選択していますが、 ⼤きい分には問題ありません。
  • 20.
    | ©2020 F5 20 (7)ELKの構築 ②ELKを構築してください。 ● SSHで接続 $ chmod 700 elkserverkey_private.pem $ ssh root@<global IP> -i elkserverkey_private.pem 仮想サーバ作成時にダウンロードしたSSHキーを指定してください。 ● モジュールインストール 下記コマンドにて、必要なモジュールをインストールしてください。 Update: [root@localhost ~]# yum update Git: [root@localhost ~]# yum install git Docker: [root@localhost ~]# yum install docker jq: [root@localhost ~]# yum install jq ※ dockerインストールにてpodmanがインストールされることにより、後の⼿ 順のdocker runコマンド実⾏時、ボリュームマウント関連でエラーとなる ケースがあるようです。その場合は「Centos8 docker インストール」等で 検索して頂き、別の⼿順(wgetでdocker関連インストーラをダウンロード 等)をお試しください。
  • 21.
    | ©2020 F5 21 (7)ELKの構築 ●テンプレートダウンロード [root@localhost ~]# git clone https://github.com/f5devcentral/f5-waf-elk-dashboards.git 場所は任意ですが、今回は root 直下にクローンしてください。 ● チューニング [root@localhost ~]# vi /etc/sysctl.d/99-sysctl.conf vm.max_map_count = 262144 ← ファイルの⼀番下に左記を追加して保存してください。 ● 再起動 [root@localhost ~]# reboot 諸々設定を⾏ったので、再起動をしてください。 再起動後、設定が反映されていることを確認してください。 確認︓ [root@localhost ~]# sysctl -p vm.max_map_count = 262144
  • 22.
    | ©2020 F5 22 (7)ELKの構築 ●SELinuxの設定 ディレクトリマウントに失敗しないように、SELinuxを無効にしておきます。(本環境以外では適切に設定 してください) # setenforce 0 ● docker run でELKを起動 [root@localhost ~]# docker run -d -v /root/f5-waf-elk- dashboards/logstash/conf.d:/etc/logstash/conf.d -p 5601:5601 -p 9200:9200 -p 5144:5144 -it - e ES_CONNECT_RETRY=300 --name elk sebp/elk 起動するまでお待ち下さい。数分かかります。 http://<global IP>:5601 にアクセスして 正常に画⾯が表⽰されれば⼤丈夫です。 docker run実⾏時にイメージ選択 が必要となった場合、docker.ioの イメージを選択してください。
  • 23.
    | ©2020 F5 23 (7)ELKの構築 ●テンプレートのインポート [root@localhost ~]# KIBANA_URL=http://<global IP>:5601 <global IP>に、仮想サーバのIPを指定してください。 [root@localhost ~]# jq -s . /root/f5-waf-elk-dashboards/kibana/overview-dashboard.ndjson | jq '{"objects": . }' | curl -k --location --request POST "$KIBANA_URL/api/kibana/dashboards/import" --header 'kbn-xsrf: true' --header 'Content-Type: text/plain' -d @- | jq [root@localhost ~]# jq -s . /root/f5-waf-elk-dashboards/kibana/false-positives- dashboards.ndjson | jq '{"objects": . }' | curl -k --location --request POST "$KIBANA_URL/api/kibana/dashboards/import" --header 'kbn-xsrf: true' --header 'Content-Type: text/plain' -d @- | jq 参考ページ https://github.com/f5devcentral/f5-waf-elk-dashboards
  • 24.
    | ©2020 F5 24 (7)ELKの構築 ●Kibanaにアクセスして確認(http://<global IP>:5601) まだデータが無いので エラー画⾯となります。
  • 25.
    | ©2020 F5 25 (8)NAPの設定 まずはDVWAにアクセスして攻撃が通ってしまうことを確認します。 その後NAPを設定し、攻撃がブロックされることを確認します。 ①攻撃(SQL Injection)の実施 SQL Injectionを試します。 下記⽂字列を⼊⼒して Submit します。 1' or 'a'='a データベース内のすべてのユーザ 情報が⾒えてしまいます。
  • 26.
    | ©2020 F5 26 (8)NAPの設定 ②NAPの設定 ● App Protectの有効化 下記ファイルを修正してください。 <NGINX DIR>/kubernetes-ingress/deployments/deployment/nginx-plus-ingress.yaml 修正後適⽤してください。 コメントを外し、1⾏新たに追加してください。 参考ページ https://docs.nginx.com/nginx-ingress-controller/app-protect/installation/ https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/
  • 27.
    | ©2020 F5 27 (8)NAPの設定 ●Policyの作成 下記マニフェストファイルを適⽤してください。 参考ページ https://docs.nginx.com/nginx-ingress-controller/installation/installation-with- manifests/#create-common-resources https://docs.nginx.com/nginx-ingress-controller/app- protect/configuration/#app-protect-policies/ apiVersion: appprotect.f5.com/v1beta1 kind: APPolicy metadata: name: default-policy spec: policy: name: default-policy template: name: POLICY_TEMPLATE_NGINX_BASE apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: waf-default-policy spec: waf: enable: true apPolicy: "default/default-policy" $ kubectl get appolicy NAME AGE default-policy 4m9s $ kubectl get policy NAME STATE AGE waf-default-policy Valid 55s default-policy.yaml policy.yaml
  • 28.
    | ©2020 F5 28 (8)NAPの設定 ●VirtualServerにPolicyを設定 (6)で作成したVirtualServerリソースにポリシーの指定を追加し、適⽤してください。 参考ページ https://docs.nginx.com/nginx-ingress-controller/installation/installation-with- manifests/#create-common-resources https://docs.nginx.com/nginx-ingress-controller/app- protect/configuration/#app-protect-policies/ apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: nginx-vs spec: host: yy.yy.yy.yy policies: - name: waf-default-policy upstreams: - name: dvwa service: dvwa-svc port: 80 ・・・ ・・・ こちらを追加します。 その後、同じようにDVWAにアクセスして SQL Injectionを実⾏してください。 NAPによって攻撃がブロックされました。 virtualserver-nginx.yaml
  • 29.
    | ©2020 F5 29 (9)NIC/NAPとELKの接続 NIC/NAPのログ設定を⾏い、ELKへログを送信します。 下記マニフェストファイルを適⽤してください。 apiVersion:appprotect.f5.com/v1beta1 kind: APLogConf metadata: name: logconf spec: filter: request_type: all content: format: default max_request_size: any max_message_size: 5k aplogconf.yaml 参考ページ https://docs.nginx.com/nginx-ingress-controller/app- protect/configuration/#app-protect-logs $ kubectl get aplogconf NAME AGE logconf 5s (8)で作成した policy.yaml を下記のように修正して適⽤してください。 apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: waf-default-policy spec: waf: enable: true apPolicy: "default/default-policy” securityLog: enable: true apLogConf: "default/logconf" logDest: "syslog:server=<global IP>:5144" policy.yaml こちらを追加します。 <global IP>には、Kibanaにアクセスする際の アドレスと同じものを指定してください。
  • 30.
  • 31.
    | ©2020 F5 31 (10)チューニングの実施 デフォルトで設定しているセキュリティポリシーを修正し、チューニングを⾏ってみます。 ●デフォルトのポリシー (8)で指定した右記のポリシーがデフォルトのポリシーとなります。 POLICY_TEMPLATE_NGINX_BASEというテンプレートを使⽤し、 OWASP TOP10への対応等、基本的な攻撃に対してのテンプレート となります。 具体的なテンプレートの中⾝は参考ページと NIC Pod内にある下記ファイルに記載されています。 /opt/app_protect/install/policy_templates/nginx_base.xml apiVersion: appprotect.f5.com/v1beta1 kind: APPolicy metadata: name: default-policy spec: policy: name: default-policy template: name: POLICY_TEMPLATE_NGINX_BASE default-policy.yaml 参考ページ https://docs.nginx.com/nginx-app- protect/configuration/#signature-sets-in-default-policy
  • 32.
    | ©2020 F5 32 (10)チューニングの実施 具体的には下記のシグネチャセットがデフォルトで適⽤されています。 参考ページ https://docs.nginx.com/nginx-app- protect/configuration/#signature-sets-in-default-policy •Command Execution Signatures • Cross Site Scripting Signatures • Directory Indexing Signatures • Information Leakage Signatures • OS Command Injection Signatures • Path Traversal Signatures • Predictable Resource Location Signatures • Remote File Include Signatures • SQL Injection Signatures • Authentication/Authorization Attack Signatures • XML External Entity (XXE) Signatures • XPath Injection Signatures • Buffer Overflow Signatures • Denial of Service Signatures • Vulnerability Scanner Signatures • High Accuracy Signatures • All CVE Signatures
  • 33.
    | ©2020 F5 33 (10)チューニングの実施 ●Botへの対応 現在の設定で curl でアクセスしてください。 # curl http://yy.yy.yy.yy/dvwa/login.php 正しくHTMLが返され、Kibanaには下記のように表⽰ されると思います。 デフォルトのテンプレートだと alerted となっていま すがcurlを含むBotからのアクセスをブロックする チューニングを⾏ってみます。 curlアクセスする度にCountが増加します。
  • 34.
    | ©2020 F5 34 (10)チューニングの実施 デフォルトのポリシーでは、BotDefenseがtrueになっています。curlは untrust Botに分類されます。 apiVersion: appprotect.f5.com/v1beta1 kind: APPolicy metadata: name: default-policy spec: policy: name: default-policy template: name: POLICY_TEMPLATE_NGINX_BASE 現⾏default-policy.yaml /opt/app_protect/install/policy_templates/nginx_base.xml ※NIC Pod内で確認 <?xml version="1.0" encoding="utf-8"?> <policy bigip_version="15.1.0" name="/Common/NGINX_BASE_TEMPLATE"> <type>Security</type> <encoding>utf-8</encoding> <description>Base Template for NGINX Standalone</description> ---(略)--- <bot_defense> <settings> <enabled>true</enabled> </settings> </bot_defense> </policy> Base Templateではデフォルトで Bot Defenseがtrueになっています。 Bot type Action trusted detect untrust alarm malicious block デフォルトのアクション
  • 35.
    | ©2020 F5 35 (10)チューニングの実施 ●チューニング Untrust BotをBlockする設定を追加し、適⽤してください。 apiVersion: appprotect.f5.com/v1beta1 kind: APPolicy metadata: name: default-policy spec: policy: name: default-policy template: name: POLICY_TEMPLATE_NGINX_BASE bot-defense: mitigations: classes: - name: untrusted-bot action: block こちらを追加します。 default-policy.yaml 適⽤後再度curlでアクセスし、ブロックされることを確認します。 # curl http://yy.yy.yy.yy/dvwa/login.php <html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.<br><br>Your support ID is: 17145546028604397486<br><br><a href='javascript:history.back();'>[Go Back]</a></body></html> Kibana上でもブロックとしてカウントされています。 blockをalermにするか、追加部分を 削除することでもとにもどります。
  • 36.