KONGとは
公式読めってのはおいといて
噛み砕いて説明すると
- マイクロサービスを構築する時のAPI Gatewayとなるもの
- リバプロの役割をしてリクエストを各APIに振り分けるよ
- pluginで認証や流量制限、ログ取りもできるよ
- kong本体もクラスタ化できるし、APIもアグリゲーションできるよ
- API GatewayみたいのがないとたくさんAPIサービス作るとわけわかんなくなっちゃうよ
- 実際はnginxの拡張モジュールのようなものでAPIを経由してnginxの設定に反映してくれる感じ
つまり色々な言語で実装されたAPIサービスの総合窓口。
KONG配下にAPIサービス群を置いてあとはfrontendでもcurlでも好きに叩けば?
くらいの構成にできそう
KONG以外だとcloud系でAWS API GatewayとかAzureのAPI ManagementとかGoogle Cloud Endpointsがあるみたい
あとは自力でApacheとかNginxとかでリバプロするとか
(これだと認証を別途自作or用意する必要があるけど)
API発行あたりの従量課金の仕組みとかを考えててAPI Gatewayの必要性にたどり着いたので試してみる
インストール
公式のinstallガイドにいろいろあるのだけれど今回はEC2のAmazon Linuxに入れる
KONG用の管理DBはCassandraかPostgresが選択できる
馴染みのPostgresでやってみる
EC2用意
Amazon Linuxをとにかく用意した
elastic IPでIPを固定
セキュリティグループで以下のportをインバウンド許可した
- 5432 - postgres
- 80 - ユーザ用api(http)*1
- 443 - ユーザ用api(https)*1
- 8001 - admin用api(http) *2
- 8443 - ユーザ用api(https) *2
*1 kongのデフォルトユーザAPIは8000と8443だが後述するkongのconf設定で80と443に変更するので。
*2 通常はadmin用APIを公開しちゃいけない。今回試す用に空けた
sshで接続して以下を操作
root password設定
sudo su -
passwd
yum 設定
# yum -y install yum-cron
# vi /etc/yum/yum-cron.conf
apply_updates = yes ← ダウンロード&アップデートを自動で行うようにする
# service yum-cron start
# chkconfig --add yum-cron
# chkconfig yum-cron on
# yum install -y git
root宛メールを転送設定
# sed -i '/^root:/d' /etc/aliases
# echo "root: xxxx@xxx.xx.xx" >> /etc/aliases
# newaliases
Postgres用意
過去の遺産を使ってソースからインストール
もちろんそんなことしないでもpostgresさえ動いていればKONGはOK
(もっと言えばRDSでもいい)
依存ライブラリのインストール
# yum install -y readline-devel zlib-devel gcc uuid uuid-devel
インストール先フォルダの作成
# mkdir -p /usr/local/postgresql_kong/data
OSユーザにpostgresを追加
# useradd postgres
インストール先フォルダのownerをpostgresに
# chown postgres:postgres -R /usr/local/postgresql_kong
パッケージダウンロードと配置
# wget "https://ftp.postgresql.org/pub/source/v9.6.2/postgresql-9.6.2.tar.gz"
# mkdir /usr/local/src/postgresql
# mv postgresql-9.6.2.tar.gz /usr/local/src/postgresql
# cd /usr/local/src/postgresql/
# tar xvfz postgresql-9.6.2.tar.gz
# cp -pr postgresql-9.6.2 postgresql_kong
postgresqlのmake
過去の遺産でuuidやらcontribやらも入れちゃってる
KONGでは使わないと思うけど面倒なのでそのまま
→KONGをpostgresで動かしたらuuidを使っていたので
postgresをソースからインストールする場合はこの手順通り
uuidを入れてやる必要がある
# cd /usr/local/src/postgresql/postgresql_kong
# ./configure -prefix=/usr/local/postgresql_kong -with-pgport=5432 --with-uuid=ossp
# make && make install
# cd /usr/local/src/postgresql/postgresql_kong/contrib/pgcrypto
# make && make install
# cd /usr/local/src/postgresql/postgresql_kong/contrib/uuid-ossp
# make && make install
switch to postgres
# su - postgres
initdb
$ cd /usr/local/postgresql_kong/bin/
$ ./initdb -D /usr/local/postgresql_kong/data/
exit postgres
$ exit
postgresql.conf
# cp -p /usr/local/postgresql_kong/data/postgresql.conf /usr/local/postgresql_kong/data/postgresql.conf.org
# vi /usr/local/postgresql_kong/data/postgresql.conf
listen_addresses = '*'
port=5432とか、コメントアウトするだけ
log_line_prefix = '<%t %u %d>'
pg_hba.conf
# cp -p /usr/local/postgresql_kong/data/pg_hba.conf /usr/local/postgresql_kong/data/pg_hba.conf.org
# vi /usr/local/postgresql_kong/data/pg_hba.conf
host kong kong 0.0.0.0/0 md5
起動スクリプト作成
# cd /usr/local/src/postgresql
# cp -p postgresql_kong/contrib/start-scripts/linux postgresql_kong.sh
# vi postgresql_kong.sh
prefix=/usr/local/pgsql
↓
prefix=/usr/local/postgresql_kong
PGDATA="/usr/local/pgsql/data"
↓
PGDATA="${prefix}/data"
起動スクリプトに実行権をつける
# chmod +x postgresql_kong.sh
起動スクリプトをサービスに登録
# ln -s /usr/local/src/postgresql/postgresql_kong.sh /etc/init.d/postgresql_kong
# service postgresql_kong start
# chkconfig --add /etc/init.d/postgresql_kong
# chkconfig postgresql_kong on
KONG用のPostgresデータベースの作成
# ln -s /usr/local/postgresql_kong/lib/libpq.so.5 /usr/lib64/libpq.so.5
# /usr/local/postgresql_kong/bin/psql -U postgres
CREATE ROLE kong WITH LOGIN SUPERUSER PASSWORD 'kong';
CREATE DATABASE "kong" WITH OWNER = kong ENCODING = 'UTF8';
KONGのインストール
wget https://github.com/Mashape/kong/releases/download/0.10.0/kong-0.10.0.aws.rpm
yumから簡単に。
yum install epel-release
yum install kong-0.10.0.aws.rpm --nogpgcheck
KONGの起動
kong start
Kong started
と出ればOK
postmanから動作していることを確認
KONGの設定
Configファイルの編集
kongのconfigは/etc/kong/kong.conf
で変更できる
nginxあたりの設定もここで。
configファイルの作成
インストール時に用意される/etc/kong/kong.conf.default
をコピーして使う
cp -p /etc/kong/kong.conf.default /etc/kong/kong.conf
ユーザ利用ポートの変更
デフォルトだと8000/8443になっているのを80/443に変更する
#proxy_listen = 0.0.0.0:8000
↓
proxy_listen = 0.0.0.0:80
#proxy_listen_ssl = 0.0.0.0:8443
↓
proxy_listen_ssl = 0.0.0.0:443
SSL関連
certを設定するのは以下の箇所(今回は飛ばす)
#ssl_cert =
#ssl_cert_key =
#admin_ssl_cert =
#admin_ssl_cert_key =
postgres関連
以下の箇所で設定できる(今回変更なし)
#database = postgres
#pg_host = 127.0.0.1
#pg_port = 5432
#pg_user = kong
#pg_password = kong
#pg_database = kong
#pg_ssl = off
#pg_ssl_verify = off
KONGに反映
kong reload
APIと認証
簡単なAPIの追加
とりあえずyahooにproxyする例
apiはport8001の/apiに対してpostすることで追加できる
渡せるパラメータは公式docを参照
postmanだとこんな感じ
これでブラウザから http://[kong host]/demo/yahoo
にアクセスするとyahooにproxysされることが確認できる
api key認証が必要なAPIの追加
kongにはいくつかの認証pluginがある
これを登録するAPI名毎に割り当てることができる
APIを作成
まずmock apiをmockbinを利用して作成
次にkongにAPIを作成
uriは /key-auth/mockbin
にした
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=mockbin&upstream_url=http://mockbin.org/bin/e3edb608-40fd-465f-bc2a-854559e55dde&uris=/key-auth/mockbin' "http://[kong host name]:8001/apis"
続いてAPIを実行
curl -X GET -d '' "http://[kong host name]/key-auth/mockbin"
これでJSONが返ってきていることを確認する
作成したAPIにkey-authを付与
認証を付与したいAPIに向けて以下のようにPOSTする
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=key-auth' "http://[kong host name]:8001/apis/mockbin/plugins/"
POST先のURLは /apis/[対象のAPI name or id]/plugins/
パラメタに name=key-auth
を入れることで
key-authプラグインが該当API(今回はmockbin)に対して適用される
この状態でもう一度APIに対してGETすると401になる
ユーザの作成
key-authを通過させる為のユーザを作成
KONGではconsumers
と呼んでいる
ユーザ作成は以下のように実行する
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'username=testuser&custom_id=A01001' "http://[kong host name]:8001/consumers/"
custom_idは任意設定。後で自力でRDBなどとの紐付けに使うkeyを入れる用途。
ユーザにAPI KEYを発行
key-authに必要なAPI KEYをユーザに対して発行する
URIは/consumers/[対象ユーザのname or id]/key-auth/
BODYにkey=[任意のAPI KEY名]
を設定してPOSTする
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'key=SAMPLE-KEY' "http://[kong host name]:8001/consumers/testuser/key-auth/"
API KEYを使ってAPIを発行する
http headerに apikey
という名前で発行したKEY値を設定しAPIを発行することで実行できる
curl -X GET -H "apikey: SAMPLE-KEY" "http://[kong host name]/key-auth/mockbin"
key値が間違っている場合403
key値が設定されていない場合401
oauth2.0認証が必要なAPIの追加
oauth2.0の色々なflowでいってみる
SSL適用
KONGのOAuth2.0を試すにはhttps通信が必要
certbotを使ってcertを取得する
(事前にpublic DNS解決が必要)
cert取得までは本題から外れるのでメモだけ残す
# kong stop
# yum install httpd
# service httpd start
# yum install python27-devel git
# easy_install pip
# pip install --upgrade pip
# pip install --upgrade virtualenv
# git clone https://github.com/certbot/certbot
# cd certbot
# ./certbot-auto certonly --webroot -w /var/www/html -d xxxx.example.co.jp --agree-tos -m xxxxx@example.co.jp --debug
# service httpd stop
# kong start
/etc/letsencrypt/live/[host name]
の配下にcertが作成されるので
これをkong.confに設定する
vi /etc/kong/kong.conf
ssl_cert = /etc/letsencrypt/live/[host name]/cert.pem
ssl_cert_key = /etc/letsencrypt/live/[host name]/privkey.pem
設定をkongに反映
kong reload
これでhttpsでアクセスできることを確認
apiの作成
mockbinでapi mockを作成
APIをKONGに登録
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=mockbin-oauth&upstream_url=http://mockbin.org/bin/2e884bd8-5b08-49c7-93bf-69a513f87739&uris=/test-oauth2/mockbin' "http://[kong host name]:8001/apis"
apiにoauth2.0を適用
code flow, password, client credentials, implicit flowを有効にした
scopeもemail phone addressと登録してみた
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=oauth2&config.scopes=email%2C phone%2C address&config.enable_authorization_code=true&config.mandatory_scope=true&config.token_expiration=7200&config.enable_client_credentials=true&config.enable_implicit_grant=true&config.enable_password_grant=true&config.hide_credentials=false' "http://[kong host name]:8001/apis/mockbin-oauth/plugins/"
適用した時のresponse内にprovision_key
が含まれている。
code flowの場合、provision_key
が必要になるのでメモっておく
もしくは
[kong host]:8001/apis/[api-name]/plugins
をGETして確認
作成されるoauth2.0 endpointは以下の2つ
(両方ともPOSTのみ)
/oauth2/authorize
/oauth2/token
ユーザの作成
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'username=oauthuser&custom_id=A01002' "http://[kong host name]:8001/consumers"
oauth applicationの作成
作成したconsumersに紐付ける形になる
postmanで確認したかったのでredirect_uri
はpostman用のcallbackを登録した
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=oauth-trial-application&client_id=oauth-trial-application&client_secret=secret&redirect_uri=https://www.getpostman.com/oauth2/callback' "http://[kong host name]:8001/consumers/oauthuser/oauth2"
Access Tokenの取得
Auth Url: https://[your kong host]/test-oauth2/mockbin/oauth2/authorize
Access Token Url: https://[your kong host]/test-oauth2/mockbin/oauth2/token
にリクエストを投げる。
URL上、endpointとなる/oauth2/authorize
や /oauth2/token
の前に各APIのPATHが入ることに注意
client credentials
いつもどおりに投げるだけでOK
直接投げるならこんな感じ
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&client_secret=secret&grant_type=client_credentials&scope=email' "https://[your kong host]/test-oauth2/mockbin/oauth2/token"
code flow
KONGのpluginにあるcode flowはprovision_key
が必要になったりするので特殊かも?
codeの取得
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&client_secret=secret&response_type=code&scope=email&provision_key=[oauthをapiにセットした時のprovision_key]&authenticated_userid=oauthuser' "https://[your kong host]/test-oauth2/mockbin/oauth2/authorize"
上記のとおり、provision_key
が必要になる。
それとauthenticated_userid
というkeyがありここに認証済みの個人IDを放り込むとのこと。
イメージとしては事前にログインID/パスワードで認証を行い、次にAPI認可として
認証済みIDを入れてcodeを取得しに行く感じか。
ちなみに成功時のレスポンスはこんな感じ
{
"redirect_uri": "https://www.getpostman.com/oauth2/callback?code=0b621f05c59b474191394040f4444267"
}
APIにOauthを設定した時、redirect_urlに指定したとこにcode付きで戻っていく。
codeをtokenにexchange
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&client_secret=secret&grant_type=authorization_code&code=0b621f05c59b474191394040f4444267' "https://[your kong host]/test-oauth2/mockbin/oauth2/token"
成功時のレスポンスはこんな感じ
{
"refresh_token": "95a8bc4570f94ecf90dbe0fe451a3ed3",
"token_type": "bearer",
"access_token": "0e76c1fd21164f289c8f74daf49d5bf5",
"expires_in": 7200
}
implicit flow
code flowができてれば簡単
response_type = tokenの場合
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&response_type=token&scope=email&provision_key=96b48acff71a4fe8a198a1771a7ffc9c&authenticated_userid=oauthuser&grunt_type=implicit' "https://[your kong host]/test-oauth2/mockbin/oauth2/authorize"
レスポンス
{
"redirect_uri": "https://www.getpostman.com/oauth2/callback#access_token=582c503605ee4e89a0c45e2b113eef83&expires_in=7200&token_type=bearer"
}
response_type = codeの場合
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&response_type=code&scope=email&provision_key=96b48acff71a4fe8a198a1771a7ffc9c&authenticated_userid=oauthuser&grunt_type=implicit' "https://[your kong host]/test-oauth2/mockbin/oauth2/authorize"
レスポンス
{
"redirect_uri": "https://www.getpostman.com/oauth2/callback?code=ec6e23952c2c4b5d9f5ab4d03ab9b9a4"
}
resource owner password credentials
これもcode flowと同じ感じで事前にログインIDとパスワードで認証済み前提。
認証が済んだらkongにPOSTしてtokenをもらう感じ。
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&client_secret=secret&scope=email&provision_key=96b48acff71a4fe8a198a1771a7ffc9c&authenticated_userid=anystring&username=anystring&password=anystring&grant_type=password' "https://[your kong host]/test-oauth2/mockbin/oauth2/token"
当たり前といえばそうだけどkong側に渡している
authenticated_userid
username
password
は検証されない。
username
とpassword
に関しては省略してもOK
refresh_token
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=oauth-trial-application&client_secret=secret&grant_type=refresh_token&refresh_token=08ff72351d5740d59259995ca258affc' "https://[your kong host]/test-oauth2/mockbin/oauth2/token"
成功時のレスポンスはこんな感じ
{
"refresh_token": "2a122910eddb43c0bb9d7d78f0fda5b6",
"token_type": "bearer",
"access_token": "8770f201c00a495a99e66a2f9fb2023a",
"expires_in": 7200
}
JWT認証が必要なAPIの作成
apiの作成
mockbinでapi mockを作成
APIをKONGに登録
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=mockbin-jwt&upstream_url=http://mockbin.org/bin/f8090f01-3a0f-418c-b516-18a3df0498ba&uris=/test-jwt/mockbin' "http://[kong host name]:8001/apis"
apiにjwt pluginを適用
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=jwt&config.uri_param_names=jwt&config.claims_to_verify=exp&config.key_claim_name=iss&config.secret_is_base64=false' "http://[kong host name]:8001/apis/mockbin-jwt/plugins/"
パラメータについて補足
parameter | 説明 | 設定例 |
---|---|---|
config.uri_param_names | jwtをqueryで渡す時のkey名 | jwt |
config.claims_to_verify |
exp かnbf を指定できる。expなら有効期限超過、nbfなら有効期限前かのチェックをする(多分) |
exp,nbf |
config.key_claim_name | 後で発行するcredentialsのkeyに設定した値を格納するkey名。通常issにしておく | iss |
config.secret_is_base64 | credentialsのsecretをbase64するかどうか。secretがbynaryの場合。通常false | false |
consumersの作成
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'username=jwtuser&custom_id=A01003' "http://[kong host name]:8001/consumers"
JWT credentialsの作成
parameter | 説明 | 設定例 |
---|---|---|
key | JWT発行時にissに設定する名前と同じものを設定する | oauth-server |
algorithm | 暗号化アルゴリズム RS256, HS256, ES256が選べる | RS256 |
rsa_public_key | 公開鍵 RS256なら -----BEGIN PUBLIC KEY----- から 省略時自動生成 |
下記参照 |
secret | HS256, ES256の時のseacret文字列、省略時自動生成 | 下記参照 |
rsa_public_key
とsecret
はurl-encodeして[[]]
でくくって送信する
postmanからだとうまく叩けなかった
公開鍵と秘密鍵を入れるのはコツがいる模様
参考
curlで叩くイメージは以下のような感じ
curl -X POST "http://[kong host name]:8001/consumers/jwtuser/jwt" --data-urlencode "key=oauth-server" --data-urlencode "algorithm=RS256" --data-urlencode "rsa_public_key=
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvc6AuzxgawTudoGXChgl
.....
0MYRedkNsYab1kpSYYyDxlhP6H/l0saI817z9U8PPasjBSahllPQxnJJceojh3SC
BQIDAQAB
-----END PUBLIC KEY-----
"
または直接鍵ファイルを送る指定も可能(multipartになる)
curl -X POST http://[kong host name]:8001/consumers/{consumer}/jwt \
-F "rsa_public_key=@/path/to/public_key.pem" \
APIの実行
残念ながらKONGにはJWT発行機能がない模様。
別の認証サーバ等で発行したJWTを使って試す
この時、発行したJWT内は以下の条件を満たす必要がある
- 秘密鍵・公開鍵のキーペアにて暗号化されていること
- kongにJWT pluginを追加した時、
config.key_claim_name
に指定したkey名のclaimがあること(例ではiss
) - 上記claimの値がkongにJWT credentialsを登録した時に
key
に指定した値がセットされていること
これはKONG側でJWTの検証時に公開鍵の検証+αの要素として検証される模様。
通常はJWT発行側でセットされるiss
の値を予め入手(決定)しておき
KONG側でJWT pluginの追加、JWT credentialsの追加の時にセットしていく感じ
APIを実行する場合はBearerにJWTを設定して実行すればOK
curl -X GET -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzcHJpbmctb2F1dGgtc2VydmVyLXN1YiIsImF1ZCI6WyJzcHJpbmctYm9vdC1hcHBsaWNhdGlvbiJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbInJlYWQiXSwiaXNzIjoic3ByaW5nLW9hdXRoLXNlcnZlci1pc3MiLCJleHAiOjE0OTMyNjI1ODYsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwianRpIjoiNjJhZTU1MmUtYWNlNy00ZWI4LWExY2YtNWYxOTIxZTUyMDY1IiwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSIsImNsaWVudF9pZCI6InB1YmxpYyJ9.XLOETjeE9Ud9pnAx6ChYryd8yeiqCEd8KPJLlS_9-U62YkvrTFVfqQdI8-JhbWWEVvW76B1TWLMUfLZ--X4NACkLOeKokXtBKpEsJ9Y-nbiyiRum-ysb8w819csTW9kV6mT70ZEwT5b_1Mo9jdRpxEPPZM1hMfSpwN50W9exZFZ4vn_vTba6JFQBQt4p_OvVqfdmsLrPIAlSYtB13100TY0CVHdLWpDxwjbhJPPcF6TVhgdJlpqjyEY5NXUzRv3A6RUfAD5NhZxWrgnZTVN_Jlnu1GVkuN3oCqj_1tuGYdMF6YPb4ToT344Xu1Qq4cHgMPYF2ns3xKD4U3w3lkNppw" "http://[kong host name]/test-jwt/mockbin"
補足
KONG上でJWT認証後、APIサーバ側にproxyする際以下の情報がHeaderに埋め込まれる
- X-Consumer-ID
- X-Consumer-Custom-ID(設定されている場合)
- X-Consumer-Username(設定されている場合)
- X-Anonymous-Consumer(認証されていない場合、trueが入る)
セキュリティ系のplugin
ACL
だいたい概要は以下のような感じ
- KONG登録済みのAPI毎に設定
- consumersにgroupを設定し、APIに対してgroupの利用可・不可を設定する
- ACLとは別にconsumersを特定するための認証pluginの設定も必要(今回key-authで実施したがOAuth, JWTでもいけるはず)
- whitelistに入っていない or blacklistに入っている consumerの場合、403 forbiddenで返る
以下試した結果
ACLを試す用のAPIを作成
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=test-acl&upstream_url=http://mockbin.org/bin/4ed664ea-cf51-4f0e-89ad-a8f86c3f8841&uris=/test-acl/mockbin' "http://[kong host name]:8001/apis"
consumersの追加
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'username=acltest&custom_id=A01005' "http://[kong host name]:8001/consumers"
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'username=acltest2&custom_id=A01006' "http://[kong host name]:8001/consumers"
apiにkey-authを適用
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=key-auth' "http://[kong host name]:8001/apis/test-acl/plugins/"
consumersにkey-authのkeyを発行
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'key=acltest-key' "http://[kong host name]:8001/consumers/acltest/key-auth/"
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'key=acltest2-key' "http://[kong host name]:8001/consumers/acltest2/key-auth/"
consumersにgroupを追加
/consumers/[consumer name]/acls
に対してPOSTする
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'group=group1' "http://[kong host name]:8001/consumers/acltest/acls"
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'group=group2' "http://[kong host name]:8001/consumers/acltest2/acls"
APIにACLを適用する
group1をwhitelistに入れる。
なおwhitelistとblacklistはどちらかしか指定できない。
また複数のグループを指定する場合はvalueをカンマ区切りで入れる
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=acl&config.whitelist=group1' "http://[kong host name]:8001/apis/test-acl/plugins"
APIをkey-auth利用して実行する
whitelistに入っているgroupに属するconsumerの場合→OK
curl -X GET -H "apikey: acltest-key" "http://[kong host name]/test-acl/mockbin"
whitelistに入っていないgroupに属するconsumerの場合→403 forbidden
curl -X GET -H "apikey: acltest2-key" "http://[kong host name]/test-acl/mockbin"
CORS
CORS用ヘッダーもKONGでつけることができる
APIに対して設定する感じ(未検証だがほぼこのままのはず)
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=cors&config.origins=mockbin.com&config.methods=GET%2C POST&config.headers=Accept%2C Accept-Version%2C Content-Length%2C Content-MD5%2C Content-Type%2C Date%2C X-Auth-Token&config.exposed_headers=X-Auth-Token&config.credentials=true&config.max_age=3600' "http://[kong host name]:8001/apis/test-acl/plugins"
2017/3/28 0.10.1 updateにより
config.origin
パラメータがconfig.origins
になり複数(カンマ区切り)が可能になっている
CORS pluginの制限事項
apiをuri指定している時のみCORS plugingが使える
apiをhosts指定している時は使えない
IP制限 plugin
APIに対して設定する
未実施だがきっとこのままなのでとりあえず公式をコピーしておく
curl -X POST http://[kong host name]:8001/apis/{api}/plugins \
--data "name=ip-restriction" \
--data "config.whitelist=54.13.21.1, 143.1.0.0/24"
なお、同時にconsumer_idをパラメタに渡すことで特定のconsumerに限ることも可能らしい。
(当然認証pluginの併用が必要)
bot制限plugin
ruleに則ってbotからのリクエストをはじくplugin
デフォルトで有名なbotはルールに登録されている デフォルトルール
ルールの追加はconfig.whitelist
かconfig.blacklist
にUser-Agentヘッダーの文字(正規表現可能)を指定することでカスタマイズできる
これも公式をコピーだけ
curl -X POST http://kong:8001/apis/{api}/plugins \
--data "name=bot-detection"
Traffic系のplugin
Rate Limiting plugin
- 流量制限のplugin
- API毎に設定
- 年・月・日・時・分・秒毎に最大アクセス回数を指定できる
- consumer_idを一緒に設定することでconsumer毎に設定できる
- これにより1日100アクセス等の制御が簡単で課金対象¥に使える(かも)
- 設定値を超えたアクセスがあった場合は429で返却する
- 残り何回かはResponseのHttp Headerに返却されるので確認できる
なお、カウンターのためのポリシーが3つ用意されている
- cluster : datastoreを使ってKONGの他ノードと共有(おすすめ)
- local : localメモリーでカウント、クラスタリングしていると別々カウント
- redis : 別途redisを立ち上げる必要がある。他で多重化したredisがあれば使うかも?
curl -X POST http://kong:8001/apis/{api}/plugins \
--data "name=rate-limiting" \
--data "config.second=5" \
--data "config.hour=10000"
設定できるconfig値の説明
key | 説明 |
---|---|
name |
rate-limiting 固定 |
consumer_id | 省略可、指定する場合認証pluginの併用が必要 |
config.second | 最大アクセス数を指定 |
config.minute | 最大アクセス数を指定 |
config.hour | 最大アクセス数を指定 |
config.day | 最大アクセス数を指定 |
config.month | 最大アクセス数を指定 |
config.year | 最大アクセス数を指定 |
config.limit_by | consumer, credential, ipが選択できる。指定した対象がlimit overした時にエラーとする。consumer, credentialがわからない場合は自動的にipになる |
config.policy | local or cluster or redis ※上記説明参照 |
config.fault_tolerant | trueにするとdatastoreが動いていない場合、rate limitは通過するようになる。falseにするとすぐさま500で返す |
config.redis_host | config.policyがredisの場合に指定 |
config.redis_port | config.policyがredisの場合に指定 |
config.redis_password | config.policyがredisの場合に指定 |
config.redis_timeout | config.policyがredisの場合に指定 |
config.redis_database | config.policyがredisの場合に指定 |
Responseの Http Headerに返却される残り回数は以下のようになる
X-RateLimit-Limit-Second: 5
X-RateLimit-Remaining-Second: 4
X-RateLimit-Limit-Minute: 10
X-RateLimit-Remaining-Minute: 9
Request Size Limiting
リクエストのサイズ制限をするplugin
DOS攻撃を防ぐ意味でも全APIへの適用が推奨されている
curl -X POST http://[kong host name]:8001/apis/{api}/plugins \
--data "name=request-size-limiting" \
--data "config.allowed_payload_size=128"
config.allowed_payload_size
に指定する単位はMb。
また、上記例にはないがconsumer_id
も追加することができる
Logging系のplugin
Logの出力先毎にpluginが分かれている
plugin | 説明 |
---|---|
TCP | TCPでログを送信する ログはJSON形式 |
UDP | UDPでログを送信する ログはJSON形式 |
HTTP | HTTP(POSTなど)でログを送信する ログはJSON形式 |
FILE | ファイルにログを出力する ログはJSON形式 |
SYSLOG | syslogにログを出力する ログはJSON形式 |
StatsD | Collectdにログを出力する Statsd plugin形式 |
Loggly | UDPでLogglyにログを出力する |
いずれも他logサービスとの連携が前提
とりあえずFILE出力だけ試す
curl -X POST http://[kong host name]:8001/apis/{api}/plugins \
--data "name=file-log" \
--data "config.path=/tmp/kong-file.log"
APIを実行するとその都度指定したファイルへJSON形式のログが出力された
Transform系のPlugin
リクエスト・レスポンスの内容を加工するplugin
Request Transformer
リクエストのheader, body, queryについてパラメータをadd, removeできる
Response Transformer
レスポンスのheader, body, queryについてパラメータをadd, removeできる
若干のjsonの加工(追加、削除くらい)もできるみたい
→parseして加工になるのでレスポンス・リソース影響あり
Correlation ID
リクエスト(とレスポンス)にUUID等のユニークなIDをHeaderに追加する
ログ等でリクエスト単位のユニークIDが確認できるようになる(使いみち?)
KONGのクラスター化
KONGを複数nodeにして(データストアは同じ)運用する場合
以下のクラスタ設定をしなくてはいけない
公式に記載があるとおり、複数node化した際にクラスタ化をしないとシンクロされないデータが発生し問題につながるとのこと
クラスタ化の設定自体は簡単だが、各nodeがネットワーク上同一セグメント内に属していない場合はIPv4にて特定できる必要がある(NAT等を通さない、NATしている場合post7946のフォワーディングが必要(未検証))
今回は別のEC2にKONGをインストールし、IPも別のものを立てて試す
またあくまでKONG間の整合を取るだけの機能で、node間のロードバランシング等は別途用意しておく必要がある
クラスタ化設定
port7946の開放
全ノードでport7946での疎通ができるようにする
今回はEC2のセキュリティグループにてport7946を許可(全ノード)
別EC2にKONGをインストール
上述した手順どおり、datastore(postgres)は不要、kong startする前に
以下のとおりkong.confを設定する
- データストア(postgres)は全ノード同じものを指す
-
cluster_advertise
に[自サーバのip(基本private ipでないもの)]:7946 を設定する→全ノードのkong.confに設定 -
kong start
で反映(全ノード)、既に稼働しているkongはkong restart
-
kong reload
では反映しない
-
クラスタ化されているか確認
kong cluster reachability
で以下のように全ノードを確認できる
Total members: 2, live members: 2
Starting reachability test...
Successfully contacted all live nodes
またkong cluster members
で一覧と状態を確認できる
ip-172-31-10-200_0.0.0.0:7946_b5bfea301c864406bc0b4878dfe2e104 xxx.xxx.xxx.xxx:7946 alive
ip-172-31-5-21_0.0.0.0:7946_b3ad232a0795474786bc9c7522ab0650 xxx.xxx.xxx.xxx:7946 alive
つまりどころ
KONGのログはどこ
/etc/kong/kong.conf
の中の prefix
で指定しているパスが
KONGのディレクトリとなる(デフォルトだと /usr/local/kong
)
KONGディレクトリ配下のlogs配下にログが出力される
DNSエラー
通常のDNS解決できないリモートホストへ接続する時、KONGインストールOSの
/etc/hosts
などを利用する場合→hosts編集後にKONG再起動が必要
/etc/hosts
を修正したあとKONGの再起動をしないとKONGからはDNSエラーのまま
Cookieを使うサイトの場合
apiを追加する際に preserve_host
をtrueに設定しておく
でないとupstream側のURLで発行したcookieが
クライアントに返却されてしまう