精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Istio 安全基礎,減輕針對你的數(shù)據(jù)、端點、通信和平臺的內外威脅

運維
Istio 為微服務提供了無侵入,可插拔的安全框架。應用不需要修改代碼,就可以利用 Istio 提供的雙向 TLS 認證實現(xiàn)服務身份認證,并基于服務身份信息提供細粒度的訪問控制。

安全是一個非常重要的話題,但也是平時容易被忽略的一個話題,我們在開發(fā)應用的時候,往往會忽略安全,但是當應用上線后,安全問題就會暴露出來,這時候就會造成很大的損失。Istio 通過在服務之間注入 Sidecar 代理,來實現(xiàn)對服務之間的流量進行控制和監(jiān)控,從而實現(xiàn)服務之間的安全通信。

接下來我們將從證書管理、認證、授權等幾個方面來學習 Istio 的安全機制。

安全概述

將單一應用程序拆分為微服務可提供各種好處,包括更好的靈活性、可伸縮性以及服務復用的能力。但是,微服務也有特殊的安全需求:

  • 為了抵御中間人攻擊,需要流量加密。
  • 為了提供靈活的服務訪問控制,需要雙向 TLS 和細粒度的訪問策略。
  • 要確定誰在什么時候做了什么,需要審計工具。

Istio 嘗試提供全面的安全解決方案來解決所有這些問題,Istio 安全性可以減輕針對你的數(shù)據(jù)、端點、通信和平臺的內外威脅。

安全概述

Istio 為微服務提供了無侵入,可插拔的安全框架。應用不需要修改代碼,就可以利用 Istio 提供的雙向 TLS 認證實現(xiàn)服務身份認證,并基于服務身份信息提供細粒度的訪問控制。Istio 安全的高層架構如下圖所示:

安全架構

上圖展示了 Istio 中的服務認證和授權兩部分。服務認證是通過控制面和數(shù)據(jù)面一起實現(xiàn)的:

  • 控制面:Istiod 中實現(xiàn)了一個 CA (Certificate Authority,證書機構) 服務器。該 CA 服務器負責為網(wǎng)格中的各個服務簽發(fā)證書,并將證書分發(fā)給數(shù)據(jù)面的各個服務的邊車代理。
  • 數(shù)據(jù)面:在網(wǎng)格中的服務相互之間發(fā)起 plain HTTP/TCP 通信時,和服務同一個 pod 中的邊車代理會攔截服務請求,采用證書和對端服務的邊車代理進行雙向 TLS 認證并建立一個 TLS 連接,使用該 TLS 連接來在網(wǎng)絡中傳輸數(shù)據(jù)。

Istio 的授權功能為網(wǎng)格中的工作負載提供網(wǎng)格、命名空間和工作負載級別的訪問控制,這種控制層級提供了許多優(yōu)點:

  • 工作負載到工作負載以及最終用戶到工作負載的授權。
  • 一個簡單的 API:它包括一個單獨的并且很容易使用和維護的 AuthorizationPolicy CRD。
  • 靈活的語義:運維人員可以在 Istio 屬性上定義自定義條件,并使用 DENY 和 ALLOW 動作。
  • 高性能:Istio 授權是在 Envoy 本地強制執(zhí)行的。
  • 高兼容性:原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 協(xié)議。

授權策略對服務器端 Envoy 代理的入站流量實施訪問控制。每個 Envoy 代理都運行一個授權引擎,該引擎在運行時授權請求。當請求到達代理時,授權引擎根據(jù)當前授權策略評估請求上下文,并返回授權結果 ALLOW 或 DENY。運維人員可以通過 YAML 資源清單文件來指定 Istio 授權策略。

授權策略

證書簽發(fā)流程

默認情況下,Istio CA 生成自簽名根證書和密鑰,并使用它們來簽署工作負載證書。為了保護根 CA 密鑰,我們應該使用在安全機器上離線運行的根 CA(比如使用 Hashicorp Vault 進行管理),并使用根 CA 向每個集群中運行的 Istio CA 頒發(fā)中間證書。Istio CA 可以使用管理員指定的證書和密鑰對工作負載證書進行簽名,并將管理員指定的根證書作為信任根分發(fā)給工作負載。

CA

簽發(fā)證書

當我們有了 Istio CA 根證書后就可以使用它來簽發(fā)工作負載證書了,那么整個的證書簽發(fā)流程又是怎樣的呢?如下圖所示:

證書簽發(fā)流程

  • Envoy 向 pilot-agent 發(fā)起一個 SDS (Secret Discovery Service) 請求(啟動的時候),要求獲取自己的證書和私鑰。
  • pilot-agent 生成私鑰和 CSR 證書簽名請求,向 Istiod 發(fā)送證書簽發(fā)請求,請求中包含 CSR 和該 Pod 中服務的身份信息。
  • Istiod 提供 gRPC 服務以接受證書簽名請求,根據(jù)請求中服務的身份信息(如果是 Kubernetes 則使用 Service Account)為其簽發(fā)證書,將證書返回給 pilot-agent。
  • pilot-agent 將證書和私鑰通過 SDS 接口返回給 Envoy。
  • pilot-agent 還會監(jiān)控工作負載證書的過期時間,上述過程會定期重復進行證書和密鑰輪換。

這個流程和我們自己用手動方式去進行證書簽發(fā)是一樣的,所以我們需要先了解下證書簽發(fā)的流程。Istio CA 根證書就是一個證書頒發(fā)機構,平時如果要為我們自己的網(wǎng)站申請 HTTPS 證書我們也是去一些正規(guī)的 CA 機構進行申請,而這個申請的信息就是生成的 CSR 證書簽名請求,然后我們將這個 CSR 和身份信息提交給 CA 機構,CA 機構根據(jù)這些信息為我們簽發(fā)證書,然后我們就可以使用這個證書了,只是我們這里在不同的組件上來執(zhí)行這些操作,整體流程是一樣的。

身份認證

