GKE 어플리케이션과 클라우드 SQL 데이터베이스 간 연결 보호

에서 클라우드 SQL 인스턴스를 만들었습니다.이 부분에서, 우리는 그것들을 함께 놓고Wordpress를Kubernetes에 배치하여 클라우드 SQL 데이터베이스에 연결할 것이다.우리의 목표는 다음과 같다.
  • 클라우드 SQL 인스턴스에 연결할 IAM 서비스 계정을 생성합니다.Wordpress Kubernetes 서비스 계정과 연결됩니다.
  • 두 개의 배치를 만듭니다. 하나는 Wordpress에 사용되고 다른 하나는 Cloud SQL Proxy에 사용됩니다.
  • 구름장갑 보안 정책을 만들고 부하 평형기 유량을 권한 수여 네트워크로만 제한한다.
  • OAuth는 인증 에이전트를 활성화하기 위해 화면과 자격 증명을 구성합니다.
  • SSL 인증서를 만들고 HTTPS 리디렉션을 활성화합니다.

  • IAM 서비스 계정


    Workload Identity는 GKE에서 실행되는 앱에서 구글 클라우드 서비스에 접근하는 것을 추천하는 방식이다.

    With Workload Identity, you can configure a Kubernetes service account to act as a Google service account. Pods running as the Kubernetes service account will automatically authenticate as the Google service account when accessing Google Cloud APIs.


    이 구글 서비스 계정을 만들어 봅시다.파일을 만듭니다infra/plan/service-account.tf.
    resource "google_service_account" "web" {
      account_id   = "cloud-sql-access"
      display_name = "Service account used to access cloud sql instance"
    }
    
    resource "google_project_iam_binding" "cloudsql_client" {
      role    = "roles/cloudsql.client"
      members = [
        "serviceAccount:cloud-sql-access@${data.google_project.project.project_id}.iam.gserviceaccount.com",
      ]
    }
    
    data "google_project" "project" {
    }
    
    그리고 infra/k8s/data/service-account.yaml의 관련 Kubernetes 서비스 계정:
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      annotations:
        iam.gke.io/gcp-service-account: cloud-sql-access@<PROJECT_ID>.iam.gserviceaccount.com
      name: cloud-sql-access
    
    업데이트된 terraform을 실행합니다.
    cd infra/plan
    
    terraform apply
    
    Kubernetes 서비스 계정을 만들려면 다음과 같이 하십시오.
    gcloud container clusters get-credentials private --region $REGION --project $PROJECT_ID
    
    $ kubectl create namespace wordpress
    
    sed -i "s/<PROJECT_ID>/$PROJECT_ID/g;" infra/k8s/data/service-account.yaml
    
    $ kubectl create -f infra/k8s/data/service-account.yaml -n wordpress
    
    클라우드 SQL 에이전트 배치는 Kubernetes 서비스 계정을 사용하여 클라우드 SQL 실례에 접근할 것입니다.
    Kubernetes 서비스 계정이 둘 사이의 IAM 정책을 통해 시뮬레이션된 Google 서비스 계정을 연결할 수 있도록 합니다.
    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:$PROJECT_ID.svc.id.goog[wordpress/cloud-sql-access]" \
      cloud-sql-access@$PROJECT_ID.iam.gserviceaccount.com
    

    클라우드 SQL 에이전트


    Cloud SQL Auth 에이전트를 사용하여 네트워크를 위임하거나 SSL을 구성할 필요 없이 Cloud SQL 인스턴스에 대한 액세스를 보호합니다.
    리소스 배포부터 시작하겠습니다.infra/k8s/data/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: cloud-sql-proxy
      name: cloud-sql-proxy
    spec:
      selector:
        matchLabels:
          app: cloud-sql-proxy
      strategy: {}
      replicas: 3
      template:
        metadata:
          labels:
            app: cloud-sql-proxy
        spec:
          serviceAccountName: cloud-sql-access
          containers: 
            - name: cloud-sql-proxy
              image: gcr.io/cloudsql-docker/gce-proxy:1.23.0
              ports:
                - containerPort: 3306
                  protocol: TCP
              envFrom:
                - configMapRef:
                    name: cloud-sql-instance
              command:
                - "/cloud_sql_proxy"
                - "-ip_address_types=PRIVATE"
                - "-instances=$(CLOUD_SQL_PROJECT_ID):$(CLOUD_SQL_INSTANCE_REGION):$(CLOUD_SQL_INSTANCE_NAME)=tcp:0.0.0.0:3306"
              securityContext:
                runAsNonRoot: true
              resources:
                requests:
                  memory: 2Gi
                  cpu: 1
    
    자원을 배치하는 것은 이전에 만들어진 서비스 계정을 가리킨다.Kubernetes 구성 매핑에서 클라우드 SQL 인스턴스 세부 정보를 읽어들이려면 다음과 같이 하십시오.infra/k8s/data/config-map.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: cloud-sql-instance
    data:
      CLOUD_SQL_INSTANCE_NAME: <CLOUD_SQL_INSTANCE_NAME>
      CLOUD_SQL_INSTANCE_REGION: <CLOUD_SQL_REGION>
      CLOUD_SQL_PROJECT_ID: <CLOUD_SQL_PROJECT_ID>
    
    Google은 Kubernetes 서비스를 사용하여 자원을 공개적으로 배치합니다.infra/k8s/data/service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: cloud-sql-proxy
      name: cloud-sql-proxy
    spec:
      ports:
        - port: 3306
          protocol: TCP
          name: cloud-sql-proxy
          targetPort: 3306
      selector:
        app: cloud-sql-proxy
    
    리소스를 만들고 연결이 설정되었는지 확인합니다.
    cd infra/plan
    
    sed -i "s/<CLOUD_SQL_PROJECT_ID>/$PROJECT_ID/g;s/<CLOUD_SQL_INSTANCE_NAME>/$(terraform output cloud-sql-instance-name | tr -d '"')/g;s/<CLOUD_SQL_REGION>/$REGION/g;" ../k8s/data/config-map.yaml
    
    $ kubectl create -f ../k8s/data -n wordpress
    
    $ kubectl get pods -l app=cloud-sql-proxy -n wordpress
    
    NAME                              READY   STATUS    RESTARTS   AGE
    cloud-sql-proxy-fb9968d49-hqlwb   1/1     Running   0          4s
    cloud-sql-proxy-fb9968d49-wj498   1/1     Running   0          5s
    cloud-sql-proxy-fb9968d49-z95zw   1/1     Running   0          4s
    
    $ kubectl logs cloud-sql-proxy-fb9968d49-hqlwb -n wordpress
    
    2021/06/23 14:43:21 current FDs rlimit set to 1048576, wanted limit is 8500. Nothing to do here.
    2021/06/23 14:43:25 Listening on 0.0.0.0:3306 for <PROJECT_ID>:<REGION>:<CLOUD_SQL_INSTANCE_NAME>
    2021/06/23 14:43:25 Ready for new connections
    
    좋아요!Wordpress 응용 프로그램으로 이동합니다.

    Wordpress 응용 프로그램


    리소스 배포부터 시작하겠습니다.infra/k8s/web/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: wordpress
      labels:
        app: wordpress
    spec:
      selector:
        matchLabels:
          app: wordpress
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: wordpress
        spec:
          containers:
            - image: wordpress
              name: wordpress
              env:
              - name: WORDPRESS_DB_HOST
                value: cloud-sql-proxy:3306
              - name: WORDPRESS_DB_USER
                value: wordpress
              - name: WORDPRESS_DB_NAME
                value: wordpress
              - name: WORDPRESS_DB_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: mysql
                    key: password
              ports:
                - containerPort: 80
                  name: wordpress
              volumeMounts:
                - name: wordpress-persistent-storage
                  mountPath: /var/www/html
              livenessProbe:
                initialDelaySeconds: 30
                httpGet:
                  port: 80
                  path: /wp-admin/install.php # at the very beginning, this is the only accessible page. Don't forget to change to /wp-login.php 
              readinessProbe:
                httpGet:
                  port: 80
                  path: /wp-admin/install.php
              resources:
                requests:
                  cpu: 1000m
                  memory: 2Gi
                limits:
                  cpu: 1200m
                  memory: 2Gi
          volumes:
            - name: wordpress-persistent-storage
              persistentVolumeClaim:
                claimName: wordpress
    
    infra/k8s/web/service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: wordpress
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
    spec:
      type: ClusterIP
      ports:
      - port: 80
        targetPort: 80
      selector:
        app: wordpress
    

    The cloud.google.com/neg annotation specifies that port 80 will be associated with a zonal network endpoint group (NEG). See Container-native load balancing for information on the benefits, requirements, and limitations of container-native load balancing.


    Wordpress를 위한 PVC를 만들었습니다.infra/k8s/web/volume-claim.yaml
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: wordpress
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi
    
    Kubernetes 입구 자원을 초기화함으로써 이 부분을 완성합니다.이 자원은 인터넷에서Wordpress 프로그램에 접근할 수 있도록 합니다.
    파일 생성infra/k8s/web/ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.global-static-ip-name: "wordpress"
        kubernetes.io/ingress.class: "gce"
      name: wordpress
    spec:
      defaultBackend:
        service:
          name: wordpress
          port:
            number: 80
      rules:
      - http:
          paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: wordpress
                port:
                  number: 80
    

    The kubernetes.io/ingress.global-static-ip-name annotation specifies the name of the global IP address resource to be associated with the HTTP(S) Load Balancer. [2]


    리소스를 만들고 Wordpress 응용 프로그램을 테스트합니다.
    cd infra/k8s
    
    $ kubectl create secret generic mysql \
        --from-literal=password=$(gcloud secrets versions access latest --secret=wordpress-admin-user-password --project $PROJECT_ID) -n wordpress
    
    gcloud compute addresses create wordpress --global
    
    $ kubectl create -f web -n wordpress
    
    $ kubectl get pods -l app=wordpress -n wordpress
    
    NAME                         READY   STATUS    RESTARTS   AGE
    wordpress-6d58d85845-2d7x2   1/1     Running   0          10m
    
    $ kubectl get ingress -n wordpress
    NAME        CLASS    HOSTS   ADDRESS         PORTS   AGE
    wordpress   <none>   *       34.117.187.51   80      16m
    

    누구나 이 프로그램에 접근할 수 있습니다.데이터 흐름을 유일하게 권한을 부여받은 네트워크로 제한하는 클라우드 장갑 보안 정책을 만듭니다.

    운장갑 안전 전략


    외부 HTTP(S) 로드 밸런서에 전송되는 전송 트래픽을 필터링하기 위해 Cloud Armor security policy를 사용합니다.
    생성ìnfra/plan/cloud-armor.tf:
    resource "google_compute_security_policy" "wordpress" {
      name = "wordpress"
    
      rule {
        action   = "allow"
        priority = "1000"
        match {
          versioned_expr = "SRC_IPS_V1"
          config {
            src_ip_ranges = var.authorized_source_ranges
          }
        }
        description = "Allow access to authorized source ranges"
      }
    
      rule {
        action   = "deny(403)"
        priority = "2147483647"
        match {
          versioned_expr = "SRC_IPS_V1"
          config {
            src_ip_ranges = ["*"]
          }
        }
        description = "default rule"
      }
    
    }
    
    업데이트된 terraform을 실행합니다.
    cd infra/plan
    
    terraform apply
    

    Kubernetes에서 백엔드 설정을 만들고 보안 정책을 참고하십시오.

    BackendConfig custom resource definition (CRD) allows us to further customize the load balancer. This CRD allows us to define additional load balancer features hierarchically, in a more structured way than annotations. [3]

    infra/k8s/web/backend.yaml
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: wordpress
    spec:
      securityPolicy:
        name: wordpress
    
    kubectl create -f infra/k8s/web/backend.yaml -n wordpress
    
    wordpress 서비스에 메모 추가cloud.google.com/backend-config: '{"default": "wordpress"}':
    kubectl apply -f infra/k8s/web/service.yaml -n wordpress
    
    HTTP 로드 밸런서에 보안 정책이 추가되었는지 확인합니다.


    괜찮아 보여요.테스트를 해보겠습니다.
    만약 우리가 거절당한다면, 나쁜 IP를 테스트하십시오
    gcloud compute security-policies rules update 1000 \
        --security-policy wordpress \
        --src-ip-ranges "85.56.40.96"
    
    curl http://34.117.187.51/
    
    <!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden
    
    올바른 IP 주소를 입력하십시오.
    gcloud compute security-policies rules update 1000 \
        --security-policy wordpress \
        --src-ip-ranges $(curl -s http://checkip.amazonaws.com/)
    
    curl http://34.117.187.51/
    <!doctype html>
    <html lang="en-GB" >
    <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <title>admin &#8211; Just another WordPress site</title>
    
    좋아요!
    이 백엔드 설정을 통해 같은 사무실의 직원만 이 프로그램에 접근할 수 있습니다.현재 우리는 그들도 신분 검증을 통해 응용 프로그램에 접근할 수 있기를 바란다.우리는 Identity Aware Proxy (Cloud IAP)를 사용하여 이 점을 실현할 수 있다.

    클라우드 IAP 사용


    IAP를 사용하여 HTTPS를 통해 액세스하는 Wordpress 응용 프로그램의 중앙 승인 계층을 구성합니다.

    IAP is integrated through Ingress for GKE. This integration enables you to control resource-level access for employees instead of using a VPN. [1]


    GCP 문서에 설명된 지침을 따르십시오.
  • Configure the OAuth consent screen
  • Create the OAuth credentials
  • Setting up IAP access
  • 이전에 만든 OAuth 클라이언트를 포장하기 위해 Kubernetes secret을 만듭니다.
    CLIENT_ID_KEY=<CLIENT_ID_KEY>
    CLIENT_SECRET_KEY=<CLIENT_SECRET_KEY>
    kubectl create secret generic wordpress --from-literal=client_id=$CLIENT_ID_KEY \
        --from-literal=client_secret=$CLIENT_SECRET_KEY \
        -n wordpress
    
    백엔드 구성 업데이트
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: wordpress
    spec:
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: wordpress
      securityPolicy:
        name: wordpress
    
    변경 사항 적용:
    kubectl apply -f infra/k8s/web/backend-config.yaml -n wordpress
    

    테스트 해달래요.

    좋아요!

    SSL 인증서


    도메인 이름이 있으면 CRDManagedCertificate를 사용하여 구글이 관리하는 SSL 인증서를 사용할 수 있습니다.

    Google-managed SSL certificates are Domain Validation (DV) certificates that Google Cloud obtains and manages for your domains. They support multiple hostnames in each certificate, and Google renews the certificates automatically. [4]


    파일 생성infra/k8s/web/ssl.yaml
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: wordpress
    spec:
      domains:
        - <DOMAIN_NAME>
    
    Terraform을 사용하여 도메인 이름을 만들거나 gcloud 명령만 사용할 수 있습니다.
    export PUBLIC_DNS_NAME=
    export PUBLIC_DNS_ZONE_NAME=
    
    gcloud dns record-sets transaction start --zone=$PUBLIC_DNS_ZONE_NAME
    gcloud dns record-sets transaction add $(gcloud compute addresses list --filter=name=wordpress --format="value(ADDRESS)") --name=wordpress.$PUBLIC_DNS_NAME. --ttl=300 --type=A --zone=$PUBLIC_DNS_ZONE_NAME
    gcloud dns record-sets transaction execute --zone=$PUBLIC_DNS_ZONE_NAME
    
    sed -i "s/<DOMAIN_NAME>/wordpress.$PUBLIC_DNS_NAME/g;" infra/k8s/web/ssl.yaml
    
    kubectl create -f infra/k8s/web/ssl.yaml -n wordpress
    
    포털 리소스에 주석networking.gke.io/managed-certificates: "wordpress"을 추가합니다.

    테스트 해달래요.

    좋아요!
    모든 HTTP 트래픽을 HTTPS로 리디렉션하려면 FrontendConfig을 만들어야 합니다.
    파일 생성infra/k8s/web/frontend-config.yaml
    apiVersion: networking.gke.io/v1beta1
    kind: FrontendConfig
    metadata:
      name: wordpress
    spec:
      redirectToHttps:
        enabled: true
        responseCodeName: MOVED_PERMANENTLY_DEFAULT
    
    kubectl create -f infra/k8s/web/frontend-config.yaml -n wordpress
    
    포털 리소스에 주석networking.gke.io/v1beta1.FrontendConfig: "wordpress"을 추가합니다.

    테스트 해달래요.
    curl -s http://wordpress.<HIDDEN>.stack-labs.com/
    
    <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
    <TITLE>301 Moved</TITLE></HEAD><BODY>
    <H1>301 Moved</H1>
    The document has moved
    <A HREF="https://wordpress.<HIDDEN>.stack-labs.com/">here</A>.
    </BODY></HTML>
    
    그래!

    결론


    축하합니다!너는 이미 이 긴 세미나를 완성했다.이 시리즈의 내용은 다음과 같습니다.
  • 클라우드 SQL 인스턴스를 호스팅할 격리 네트워크를 만들었습니다
  • .
  • 클라우드 SQL 인스턴스
  • 에 대한 세분화된 액세스 제어를 위한 Google Kubernetes 엔진 오토매틱 클러스터 구성
  • Kubernetes 용기와 클라우드 SQL 실례 데이터베이스 간의 연결을 테스트했다.
  • Wordpress 어플리케이션
  • 에 대한 액세스 보장
    이렇게!

    깨끗했어


    NEG 리소스를 제거합니다.너는 Compute Engine > Network Endpoint Group에서 그것들을 찾을 수 있다.
    다음 명령을 실행합니다.
    terraform destroy 
    
    gcloud dns record-sets transaction remove $(gcloud compute addresses list --filter=name=wordpress --format="value(ADDRESS)") --name=wordpress.$PUBLIC_DNS_NAME. --ttl=300 --type=A --zone=$PUBLIC_DNS_ZONE_NAME
    gcloud dns record-sets transaction execute --zone=$PUBLIC_DNS_ZONE_NAME
    
    gcloud compute addresses delete wordpress
    
    gcloud secrets delete wordpress-admin-user-password
    

    마지막 말


    The source code is available on Gitlab .
    질문이나 피드백이 있으면 언제든지 댓글을 달아주세요.
    그렇지 않으면 GKE Autopilot를 클라우드 SQL에 연결하고 네트워크와 신분 검증 층에서pod급 심도 있는 방어 보안 정책을 제공하는 데 대한 난제에 대한 답변을 도와드렸으면 합니다.
    겸사겸사 한마디 하자면 또래와 나누는 것을 주저하지 마라😊
    읽어주셔서 감사합니다!

    문서


    [1] https://cloud.google.com/iap/docs/enabling-kubernetes-howto
    [2] https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip
    [3] https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-features#configuring_ingress_features
    [4] https://cloud.google.com/load-balancing/docs/ssl-certificates/google-managed-certs

    좋은 웹페이지 즐겨찾기