Google Distributed Cloud (GDC) 에어 갭은 기본 제공 관리형 레이어 4 (L4) 부하 분산기를 제공하지만 많은 엔터프라이즈 애플리케이션에는 호스트 기반 라우팅, 중앙 집중식 TLS 관리, 복잡한 트래픽 분할과 같은 고급 레이어 7 (L7) 기능이 필요합니다. 이전에는 Kubernetes 커뮤니티에서 현재 기능이 고정된 것으로 간주되는 인그레스 API를 사용하여 이 작업을 수행했습니다.
이 참조 아키텍처는 자체 관리형 레이어 7 부하 분산 솔루션을 제공합니다. 고객은 GDC Standard 클러스터에 널리 사용되는 NGINX Gateway Fabric 오픈소스 컨트롤러를 배포하여 L7 트래픽을 하이브리드 환경으로 원활하게 라우팅할 수 있습니다. 이 아키텍처는 TLS 종료(HTTPRoute)를 사용하여 서버 이름 표시 (SNI)를 기반으로 트래픽을 기본 제공 컨테이너화된 포드와 외부 가상 머신에서 호스팅되는 애플리케이션으로 라우팅합니다.
아키텍처

솔루션의 주요 구성요소는 다음과 같습니다.
- 클라이언트: 애플리케이션과 상호작용하기 위해 HTTPS 요청을 시작하는 항목입니다.
- GDC Standard 클러스터: GDC는 Kubernetes Vanilla 클러스터를 만드는 기본 제공 방법을 제공합니다. 이 솔루션에서 클러스터는 L7 LB 및 해당 컨트롤러와 함께 워크로드 및 외부 VM의 헤드리스 서비스를 호스팅합니다.
- GDC L4 부하 분산기: 진입점 역할을 하는 기본 제공 L4 부하 분산기로, TCP/443 트래픽을 게이트웨이 컨트롤러를 실행하는 Kubernetes 포드로 직접 분산합니다.
- 게이트웨이 컨트롤러: Standard 클러스터에서 실행되는 NGINX 연산자입니다.
게이트웨이 API 리소스 (
Gateway,HTTPRoute등)를 모니터링하고 기본 프록시를 동적으로 업데이트합니다. Nginx Gateway Fabric은 솔루션에 사용됩니다. - 게이트웨이 (HTTPRoute 포함): TLS 종료를 사용하여 실제 리슨 포트 (443)와 SNI 기반 호스트 라우팅 규칙을 정의하는 표준화된 Kubernetes 리소스입니다.
- 컨테이너화된 워크로드 (포드): 일반 Kubernetes
Service를 사용하여 내부적으로 노출되는 표준 Kubernetes 배포입니다. - VM 기반 워크로드 (외부): 프로젝트 네트워크의 외부 VM에서 호스팅되는 워크로드로, 헤드리스 Kubernetes
Service및 VM의 직접 IP가 포함된 커스텀 엔드포인트로 프록시에 노출됩니다. - Harbor Registry: 에어 갭 환경에서 프록시 및 애플리케이션 이미지를 저장하고 제공하는 데 사용되는 비공개 컨테이너 레지스트리입니다.
Standard 클러스터에서 네임스페이스 4개를 만듭니다.
Nginx Gateway Fabric 리소스를 호스팅하는
nginx-gateway네임스페이스:
Gateway리소스를 호스팅하는load-balancer네임스페이스:
vm-app네임스페이스는 외부 VM IPvm-app, 헤드리스 서비스, 외부 IP를 가리키는EndpointSlice,Gateway의HTTPRoute를 호스팅합니다.
hello-app네임스페이스는 데모 컨테이너 워크로드의Deployment,Service,HTTPRoute,Gateway를 호스팅합니다.
시작하기 전에
이 솔루션을 배포하기 전에 다음 기본 요건이 준비되었는지 확인합니다.
- 필요한 소프트웨어: helm, docker, kubectl
CLI 로그인 및 로컬 설정: GDC 콘솔에서 gdcloud CLI를 다운로드하고 로컬에서 환경을 설정합니다.
export USER_NAME="USER_NAME" export PROJECT_ID="PROJECT_ID" export ZONE="ZONE" export ORG_NAME="ORG_NAME" export GDCH_URL="GDC_URL" gdcloud components install gdcloud-k8s-auth-plugin gdcloud config set core/organization_console_url \ https://console.$ORG_NAME.$ZONE.$GDC_URL gdcloud config set core/zone $ZONE gdcloud config set core/project ${PROJECT_ID} gdcloud auth login # use --login-config-cert option in case of TLS error프로젝트 설정: GDC 에어 갭 환경에서 리소스를 보관할 프로젝트를 만듭니다.
gdcloud projects create $PROJECT_IDIAM 역할: 사용자에게 Kubernetes 리소스를 관리할 클러스터 관리자 및 Standard 클러스터 관리자 역할을 부여하고 이미지를 푸시할 Harbor 인스턴스 관리자 역할을 부여합니다.
# Grant standard cluster and cluster admin roles gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=cluster-admin gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=standard-cluster-admin # Grant Harbor instance admin role gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member="user:${USER_NAME}" \ --role=harbor-instance-admin
Standard 클러스터 만들기
이 섹션에서는 GDC 에어 갭 환경 내에서 표준 Kubernetes 클러스터를 설정하는 프로세스를 안내합니다. Standard 클러스터는 Nginx Gateway Controller 및 커스텀 애플리케이션을 비롯한 다양한 워크로드를 배포하기 위한 유연하고 강력한 기반을 제공합니다. 다음 단계에서는 후속 배포를 위해 클러스터가 올바르게 구성되고 액세스할 수 있도록 합니다.
다음을 실행하여 사용 가능한 가상 머신 이미지 유형을 식별합니다.
gdcloud compute machine-types list클러스터 작업자 노드에 적합한 머신 유형을 선택합니다. 이 튜토리얼에서는 vCPU가 4개 이상 인 머신 유형을 사용하는 것이 좋습니다.
export MACHINE_TYPE="MACHINE_TYPE"관리 API 서버 kubeconfig를 가져오고 별칭을 설정합니다.
export CLUSTER_NAME="CLUSTER_NAME" KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \ get-credentials ${ORG_NAME}-admin alias km="kubectl --kubeconfig kubeconfig-admin.yaml"작업자 노드가 2개인 Standard 클러스터를 만듭니다.
km create -f - <<EOF apiVersion: cluster.gdc.goog/v1 kind: Cluster metadata: name: ${CLUSTER_NAME} namespace: ${PROJECT_ID} spec: nodePools: - machineTypeName: ${MACHINE_TYPE} nodeCount: 2 name: ${CLUSTER_NAME}-node-pool EOF사용 가능한 옵션에 대한 자세한 내용은 문서를 참조하세요.
Standard 클러스터 생성을 완료하는 데 최대 60분이 걸릴 수 있습니다. 상태를 확인하려면 다음 명령어를 사용합니다.
km get clusters/${CLUSTER_NAME} \ -n ${PROJECT_ID} \ --watch클러스터가 준비되면 다음과 같이 상태가 실행 중으로 표시됩니다.
NAME STATE K8S VERSION my-cluster Running 1.30.12-gke.300클러스터가 준비되면 사용자 인증 정보를 가져옵니다.
KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \ get-credentials ${CLUSTER_NAME} \ --standard \ --project ${PROJECT_ID} \ --zone ${ZONE}이 가이드의 나머지 부분에서
kubectl명령어를 더 간결하게 유지하기 위해 별칭을 만듭니다. 이 별칭은 Standard 클러스터와 상호작용하는 데 사용됩니다.alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"컨트롤러, 'hello-app' 데모 컨테이너화된 앱, VM 기반 데모 앱의 네임스페이스를 만듭니다.
kk create namespace load-balancer kk create namespace hello-app kk create namespace vm-app
Harbor Registry 만들기 및 통합
Harbor는 GDC 에어 갭에서 기본 제공 지원되는 컨테이너 이미지 레지스트리입니다. 이 섹션에서는 사용자 인증 정보 및 보안 비밀을 구성하여 이미지를 안전하게 가져오고 푸시하는 등 Harbor Registry를 Standard 클러스터와 통합하는 단계를 안내합니다.
- 프로젝트에서 Harbor 인스턴스 를 만듭니다.
- Harbor 인스턴스에서 Harbor 프로젝트 를 만듭니다.
환경 변수를 설정합니다.
export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME" export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL" export HARBOR_PROJECT="HARBOR_INSTANCE_PROJECT" export IMAGE_PULL_SECRET_NAME="harbor-secret"로봇 계정을 사용하여 Harbor 인스턴스에 로그인합니다.
docker --config=./docker login ${HARBOR_INSTANCE_URL}Standard 클러스터에서 보안 비밀을 만듭니다.
kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \ --from-file=.dockerconfigjson=./docker/config.json \ -n load-balancer kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \ --from-file=.dockerconfigjson=./docker/config.json \ -n hello-app
데모 컨테이너화된 앱 배포
이 섹션에서는 GDC 에어 갭 Kubernetes 클러스터 내에서 데모 컨테이너화된 애플리케이션(hello-app)을 배포하는 방법을 자세히 설명합니다. 필요한 Kubernetes 배포 및 서비스 리소스를 만들어 hello-app을 실행하고 클러스터 내에서 내부적으로 노출하여 L7 부하 분산기를 사용하여 액세스할 수 있도록 준비합니다.
데모 컨테이너화된 앱의 샘플 이미지를 Harbor에 업로드합니다.
docker pull gcr.io/google-samples/hello-app:1.0 \ --platform linux/amd64 docker tag gcr.io/google-samples/hello-app:1.0 \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0 docker --config=./docker push \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0다음 매니페스트를 Standard 클러스터에 배포합니다.
cat << EOF > hello-app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hello-app namespace: hello-app spec: replicas: 2 selector: matchLabels: app: hello-app template: metadata: labels: app: hello-app spec: containers: - name: hello-server image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0 ports: - containerPort: 8080 imagePullSecrets: - name: ${IMAGE_PULL_SECRET_NAME} --- apiVersion: v1 kind: Service metadata: name: hello-app namespace: hello-app spec: type: ClusterIP selector: app: hello-app ports: - protocol: TCP port: 80 targetPort: 8080 EOF kk apply -f hello-app.yaml
그런 다음 배포 및 서비스가 있는지 확인합니다.
kk get svc,deploy -n hello-app
VM에 데모 앱 배포
이 섹션에서는 Kubernetes 클러스터 외부의 가상 머신 (VM) 내에서 데모 애플리케이션을 배포하는 방법을 자세히 설명합니다. VM에 HTTP 서버를 설정하면 부하 분산기가 노출할 수 있는 외부 애플리케이션을 시뮬레이션하여 클러스터 내부 및 외부의 리소스에 대한 트래픽을 관리하는 기능을 보여줍니다.
먼저 데모 앱의 VM을 만듭니다.
- 웹브라우저에서 GDC 콘솔을 엽니다.
- 표준 Kubernetes 클러스터를 만든 프로젝트와 동일한 프로젝트를 선택합니다.
- 메뉴를 열고 가상 머신 을 클릭합니다.
- 인스턴스 만들기 를 클릭합니다.
- VM 이름을
vm-workload로 지정합니다. 이 예시에서는 vCPU가 2개인 이미지가 충분합니다. - 부팅 디스크 이미지의 경우 Python이 사전 설치된 Ubuntu 22.04 배포를 선택합니다.
- 만들기 를 클릭합니다.
- VM이 준비될 때까지 몇 분 정도 기다립니다.
- VM에 SSH 연결을 설정합니다.
- GDC 콘솔에서 VM을 클릭합니다.
- SSH로 연결 을 클릭합니다.
SSH 콘솔에 연결한 후 다음을 실행합니다.
mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &
VM으로 트래픽을 라우팅하려면 선택자 없이 헤드리스 서비스를 만듭니다. 이는 EndpointSlice 리소스를 사용하여 VM의 내부 IP 주소에 수동으로 매핑됩니다.
kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: vm-app-svc
namespace: vm-app
spec:
ports:
- protocol: TCP
port: 443
targetPort: 443
EOF
다음을 실행하여 vm-workload VM의 IP 주소를 가져옵니다.
gdcloud compute instances list --project ${PROJECT_ID} \
| grep workload-vm | awk '{print $3}'
출력은 EndpointSlice 리소스를 설정하는 데 필요한 VM의 IP 주소입니다.
VM 앱 선택자 없는 서비스에 연결하고 트래픽이 라우팅되어야 하는 VM의 IP 주소를 지정하는 리소스 EndpointSlice를 만듭니다.
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: vm-app-endpoints
namespace: vm-app
labels:
kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
- port: 8080
endpoints:
- addresses:
- "VM_IP"
conditions:
ready: true
자체 서명 인증서 만들기
이 섹션에서는 애플리케이션의 자체 서명 TLS 인증서를 생성하는 프로세스를 안내합니다. 이 가이드에서는 편의를 위해 자체 서명 인증서를 사용하지만 프로덕션 환경에서는 선택사항: 프로덕션 준비 인증서 사용에 설명된 대로 프로덕션 등급 인증서를 사용해야 합니다. 이러한 인증서는 Nginx Gateway에서 HTTPS 종료를 사용 설정하고 컨테이너화된 워크로드와 VM 기반 워크로드 모두에 대해 클라이언트와 부하 분산기 간의 암호화된 통신을 보장하는 데 중요합니다.
컨테이너화된 앱의 인증서를 만듭니다.
openssl req -x509 -newkey rsa:2048 -nodes \ -keyout tls-containerized.key \ -out tls-containerized.crt \ -subj "/CN=k8s-app.example.com" \ -days 365 kk create secret tls tls-containerized \ --namespace load-balancer \ --key tls-containerized.key \ --cert tls-containerized.crt kk create secret tls tls-containerized \ --namespace hello-app \ --key tls-containerized.key \ --cert tls-containerized.crtVM 앱의 인증서를 만듭니다.
openssl req -x509 -newkey rsa:2048 -nodes \ -keyout tls-vm.key \ -out tls-vm.crt \ -subj "/CN=vm-app.example.com" \ -days 365 kk create secret tls tls-vm \ --namespace load-balancer \ --key tls-vm.key \ --cert tls-vm.crt kk create secret tls tls-vm \ --namespace vm-app \ --key tls-vm.key \ --cert tls-vm.crt
NGINX 배포
이 섹션에서는 게이트웨이 API 커스텀 리소스 정의 (CRD) 설치, Helm을 사용하여 Nginx Gateway Fabric 설정, Standard 클러스터 내에서 설치 확인을 비롯한 Nginx Gateway Controller 배포 단계를 설명합니다. 이렇게 하면 고급 레이어 7 라우팅을 위한 인프라가 준비됩니다.
게이트웨이 API CRD 설치
게이트웨이 API를 사용하려면 컨트롤러를 배포하기 전에 클러스터에 커스텀 리소스 정의 (CRD)를 설치해야 합니다. 게이트웨이 API 프로젝트의 공식 실험용 커스텀 리소스 정의 (CRD)를 사용합니다 (이 가이드에서는 버전 1.2.0 사용).
실험용 CRD를 설치합니다.
kk apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yamlkk get crd gateways.gateway.networking.k8s.io를 실행하여 CRD가 성공적으로 설치되었는지 확인합니다.
NGINX Gateway Fabric 설치
Helm을 사용하여 NGINX Gateway Fabric 컨트롤러를 배포합니다. 이 컨트롤러는 게이트웨이 API 리소스를 감시하고 트래픽을 처리하도록 NGINX를 구성합니다.
NGINX 이미지 태그를 설정합니다.
helm template nfg oci://ghcr.io/nginx/charts/nginx-gateway-fabric | grep "image:" # get the tag of the nginx-gateway-fabric (in following case 2.4.2) export NGINX_TAG="2.4.2"NGINX Gateway Fabric 및 NGINX 이미지를 가져온 후 Harbor 레지스트리에 푸시합니다.
docker pull ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} docker tag ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG} docker --config=./docker push \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG} docker pull nginx:1.27.3 docker tag nginx:1.27.3 \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3 docker --config=./docker push \ ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3nginx-gateway네임스페이스를 만들고 Harbor 이미지 가져오기 보안 비밀을 추가합니다.kk create namespace nginx-gateway kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \ --from-file=.dockerconfigjson=./docker/config.json \ -n nginx-gatewayHarbor 레지스트리의 이미지를 가리키는 Helm을 사용하여 NGINX Gateway Fabric을 배포합니다.
KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml helm upgrade --install ngf \ oci://ghcr.io/nginx/charts/nginx-gateway-fabric \ --create-namespace -n nginx-gateway \ --set nginxGateway.image.tag="${NGINX_TAG}" \ --set nginxGateway.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric" \ --set nginx.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx" \ --set nginxGateway.serviceAccount.imagePullSecret="${IMAGE_PULL_SECRET_NAME}" \ --set nginx.imagePullSecret="${IMAGE_PULL_SECRET_NAME}"Kubernetes 배포는 Harbor 로봇 계정의 사용자 인증 정보가 포함된 제공된 보안 비밀 (
${IMAGE_PULL_SECRET_NAME})을 사용하여 Harbor에서 이미지를 안전하게 가져옵니다.GatewayClass리소스가 허용되는지 확인합니다.kk get gatewayclassnginx가ACCEPTED = True로 나열되어야 합니다.
게이트웨이 인스턴스 만들기
포트 443에서 리슨하는 논리적 부하 분산기 인스턴스를 정의합니다. 게이트웨이가 TLS 종료를 수행하고 트래픽을 전달하기 전에 트래픽을 복호화하는 Terminate 모드로 구성합니다.
gateway.yaml을 만들고 적용합니다.
cat << EOF > gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: load-balancer
spec:
gatewayClassName: nginx
listeners:
- name: https-k8s-workload
hostname: "k8s-app.example.com"
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: tls-containerized
- name: https-vm-workload
hostname: "vm-app.example.com"
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: tls-vm
EOF
kk apply -f gateway.yaml
PROGRAMMED가 True인지 확인하여 게이트웨이가 성공적으로 배포되었는지 확인합니다.
kk get gateway my-gateway --n load-balancer
관리형 GDC L4 부하 분산기가 게이트웨이와 함께 서비스로 배포되었는지 확인합니다.
kk get services -n load-balancer
Nginx 서비스가 생성되고 구성되었는지 확인합니다. 출력은 다음과 같아야 합니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-gateway-nginx LoadBalancer 10.252.19.148 10.200.32.43 443:30649/TCP 45h
L7 라우팅 로직 (HTTPRoute) 정의
요청된 호스트 이름 (SNI)을 기반으로 트래픽을 분산하는 방법을 정의하려면 HTTPRoute를 게이트웨이에 바인딩합니다.
routing.yaml을 만들고 적용합니다.
cat << EOF > routing.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: k8s-http-route
namespace: hello-app
spec:
parentRefs:
- name: my-gateway
namespace: load-balancer
hostnames:
- "k8s-app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: hello-app
namespace: hello-app
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: vm-http-route
namespace: vm-app
spec:
parentRefs:
- name: my-gateway
namespace: load-balancer
hostnames:
- "vm-app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: vm-app-svc
namespace: vm-app
port: 443
EOF
kk apply -f routing.yaml
부하 분산기 IP 가져오기
명령어를 실행하여 Nginx 부하 분산기의 IP를 가져옵니다.
kk get services/my-gateway-nginx \
-n load-balancer \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}'
이는 앱에 대한 액세스를 확인할 때 필요합니다. 이를 LOAD_BALANCER_IP라고 합니다.
클라이언트 VM 만들기
클라이언트 VM을 만드는 단계를 따릅니다.
- 웹브라우저에서 GDC 콘솔을 엽니다.
- 메뉴를 열고 가상 머신 을 클릭합니다.
- 인스턴스 만들기 를 클릭합니다.
client라는 VM을 만들고 소형 머신 유형을 선택한 후curl이 사전 설치된 Rocky Linux 또는 Ubuntu를 선택합니다.- 만들기 를 클릭합니다.
- VM이 준비될 때까지 몇 분 정도 기다립니다.
- VM이 준비되면 VM에 SSH 연결을 설정합니다.
- GDC 콘솔에서 VM을 클릭합니다.
- SSH로 연결 을 클릭합니다.
액세스 및 라우팅 확인
라우팅을 테스트하려면 클라이언트 VM에서 curl 명령어를 실행합니다. 부하 분산기의 IP 주소를 사용하여 정의된 호스트 이름으로 두 애플리케이션에 모두 연결할 수 있습니다.
curl에서 --resolve 플래그를 전달하면 도메인 이름이 GDC 에어 갭 L4 부하 분산기의 IP 주소로 확인되도록 강제할 수 있습니다.
자체 서명 인증서를 신뢰하기 위해 -k 플래그를 전달합니다.
Kubernetes 컨테이너화된 앱을 테스트합니다.
curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v
외부 VM 앱을 테스트합니다.
curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v
올바르게 구성되면 게이트웨이 컨트롤러가 TLS 종료자 역할을 원활하게 수행하고 트래픽을 대상으로 전달합니다.
선택사항: 프로덕션 준비 인증서 사용
이 섹션에서는 GDC 에어 갭 CA 서비스를 활용하여 비공개 루트 인증 기관 (CA)을 만들고, 워크로드에 서명된 인증서를 발급하고, GDC 에어 갭 Standard 클러스터 및 클라이언트 VM을 안전하게 업데이트하는 방법을 설명합니다.
이 섹션에서는 GDC 에어 갭 CA
Service를 사용하여
비공개 루트 인증 기관 (CA)을 만들고
애플리케이션에 유효한 인증서를 발급하는 방법을 설명합니다. 클라이언트 VM에 이 루트 CA를 설치하면 SSL 경고를 무시하지 않고도 (예: curl -k 사용) TLS 종료가 신뢰할 수 있는 인증서와 원활하게 작동하는지 확인할 수 있습니다.
필요한 권한 부여 및 사용자 인증 정보 가져오기
CA 서비스를 관리하고 인증서를 발급하려면 사용자에게 프로젝트의 적절한 IAM 역할이 필요합니다.
certificate-authority-service-admin및certificate-requester역할을 부여합니다.gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member=user:${USER_NAME} \ --role=certificate-authority-service-admin gdcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member=user:${USER_NAME} \ --role=certificate-requester관리 API 서버의 사용자 인증 정보를 가져옵니다.
gdcloud clusters get-credentials ${ORG_NAME}-admin
루트 CA 만들기
프로젝트 네임스페이스 내의 관리 API 서버에서 인증 기관을 만듭니다.
CertificateAuthority리소스를 적용합니다.km apply -f - <<EOF apiVersion: pki.security.gdc.goog/v1 kind: CertificateAuthority metadata: name: my-root-ca namespace: ${PROJECT_ID} spec: caProfile: commonName: "My Root CA" duration: 87600h # 10 years keyAlgorithm: RSA_2048 maxChainLength: 1 caType: ROOT keyLocation: HSM rotationPolicy: cronTime: 0 0 1 1 * EOFkm -n ${PROJECT_ID} get \ certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \ | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
인증서 발급 및 배포
CA가 준비되면 컨테이너화된 앱과 VM 기반 앱 모두에 대해 인증서를 요청합니다. 이러한 요청은 관리 API 서버에서 발생하며 결과 키는 Standard 클러스터로 이동해야 합니다.
두 도메인 모두에 대한 요청을 만듭니다.
km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
name: tls-containerized-req
namespace: ${PROJECT_ID}
spec:
certificateAuthorityRef:
name: my-root-ca
namespace: ${PROJECT_ID}
certificateConfig:
subjectConfig:
commonName: "k8s-app.example.com"
dnsNames:
- "k8s-app.example.com"
signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
name: tls-vm-req
namespace: ${PROJECT_ID}
spec:
certificateAuthorityRef:
name: my-root-ca
namespace: ${PROJECT_ID}
certificateConfig:
subjectConfig:
commonName: "vm-app.example.com"
dnsNames:
- "vm-app.example.com"
signedCertificateSecret: tls-vm-signed
EOF
인증서가 발급될 때까지 잠시 기다립니다. 준비 상태가 True이면 준비되었는지 확인할 수 있습니다.
km get certificaterequests -n ${PROJECT_ID}
Standard 클러스터 업데이트
이 가이드의 이전 섹션을 따른 경우 Standard 클러스터에 자체 서명된 보안 비밀이 있습니다. 새 서명된 버전을 만들기 전에 삭제해야 합니다.
kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer
kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app
이제 관리 API 서버에서 서명된 인증서를 추출하고 Standard 클러스터에서 새 보안 비밀을 만듭니다.
km get secret -n ${PROJECT_ID} tls-containerized-signed \
-o jsonpath='{.data.tls\.crt}' \
| base64 -d > tls-containerized.crt
km get secret -n ${PROJECT_ID} tls-containerized-signed \
-o jsonpath='{.data.tls\.key}' \
| base64 -d > tls-containerized.key
kk create secret tls tls-containerized \
--namespace load-balancer \
--key tls-containerized.key \
--cert tls-containerized.crt
kk create secret tls tls-containerized \
--namespace hello-app \
--key tls-containerized.key \
--cert tls-containerized.crt
km get secret -n ${PROJECT_ID} tls-vm-signed \
-o jsonpath='{.data.tls\.crt}' \
| base64 -d > tls-vm.crt
km get secret -n ${PROJECT_ID} tls-vm-signed \
-o jsonpath='{.data.tls\.key}' \
| base64 -d > tls-vm.key
kk create secret tls tls-vm \
--namespace load-balancer \
--key tls-vm.key \
--cert tls-vm.crt
kk create secret tls tls-vm \
--namespace vm-app \
--key tls-vm.key \
--cert tls-vm.crt
새 보안 비밀은 부하 분산기에 의해 자동으로 가져오고 새로고침됩니다.
클라이언트 트러스트 구성
설정을 확인하려면 클라이언트 VM이 새 루트 CA를 신뢰하도록 해야 합니다.
루트 CA 인증서를 파일로 추출합니다.
km get secret -n ${PROJECT_ID} my-root-ca-secret \
-o jsonpath='{.data.tls\.crt}' \
| base64 -d > my-root-ca.crt
인증서를 클라이언트 VM으로 전송합니다. (my-root-ca.crt의 콘텐츠를 복사하여 클라이언트 VM의 파일에 붙여넣을 수 있습니다.)
클라이언트 VM에서 트러스트 저장소를 업데이트합니다.
client VM이 Ubuntu인 경우:
sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates
client VM이 Rocky Linux인 경우:
sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
액세스 확인
이제 -k 플래그 없이 curl을 사용하여 애플리케이션에 액세스할 수 있습니다. 연결은 완전히 신뢰할 수 있습니다.
Kubernetes 컨테이너화된 앱을 테스트합니다.
curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com
VM 앱을 테스트합니다.
curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com
성공하면 SSL 인증서 경고 없이 애플리케이션 출력이 즉시 표시됩니다.