另外要通過服務證書來實現(xiàn)網(wǎng)格中服務的身份認證,必須首先確保服務從控制面獲取自身證書的流程是安全的。Istio 通過 Istiod 和 pilog-agent 之間的 gRPC 通道傳遞 CSR 和證書,因此在這兩個組件進行通信時,雙方需要先驗證對方的身份,以避免惡意第三方偽造 CSR 請求或者假冒 Istiod CA 服務器。Istio 中主要包含下面兩種認證方式:

  • Istiod 身份認證
  • Istiod 采用其內置的 CA 服務器為自身簽發(fā)一個服務器證書,并采用該服務器證書對外提供基于 TLS 的 gPRC 服務。
  • Istiod 調用 Kubernetes APIServer 生成一個名為 istio-ca-root-cert 的 ConfigMap 對象, 在該 ConfigMap 中放入了 Istiod 的 CA 根證書。
  • 該 ConfigMap 被 Mount 到 istio-proxy 容器中,被 pilot-agent 用于驗證 Istiod 的服務器證書。
  • 在 pilot-agent 和 Istiod 建立 gRPC 連接時,pilot-agent 采用標準的 TLS 服務器認證流程對 Istiod 的服務器證書進行認證。
  • pilot-agent 身份認證
  • 在 Kubernetes 中可以為每一個 Pod 關聯(lián)一個 ServiceAccount,以表明該 Pod 中運行的服務的身份信息。

  • Kubernetes 會為該 ServiceAccount 生成一個 jwt token,并將該 token 通過 secret 加載到 pod 中的一個文件。

  • pilot-agent 在向 Istiod 發(fā)送 CSR 時,將其所在 Pod 的 service account token 也隨請求發(fā)送給 Istiod。

  • Istiod 調用 Kube-apiserver 接口驗證請求中附帶的 service account token,以確認請求證書的服務身份是否合法。

這里需要注意的是不同版本的 Kubernetes 集群下面的 ServiceAccount Token 生成方式并不一樣,但最終都是通過改 Token 來進行身份認證的。

  • 1.20(含 1.20)之前的版本,在創(chuàng)建 sa 時會自動創(chuàng)建一個 secret,然后這個會把這個 secret 通過投射卷掛載到 pod 里,該 secret 里面包含的 token 是永久有效的。
  • 1.21~1.23 版本,在創(chuàng)建 sa 時也會自動創(chuàng)建 secret,但是在 pod 里并不會使用 secret 里的 token,而是由 kubelet 到 TokenRequest API 去申請一個 token,該 token 默認有效期為一年,但是 pod 每一個小時會更新一次 token。
  • 1.24 版本及以上,在創(chuàng)建 sa 時不再自動創(chuàng)建 secret 了,只保留由 kubelet 到 TokenRequest API 去申請 token。

認證

Istio 提供兩種類型的認證用于管控網(wǎng)格服務間的雙向 TLS 和終端用戶的身份認證。:

  • 對等認證:用于服務到服務的認證,以驗證建立連接的客戶端。Istio 提供雙向 TLS 作為傳輸認證的全棧解決方案,無需更改服務代碼就可以啟用它。這個解決方案:
  • 為每個服務提供代表其角色的強大身份,以實現(xiàn)跨集群和云的互操作性。
  • 確保服務間通信的安全。
  • 提供密鑰管理系統(tǒng),以自動進行密鑰和證書的生成、分發(fā)和輪換。
  • 請求認證:用于終端用戶認證,以驗證附加到請求的憑據(jù)。Istio 使用 JSON Web Token(JWT)驗證啟用請求級認證,并使用自定義認證實現(xiàn)或任何 OpenID Connect 的認證實現(xiàn)來簡化的開發(fā)人員體驗。

對等認證

下面我們來創(chuàng)建幾個示例服務來對認證配置進行測試。這里我們將在 foo 和 bar 命名空間下各自創(chuàng)建帶有 Envoy 代理(Sidecar)的 httpbin 和 sleep 服務。還將在 legacy 命名空間下創(chuàng)建不帶 Envoy 代理(Sidecar)的 httpbin 和 sleep 服務:

$ kubectl create ns foo
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n foo
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
$ kubectl create ns bar
$ kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml) -n bar
$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n bar
$ kubectl create ns legacy
$ kubectl apply -f samples/httpbin/httpbin.yaml -n legacy
$ kubectl apply -f samples/sleep/sleep.yaml -n legacy

現(xiàn)在可以在 foo、bar 或 legacy 三個命名空間下的任意 sleep Pod 中使用 curl 向 httpbin.foo、httpbin.bar 或 httpbin.legacy 發(fā)送 HTTP 請求來驗證部署結果,所有請求都應該成功并返回 HTTP 200。

例如驗證 sleep.bar 到 httpbin.foo 可達性如下:

$ kubectl exec "$(kubectl get pod -l app=sleep -n bar -o jsnotallow={.items..metadata.name})" -c sleep -n bar -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}\n"
200

也可以使用一行指令檢查所有可能的組合:

$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsnotallow={.items..metadata.name})" -c sleep -n ${from} -- curl -s "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 200
sleep.legacy to httpbin.bar: 200
sleep.legacy to httpbin.legacy: 200

這樣保證了我們的服務之間是可以互相訪問的,接下來我們就來看下如何對服務進行認證。

默認情況下,在 Istio 網(wǎng)格內部的服務之間的所有流量都是通過雙向 TLS 進行加密的,不需要做額外的操作,當使用雙向 TLS 時,代理會將 X-Forwarded-Client-Cert 這個 Header 頭注入到后端的上游請求,這個頭信息的存在就是啟用雙向 TLS 的證據(jù)。例如:

$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsnotallow={.items..metadata.name})" -c sleep -n foo -- curl -s http://httpbin.foo:8000/headers -s
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.foo:8000",
    "User-Agent": "curl/7.81.0-DEV",
    "X-B3-Parentspanid": "a59be7609a15c41f",
    "X-B3-Sampled": "1",
    "X-B3-Spanid": "034af52cfc2286b4",
    "X-B3-Traceid": "eb07847c5c14c17fa59be7609a15c41f",
    "X-Envoy-Attempt-Count": "1",
    "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=bb907e90c93bc3f1dd22763f952746e7d2b8c5ad7903ecbcc64324f3b5e55179;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/sleep"
  }
}

可以看到上面我們的請求中包含了 X-Forwarded-Client-Cert 這個 Header 頭,這就是啟用雙向 TLS 的證據(jù),得到的這個值是一個 spiffe:// 開頭的字符串,這個字符串就是 SPIFFE ID,這個 SPIFFE ID 就是用來表示服務的身份的,后面我們會詳細介紹 SPIFFE。

