NICによるWebアプリの通信制御
この章では、実際にデプロイしたNGINX Ingress Controllerを使い、様々なサンプルアプリケーションを動作させ、その設定方法や動きを確認いただきます。 設定例は NGINX Inc GitHubの examples/custom-resources/ に管理されております
シンプルなWebアプリケーションのデプロイ
シンプルなWebアプリケーションをデプロイします。 Kubernetes環境で、Webアプリケーションをデプロイします。そのアプリケーションに対し通信制御を行うVirtualServer、及びHTTPSに必要な証明書をデプロイします。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/basic-configuration/
kubectl create -f cafe.yaml
kubectl create -f cafe-secret.yaml
kubectl create -f cafe-virtual-server.yaml
リソースを確認
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get pod
1 2 3 4 | NAME READY STATUS RESTARTS AGE coffee-7c86d7d67c-wjxss 1/1 Running 0 1m coffee-7c86d7d67c-8jm9z 1/1 Running 0 1m tea-5c457db9-dc4cs 1/1 Running 0 1m |
kubectl get deployment
1 2 3 | NAME READY UP-TO-DATE AVAILABLE AGE coffee 2/2 2 2 1m tea 1/1 1 1 1m |
kubectl get secret | grep cafe-secret
1 | cafe-secret kubernetes.io/tls 2 1m |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE cafe Valid cafe.example.com 94s |
動作確認
curlコマンドでリクエストを送信します。作成したWebアプリケーションから応答があることを確認します。 /coffee
、 /tea
というURLに応じて異なるアプリケーションに転送されていることが確認できます
curl -H "Host:cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.25:8080 Server name: coffee-7c86d7d67c-wjxss Date: 17/Jan/2022:00:14:03 +0000 URI: /coffee Request ID: 069567120c306da6f92e16e5d73e5040 |
curl -H "Host:cafe.example.com" http://localhost/tea
1 2 3 4 5 | Server address: 192.168.127.20:8080 Server name: tea-5c457db9-dc4cs Date: 17/Jan/2022:00:14:08 +0000 URI: /tea Request ID: 6fd58877d9e85903300df7ceb0f81eb2 |
同様に、HTTPSの接続を確認します。
curl -kv -H "Host:cafe.example.com" https://localhost/coffee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | * Trying 127.0.0.1:443... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=NGINXIngressController * start date: Sep 12 18:03:35 2018 GMT * expire date: Sep 11 18:03:35 2023 GMT * issuer: CN=NGINXIngressController * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET /coffee HTTP/1.1 > Host:cafe.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.21.3 < Date: Mon, 17 Jan 2022 00:14:34 GMT < Content-Type: text/plain < Content-Length: 164 < Connection: keep-alive < Expires: Mon, 17 Jan 2022 00:14:33 GMT < Cache-Control: no-cache < Server address: 192.168.127.26:8080 Server name: coffee-7c86d7d67c-8jm9z Date: 17/Jan/2022:00:14:34 +0000 URI: /coffee Request ID: 3af5bd62d9756c934b4c731d0cadfcb1 * Connection #0 to host localhost left intact |
curl -kv -H "Host:cafe.example.com" https://localhost/tea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | * Trying 127.0.0.1:443... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=NGINXIngressController * start date: Sep 12 18:03:35 2018 GMT * expire date: Sep 11 18:03:35 2023 GMT * issuer: CN=NGINXIngressController * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET /tea HTTP/1.1 > Host:cafe.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.21.3 < Date: Mon, 17 Jan 2022 00:14:39 GMT < Content-Type: text/plain < Content-Length: 156 < Connection: keep-alive < Expires: Mon, 17 Jan 2022 00:14:38 GMT < Cache-Control: no-cache < Server address: 192.168.127.20:8080 Server name: tea-5c457db9-dc4cs Date: 17/Jan/2022:00:14:39 +0000 URI: /tea Request ID: af1466d1fc1b7481cb82352885f9cbc2 |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/basic-configuration/
kubectl delete -f cafe-secret.yaml
kubectl delete -f cafe-virtual-server.yaml
kubectl delete -f cafe.yaml
複数アプリケーション・チームを想定した VS / VSR 設定
NGINX Ingress Controller はCRDを用い、Virtual Server / Virtual Server Router / Policy といったリソースを使うことで、権限と設定範囲を適切に管理することが可能です。
ここでは、通信を待ち受けるため cafe
namespace に、VirtualServer をデプロイします。そして tea
/ coffee
namespace に アプリケーションと、アプリケーション宛に通信を転送するための VirtualServerRoute をデプロイします。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/cross-namespace-configuration
kubectl create -f namespaces.yaml
kubectl create -f tea.yaml
kubectl create -f coffee.yaml
kubectl create -f tea-virtual-server-route.yaml
kubectl create -f coffee-virtual-server-route.yaml
kubectl create -f cafe-secret.yaml
kubectl create -f cafe-virtual-server.yaml
リソースを確認
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get ns --sort-by=.metadata.creationTimestamp
1 2 3 4 5 | NAME STATUS AGE **省略** coffee Active 75s cafe Active 75s tea Active 75s |
kubectl get vsr -A
1 2 3 | NAMESPACE NAME STATE HOST IP PORTS AGE coffee coffee Valid cafe.example.com 89s tea tea Valid cafe.example.com 93s |
kubectl get vs -A
1 2 | NAMESPACE NAME STATE HOST IP PORTS AGE cafe cafe Valid cafe.example.com 85s |
kubectl get secret -A | grep cafe
1 2 | cafe cafe-secret kubernetes.io/tls 2 101s cafe default-token-94nrl kubernetes.io/service-account-token 3 2m3s |
kubectl get secret -A | grep cafe-secret
1 2 | NAME TYPE DATA AGE cafe-secret kubernetes.io/tls 2 2m5s |
kubectl get pod -o wide -A|grep -e coffee -e tea
1 2 | coffee coffee-7c86d7d67c-pq5w2 1/1 Running 0 88s 192.168.127.22 ip-10-1-1-9 <none> <none> tea tea-5c457db9-h5sm9 1/1 Running 0 14m 192.168.127.24 ip-10-1-1-9 <none> <none> |
動作確認
curlコマンドでリクエストを送信します。作成したWebアプリケーションから応答があることを確認します。 /coffee
、 /tea
というURLに応じて異なるアプリケーションに転送されていることが確認できます
curl -H "Host: cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.22:8080 Server name: coffee-7c86d7d67c-pq5w2 Date: 17/Jan/2022:05:44:25 +0000 URI: /coffee Request ID: 1414627aac091b5a7897bac37d046cea |
curl -H "Host: cafe.example.com" http://localhost/tea
1 2 3 4 5 | Server address: 192.168.127.24:8080 Server name: tea-5c457db9-h5sm9 Date: 17/Jan/2022:05:44:29 +0000 URI: /tea Request ID: 698ab29da633f24a9bf5384c1499b056 |
同様にHTTPSの接続を確認します。HTTPSの結果は /tea
にアクセスした結果のみ掲載します。 /coffee
の結果も合わせて確認ください。
curl -vk -H "Host: cafe.example.com" https://localhost/tea
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | * Trying 127.0.0.1:443... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=NGINXIngressController * start date: Sep 12 18:03:35 2018 GMT * expire date: Sep 11 18:03:35 2023 GMT * issuer: CN=NGINXIngressController * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET /tea HTTP/1.1 > Host: cafe.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.21.3 < Date: Mon, 17 Jan 2022 05:44:42 GMT < Content-Type: text/plain < Content-Length: 156 < Connection: keep-alive < Expires: Mon, 17 Jan 2022 05:44:41 GMT < Cache-Control: no-cache < Server address: 192.168.127.24:8080 Server name: tea-5c457db9-h5sm9 Date: 17/Jan/2022:05:44:42 +0000 URI: /tea Request ID: 8ec25fd33d381df7261fda9f9da66558 * Connection #0 to host localhost left intact |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/cross-namespace-configuration]
kubectl delete -f tea-virtual-server-route.yaml
kubectl delete -f cafe-virtual-server.yaml
kubectl delete -f coffee-virtual-server-route.yaml
kubectl delete -f cafe-secret.yaml
kubectl delete -f tea.yaml
kubectl delete -f coffee.yaml
kubectl delete -f namespaces.yaml
通信内容による条件分岐・サービスへの転送
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/advanced-routing
kubectl create -f cafe.yaml
kubectl create -f cafe-virtual-server.yaml
リソースを確認
ポイントとなるファイルの内容を確認します。
cafe-virtual-server.yaml
で通信制御の条件を指定しています。条件は matches
というパラメータで指定します。このサンプルの条件は以下の内容です。
- path: /tea
- リクエストのHTTPメソッド($request_method)が、POSTの場合、
tea-post
へ転送する。 それ以外はtea
へ転送する。
- リクエストのHTTPメソッド($request_method)が、POSTの場合、
- path: /coffee
- cookie の version の値が v2 の場合、
coffee-v2
へ転送する。それ以外はcoffee-v1
へ転送する。
- cookie の version の値が v2 の場合、
それぞれの記述内容を以下で確認してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: cafe spec: host: cafe.example.com upstreams: - name: tea-post service: tea-post-svc port: 80 - name: tea service: tea-svc port: 80 - name: coffee-v1 service: coffee-v1-svc port: 80 - name: coffee-v2 service: coffee-v2-svc port: 80 routes: - path: /tea matches: - conditions: - variable: $request_method value: POST action: pass: tea-post action: pass: tea - path: /coffee matches: - conditions: - cookie: version value: v2 action: pass: coffee-v2 action: pass: coffee-v1 |
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get deployment
1 2 3 4 5 | NAME READY UP-TO-DATE AVAILABLE AGE coffee-v1 1/1 1 1 16s coffee-v2 1/1 1 1 15s tea 1/1 1 1 15s tea-post 1/1 1 1 15s |
kubectl get pod -o wide
1 2 3 4 5 | NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coffee-v1-6b78998db9-8cv49 1/1 Running 0 26s 192.168.127.23 ip-10-1-1-9 <none> <none> coffee-v2-748cbbb49f-mbxpr 1/1 Running 0 26s 192.168.127.27 ip-10-1-1-9 <none> <none> tea-5c457db9-dcswc 1/1 Running 0 26s 192.168.127.33 ip-10-1-1-9 <none> <none> tea-post-7db8cd8bf-m5gbz 1/1 Running 0 26s 192.168.127.32 ip-10-1-1-9 <none> <none> |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE cafe Valid cafe.example.com 28s |
動作確認
先程、設定ファイルから確認した条件を再度記載します。
- path: /tea
- リクエストのHTTPメソッド($request_method)が、POSTの場合、
tea-post
へ転送する。 それ以外はtea
へ転送する。
- リクエストのHTTPメソッド($request_method)が、POSTの場合、
- path: /coffee
- cookie の version の値が v2 の場合、
coffee-v2
へ転送する。それ以外はcoffee-v1
へ転送する。
- cookie の version の値が v2 の場合、
Curlコマンドで動作を確認します。
/tea
宛でHTTPメソッドを指定しない(GET)の場合の動作は以下の通りです
curl -H "Host: cafe.example.com" http://localhost/tea
1 2 3 4 5 | Server address: 192.168.127.33:8080 Server name: tea-5c457db9-dcswc Date: 17/Jan/2022:09:00:56 +0000 URI: /tea Request ID: 00e9eb4d61f7afdb8c5656da94d15b98 |
/tea
宛でHTTP POSTメソッドを指定した場合の動作は以下の通りです。
curl -H "Host: cafe.example.com" http://localhost/tea -X POST
1 2 3 4 5 | Server address: 192.168.127.32:8080 Server name: tea-post-7db8cd8bf-m5gbz Date: 17/Jan/2022:09:01:02 +0000 URI: /tea Request ID: 4deeb82434a6f799ffc894a229ac361a |
/coffee
宛でCookieの値を指定しない場合の動作は以下の通りです。
curl -H "Host: cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.23:8080 Server name: coffee-v1-6b78998db9-8cv49 Date: 17/Jan/2022:09:01:25 +0000 URI: /coffee Request ID: 8d182c9c060d5a4d4dec226292ac2820 |
/coffee
宛でCookieに”version=v2”と指定した場合の動作は以下の通りです。
curl -H "Host: cafe.example.com" http://localhost/coffee --cookie "version=v2"
1 2 3 4 5 | Server address: 192.168.127.27:8080 Server name: coffee-v2-748cbbb49f-mbxpr Date: 17/Jan/2022:09:01:35 +0000 URI: /coffee Request ID: befacc5e7ca56a1a09e5982315c74fa0 |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/advanced-routing
kubectl delete -f cafe-virtual-server.yaml
kubectl delete -f cafe.yaml
割合を指定した分散 (Traffic Split)
割合を指定し、トラフィックを分散することができます。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/traffic-splitting
kubectl create -f cafe.yaml
kubectl create -f cafe-virtual-server.yaml
Virtual Serverの内容を確認します。 cafe-virtual-server.yaml
の /coffee
に splits
を指定し、更に weight
でサービスへ転送する割合を指定しています。
リソースを確認
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get deployment
1 2 3 | NAME READY UP-TO-DATE AVAILABLE AGE coffee-v1 2/2 2 2 19s coffee-v2 2/2 2 2 19s |
kubectl get pod -o wide
1 2 3 4 5 | NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coffee-v1-6b78998db9-h4jkb 1/1 Running 0 25s 192.168.127.47 ip-10-1-1-9 <none> <none> coffee-v1-6b78998db9-nn42z 1/1 Running 0 25s 192.168.127.44 ip-10-1-1-9 <none> <none> coffee-v2-748cbbb49f-llpb6 1/1 Running 0 25s 192.168.127.45 ip-10-1-1-9 <none> <none> coffee-v2-748cbbb49f-vrpzx 1/1 Running 0 25s 192.168.127.46 ip-10-1-1-9 <none> <none> |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE cafe Valid cafe.example.com 26s |
動作確認
Curlコマンドで複数回リクエストを送ると、 coffee-v1
、 coffee-v2
のそれぞれに転送されていることが確認できます。
curl -s -H "Host: cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.44:8080 Server name: coffee-v1-6b78998db9-nn42z Date: 17/Jan/2022:12:26:49 +0000 URI: /coffee Request ID: c127f0f724eb1b3becd57603b6d603ea |
curl -s -H "Host: cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.45:8080 Server name: coffee-v2-748cbbb49f-llpb6 Date: 17/Jan/2022:12:26:37 +0000 URI: /coffee Request ID: 357237a3fea498b6efd90c929d526e64 |
以下コマンドを参考に複数回Curlを実行し、その結果をファイルに記録します。記録の内容より coffee-v1
に coffee-v2
転送した数を確認できます。
分散する割合は少しばらつきが発生しますが、参考として分散した数の結果を確認してください。
## cd ~/kubernetes-ingress/examples/custom-resources/traffic-splitting
> split.txt ;\
for i in {1..20}; \
do curl -s -H "Host: cafe.example.com" http://localhost/coffee | grep "Server name" >> split.txt ; \
done ; \
echo -n "v1:" ; grep v1 split.txt | wc -l ; echo -n "v2:" ; grep v2 split.txt | wc -l
1 2 | v1:18 v2:2 |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/traffic-splitting
kubectl delete -f cafe-virtual-server.yaml
kubectl delete -f cafe.yaml
rm split.txt
IPアドレスによる通信の制御 (Access Control)
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/access-control
Policyにより通信制御を行う方法を確認します。リクエストの送信元IPアドレスに応じて通信の許可・拒否を行う方法を確認します。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/access-control
kubectl apply -f webapp.yaml
kubectl apply -f access-control-policy-deny.yaml
kubectl apply -f virtual-server.yaml
リソースを確認
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get pod
1 2 | NAME READY STATUS RESTARTS AGE webapp-64d444885-j4q7z 1/1 Running 0 2m7s |
kubectl get deployment
1 2 | NAME READY UP-TO-DATE AVAILABLE AGE webapp 1/1 1 1 2m13s |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE webapp Valid webapp.example.com 2m8s |
kubectl get policy
1 2 | NAME STATE AGE webapp-policy Valid 2m18s |
VirtualServerに webapp-policy
が割り当てられていることが確認できます。
kubectl describe vs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | Name: webapp Namespace: default Labels: <none> Annotations: <none> API Version: k8s.nginx.org/v1 Kind: VirtualServer ** 省略 ** Spec: Host: webapp.example.com Policies: Name: webapp-policy Routes: Action: Pass: webapp Path: / Upstreams: Name: webapp Port: 80 Service: webapp-svc Status: External Endpoints: Ip: Ports: Message: Configuration for default/webapp was added or updated Reason: AddedOrUpdated State: Valid |
Spec
に記載されています。kubectl describe policy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Name: webapp-policy Namespace: default Labels: <none> Annotations: <none> API Version: k8s.nginx.org/v1 Kind: Policy ** 省略 ** Spec: Access Control: Deny: 10.0.0.0/8 Status: Message: Policy default/webapp-policy was added or updated Reason: AddedOrUpdated State: Valid Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal AddedOrUpdated 61s (x3 over 2m31s) nginx-ingress-controller Policy default/webapp-policy was added or updated |
動作確認
curlコマンドで動作を確認します。以下のように通信が 拒否
されていることが確認できます
curl -H "Host:webapp.example.com" http://localhost/
1 2 3 4 5 6 7 | <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.21.3</center> </body> </html> |
webapp-policy
の内容を変更します
## cd ~/kubernetes-ingress/examples/custom-resources/access-control
kubectl apply -f access-control-policy-allow.yaml
コマンドを実行しPolicyの内容を確認します。Policyの内容が Spec
に記載されています。
kubectl describe policy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Name: webapp-policy Namespace: default Labels: <none> Annotations: <none> API Version: k8s.nginx.org/v1 Kind: Policy ** 省略 ** Spec: Access Control: Allow: 10.0.0.0/8 Status: Message: Policy default/webapp-policy was added or updated Reason: AddedOrUpdated State: Valid |
curlコマンドで動作を確認します。以下のように通信が 許可
されていることが確認できます
curl -H "Host:webapp.example.com" http://localhost/
1 2 3 4 5 | Server address: 192.168.127.48:8080 Server name: webapp-64d444885-j4q7z Date: 17/Jan/2022:12:48:51 +0000 URI: / Request ID: 752997339b21d94210fc911cb41f7216 |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/access-control
kubectl delete -f access-control-policy-allow.yaml
kubectl delete -f virtual-server.yaml
kubectl delete -f webapp.yaml
URL Path の 変換 (Rewrite)
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/rewrites
Rewrite を用いて、URL Path を書換えることが可能です。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/rewrites
cat << EOF > rewrite-virtual-server.yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: cafe
spec:
host: cafe.example.com
upstreams:
- name: tea
service: tea-svc
port: 80
- name: coffee
service: coffee-svc
port: 80
routes:
- path: /tea/
action:
proxy:
upstream: tea
rewritePath: /
- path: /coffee
action:
proxy:
upstream: coffee
rewritePath: /beans
- path: ~ /(\w+)/(.+\.(?:gif|jpg|png)$)
action:
proxy:
upstream: tea
rewritePath: /service/\$1/image/\$2
EOF
kubectl apply -f ../basic-configuration/cafe.yaml
kubectl apply -f rewrite-virtual-server.yaml
リソースを確認
Virtual Serverの定義内容を確認します。route に 3つのPathを定義し、rewritePath でURLの書換えを行います。該当のPathでそれぞれのサービスに適したPathの書換えルールを定義します。
書換えのルールを表にまとめます。
Path | 一致タイプ | Rewrite | 結果 |
---|---|---|---|
/tea/ | 完全一致 | / | /tea/abc -> /abc |
/coffee | 完全一致 | /beans | /coffee/def/ghi -> /beans/def/ghi |
~ /(w+)/(.+.(?:gif|jpg|png)$) | 正規表現 | /service/$1/image/$2 | /cafe/top.jpg -> /service/cafe/image/top.jpg |
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get pod
1 2 3 4 | NAME READY STATUS RESTARTS AGE coffee-7c86d7d67c-ws2t8 1/1 Running 0 39m coffee-7c86d7d67c-zt5tr 1/1 Running 0 39m tea-5c457db9-ksljs 1/1 Running 0 39m |
kubectl get deployment
1 2 3 | NAME READY UP-TO-DATE AVAILABLE AGE coffee 2/2 2 2 39m tea 1/1 1 1 39m |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE cafe Valid cafe.example.com 39m |
動作確認
先程定義を確認したとおり、URLが書換えられていることが確認できます。
curl -H "Host:cafe.example.com" http://localhost/tea/
1 2 3 4 5 | Server address: 192.168.127.40:8080 Server name: tea-5c457db9-ksljs Date: 17/Jan/2022:14:22:46 +0000 URI: / Request ID: 2576a16546e7d17467e04da2ab794109 |
curl -H "Host:cafe.example.com" http://localhost/tea/abc
1 2 3 4 5 | Server address: 192.168.127.40:8080 Server name: tea-5c457db9-ksljs Date: 17/Jan/2022:14:22:14 +0000 URI: /abc Request ID: 5ce49a600fb24a40340ba6edad91ffb2 |
curl -H "Host:cafe.example.com" http://localhost/coffee
1 2 3 4 5 | Server address: 192.168.127.39:8080 Server name: coffee-7c86d7d67c-zt5tr Date: 17/Jan/2022:14:22:40 +0000 URI: /beans Request ID: 9b15d10a624faee145b875b8f83460e3 |
curl -H "Host:cafe.example.com" http://localhost/coffee/def/ghi
1 2 3 4 5 | Server address: 192.168.127.39:8080 Server name: coffee-7c86d7d67c-zt5tr Date: 17/Jan/2022:14:22:27 +0000 URI: /beans/def/ghi Request ID: f70d98547c615a145b2a40ddfe5884a4 |
curl -H "Host:cafe.example.com" http://localhost/cafe/top.jpg
1 2 3 4 5 | Server address: 192.168.127.40:8080 Server name: tea-5c457db9-ksljs Date: 17/Jan/2022:14:23:02 +0000 URI: /service/cafe/image/top.jpg Request ID: 38c3cf24e3f5e0cdfe451b0d646c0e1d |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/rewrites
kubectl delete -f ../basic-configuration/cafe.yaml
kubectl delete -f rewrite-virtual-server.yaml
Ingress Controller で JWT Validation のデプロイ
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/jwt
NGINX Ingress Controller で JWT の Validation を行い、通信制御を行うことが可能です。
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/jwt/
kubectl apply -f webapp.yaml
kubectl apply -f jwk-secret.yaml
kubectl apply -f jwt.yaml
kubectl apply -f virtual-server.yaml
リソースを確認
利用するファイルの内容を確認します
まず、JWK(Json Web Key)としてVirtual ServerのPolicy内で指定するsecretの内容を確認します
1 2 3 4 5 6 7 | apiVersion: v1 kind: Secret metadata: name: jwk-secret type: nginx.org/jwk data: jwk: eyJrZXlzIjoKICAgIFt7CiAgICAgICAgImsiOiJabUZ1ZEdGemRHbGphbmQwIiwKICAgICAgICAia3R5Ijoib2N0IiwKICAgICAgICAia2lkIjoiMDAwMSIKICAgIH1dCn0K |
jwk
というKeyに対し、 値
として文字列が指定されていることが確認できます。
文字列の内容をbase64デコードします
# echo -n <jwk に指定された文字列> | base64 -d
echo -n "eyJrZXlzIjoKICAgIFt7CiAgICAgICAgImsiOiJabUZ1ZEdGemRHbGphbmQwIiwKICAgICAgICAia3R5Ijoib2N0IiwKICAgICAgICAia2lkIjoiMDAwMSIKICAgIH1dCn0K" | base64 -d
出力結果が以下となります。
1 2 3 4 5 6 7 | {"keys": [{ "k":"ZmFudGFzdGljand0", "kty":"oct", "kid":"0001" }] } |
各パラメータ内容は以下の通り
Parameter | 意味 | Link |
---|---|---|
k | k (key value) パラメータは, kty octで利用する base64url encodeされたKey文字列をもつ | JSON Web Algorithms (JWA) 6.4.1 “k” |
kty | kty (key type) パラメータは, RSA や EC といった暗号アルゴリズムファミリーを示す | JSON Web Key (JWK) 4.1 “kty” |
kid | kid (key ID) パラメータは特定の鍵を識別するために用いられる | JSON Web Key (JWK) 4.5 “kid” |
kty “oct” で利用する Keyの内容をBase64デコードした結果は以下の通り
echo -n "ZmFudGFzdGljand0" | base64 -d
1 | fantasticjwt |
この結果により、このサンプルでは fantasticjwt
という文字列がKeyとして使用されていることが確認できます。
今回サンプルリクエストに利用するJWTがこの文字列で署名されたものであるか確認します。 token.jwt
の内容を表示します。
1 | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEifQ.eyJuYW1lIjoiUXVvdGF0aW9uIFN5c3RlbSIsInN1YiI6InF1b3RlcyIsImlzcyI6Ik15IEFQSSBHYXRld2F5In0.ggVOHYnVFB8GVPE-VOIo3jD71gTkLffAY0hQOGXPL2I |
HS256
であることを確認します。your-256-bit-secret
に先程 jwk
の内容をデコードして確認した文字列 fantasticjwt
を入力してください。token.jwt
の内容を貼り付け、左下の表示が Signature Verified
となることを確認してください。その他、NGINX Plus / JWT に関する詳細は Blog:Authenticating API Clients with JWT and NGINX Plus を参照してください
VirtualServerで利用するPolicyについて確認します。まずVirtualServerの内容は以下です
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: webapp spec: host: webapp.example.com policies: - name: jwt-policy upstreams: - name: webapp service: webapp-svc port: 80 routes: - path: / action: pass: webapp |
hostに対し jwt-policy
というポリシーが適用されていることが確認できます。
では次に、Policyの内容を確認します
1 2 3 4 5 6 7 8 9 | apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: jwt-policy spec: jwt: realm: MyProductAPI secret: jwk-secret token: $http_token |
jwt-policy
という名前のPolicyとなります。jwt-secret
が指定されており、token
というhttp headerの値とするため、 $http_token
を指定しています。以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get deployment
1 2 | NAME READY UP-TO-DATE AVAILABLE AGE webapp 1/1 1 1 23s |
kubectl get secret | grep jwk
1 | jwk-secret nginx.org/jwk 1 40s |
kubectl get policy
1 2 | NAME STATE AGE jwt-policy Valid 38s |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE webapp Valid webapp.example.com 35s |
動作確認
Policyが適用されたVirtualServerにJWTをHeaderに付与していないため、通信に対し 401 Authorization required
が応答されていることを確認します
curl -H "Host:webapp.example.com" http://localhost/
1 2 3 4 5 6 7 | <html> <head><title>401 Authorization Required</title></head> <body> <center><h1>401 Authorization Required</h1></center> <hr><center>nginx/1.23.4</center> </body> </html> |
curlコマンドで動作を確認します。以下のように通信が 許可
されていることが確認できます
curl -H "Host:webapp.example.com" http://localhost/ -H "Token: `cat token.jwt`"
1 2 3 4 5 | Server address: 192.168.127.57:8080 Server name: webapp-64d444885-r5fnt Date: 18/Jan/2022:12:49:59 +0000 URI: / Request ID: 86182122eec0392769b4d86d64653419 |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/jwt/
kubectl delete -f virtual-server.yaml
kubectl delete -f jwt.yaml
kubectl delete -f jwk-secret.yaml
kubectl delete -f webapp.yaml
Ingress Controller で OIDC RPのデプロイ
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/oidc
サンプルアプリケーションをデプロイ
リソースをデプロイします。ここでIDPとして動作させる KeyCloak
をデプロイします
cd ~/kubernetes-ingress/examples/custom-resources/oidc
kubectl apply -f tls-secret.yaml
kubectl apply -f webapp.yaml
kubectl apply -f keycloak.yaml
kubectl apply -f virtual-server-idp.yaml
このサンプルで利用するFQDNを確認します。ラボ環境のJumpHostでは予め双方のFQDNを登録しています。
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
grep host virtual-server*yaml
1 2 | virtual-server-idp.yaml: host: keycloak.example.com virtual-server.yaml: host: webapp.example.com |
https://keycloak.example.com
へアクセスしてください。Administration Console を開きます。ログイン画面が表示されますので以下の情報でログインしてください。
- ログイン情報
usename | password |
---|---|
admin | admin |
左メニューより Clients を開き、 Create から新規作成を行います。
Client ID: nginx-plus
を指定し、 Save します。
SettingsタブのAccess Type: confidential
を選択し、Valid Redirect URIs: https://webapp.example.com:443/_codexch
を入力し、 Save します。
Credentialsタブを開きます。後ほどSecretの値を利用しますので表示されている文字列を記録しておきます。
Rolesタブを開き、 Add Role から追加を行います。
Role Name: nginx-keycloak-role
を指定し、 Save します。
左メニュー Users を開き、 Add user からユーザの新規作成を行います。
Username: nginx-user
を指定し、 Save します。
Credentialsタブを開き、Password: test
を入力、Temporary: Off
を選択し、nginx-userのパスワードを設定します。
Role Mappingsタブを開き、Client Roles: nginx-plus
を選択し、Available Rolesに表示される nginx-keycloak-role
を選択し、 Add selected でRoleをAssignします。
これでKeycloakの準備は完了しました。
先程、Keycloakで確認したSecretの内容をbase64エンコードします
echo -n "f0558674-70a1-45a9-8c90-02245628b8f1" | base64
1 | ZjA1NTg2NzQtNzBhMS00NWE5LThjOTAtMDIyNDU2MjhiOGYx |
client-secret.yaml
に設定します
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
vi client-secret.yaml
1 2 3 4 5 6 7 | apiVersion: v1
kind: Secret
metadata:
name: oidc-secret
type: nginx.org/oidc
data:
client-secret: ***BASE64 EncodeしたSECRET情報***
|
OIDC PolicyとClientSecretをデプロイします。
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
kubectl apply -f client-secret.yaml
kubectl apply -f oidc.yaml
本書の環境では単一のPodでNGINX Ingress Controllerを動作させているためZone Synchronizationの設定はしません。必要となる方は手順を参考に実施してください。
最後にNGINX Ingress ControllerをWebアプリケーション用のOIDC RP として動作させるため、VirtualServerを作成します。kbue-dnsのIPアドレスを確認し、virtual-server.yamlに設定を追加します。
kubectl get svc -n kube-system | grep kube-dns
1 | kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 12d |
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
vi virtual-server.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: webapp spec: host: webapp.example.com tls: secret: tls-secret redirect: enable: true server-snippets: | resolver 10.96.0.10; # kube-dnsのIPアドレスを指定します upstreams: - name: webapp service: webapp-svc port: 80 routes: - path: / policies: - name: oidc-policy action: pass: webapp |
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
kubectl apply -f virtual-server.yaml
リソースを確認
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get secret | grep -e oidc -e tls-secret
1 2 | oidc-secret nginx.org/oidc 1 4m29s tls-secret kubernetes.io/tls 2 21m |
kubectl get deployment
1 2 3 | NAME READY UP-TO-DATE AVAILABLE AGE keycloak 1/1 1 1 22m webapp 1/1 1 1 22m |
kubectl get svc
1 2 3 4 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE keycloak ClusterIP 10.97.4.138 <none> 8080/TCP 22m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d webapp-svc ClusterIP 10.104.69.230 <none> 80/TCP 22m |
kubectl get policy
1 2 | NAME STATE AGE oidc-policy Valid 9m28s |
kubectl get vs
1 2 3 | NAME STATE HOST IP PORTS AGE keycloak Valid keycloak.example.com 23m webapp Valid webapp.example.com 7m40s |
動作確認
Chromeブラウザを開き、 Secret Tab (New Incognito Window)
を開いてください。
https://webapp.example.com
へアクセスしてください。
Keycloakのログイン画面が表示されます。先程設定を行った nginx-user
でログインしてください。
- ログイン情報
usename | password |
---|---|
nginx-user | test |
ログインが正常に行われた場合、Webアプリケーションの結果をブラウザで確認いただけます。
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/oidc
kubectl delete -f webapp.yaml
kubectl delete -f keycloak.yaml
kubectl delete -f virtual-server-idp.yaml
kubectl delete -f client-secret.yaml
kubectl delete -f oidc.yaml
kubectl delete -f virtual-server.yaml
Ingress MTLS
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/ingress-mtls
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/ingress-mtls
kubectl apply -f webapp.yaml
kubectl apply -f ingress-mtls-secret.yaml
kubectl apply -f ingress-mtls.yaml
kubectl replace --force -f tls-secret.yaml
kubectl apply -f virtual-server.yaml
リソースを確認
ポイントとなるファイルの内容を確認します。
ingress-mtls-secret.yaml
でクライアント証明書の評価に用いる証明書を作成します。
1 2 3 4 5 6 7 | kind: Secret metadata: name: ingress-mtls-secret apiVersion: v1 type: nginx.org/ca data: ca.crt: **省略** |
ingress-mtls.yaml
は別途作成した ingress-mtls-secret
をclientCertSecretに指定し(7)、Virtual Serverで利用するPolicyを作成します。
1 2 3 4 5 6 7 8 9 | apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: ingress-mtls-policy spec: ingressMTLS: clientCertSecret: ingress-mtls-secret verifyClient: "on" verifyDepth: 1 |
作成した ingress-mtls-policy
というPolicyをリクエストに対し適用するため、TLSの指定(7,8)と、Policyの指定(9,10)を行っています
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: webapp spec: host: webapp.example.com tls: secret: tls-secret policies: - name: ingress-mtls-policy upstreams: - name: webapp service: webapp-svc port: 80 routes: - path: / action: pass: webapp |
通信に利用される証明書の内容は、以下コマンドを参考に確認してください
# echo -n <ca.crt に指定された文字列> | base64 -d > ca-crt.txt
echo -n "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQvVENDQXVXZ0F3SUJBZ0lVSzdhbU14OFlLWG1BVG51SkZETDlWS2ZUR2ZNd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZMHhDekFKQmdOVkJBWVRBbFZUTVFzd0NRWURWUVFJREFKRFFURVdNQlFHQTFVRUJ3d05VMkZ1SUVaeQpZVzVqYVhOamJ6RU9NQXdHQTFVRUNnd0ZUa2RKVGxneEREQUtCZ05WQkFzTUEwdEpRekVXTUJRR0ExVUVBd3dOCmEybGpMbTVuYVc1NExtTnZiVEVqTUNFR0NTcUdTSWIzRFFFSkFSWVVhM1ZpWlhKdVpYUmxjMEJ1WjJsdWVDNWoKYjIwd0hoY05NakF3T1RFNE1qQXlOVEkyV2hjTk16QXdPVEUyTWpBeU5USTJXakNCalRFTE1Ba0dBMVVFQmhNQwpWVk14Q3pBSkJnTlZCQWdNQWtOQk1SWXdGQVlEVlFRSERBMVRZVzRnUm5KaGJtTnBjMk52TVE0d0RBWURWUVFLCkRBVk9SMGxPV0RFTU1Bb0dBMVVFQ3d3RFMwbERNUll3RkFZRFZRUUREQTFyYVdNdWJtZHBibmd1WTI5dE1TTXcKSVFZSktvWklodmNOQVFrQkZoUnJkV0psY201bGRHVnpRRzVuYVc1NExtTnZiVENDQVNJd0RRWUpLb1pJaHZjTgpBUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTmFINVRzaTZzaUFsU085dEJnYmY3VVRwcWowMUhRTlQ2UjhtQy9pCjhLYXFaSW9XSUdvN2xhTW9xTDYydTc4ay9WOHM2Z0FJaU1DSzBjekFvTFhNSnlJQkxQeTg4Yzdtc2xwZXgxTkEKVmRtMkVTVkN6bVlERE1TT3FpVmszWmpYeC9URmo2QzhNRFhhRkZUWFg1dWdtbWdscnFCWlh0OVI5VVBwVTJMNwo1bEZ0NlJ2R3VGczgvbVZORVR5c1A0SFhCWlh2ZE9mdG1YWUkvK01hOW5CMzIzNjdmcTI0L0RKZ2YvK2xRbUsxCkJLR3poSTZSc1pSSmdWOXdpK1VuZTBYNjlaS2lLOFdXU3lZS252YnRrcHZuTDA2dGNJaXJZNi80UzZ4Sm1HRVQKZEJUNmVxc0NoSUpQUStWSEp5dTROdnV6WmVCUXpGdmMwNytnUGZkVWZra1FXODhDQXdFQUFhTlRNRkV3SFFZRApWUjBPQkJZRUZKUGdhcnFYa00rdEJ0djVhdndTUWhUQmpTU2VNQjhHQTFVZEl3UVlNQmFBRkpQZ2FycVhrTSt0CkJ0djVhdndTUWhUQmpTU2VNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUIKQUl3WXpoY0s4OWtRL0xGWjZFRHgrQWp2bnJTVSs1cmdwQkgrRjVTNUUyY3pXOE5rNXhySnl0Y0ZUbUtlKzZScwpENHlxeTZSVVFEeWNYaDlPelBjbzgzYTBoeFlCZ1M5MWtJa25wYWF4dndLRDJleWc3UGNnK1lkS1FhZFlMcUY0CmI3cWVtc1FVVkpOWHdkZS9VanRBejlEOTh4dngwM2hQY2Qwb2dzUUhWZ21BZVpFd2l3UzFmTy9WNUE4dTl3MEkKcHlJRTVReXlHcHNpS2dpalpiMmhrS05RVHVJcEhiVnFydVA4eEV6TlFnamhkdS9uUW5OYy9lRUltVUlrQkFUVQpiSHdQc2xwYzVhdVV1TXJxR3lEQ0p2QUJpV3J2SmE3Yi9XcmtDT3FUWVhtR2NGM0w1ZU9FeTBhYkp0M2NNcSs5CnJLTUNVQWlkNG0yNEthWnc3OUk2anNBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==" | base64 -d > ca-crt.txt
openssl x509 -text -noout -in ca-crt.txt
1 2 3 4 5 6 7 8 9 10 11 12 | Certificate: Data: Version: 3 (0x2) Serial Number: 2b:b6:a6:33:1f:18:29:79:80:4e:7b:89:14:32:fd:54:a7:d3:19:f3 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = CA, L = San Francisco, O = NGINX, OU = KIC, CN = kic.nginx.com, emailAddress = kubernetes@nginx.com Validity Not Before: Sep 18 20:25:26 2020 GMT Not After : Sep 16 20:25:26 2030 GMT Subject: C = US, ST = CA, L = San Francisco, O = NGINX, OU = KIC, CN = kic.nginx.com, emailAddress = kubernetes@nginx.com **省略** |
openssl x509 -text -noout -in client-cert.pem
1 2 3 4 5 6 7 8 9 10 11 | Certificate: Data: Version: 1 (0x0) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = CA, L = San Francisco, O = NGINX, OU = KIC, CN = kic.nginx.com, emailAddress = kubernetes@nginx.com Validity Not Before: Sep 18 20:27:15 2020 GMT Not After : Sep 16 20:27:15 2030 GMT Subject: C = US, ST = CA, L = San Francisco, O = NGINX **省略** |
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get deployment
1 2 | NAME READY UP-TO-DATE AVAILABLE AGE webapp 1/1 1 1 8s |
kubectl get secret | grep -e tls-secret
1 2 | ingress-mtls-secret nginx.org/ca 1 32s tls-secret kubernetes.io/tls 2 31s |
kubectl get policy
1 2 | NAME STATE AGE ingress-mtls-policy Valid 44s |
kubectl get vs
1 2 | NAME STATE HOST IP PORTS AGE webapp Valid webapp.example.com 48s |
動作確認
curl -v -k --resolve webapp.example.com:443:127.0.0.1 https://webapp.example.com:443/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | * Added webapp.example.com:443:127.0.0.1 to DNS cache * Hostname webapp.example.com was found in DNS cache * Trying 127.0.0.1:443... * TCP_NODELAY set * Connected to webapp.example.com (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Request CERT (13): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=webapp.example.com * start date: Sep 29 22:19:59 2020 GMT * expire date: Sep 27 22:19:59 2030 GMT * issuer: CN=webapp.example.com * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET / HTTP/1.1 > Host: webapp.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 400 Bad Request < Server: nginx/1.21.3 < Date: Wed, 19 Jan 2022 12:16:54 GMT < Content-Type: text/html < Content-Length: 237 < Connection: close < <html> <head><title>400 No required SSL certificate was sent</title></head> <body> <center><h1>400 Bad Request</h1></center> <center>No required SSL certificate was sent</center> <hr><center>nginx/1.21.3</center> </body> </html> * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): |
curl -v -k --resolve webapp.example.com:443:127.0.0.1 https://webapp.example.com:443/ --cert ./client-cert.pem --key ./client-key.pem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | * Added webapp.example.com:443:127.0.0.1 to DNS cache * Hostname webapp.example.com was found in DNS cache * Trying 127.0.0.1:443... * TCP_NODELAY set * Connected to webapp.example.com (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Request CERT (13): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS handshake, CERT verify (15): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: CN=webapp.example.com * start date: Sep 29 22:19:59 2020 GMT * expire date: Sep 27 22:19:59 2030 GMT * issuer: CN=webapp.example.com * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET / HTTP/1.1 > Host: webapp.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.21.3 < Date: Wed, 19 Jan 2022 12:16:56 GMT < Content-Type: text/plain < Content-Length: 157 < Connection: keep-alive < Expires: Wed, 19 Jan 2022 12:16:55 GMT < Cache-Control: no-cache < Server address: 192.168.127.22:8080 Server name: webapp-64d444885-x5d4p Date: 19/Jan/2022:12:16:56 +0000 URI: / Request ID: c1b1c9c9b30331cbc7f034e026b939fc * Connection #0 to host webapp.example.com left intact |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/ingress-mtls
kubectl delete -f webapp.yaml
kubectl delete -f ingress-mtls-secret.yaml
kubectl delete -f ingress-mtls.yaml
kubectl delete -f tls-secret.yaml
kubectl delete -f virtual-server.yaml
rm ca-crt.txt
Egress MTLS
https://github.com/nginxinc/kubernetes-ingress/tree/v3.1.1/examples/custom-resources/egress-mtls
サンプルアプリケーションをデプロイ
cd ~/kubernetes-ingress/examples/custom-resources/egress-mtls
kubectl apply -f secure-app.yaml
kubectl apply -f egress-mtls-secret.yaml
kubectl apply -f egress-trusted-ca-secret.yaml
kubectl apply -f egress-mtls.yaml
kubectl apply -f virtual-server.yaml
リソースを確認
secure-app.yaml
は、Kubernetes環境内で動作するアプリケーションで、クライアント証明書の評価を行います。ポイントとなる箇所を以下に示します。- volumeMountsでそれぞれのPathにVolumeをマウントしています。/etc/nginx/sslに
app-tls-secret
というSecret(22,29)、/etc/nginx/conf.d/にsecure-config
というConfigMap(24,32)の内容がそれぞれマウントされます secure-config
というConfigMapではNGINXの設定を指定します。SSLの終端(58,59)及び、クライアント証明書(61,62)の評価を行うよう設定を記述しています
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | apiVersion: apps/v1 kind: Deployment metadata: name: secure-app spec: replicas: 1 selector: matchLabels: app: secure-app template: metadata: labels: app: secure-app spec: containers: - name: secure-app image: nginxdemos/nginx-hello:plain-text ports: - containerPort: 8443 volumeMounts: - name: secret mountPath: /etc/nginx/ssl readOnly: true - name: config-volume mountPath: /etc/nginx/conf.d volumes: - name: secret secret: secretName: app-tls-secret - name: config-volume configMap: name: secure-config --- apiVersion: v1 kind: Service metadata: name: secure-app spec: ports: - port: 8443 targetPort: 8443 protocol: TCP name: https selector: app: secure-app --- apiVersion: v1 kind: ConfigMap metadata: name: secure-config data: app.conf: |- server { listen 8443 ssl; server_name secure-app.example.com; ssl_certificate /etc/nginx/ssl/tls.crt; ssl_certificate_key /etc/nginx/ssl/tls.key; ssl_verify_client on; ssl_client_certificate /etc/nginx/ssl/ca.crt; default_type text/plain; location / { return 200 "hello from pod $hostname\n"; } } --- apiVersion: v1 kind: Secret metadata: name: app-tls-secret type: Opaque data: tls.crt: **省略** tls.key: **省略** ca.crt: **省略** |
egress-mtls.yaml
は、VirtualServerに適用する EgressTlsのPolicyとなります。アプリケーションへ転送する際にの証明書として egress-mtls-secret
、 egress-trusted-ca-secret
として作成したSecretを参照します(7,8)。
1 2 3 4 5 6 7 8 9 10 11 12 | apiVersion: k8s.nginx.org/v1 kind: Policy metadata: name: egress-mtls-policy spec: egressMTLS: tlsSecret: egress-mtls-secret trustedCertSecret: egress-trusted-ca-secret verifyServer: on verifyDepth: 2 serverName: on sslName: secure-app.example.com |
virtual-server.yaml
は、upstreamへtlsを有効にし(11,12)、routesで、 egress-mtls-policy
を指定しています(14,15)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: webapp spec: host: webapp.example.com upstreams: - name: secure-app service: secure-app port: 8443 tls: enable: true routes: - path: / policies: - name: egress-mtls-policy action: pass: secure-app |
以下の通り、各リソースを適切に作成されていることを確認します。
kubectl get deployment
1 2 | NAME READY UP-TO-DATE AVAILABLE AGE secure-app 1/1 1 1 73s |
kubectl get pod
1 2 | NAME READY STATUS RESTARTS AGE secure-app-6dc947cc5f-8855b 1/1 Running 0 75s |
kubectl get svc | grep secure-app
1 | secure-app ClusterIP 10.101.84.115 <none> 8443/TCP 5m17s |
kubectl get secret | grep -e app-tls -e egress
1 2 3 | app-tls-secret Opaque 3 6m53s egress-mtls-secret kubernetes.io/tls 2 6m48s egress-trusted-ca-secret nginx.org/ca 1 6m42s |
動作確認
curl -v -H "Host:webapp.example.com" http://localhost/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | * Trying 127.0.0.1:80... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 80 (#0) > GET / HTTP/1.1 > Host:webapp.example.com > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Server: nginx/1.21.3 < Date: Wed, 19 Jan 2022 15:14:03 GMT < Content-Type: text/plain < Content-Length: 43 < Connection: keep-alive < hello from pod secure-app-6dc947cc5f-8855b * Connection #0 to host localhost left intact |
リソースの削除
## cd ~/kubernetes-ingress/examples/custom-resources/egress-mtls
kubectl delete -f secure-app.yaml
kubectl delete -f egress-mtls-secret.yaml
kubectl delete -f egress-trusted-ca-secret.yaml
kubectl delete -f egress-mtls.yaml
kubectl delete -f virtual-server.yaml