Istion-ingress Gateway+cert-Manager로 GKE의 HTTPS 대응을 신속하게 실현

15363 단어 KubernetesIstiotech
이 글은 Istion-ingress Gateway+cert-Manager를 사용하는 HTTPS에 대응할 때의 설정 절차와 중점을 총결하였다.
이번 검증에는 다음과 같은 동기가 있다.
  • Istio에서 놀고 싶은 환경
  • GKE에 있는 HTTPS에 대응하는 설정도 확인하고 싶다
  • (簇外의 연결,cert-Manager의 인증서 관리를 이용한다)
  • (GKE Cluster 제작에 대한 검증이 있었기 때문에)
  • 비슷한 시기에도 다음 기사를 검증했기 때문에 링크부터 거슬러 올라가는 GKE 클러스터 제작용 tf 파일군 제작 기반인 GKE 클러스터를 활용할 수 있다.
    https://zenn.dev/taxin/articles/gke-infra-cicd
    그 밖에 이번에는 다음과 같은 전제를 바탕으로 진행한다.
  • 인증에 사용된 도메인 이름은 Google Domaains에서 가져옵니다
  • .
  • Istio-ingress Gateway가 type: NodePort(Cloud Load Balaning(CLB)의 비용 절약을 위해)
  • 로 변경됨)

    GKE 만들기


    각 어셈블리에 대한 Deploy의 GKE를 생성하는 Cluster.
    다음 규격을 사용하여 그룹을 만들고 있습니다.
  • 노드 시스템 유형: e2-medium
  • 노드 수: 3
  • Node Pool: Preemtible VMs
  • Network Tag: istio
  • 비활성화된 추가: Istio, HTTP load balancing, Kubernetes Engine Monitoring
  • 이번에 GKE Adoon으로 제공된 Istio는 무효화를 바탕으로 수동으로 Istio 설정을 진행한다.
    각종 add-on의 무효화에 관하여 GCP의 공식 지침이 있으니 참고하십시오.
    https://cloud.google.com/kubernetes-engine/docs/how-to/small-cluster-tuning?hl=ja#kubernetes-engine-monitoring
    또 Istio의 Setup을 구상해 다음과 같은 변경을 추가했다.
    (변경 사항에 대한 자세한 내용은 아래 링크를 참조하십시오.)
  • Firewall Rule의 제작allow - tcp:10250,tcp:443,tcp:15017
  • Network Policy의 추가 유효성
  • https://istio.io/latest/docs/setup/platform-setup/gke/

    도메인 획득 + Cloudflare DNS 설정


    HTTPS에 대응하기 위해 도메인 취득과 Cloudflare DNS 설정을 진행합니다.
    우선, 임의의 등록표를 사용하여 도메인 이름을 얻는다.
    (Google Domaains 검색 방법은 다음 링크를 참조하십시오.)
    https://support.google.com/domains/answer/4491208?hl=ja&ref_topic=9143021
    그런 다음 Cloudflare DNS 측면의 설정 작업을 수행합니다.
    계정을 미리 만든 후 계정의 홈 화면에서 "Adda site"를 클릭하여 도메인 이름을 추가합니다.
    https://support.cloudflare.com/hc/ja/articles/201720164-Cloudflare계정 만들기 및 사이트 추가
    그런 다음 레지스트리 옆에 지정된 DNS 서버 목록을 Cloudflare DNS 서버에 재지정합니다.
    https://support.cloudflare.com/hc/ja/articles/205195708
    https://support.google.com/domains/answer/3290309?hl%3Den

    Cloudflare Sync 설정


    이번 GKE 클러스터는 노드로 활용Preemtible VMs되고 있다.Preemtible VMs 최장 24시간으로 종료 후 노드의 Public IP도 변경되므로 A 레코드 업데이트(동기화)가 필요합니다.
    https://cloud.google.com/kubernetes-engine/docs/how-to/preemptible-vms?hl=ja
    IP는 kubernetes-Coludflare-sync를 동기화합니다.
    이 Custom Controller는 자신이 관리하는 도메인 이름에서 GKE Nodes의 외부 IP를 뺀 상태로 유지됩니다.
    https://github.com/calebdoxsey/kubernetes-Cloudflare-sync
    // CloudflareのAPI keysをSecretsとして登録する
    kubectl create secret generic cloudflare \
        --from-literal=email=<email> \
        --from-literal=api-key=<api_key>
    
    // Service Accountの設定
    kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user <email>
    kubectl apply -f ./sync-sa.yaml
    
    // ImageのBuild + Push
    docker build -t gcr.io/<gcp_project_id>/kubernetes-cloudflare-sync:latest . 
    docker push gcr.io/<gcp_project_id>/kubernetes-cloudflare-sync:latest
    
    // Deploymentの作成([Configure]のsample deployment)
    kubectl apply -f ./sync-deployment.yaml
    

    Istio(IngressGateway) 설정


    여기까지의 준비가 완료되면 Istio-Ingress Gateway 설정을 진행한다.
    단계는 getting-started의 내용과 같다.
    https://istio.io/latest/docs/setup/getting-started/
    Ingress Gateway의 Manifest 내type: LoadBalancertype: NodePort 변경을 위해 프로필은 지정된 demo 이후에generate Manifest입니다.
    https://istio.io/latest/docs/setup/additional-setup/config-profiles/
    // demo Profile用のManifestのディレクトリを用意しておく
    $ mkdir temp-profile 
    
    <dir>
    |
    |- istio-1.8.1
    |
    |- temp-profile
    
    // Istioのdownload
    $ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.8.1 TARGET_ARCH=x86_64 sh -
    
    $ cd istio-1.8.1
    $ ./bin/istioctl manifest generate --set profile=demo >> ./../temp/istio-demo-profile.yaml
    
    Ingress Gateway의 Manifest에서 type: LoadBalancertype: NodePort 수정된 Manifest를 Apply로 합니다.
    ---
    apiVersion: v1
    kind: Service
    metadata:
      annotations: null
      labels:
        app: istio-ingressgateway
        install.operator.istio.io/owning-resource: unknown
        istio: ingressgateway
        istio.io/rev: default
        operator.istio.io/component: IngressGateways
        release: istio
      name: istio-ingressgateway
      namespace: istio-system
    
      ...
      
      selector:
        app: istio-ingressgateway
        istio: ingressgateway
      
      // NodePortに変更する
      type: NodePort
    ---
    
    $ kubectl apply -f ./../temp/istio-demo-profile.yaml
    
    $ kubectl label namespace default istio-injection=enabled
    
    $ kubectl get svc --all-namespaces
    NAMESPACE      NAME                   TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                                                                      AGE
    default        kubernetes             ClusterIP   10.1.0.1     <none>        443/TCP                                                                      3h38m
    istio-system   istio-egressgateway    ClusterIP   10.1.0.190   <none>        80/TCP,443/TCP,15443/TCP                                                     72s
    istio-system   istio-ingressgateway   NodePort    10.1.1.172   <none>        15021:32308/TCP,80:31232/TCP,443:30791/TCP,31400:32322/TCP,15443:32480/TCP   71s
    istio-system   istiod                 ClusterIP   10.1.1.23    <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        70s
    kube-system    calico-typha           ClusterIP   10.1.3.58    <none>        5473/TCP                                                                     173m
    kube-system    kube-dns               ClusterIP   10.1.0.10    <none>        53/UDP,53/TCP                                                                3h38m
    kube-system    metrics-server         ClusterIP   10.1.0.54    <none>        443/TCP                                                                      3h38m
    
    $ kubectl describe node | grep ExternalIP
      ExternalIP:   <node1_ip>
      ExternalIP:   <node2_ip>
      ExternalIP:   <node3_ip>
    
    다음에 Istio-ingress Gateway를 만들 때 Firewall Rule를 만들어서 분배된 GKE 노드의 포트를 통신하고 NodePort에서 외부에서 통신할 수 있도록 한다.
    필요한 경우 GKE 노드에 대한 네트워크 태그를 제공합니다.
    // 15021:32308/TCP,80:31232/TCP,443:30791/TCP,31400:32322/TCP,15443:32480/TCP の例であれば
    // <http_port_number> → 31232, <https_port_number> → 30791となる
    gcloud compute firewall-rules create allow-conn-from-nodeport \
        --network=default \
        --project <gcp_project_id> \
        --target-tags istio \
        --allow tcp:<http_port_number>,<https_port_number>
    
    HTTP 통신은 이런 상태에서도 가능할 것이다.
    Deploy에서 httpbin 등의 Sample deployment를 받은 후 소통 확인을 해주세요.
    https://github.com/istio/istio/tree/release-1.8/samples/httpbin

    cert-Manager 설정


    HTTPS에 대응하기 위해 이번에는cert-Manager를 이용한 증명서와 Istio 측의 라우팅 설정을 추가로 발행한다.
    https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/
    $ export CM_VERSION="v1.1.0"
    $ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/$CM_VERSION/cert-manager.yaml
    customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
    ...
    mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
    validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
    
    $ kubectl get pods --namespace cert-manager
    NAME                                      READY   STATUS    RESTARTS   AGE
    cert-manager-64887fb9d6-2hjxv             1/1     Running   0          103s
    cert-manager-cainjector-99977ff45-tdw7s   1/1     Running   0          104s
    cert-manager-webhook-64c5d4c9db-29b2c     1/1     Running   0          103s
    
    cert-Manager의 Deploy가 완성되면 다음 문서에 따라 Cloudflare의 DNS-01 도전에 사용할 Issuer/Cluster Issuer를 만듭니다.
    https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/#api-tokens
    apiVersion: v1
    kind: Secret
    metadata:
      name: cloudflare-api-token-secret
      namespace: istio-system
    type: Opaque
    stringData:
      api-token: <token>
    
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: cloudflare-prod
      namespace: istio-system
    spec:
      acme:
        email: <email>
        privateKeySecretRef:
          name: cloudflare-account-key
        server: https://acme-v02.api.letsencrypt.org/directory
        solvers:
        - dns01:
            cloudflare:
              apiTokenSecretRef:
                key: api-token
                name: cloudflare-api-token-secret
              email: <email>
    
    에서 Issuer/ClusterIssuer를 만든 후 Ceertificate를 만듭니다.
    https://istio.io/latest/docs/ops/integrations/certmanager/
    Certficate를 제작할 때 주의해야 할 것은 istio-ingessgateway의 Deployment와 같은 Namespaceistio-system가 제작했다는 점이다.
    (이번 검증에서는 Issuer, Celtificate 등cert-Manager 관련 리소스istio-system가 제작했다.)
    The Certificate should be created in the same namespace as the istio-ingressgateway deployment.
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: <domain>
      namespace: istio-system
    spec:
      commonName: <domain>
      dnsNames:
      - <domain>
      issuerRef:
        kind: Issuer
        name: cloudflare-prod
      secretName: <secret_name>
    
    Certficate의 Manifest에 지정된 Secret Name에서 Secret이 제대로 만들어졌는지 확인합니다.
    $ kubectl get secret -n istio-system
    ...
    <secret_name>                          Opaque                                1      21s
    
    다음으로Manifest에서 지불한 Domaain, 제작된 Certficate(Secret)를 지정하고gateway, vs 서비스의 자원을 제작한다.
    https://istio.io/latest/docs/tasks/traffic-management/ingress/secure-ingress/
    여기서 만든 자원은 다음과 같은 역할을 합니다.
  • gateway: 요청을 받는istio-ingssgateway(Deployment)를 설정하는 자원(port,protocol,cert)
  • vservice: 업무의 루트 목적지를 설정하는 규칙에 사용되는 자원
  • apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway # use Istio default gateway implementation
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          # secret name of certificate
          credentialName: <secret_name>
        # This should match a DNS name in the Certificate
        hosts:
        - <domain>
    
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - <domain>
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /status
        - uri:
            prefix: /delay
        route:
        - destination:
            port:
              number: 8000
            # The name of a service from the service registry.
            host: httpbin
    
    이렇게 하면 집단 이외의 요청 루트를 Backend의Pod에 연결할 수 있다.
    생성된 가상 리소스를 사용하여 받은 HTTP(S) 요청을 다음과 같이 처리합니다.
  • gateway 측에서host,port,protocol 등 조건 확인
  • (LB 없이 Host Header 부여)
  • vs 서비스 측에서 정의한 URL 모드의 규칙에 따라 목적지를 확정한다(ex./status
  • Istio-IngressGateway의 라우팅 프로세스는 아래 Blog를 참조하십시오.
    https://blog.jayway.com/2018/10/22/understanding-istio-ingress-gateway-in-kubernetes/

    HTTPS 연결을 통한 인증


    모든 설정이 완료되면 연결을 확인합니다.
    요청한 라우팅 목적지로서 Deployment 를 미리 Deploy httpbin 으로 설정합니다.
    https://github.com/istio/istio/tree/release-1.8/samples/httpbin
    $ cd istio-1.8.1
    $ kubectl apply -f samples/httpbin/httpbin.yaml
    
    도메인 이름과 Istio-ingress Gateway에서 지불한 HTTPS용port을 확인하고 다음curl 명령을 실행합니다.200 OK회신 후 정상적으로 설치되었는지 확인할 수 있습니다.
    $ curl -s -I -HHost:<domain> "https://<domain>:<port_number>/status/200"
    HTTP/2 200
    server: istio-envoy
    date: Fri, 01 Jan 2021 13:35:47 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 1
    

    끝맺다


    우리는 Istio-Ingress Gateway+cert-Manager를 사용하는 HTTPS에 대응할 때의 설정 절차를 총괄하였다.
    앞으로도 아이스티오 자체 검증을 할 생각이다.

    참고 자료

  • http://www.doxsey.net/blog/kubernetes--the-surprisingly-affordable-platform-for-personal-projects
  • 좋은 웹페이지 즐겨찾기