零信任架構下,需要嚴格區(qū)分工作負載的識別和信任,而簽發(fā) X.509 證書是推薦的一種認證方式,在 Kubernetes 集群中,服務間是通過 DNS 名稱互相訪問的,而網(wǎng)絡流量可能被 DNS 欺騙、BGP/路由劫持、ARP 欺騙等手段劫持,為了將服務名稱(DNS 名稱)與服務身份強關聯(lián)起來,Istio 使用置于 X.509 證書中的安全命名(Secure naming)機制。

SPIFFE 是 Istio 所采用的安全命名的規(guī)范,它也是云原生定義的一種標準化的、可移植的工作負載身份規(guī)范。Secure Production Identity Framework For Everyone (SPIFFE) 是一套服務之間相互進行身份識別的標準,主要包含以下內容:

  • SPIFFE ID 標準,SPIFFE ID 是服務的唯一標識,具體實現(xiàn)使用 URI 資源標識符。
  • SPIFFE Verifiable Identity Document (SVID) 標準,將 SPIFFE ID 編碼到一個加密的可驗證的數(shù)據(jù)格式中。
  • 頒發(fā)與撤銷 SVID 的 API 標準。

SPIFFE ID 規(guī)定了形如 spiffe://<trust domain>/<workload identifier> 的 URI 格式,作為工作負載(Workload)的唯一標識。Istio 使用形如 spiffe://<trust_domain>/ns/<namespace>/sa/<service_account> 格式的 SPIFFE ID 作為安全命名,注入到 X.509 證書的 subjectAltName 擴展中。其中的 trust domain 參數(shù)通過 Istiod 環(huán)境變量 TRUST_DOMAIN 注入,用于在多集群環(huán)境中交互,比如我們這里就是 cluster.local,所以其實最終在 Envoy 的配置中可以看到匹配證書的 subjectAltName 值也是這個格式:

{
  "combined_validation_context": {
    "default_validation_context": {
      "match_subject_alt_names": [
        {
          "exact": "spiffe://cluster.local/ns/istio-system/sa/istiod"
        }
      ]
    },
    "validation_context_sds_secret_config": {
      "name": "ROOTCA",
      "sds_config": {
        "api_config_source": {
          "api_type": "GRPC",
          "grpc_services": [
            {
              "envoy_grpc": {
                "cluster_name": "sds-grpc"
              }
            }
          ],
          "set_node_on_first_message_only": true,
          "transport_api_version": "V3"
        },
        "initial_fetch_timeout": "0s",
        "resource_api_version": "V3"
      }
    }
  }
}

當服務器沒有 Sidecar 時,X-Forwarded-Client-Cert 這個 Header 頭將不會存在,這意味著請求是明文的,比如我們請求 httpbin.legacy 服務:

kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsnotallow={.items..metadata.name})" -c sleep -n foo -- curl http://httpbin.legacy:8000/headers -s | grep X-Forwarded-Client-Cert

全局嚴格 mTLS 模式

事實上當 Istio 自動將代理和工作負載之間的所有流量升級到雙向 TLS 時,工作負載仍然可以接收明文流量,如果想要禁用非 mTLS 的通信流量,我們可以使用一個 PeerAuthentication 資源對象來進行配置,只需要將整個網(wǎng)格的對等認證策略設置為 STRICT 模式,作用域為整個網(wǎng)格范圍的對等認證策略不設置 selector 即可,這種認證策略必須應用于根命名空間(istiod 所在的命名空間),例如:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication # 對等認證策略
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT # STRICT 模式表示只允許 mTLS

對等認證策略指定 Istio 對目標工作負載實施的雙向 TLS 模式。支持以下模式:

  • PERMISSIVE:工作負載接受雙向 TLS 和純文本流量,也就是所謂的寬容模式。此模式在遷移因為沒有 Sidecar 而無法使用雙向 TLS 的工作負載的過程中非常有用。一旦工作負載完成 Sidecar 注入的遷移,應將模式切換為 STRICT。
  • STRICT:工作負載僅接收雙向 TLS 流量。
  • DISABLE:禁用雙向 TLS。從安全角度來看,除非提供自己的安全解決方案,否則請勿使用此模式。

這個對等認證策略將工作負載配置為僅接受 mTLS 加密的請求。由于未對 selector 字段指定值,因此該策略適用于網(wǎng)格中的所有工作負載。

直接應用上面這個對等認證策略后,我們再次發(fā)送請求來進行測試:

$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsnotallow={.items..metadata.name})" -c sleep -n ${from} -- curl -s "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 000
command terminated with exit code 56
sleep.legacy to httpbin.legacy: 200

我們可以發(fā)現(xiàn)從 sleep.legacy 到 httpbin.foo 和 httpbin.bar 的請求都失敗了,其他依然是成功的,這是因為我們現(xiàn)在配置了 STRICT 嚴格要求使用 mTLS,由于 sleep.legacy 沒有 Envoy Sidecar,所以無法滿足這一要求,所以要訪問網(wǎng)格內部的工作負載是不被允許的。那為什么可以訪問 httpbin.legacy 呢?這是因為我們在 legacy 命名空間下的 httpbin 服務沒有 Envoy Sidecar,所以它不會被 Istio 管理,也就不會被強制要求使用 mTLS 了,所以我們可以直接訪問它。

命名空間級別策略

上面我們是在根命名空間(istiod 所在的命名空間)下配置的對等認證策略,這樣會影響到整個網(wǎng)格,如果我們只想對某個命名空間下的服務進行配置,那么我們可以使用命名空間級別的對等認證策略,該策略的規(guī)范與整個網(wǎng)格級別的規(guī)范相同,但是可以在 metadata 字段指定具體的命名空間的名稱。比如我們要在 foo 命名空間上啟用嚴格的雙向 TLS 對等策略,可以創(chuàng)建如下所示的資源對象:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: foo # 命名空間級別
spec:
  mtls:
    mode: STRICT

直接應用上面的資源對象,然后再次發(fā)送請求來進行測試:

# 首先刪除上面創(chuàng)建的全局對等認證策略
$ kubectl delete peerauthentication -n istio-system default
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsnotallow={.items..metadata.name})" -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 200
sleep.legacy to httpbin.legacy: 200

由于這些策略只應用于命名空間 foo 中的服務,正常我們會看到只有從沒有 Sidecar 的客戶端(sleep.legacy)到有 Sidecar 的客戶端(httpbin.foo)的請求會失敗,其余都是成功的。

