• istio-ingress网关安全-为 Gateway 提供 HTTPS 加密支持


    为服务器和客户端生成证书

    可以使用各种常用工具来生成证书和私钥。这个例子中用了一个来自 https://github.com/nicholasjackson/mtls-go-example脚本来完成工作。

    1、克隆示例代码库

    git clone https://github.com/nicholasjackson/mtls-go-example

    2、进入代码库文件夹

    pushd mtls-go-example

    3、为 httpbin.example.com 生成证书。注意要把下面命令中的 password 替换为其它值。

    ./generate.sh httpbin.example.com <password>

    看到提示后,所有问题都输入 Y 即可。这个命令会生成四个目录:1_root2_intermediate3_application 以及 4_client。这些目录中包含了后续过程所需的客户端和服务端证书。

    4、把证书移动到 httpbin.example.com 目录之中:

    mkdir ../httpbin.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.example.com

    为单一主机配置 TLS Ingress Gateway

    1、启动 httpbin 样例:

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
    spec:
      ports:
      - name: http
        port: 8000
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          containers:
          - image: docker.io/citizenstig/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 8000
    EOF

    2、为 Ingress Gateway 创建 Secret:

    kubectl create -n istio-system secret generic httpbin-credential 
    --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem 
    --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem

    secret name 不能istio 或者 prometheus为开头, 且 secret 不能 包含 token 字段。

    3、创建一个 Gateway ,其 servers: 字段的端口为 443,设置 credentialName 的值为 httpbin-credential。这个值就是 Secret 的名字。TLS 模式设置为 SIMPLE

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: mygateway
    spec:
      selector:
        istio: ingressgateway # use istio default ingress gateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          credentialName: "httpbin-credential" # must be the same as secret
        hosts:
        - "httpbin.example.com"
    EOF

    4、配置 Gateway 的 Ingress 流量路由,并配置对应的 VirtualService

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "httpbin.example.com"
      gateways:
      - mygateway
      http:
      - match:
        - uri:
            prefix: /status
        - uri:
            prefix: /delay
        route:
        - destination:
            port:
              number: 8000
            host: httpbin
    EOF

    5、用 HTTPS 协议访问 httpbin 服务:

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418

    httpbin 服务会返回 418 I’m a Teapot

    6、删除 Gateway 的 Secret,并新建另外一个,然后修改 Ingress Gateway 的凭据:

    kubectl -n istio-system delete secret httpbin-credential
    pushd mtls-go-example
    ./generate.sh httpbin.example.com <password>
    mkdir ../httpbin.new.example.com && mv 1_root 2_intermediate 3_application 4_client ../httpbin.new.example.com
    kubectl create -n istio-system secret generic httpbin-credential 
    --from-file=key=httpbin.new.example.com/3_application/private/httpbin.example.com.key.pem 
    --from-file=cert=httpbin.new.example.com/3_application/certs/httpbin.example.com.cert.pem

    7、使用 curl 访问 httpbin 服务:

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.new.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
    ...
    HTTP/2 418
    ...
    -=[ teapot ]=-
    
       _...._
     .'  _ _ `.
    | ."` ^ `". _,
    \_;`"---"`|//
      |       ;/
      \_     _/
        `"""`

    8、如果尝试使用之前的证书链来再次访问 httpbin,就会得到失败的结果:

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (OUT), TLS alert, Server hello (2):
    * SSL certificate problem: unable to get local issuer certificate

    为 TLS Ingress Gateway 配置多个主机名

    可以把多个主机名配置到同一个 Ingress Gateway 上,例如 httpbin.example.comhelloworld-v1.example.com。Ingress Gateway 会为每个 credentialName 获取一个唯一的凭据。

    1、要恢复 “httpbin” 的凭据,请删除对应的 secret 并重新创建。

    kubectl -n istio-system delete secret httpbin-credential
    kubectl create -n istio-system secret generic httpbin-credential 
    --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem 
    --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem

    2、启动 hellowworld-v1 示例:

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: helloworld-v1
      labels:
        app: helloworld-v1
    spec:
      ports:
      - name: http
        port: 5000
      selector:
        app: helloworld-v1
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld-v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: helloworld-v1
          version: v1
      template:
        metadata:
          labels:
            app: helloworld-v1
            version: v1
        spec:
          containers:
          - name: helloworld
            image: istio/examples-helloworld-v1
            resources:
              requests:
                cpu: "100m"
            imagePullPolicy: IfNotPresent #Always
            ports:
            - containerPort: 5000
    EOF

    3、为 Ingress Gateway 创建一个 Secret。如果已经创建了 httpbin-credential,就可以创建 helloworld-credential Secret 了。

     ./generate.sh helloworld-v1.example.com <password>
    mkdir ../helloworld-v1.example.com && mv 1_root 2_intermediate 3_application 4_client ../helloworld-v1.example.com
    kubectl create -n istio-system secret generic helloworld-credential 
    --from-file=key=helloworld-v1.example.com/3_application/private/helloworld-v1.example.com.key.pem 
    --from-file=cert=helloworld-v1.example.com/3_application/certs/helloworld-v1.example.com.cert.pem

    4、定义一个 Gateway ,其中包含了两个 server,都开放了 443 端口。两个 credentialName 字段分别赋值为 httpbin-credentialhelloworld-credential。设置 TLS 的 mode 为 SIMPLE

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: mygateway
    spec:
      selector:
        istio: ingressgateway # use istio default ingress gateway
      servers:
      - port:
          number: 443
          name: https-httpbin
          protocol: HTTPS
        tls:
          mode: SIMPLE
          credentialName: "httpbin-credential"
        hosts:
        - "httpbin.example.com"
      - port:
          number: 443
          name: https-helloworld
          protocol: HTTPS
        tls:
          mode: SIMPLE
          credentialName: "helloworld-credential"
        hosts:
        - "helloworld-v1.example.com"
    EOF

    5、配置 Gateway 的流量路由,配置 VirtualService

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: helloworld-v1
    spec:
      hosts:
      - "helloworld-v1.example.com"
      gateways:
      - mygateway
      http:
      - match:
        - uri:
            exact: /hello
        route:
        - destination:
            host: helloworld-v1
            port:
              number: 5000
    EOF

    6、向 helloworld-v1.example.com 发送 HTTPS 请求:

    curl -v -HHost:helloworld-v1.example.com 
    --resolve helloworld-v1.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert helloworld-v1.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://helloworld-v1.example.com:$SECURE_INGRESS_PORT/hello
    HTTP/2 200

    7、发送 HTTPS 请求到 httpbin.example.com,还是会看到茶壶:

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
        -=[ teapot ]=-
    
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/
            `"""`

    配置双向 TLS Ingress Gateway

    可以对 Gateway 的定义进行扩展,加入双向 TLS 的支持。要修改 Ingress Gateway 的凭据,就要删除并重建对应的 Secret。服务器会使用 CA 证书对客户端进行校验,因此需要使用 cacert 字段来保存 CA 证书:

    kubectl -n istio-system delete secret httpbin-credential
    kubectl create -n istio-system secret generic httpbin-credential  
    --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem 
    --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem 
    --from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem

    1、修改 Gateway 定义,设置 TLS 的模式为 MUTUAL

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
     name: mygateway
    spec:
     selector:
       istio: ingressgateway # use istio default ingress gateway
     servers:
     - port:
         number: 443
         name: https
         protocol: HTTPS
       tls:
         mode: MUTUAL
         credentialName: "httpbin-credential" # must be the same as secret
       hosts:
       - "httpbin.example.com"
    EOF

    2、使用前面的方式尝试发出 HTTPS 请求,会看到失败的过程:

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
    * TLSv1.3 (OUT), TLS handshake, Client hello (1):
    * TLSv1.3 (IN), TLS handshake, Server hello (2):
    * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
    * TLSv1.3 (IN), TLS handshake, Request CERT (13):
    * TLSv1.3 (IN), TLS handshake, Certificate (11):
    * TLSv1.3 (IN), TLS handshake, CERT verify (15):
    * TLSv1.3 (IN), TLS handshake, Finished (20):
    * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.3 (OUT), TLS handshake, Certificate (11):
    * TLSv1.3 (OUT), TLS handshake, Finished (20):
    * TLSv1.3 (IN), TLS alert, unknown (628):
    * OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0

    3、在 curl 命令中加入客户端证书和私钥的参数,重新发送请求。(客户端证书参数为 --cert,私钥参数为 --key

    curl -v -HHost:httpbin.example.com 
    --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST 
    --cacert httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem 
    --cert httpbin.example.com/4_client/certs/httpbin.example.com.cert.pem 
    --key httpbin.example.com/4_client/private/httpbin.example.com.key.pem 
    https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418
        -=[ teapot ]=-
    
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/

    4、

    如果不想用 httpbin-credential secret 来存储所有的凭据, 可以创建两个单独的 secret :

    • httpbin-credential 用来存储服务器的秘钥和证书
    • httpbin-credential-cacert 用来存储客户端的 CA 证书且一定要有 -cacert 后缀

    使用以下命令创建两个单独的 secret :

    kubectl -n istio-system delete secret httpbin-credential
    kubectl create -n istio-system secret generic httpbin-credential  
    --from-file=key=httpbin.example.com/3_application/private/httpbin.example.com.key.pem 
    --from-file=cert=httpbin.example.com/3_application/certs/httpbin.example.com.cert.pem
    kubectl create -n istio-system secret generic httpbin-credential-cacert  
    --from-file=cacert=httpbin.example.com/2_intermediate/certs/ca-chain.cert.pem

    参考:

    https://preliminary.istio.io/latest/zh/docs/tasks/traffic-management/ingress/secure-ingress-sds/

  • 相关阅读:
    GdiPlus[34]: IGPGraphicsPath (一)
    GdiPlus[33]: 基本绘图与填充命令
    GdiPlus[29]: IGPPen: 虚线样式
    [征询意见]博客园logo
    [公告]网站恢复正常运行
    [公告]博客园将与博文视点合作推出一系列.NET图书
    [公告]由Bruce Zhang负责博客园的出书工作
    通过Windows Live Alerts订阅博客园首页RSS
    [征询意见]博客园新logo
    [新功能]新闻管理
  • 原文地址:https://www.cnblogs.com/fat-girl-spring/p/15210599.html
Copyright © 2020-2023  润新知