為每個工作負載啟用雙向 TLS

要為特定工作負載設置對等認證策略,我們就必須配置 selector 字段指定與所需工作負載匹配的標簽。比如我們只想要為 httpbin.bar 服務啟用嚴格模式的 mTLS,則可以創(chuàng)建如下所示的資源對象:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "httpbin"
  namespace: "bar"
spec:
  selector:
    matchLabels:
      app: httpbin # 匹配 httpbin 應用的標簽
  mtls:
    mode: STRICT

上面的資源對象將為 bar 命名空間中的 httpbin 應用啟用嚴格模式的 mTLS,其他工作負載不受影響。直接應用上面的資源對象,然后再次發(fā)送請求來進行測試:

$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsnotallow={.items..metadata.name})" -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 000
command terminated with exit code 56
sleep.legacy to httpbin.legacy: 200

跟預期一樣,從 sleep.legacy 到 httpbin.bar 的請求因為同樣的原因失敗。

除此之外我們還可以為每個端口配置不同的對等認證策略,例如,以下對等認證策略要求在除 80 端口以外的所有端口上都使用雙向 TLS:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: "httpbin"
  namespace: "bar"
spec:
  selector:
    matchLabels:
      app: httpbin
  mtls:
    mode: STRICT
  portLevelMtls:
    80:
      mode: DISABLE

上面的資源對象中我們配置了一個 portLevelMtls 字段,該字段用于配置端口級別的對等認證策略,這里我們配置了 80 端口的對等認證策略為 DISABLE,即禁用雙向 TLS,其他端口的對等認證策略為 STRICT,即啟用雙向 TLS,也就是說我們只允許 httpbin 應用的 80 端口接收明文流量,其他端口都必須使用雙向 TLS。直接應用上面的資源對象,然后再次發(fā)送請求來進行測試:

$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar" "legacy"; do kubectl exec "$(kubectl get pod -l app=sleep -n ${from} -o jsnotallow={.items..metadata.name})" -c sleep -n ${from} -- curl "http://httpbin.${to}:8000/ip" -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
sleep.foo to httpbin.foo: 200
sleep.foo to httpbin.bar: 200
sleep.foo to httpbin.legacy: 200
sleep.bar to httpbin.foo: 200
sleep.bar to httpbin.bar: 200
sleep.bar to httpbin.legacy: 200
sleep.legacy to httpbin.foo: 000
command terminated with exit code 56
sleep.legacy to httpbin.bar: 200
sleep.legacy to httpbin.legacy: 200

可以看到現(xiàn)在我們從 sleep.legacy 到 httpbin.bar 的請求成功了,因為我們禁用了 80 端口的雙向 TLS,所以 sleep.legacy 可以訪問到 httpbin.bar 的服務了。

測試完成后記得刪除上面創(chuàng)建的對等認證策略:

$ kubectl delete peerauthentication default -n foo
$ kubectl delete peerauthentication httpbin -n bar

請求認證

Istio 的請求認證用于終端用戶認證,以驗證附加到請求的憑據(jù)。Istio 使用 JWT 驗證啟用請求級認證,并使用自定義認證實現(xiàn)或任何 OpenID Connect 的認證實現(xiàn)來進行認證簡化。

要在 Istio 中進行請求認證,可以通過一個 RequestAuthentication 資源對象來進行配置,如果請求包含無效的認證信息,它將根據(jù)配置的認證規(guī)則拒絕該請求。不包含任何認證憑證的請求將被接受,但不會有任何認證的身份。

JWK 與 JWKS 概述

Istio 使用 JWT 對終端用戶進行身份驗證,Istio 要求提供 JWKS 格式的信息,用于 JWT 簽名驗證。因此這里得先介紹一下 JWK 和 JWKS。

JWK 即 JSON Web Key,是 JWT 的秘鑰,它描述了一個加密密鑰(公鑰或私鑰)的值及其各項屬性。JWKS 描述一組 JWK 密鑰,JWKS 的 JSON 文件格式如下:

{
"keys": [
  <jwk-1>,
  <jwk-2>,
  ...
]}

Istio 使用 JWK 描述驗證 JWT 簽名所需要的信息。在使用 RSA 簽名算法時,JWK 描述的應該是用于驗證的 RSA 公鑰。一個 RSA 公鑰的 JWK 描述如下:

{
    "alg": "RS256",  # 算法「可選參數(shù)」
    "kty": "RSA",    # 密鑰類型
    "use": "sig",    # 被用于簽名「可選參數(shù)」
    "kid": "DHFxxxxx_-envvQ",  # key 的唯一 id
    "n": "xAExxxxMQ", 公鑰的指數(shù)(exponent)
    "e": "AQAB"  # 公鑰的模數(shù)(modulus)
}

那么需要如何生成 JWK 呢?我們可以使用 https://github.com/lestrrat-go/jwx 這個命令行工具,這是一個用 Go 語言開發(fā)的命令行工具,內置了對各種 JWx(JWT, JWK, JWA, JWS, JWE) 的支持。

我們可以使用下面的命令來安裝 jwx 命令行工具:

$ export GOPROXY="https://goproxy.io"
$ git clone https://github.com/lestrrat-go/jwx.git
$ cd jwx
$ make jwx
go: downloading github.com/lestrrat-go/jwx/v2 v2.0.11
go: downloading github.com/urfave/cli/v2 v2.24.4
# ......
go: downloading github.com/russross/blackfriday/v2 v2.1.0
go: downloading golang.org/x/sys v0.8.0
Installed jwx in /root/go/bin/jwx

下面我們使用 jwx 命令行工具生成一個 JWK,通過模板指定 kid 為 youdianzhishi-key:

$ jwx jwk generate --keysize 4096 --type RSA  --template '{"kid":"youdianzhishi-key"}' -o rsa.jwk
$ cat rsa.jwk
{
  "d": "AxxxwBw6Jok",
  "dp": "j3xxxuvQ",
  "dq": "zzxxxqQ",
  "e": "AQAB",
  "kid": "youdianzhishi-key",
  "kty": "RSA",
  "n": "5sxxxwV8",
  "p": "-yxxxQ",
  "q": "6zkC_xxxxKw",
  "qi": "LExxxTw"
}

然后從 rsa.jwk 中提取 JWK 公鑰:

$ jwx jwk fmt --public-key -o rsa-public.jwk rsa.jwk
$ cat rsa-public.jwk
{
  "e": "AQAB",
  "kid": "youdianzhishi-key",
  "kty": "RSA",
  "n": "5sxxxV8"
}

上面生成的 JWK 其實就是 RSA 公鑰私鑰換了一種存儲格式而已,我們可以使用下面的命令將它們轉換成 PEM 格式的公鑰和私鑰:

$ jwx jwk fmt -I json -O pem rsa.jwk
-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCym3O0Ik5QGZ8i
......
-----END PRIVATE KEY-----

$ jwx jwk fmt -I json -O pem rsa-public.jwk
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsptztCJOUBmfIqSE8LR5
......
-----END PUBLIC KEY-----

接下來我們就可以使用 jwx 命令行簽發(fā) JWT Token 并驗證其有效性了:

jwx jws sign --key rsa.jwk --alg RS256 --header '{"typ":"JWT"}' -o token.txt - <<EOF
{
  "iss": "testing@secure.istio.io",
  "sub": "cnych001",
  "iat": 1700648397,
  "exp": 1700656042,
  "name": "Yang Ming"
}
EOF

然后查看生成的 Token 文件內容:

$ cat token.txt
eyJhbGciOiJSUzI1NiIsImtpZCI6InlvdWRpYW56aGlzaGkta2V5In0......

上面生成 JWT Token 實際上是由下面的算法生成的:

base64url_encode(Header) + '.' + base64url_encode(Claims) + '.' + base64url_encode(Signature)

我們可以將該 Token 粘貼到 jwt.io 網(wǎng)站上來解析:

jwt

先看一下 Headers 部分,包含了一些元數(shù)據(jù):

  • alg: 所使用的簽名算法,這里是 RSA256
  • kid: JWK 的 kid

然后是 Payload(Claims) 部分,payload 包含了這個 token 的數(shù)據(jù)信息,JWT 標準規(guī)定了一些字段,另外還可以加入一些承載額外信息的字段。

  • iss: issuer,token 是誰簽發(fā)的
  • sub: token 的主體信息,一般設置為 token 代表用戶身份的唯一 id 或唯一用戶名
  • exp: token 過期時間,Unix 時間戳格式
  • iat: token 創(chuàng)建時間, Unix 時間戳格式

最后看一下簽名 Signature 信息,簽名是基于 JSON Web Signature (JWS) 標準來生成的,簽名主要用于驗證 token 是否有效,是否被篡改。簽名支持很多種算法,這里使用的是 RSASHA256,具體的簽名算法如下:

RSASHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  <rsa-public-key>,
  <rsa-private-key>

最后可以使用 RSA Public Key 驗證 JWT Token 的有效性:

$ jwx jws verify --alg RS256 --key rsa-public.jwk token.txt
{
  "iss": "testing@secure.istio.io",
  "sub": "cnych001",
  "iat": 1700648397,
  "exp": 1700656042,
  "name": "Yang Ming"
}

配置 JWT 終端用戶認證

上面我們了解了 JWT、JWK、JWKS 這些概念,接下來我們來配置 Istio 的認證策略使用我們自己創(chuàng)建的 JWKS。

為了方便訪問,我們這里通過 Ingress 網(wǎng)關來暴露 httpbin.foo 服務,為其創(chuàng)建一個 Gateway 對象:

kubectl apply -f samples/httpbin/httpbin-gateway.yaml -n foo

可以通過如下命令獲取 HTTP 的訪問端口:

export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsnotallow='{.spec.ports[?(@.name=="http2")].nodePort}')

然后獲取集群中任意一個節(jié)點的 IP 地址:

export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsnotallow='{.items[0].status.hostIP}')

然后可以通過下面的命令來測試 httpbin.foo 服務是否可以正常訪問:

curl "$INGRESS_HOST:$INGRESS_PORT/headers" -s -o /dev/null -w "%{http_code}\n"

如果上面命令返回 200,則表示 httpbin.foo 服務可以正常訪問。

接下來我們就可以添加一個請求認證策略對象,該策略要求 Ingress 網(wǎng)關指定終端用戶的 JWT。

apiVersion: "security.istio.io/v1"
kind: RequestAuthentication
metadata:
  name: jwt-example
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  jwtRules:
    - issuer: "testing@secure.istio.io" # 簽發(fā)者,需要和 JWT payload 中的 iss 屬性完全一致。
      # forwardOriginalToken: true
      jwks: |
        {
            "keys": [
              {
                "e": "AQAB",
                "kid": "youdianzhishi-key",
                "kty": "RSA",
                "n": "5sbkUCkQDuM3hiw9UTxmxO2wUYOT69IZje7M6O_R-ApJ3KkrhQS1C2SJelBTLgbaWhAsO4jBYOmFfWGLBA-XxrhoB9KxWCGA4EXf6fukp0ljGTYE6Th6r393jIJGDFUt8vQCjj5ivmBAQHLjwmnWiG6I93mrTQhoNHQWAde21O7yYNpg6fvjVJgRFqeAtpieA-5f2sQ8fBkefM0RFgQTqWPGfLHse5nqRWY4hG_gb23GzCo_Ti2h9wJZNuTfdK8hitahOq3eLlDVVvCu8hx-8BEs5APCj54gtqePswHeRXZi_03ccNii5CnW7Y1rHiL8LHKNHhY5tD2iZByh4YrnhkUWD-CXNqyUKx90de0R9H1ON6pqsmdEx4iAMx2xvnZ0S9NbKlk3glw_AvudjJUHa41xx7qy9OZ7QV6cB_ntwLtw513lk5Tfm-RDlVgyU-EO2jKXbOeiDpnb8kgRNBMKDqY9mgLfISW54N-LBjyVwVVHOvICWo0oPJypRgPRWD8f25wHqzjlsB8nIqJkj_e9p2c5WnAGiZWuZjm6t94IfFq9lWYUsSn-JtJvh3ATsv7ptDKFz2Ko82r1uD3446mr4I0J56C-7WOHGchlSOrDWKErwkIGxyrQ_3GEkUhkSxfArAv0bajmcMCu1_j8Eekqk7Fnm5QqytCFmFevzIJkwV8"
              }
            ]
        }

在上面的資源對象中我們通過 selector 匹配了 istio-ingressgateway 服務,因為我們要為 Ingress 網(wǎng)關添加請求認證,具體的請求認證規(guī)則通過 jwtRules 來進行配置,這里我們配置了一個 issuer 字段,該字段用于指定 JWT 的 Issuer 發(fā)行人,然后配置了一個 jwks 字段,該字段用于指定 JWT 的公鑰集數(shù)據(jù),我們也可以通過 jwksUri 來指向一個公鑰集地址。對同一個 issuers(jwt 簽發(fā)者),可以設置多個公鑰,以實現(xiàn) JWT 簽名密鑰的輪轉。JWT 的驗證規(guī)則是:

  • JWT 的 payload 中有 issuer 屬性,首先通過 issuer 匹配到對應的 istio 中配置的 jwks。
  • JWT 的 header 中有 kid 屬性,第二步在 jwks 的公鑰列表中,中找到 kid 相同的公鑰。
  • 使用找到的公鑰進行 JWT 簽名驗證。

配置中的 spec.selector 可以省略,這樣會直接在整個命名空間中生效,比如在 istio-system 命名空間,該配置將在全集群的所有 sidecar/ingressgateway 上生效!

默認情況下,Istio 在完成了身份驗證之后,會去掉 Authorization 請求頭再進行轉發(fā)。這將導致我們的后端服務獲取不到對應的 Payload,無法判斷終端用戶的身份。因此我們需要啟用 Istio 的 Authorization 請求頭的轉發(fā)功能,只需要在上面的資源對象中添加一個 forwardOriginalToken: true 字段即可。

直接應用上面的資源對象,然后再次發(fā)送請求來進行測試:

$ curl "$INGRESS_HOST:$INGRESS_PORT/headers" -s -o /dev/null -w "%{http_code}\n"
200

可以看到現(xiàn)在依然可以正常訪問,但是如果我們請求的時候帶上一個無效的 JWT Token,則會返回 401 錯誤:

$ curl --header "Authorization: Bearer abcdef" "$INGRESS_HOST:$INGRESS_PORT/headers" -s -o /dev/null -w "%{http_code}\n"
401

要想正常訪問,我們需要使用上面生成的 JWT Token 來進行訪問:

$ TOKEN=$(cat token.txt)
$ curl --header "Authorization: Bearer $TOKEN" "$INGRESS_HOST:$INGRESS_PORT/headers" -s -o /dev/null -w "%{http_code}\n"
200

可以看到就可以正常訪問了。

設置強制認證規(guī)則

從上面的測試可以看出 Istio 的 JWT 驗證規(guī)則,默認情況下會直接忽略不帶 Authorization 請求頭(即 JWT)的流量,因此這類流量能直接進入網(wǎng)格內部。通常這是沒問題的,因為沒有 Authorization 的流量即使進入到內部,也會因為無法通過 payload 判別身份而被拒絕操作。但是如果我們需要禁止不帶 JWT 的流量,那么可以通過一個 AuthorizationPolicy 對象來進行配置了。

比如拒絕任何 JWT 無效的請求,則可以創(chuàng)建如下 d 資源對象:

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: deny-requests-without-authorization
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  action: DENY # 拒絕
  rules:
    - from:
        - source:
            notRequestPrincipals: ["*"] # 不存在任何請求身份(Principal)的 requests

上面的資源對象中我們配置的 action: DENY 表示拒絕,然后通過 rules 字段來配置拒絕的規(guī)則,這里我們配置了一個 from 字段,該字段用于指定請求的來源,這里我們配置了一個 notRequestPrincipals 字段,該字段用于指定請求的身份,這里我們配置為 *,表示任何請求身份都不允許。

應用上面的資源對象后,重新發(fā)送沒有令牌的請求,請求失敗并返回錯誤碼 403:

$ curl "$INGRESS_HOST:$INGRESS_PORT/headers" -s -o /dev/null -w "%{http_code}\n"
403

如果僅希望強制要求對部分 path 的請求必須帶有 Authorization Header,可以這樣設置:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-requests-without-authorization
  namespace: istio-system
spec:
  selector:
    matchLabels:
      istio: ingressgateway
  action: DENY # 拒絕
  rules:
    - from:
        - source:
            notRequestPrincipals: ["*"] # 不存在任何請求身份的 requests
      # 僅強制要求如下 host/path 相關的請求,必須帶上 JWT token
      to:
        - operation:
            hosts: ["another-host.com"]
            paths: ["/headers"]

需要注意的是 RequestsAuthentication 和 AuthorizationPolicy 這兩個對象返回的錯誤碼是不同的:

  • RequestsAuthentication 驗證失敗的請求,Istio 會返回 401 狀態(tài)碼。
  • AuthorizationPolicy 驗證失敗的請求,Istio 會返回 403 狀態(tài)碼。

到這里我們就實現(xiàn)了對 JWT 的驗證,當然除了驗證之外,我們還需要授權,這個我們在下面的章節(jié)中來實現(xiàn)。

參考文檔

  • https://www.zhaohuabing.com/post/2020-05-25-istio-certificate/。
  • https://istio.io/latest/docs/concepts/security/。
  • https://github.com/YaoZengzeng/KubernetesResearch/blob/master/Istio%E5%AE%89%E5%85%A8%E6%A1%86%E6%9E%B6%E8%A7%A3%E6%9E%90.md。
責任編輯:姜華 來源: k8s技術圈
相關推薦

2021-03-12 09:47:52

數(shù)據(jù)管理

2021-03-08 16:59:55

數(shù)據(jù)安全勒索病毒攻擊

2023-06-15 14:45:29

2022-03-03 10:18:02

物聯(lián)網(wǎng)安全漏洞

2018-02-23 10:07:04

2020-04-02 11:06:56

網(wǎng)站安全HTTPS加密

2017-11-01 06:29:59

2016-04-07 08:56:06

2015-12-21 10:08:53

數(shù)據(jù)中心IT安全威脅

2016-01-26 10:51:50

2023-06-13 07:17:12

2015-12-18 10:24:08

2011-08-19 14:48:18

2012-12-27 14:12:23

2022-06-14 07:17:43

Wazuh開源

2018-07-04 13:14:35

2021-12-17 14:06:55

云計算安全工具

2011-08-19 15:22:01

2019-07-02 05:54:27

網(wǎng)絡安全攻擊安全威脅

2020-10-26 10:37:25

邊緣計算
點贊
收藏

51CTO技術棧公眾號

久久久久99| 伊人久久大香线蕉| 亚洲一区在线免费观看| 精品无码久久久久久久动漫| 在线免费观看国产精品| 日韩欧美一区二区三区在线视频 | 久久综合久色欧美综合狠狠| 国产精品日韩专区| 国产午夜小视频| 成人aaaa| 日韩大片免费观看视频播放| 手机看片一级片| 97人澡人人添人人爽欧美| 日本一区二区三区四区在线视频 | 国产不卡一区| 日韩亚洲欧美在线观看| 欧美日韩亚洲一二三| 手机av在线播放| 欧美高清在线精品一区| 黄色99视频| 91精品短视频| 丁香六月久久综合狠狠色| 青草热久免费精品视频| 男女性高潮免费网站| 西野翔中文久久精品国产| 91精品国产综合久久久蜜臀粉嫩 | 韩国欧美一区二区| 欧日韩不卡在线视频| 久草免费在线观看视频| 亚洲男人7777| 国产高潮呻吟久久久| 日本大臀精品| 成人在线一区二区三区| 国产精品久久久久久av| 国产又色又爽又黄的| 综合在线视频| 丝袜亚洲另类欧美重口| 无码h肉动漫在线观看| 国产一级一区二区| 欧美性感一类影片在线播放| 国产精品www在线观看| 日本成人在线播放| 999久久久精品一区二区| 欧美中文字幕一二三区视频| 国产精品50p| 69av成人| 婷婷久久综合九色国产成人 | 欧美少妇一区二区| 女人喷潮完整视频| 都市激情国产精品| 亚洲国产aⅴ天堂久久| 日韩国产小视频| 岛国中文字幕在线| 亚洲天堂网中文字| 黄色www在线观看| 黄色网页在线免费看| 亚洲欧美视频在线观看| 国风产精品一区二区| 3d玉蒲团在线观看| 亚洲一二三区在线观看| 免费国产a级片| 自拍网站在线观看| 欧美小视频在线| 精品久久久久久无码国产| 亚洲a∨精品一区二区三区导航| 日韩欧美一区二区三区久久| 毛片一区二区三区四区| 成人综合网站| 日韩一区二区三区观看| 男人的天堂影院| 最近国产精品视频| 日韩中文字幕在线| 久草视频免费播放| 午夜亚洲性色视频| 国产精品天天狠天天看| 999av视频| 99精品久久久久久| 日韩欧美精品一区二区三区经典| 日韩精品成人av| 亚洲激情中文1区| 天天夜碰日日摸日日澡性色av| 都市激情综合| 欧美乱妇20p| 亚洲av永久无码精品| 国产欧美日韩影院| 欧美精品亚州精品| 中文字幕第四页| 蜜臀久久久99精品久久久久久| 国产一区二区色| 人妻少妇精品无码专区久久| 国产人成亚洲第一网站在线播放| 亚洲精品一区二区三区四区五区| 日本高清成人vr专区| 天天射综合影视| 国产美女18xxxx免费视频| japanese色系久久精品| 国产香蕉一区二区三区在线视频| 深夜福利影院在线观看| 免费在线成人| 97超碰最新| 精品亚洲综合| 亚洲伊人伊色伊影伊综合网| 日韩欧美黄色大片| 精品少妇3p| 久久久精品一区二区| 日产精品久久久| 国内精品免费**视频| 欧美黑人3p| 欧美卡一卡二| 欧美亚洲精品一区| 中文字幕第3页| 香蕉久久网站| 国产精品久久久久久久av电影| 亚洲毛片欧洲毛片国产一品色| 中文字幕av资源一区| 一区二区传媒有限公司| 日韩中文一区二区| 日韩在线中文字| 在线永久看片免费的视频| 国产a区久久久| 亚洲综合第一| 日韩高清中文字幕一区二区| 亚洲国产成人在线视频| 波多野结衣亚洲一区二区| 人禽交欧美网站| 欧美国产视频在线观看| 99色在线观看| 欧美va日韩va| 麻豆天美蜜桃91| 蜜臀久久久99精品久久久久久| 蜜桃臀一区二区三区| 久久www人成免费看片中文| 欧美日韩国产不卡| 日本视频在线免费| 日本伊人午夜精品| 日本一区二区在线视频观看| 在线手机中文字幕| 亚洲精品ady| 日本少妇全体裸体洗澡| 国产传媒日韩欧美成人| 91大学生片黄在线观看| 免费看日产一区二区三区 | 91九色在线播放| 欧美r级在线观看| 欧美日韩国产精品一区二区三区| 日韩有码第一页| 国产电影一区| 在线观看亚洲区| 国产黄网在线观看| 99久久国产综合精品色伊| 欧美交换配乱吟粗大25p| 95精品视频| 久久人人爽人人爽爽久久| 91女人18毛片水多国产| 中文字幕佐山爱一区二区免费| 亚洲美女爱爱视频| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 一区二区三区欧洲区| 欧美成人精品三级在线观看 | 国产suv精品一区二区883| 成人区一区二区| 精品日产乱码久久久久久仙踪林| 亚洲91精品在线| 香港一级纯黄大片| 色综合天天综合网国产成人综合天| 中文字幕一二三四区| 日韩不卡手机在线v区| 一级做a爰片久久| 欧美影院在线| 6080yy精品一区二区三区| 蜜桃成人在线视频| 欧美性大战久久久久久久蜜臀| 国产三级精品三级观看| 国产精品资源网站| 丁香花在线影院观看在线播放| 天堂网av成人| 国产中文字幕91| 俄罗斯一级**毛片在线播放| 日韩精品在线视频美女| 在线电影一区二区| 中文字幕在线成人| 91theporn国产在线观看| 中文字幕一区二区三区在线不卡 | 精品少妇一区二区| 欧美激情国产精品免费| 91在线看国产| 最新国产黄色网址| 伊人成年综合电影网| 欧美一区二区三区成人久久片| 欧美男女视频| 国产欧美一区二区| 亚洲成人精品女人久久久| 偷拍日韩校园综合在线| 微拍福利一区二区| 国产精品小仙女| 成人精品免费网站| 日韩精品资源| 国产美女视频一区二区 | 日本一区免费看| 一级中文字幕一区二区| 青青草原国产免费| 91综合精品国产丝袜长腿久久| 国产97免费视| 色爱综合区网| 中文字幕欧美在线| 天堂网2014av| 91精品国产色综合久久不卡电影| 久久久久久在线观看| 亚洲图片一区二区| 手机免费观看av| 91在线视频播放地址| 人妻巨大乳一二三区| 美女网站一区二区| 人妻熟妇乱又伦精品视频| 综合一区在线| 一区二区成人国产精品 | 亚洲视频sss| 欧美国产极品| 成人综合电影| 国产一区二区| 国产美女精彩久久| 国产精品久久久久av电视剧| 韩国v欧美v日本v亚洲| jizz性欧美10| 播播国产欧美激情| 91在线视频免费看| 在线亚洲欧美视频| 每日更新在线观看av| 亚洲国产精彩中文乱码av在线播放| 国产精品午夜福利| 欧美日本在线看| 在线观看国产小视频| 在线观看日韩高清av| 日韩人妻精品中文字幕| 精品日韩视频在线观看| 日韩av在线播| 亚洲h精品动漫在线观看| 免费人成视频在线| 亚洲一二三区视频在线观看| 久久久久久久久久久久久久久久久 | 国产一区喷水| 美腿丝袜亚洲图片| 国产在线精品一区二区三区| 国产 日韩 欧美 综合 一区| 国产不卡一区二区在线观看| 国产欧美88| 2020国产精品久久精品不卡| 亚洲成人黄色| 国产不卡一区二区在线观看 | 中文字幕九色91在线| av在线免费观看网| 日韩中文在线中文网三级| 自拍视频在线网| 久久精品久久久久久| 尤物在线网址| 韩国一区二区电影| 欧美xoxoxo| 国产精品久久久久久久久久新婚 | 欧美日韩激情电影| 国产精品高潮呻吟久久av无限| jizz久久久久久| 91在线网站视频| 国产精品香蕉| 美日韩精品免费| 日韩三级在线| 久久亚洲a v| 久久狠狠婷婷| jizz18女人| 懂色av一区二区夜夜嗨| 黄色网址在线视频| 国产午夜三级一区二区三| 日韩精品久久久久久久的张开腿让| 亚洲精品国产一区二区精华液 | 日韩精品福利视频| 欧美高清视频在线观看mv| 欧美一二三不卡| 久久成人亚洲| 在线a免费观看| 成人黄页毛片网站| 性欧美精品中出| 亚洲欧美aⅴ...| 少妇一级淫片免费放中国 | 韩日在线一区| 国产成人精品无码播放| 国产一区在线不卡| 给我免费观看片在线电影的| 国产精品伦理在线| 日韩 欧美 亚洲| 欧美日韩国产影片| 天天干天天草天天射| 中文字幕亚洲自拍| 激情网站在线| 国产精品一区电影| 网友自拍一区| 日韩亚洲欧美一区二区| 日本不卡不码高清免费观看| 国产人妖在线观看| 欧美国产精品中文字幕| 日本免费一二三区| 欧美日韩亚洲丝袜制服| 三级小视频在线观看| 精品国产一区久久久| 日本蜜桃在线观看视频| 91最新在线免费观看| 国产一区二区三区日韩精品 | 亚洲精品98久久久久久中文字幕| av电影在线观看| 91精品国产乱码久久久久久蜜臀 | 免费av成人在线| 国产又黄又粗又猛又爽的视频| 亚洲欧美国产77777| 国产免费www| 亚洲激情在线视频| 里番在线播放| 91色视频在线观看| 日韩大片在线播放| www.亚洲天堂网| av亚洲精华国产精华精华| 黄色一级视频免费| 91精品国产日韩91久久久久久| 97电影在线| 国产精品jizz在线观看麻豆| 美女主播精品视频一二三四| 六月婷婷激情综合| 国产麻豆精品在线| 国产一区二区三区视频播放| 91福利视频网站| 黄色国产在线| 日本亚洲欧美三级| 欧美性生活一级片| 午夜免费福利小电影| 成人国产电影网| 亚洲一区二区91| 欧美精品一区二区三区蜜臀| 福利在线导航136| 国产精品推荐精品| 亚洲深夜福利| 亚洲第一成人网站| 色综合久久六月婷婷中文字幕| 天堂中文在线资| 欧美最近摘花xxxx摘花| 精品一区在线| 中文字幕国产传媒| 国产精品久久久久久久久果冻传媒 | 日本在线看片免费人成视1000| 国产精品在线看| 91视频久久| a级大片免费看| 亚洲午夜久久久久久久久电影院 | 国产夫绿帽单男3p精品视频| 欧美大片免费播放| 九色国产在线观看| 欧美肥臀大乳一区二区免费视频| 电影一区中文字幕| 中文字幕免费高| 国产精品一二二区| 国产在线视频卡一卡二| 亚洲精品久久久久久下一站| 亚洲色图官网| 日本高清视频一区二区三区| 毛片在线视频| 亚洲一区二区三区四区视频| 欧美精品麻豆| 制服丝袜第一页在线观看| 欧美日韩一区二区免费视频| 福利视频在线导航| 成人免费看黄网站| 狠狠综合久久| 中日韩精品一区二区三区| 欧美性色aⅴ视频一区日韩精品| aaa日本高清在线播放免费观看| 亚洲a中文字幕| 99国产精品99久久久久久粉嫩| 性少妇bbw张开| 在线不卡中文字幕| 91资源在线观看| 日本视频精品一区| 精品写真视频在线观看| 精品无码一区二区三区电影桃花| 日韩av在线高清| 亚洲精品成a人ⅴ香蕉片| 日韩激情视频一区二区| 久久精品这里都是精品| 99久久精品无免国产免费 | 欧美午夜精品久久久久久蜜| 蜜桃av噜噜一区二区三区小说| 精品97人妻无码中文永久在线 | 国产欧美日韩亚洲| 麻豆久久久久久| 动漫精品一区一码二码三码四码| 夜夜嗨av一区二区三区免费区| 69精品国产久热在线观看| 欧美伦理片在线看| 亚洲国产视频一区二区| av在线电影院| 久久国产精品高清| 狠狠色丁香婷综合久久| 日韩三级一区二区| 欧美极品少妇xxxxⅹ免费视频| 色综合狠狠操|