외부 서비스 종료 게이트웨이 등록

외부 서비스 종료 게이트웨이 등록 (Register External Services with a Terminating Gateway on Kubernetes)

이 문서는 Kubernetes에서 종료 게이트웨이(terminating gateway)를 사용해 외부 서비스를 Consul에 등록하는 방법을 설명해요. Helm 차트 구성, 외부 서비스 등록, ACL 역할 갱신, 구성 항목 생성, 업스트림 정의까지 다단계 과정을 다룰게요.

출처: 문서

본문

종료 게이트웨이를 추가하는 것은 다단계 과정입니다:

  • 종료 게이트웨이 구성 옵션으로 Helm 차트 업데이트
  • Helm 차트 배포
  • Consul 에이전트 접근
  • 외부 서비스를 Consul에 등록

요구 사항 (Requirements)

종료 게이트웨이 구성 옵션으로 Helm 차트 업데이트 (Update the Helm chart with terminating gateway configuration options)

최소 필수 Helm 옵션:

values.yaml

global:
  name: consul
terminatingGateways:
  enabled: true

Helm 차트 배포 (Deploying the Helm chart)

Helm 차트는 Kubernetes용 Consul CLI를 사용해 배포할 수 있습니다.

$ consul-k8s install --config-file values.yaml

Consul 에이전트 접근 (Accessing the Consul agent)

kubectl port-forward를 실행해 호스트에서 Consul 서버에 직접 접근할 수 있습니다. 이는 로컬에서 Consul UI와 상호작용하고 애플리케이션의 연결성을 검증하는 데 유용합니다.

TLS 없음 (Without TLS)

$ kubectl port-forward service/consul-server 8500 &
$ export CONSUL_HTTP_ADDR=http://localhost:8500

TLS 사용 (With TLS)

TLS가 활성화되면 포트 8501을 사용합니다:

$ kubectl port-forward service/consul-server 8501 &
$ export CONSUL_HTTP_ADDR=https://localhost:8501
$ export CONSUL_HTTP_SSL_VERIFY=false

ACL이 활성화되면 다음도 설정합니다:

$ export CONSUL_HTTP_TOKEN=$(kubectl get secret consul-bootstrap-acl-token --template='{{.data.token | base64decode }}')

외부 서비스를 Consul에 등록 (Register external services with Consul)

외부 서비스를 Consul에 등록하는 것은 다단계 과정입니다:

  • 외부 서비스를 Consul에 등록
  • ACL이 활성화된 경우 종료 게이트웨이 ACL 토큰 업데이트
  • 종료 게이트웨이를 구성할 TerminatingGateway 리소스 생성
  • 메시의 서비스에서 외부 서비스로의 접근을 허용할 ServiceIntentions 리소스 생성
  • 외부 서비스와 통신해야 하는 서비스에 대한 업스트림 어노테이션 정의

외부 서비스를 Consul에 등록 (Register external services with Consul)

TransparentProxy가 활성화된 경우 ServiceDefaults를 사용해 외부 서비스를 Consul에 등록할 수 있습니다. 그렇지 않으면 서비스를 Consul 카탈로그의 노드로 등록할 수 있습니다.

ServiceDefaults 및 TransparentProxy 사용 (Using ServiceDefaults and TransparentProxy)

ServiceDefaults Custom Resource Definition (CRD)의 destination 필드를 사용하면 클라이언트가 외부 서비스를 직접 다이얼할 수 있습니다. 이 방법이 작동하려면 TransparentProxy가 활성화되어야 합니다.

destination 필드를 사용해 종료 게이트웨이를 통해 트래픽을 라우팅할 때의 트래픽 동작은 다음 표에 설명되어 있습니다:

| 외부 서비스 레이어 (External Services Layer) | 클라이언트 다이얼 (Client dials) | 클라이언트 TLS 사용 (Client uses TLS) | 허용 여부 (Allowed) | 참고 (Notes) | | L4 | 호스트네임 | 예 | 허용 | CAFiles는 트래픽이 이미 클라이언트에 의해 종단 간 암호화되어 있으므로 허용되지 않음. | | L4 | IP | 예 | 허용 | CAFiles는 트래픽이 이미 클라이언트에 의해 종단 간 암호화되어 있으므로 허용되지 않음. | | L4 | 호스트네임 | 아니요 | 허용되지 않음 | 사이드카는 프로토콜을 인식하지 못해 외부 서비스로 가는 트래픽을 식별할 수 없음. | | L4 | IP | 아니요 | 허용 | TLS 없이 IP를 다이얼하는 데 제한 없음. | | L7 | 호스트네임 | 예 | 허용되지 않음 | 트래픽이 사이드카 이전에 이미 암호화되어 L7 트래픽으로 라우팅할 수 없음. | | L7 | IP | 예 | 허용되지 않음 | 트래픽이 사이드카 이전에 이미 암호화되어 L7 트래픽으로 라우팅할 수 없음. | | L7 | 호스트네임 | 아니요 | 허용 | Host 또는 :authority 헤더가 필요함. | | L7 | IP | 아니요 | 허용 | TLS 없이 IP를 다이얼하는 데 제한 없음. |

종료 게이트웨이를 통해 외부 서비스에 연결되는 트래픽을 보호하기 위해 caFile을 제공할 수 있습니다. 자세한 내용은 종료 게이트웨이의 구성 항목 생성을 참조하세요.

참고: ServiceDefaults에 지정된 protocol과 무관하게 L7 인텐션은 현재 ServiceDefaults destination에서 지원되지 않습니다.

외부 서비스에 대한 ServiceDefaults 커스텀 리소스를 만듭니다:

service-defaults.yaml

  apiVersion: consul.hashicorp.com/v1alpha1
  kind: ServiceDefaults
  metadata:
    name: example-https
  spec:
    protocol: tcp
    destination:
      addresses:
        - "example.com"
      port: 443

kubectl apply로 ServiceDefaults 리소스를 적용합니다:

$ kubectl apply --filename service-defaults.yaml

다른 모든 종료 게이트웨이 작업은 이 경우 "example-https"라는 ServiceDefaults 컴포넌트의 이름을 Consul 서비스 이름으로 사용할 수 있습니다.

Consul 카탈로그 사용 (Using Consul catalog)

일반적으로 Consul 서비스는 실행 중인 노드에 등록됩니다. 이 서비스는 외부 서비스이므로 등록할 Consul 노드가 없습니다. 대신 노드 이름을 만들어 그 노드에 서비스를 등록해야 합니다.

샘플 외부 서비스를 만들어 Consul에 등록합니다.

external.json

{
  "Node": "example_com",
  "Address": "example.com",
  "NodeMeta": {
    "external-node": "true",
    "external-probe": "true"
  },
  "Service": {
    "Address": "example.com",
    "ID": "example-https",
    "Service": "example-https",
    "Port": 443
  }
}
  • "Node": "example_com"은 우리가 만든 노드 이름입니다.
  • "Address": "example.com"은 우리 노드의 주소입니다. 그 노드에 등록된 서비스는 자체 주소를 지정하지 않으면 이 주소를 사용합니다. 여러 외부 서비스를 등록하는 경우 다른 주소로 다른 노드 이름을 사용하거나 Service.Address 키를 설정해야 합니다.
  • "Service": { "Address": "example.com" ... }은 우리 서비스의 주소입니다. 이 예제에서는 노드 주소와 같으므로 설정할 필요가 없지만 같은 노드에 두 서비스가 등록된 경우에는 설정해야 합니다.

외부 서비스를 Consul에 등록합니다:

$ curl --request PUT --data @external.json --insecure $CONSUL_HTTP_ADDR/v1/catalog/register
true

ACL과 TLS가 활성화된 경우:

$ curl --request PUT --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" --data @external.json --insecure $CONSUL_HTTP_ADDR/v1/catalog/register
true

ACL이 활성화된 경우 종료 게이트웨이 ACL 역할 업데이트 (Update terminating gateway ACL role if ACLs are enabled)

ACL이 활성화된 경우 종료 게이트웨이 ACL 역할을 게이트웨이가 나타내는 모든 서비스에 대한 service:write 권한이 있도록 업데이트합니다.

생성한 서비스에 대한 쓰기 권한을 포함하는 새 정책을 만듭니다.

write-policy.hcl

service "example-https" {
  policy = "write"
}
$ consul acl policy create -name "example-https-write-policy" -rules @write-policy.hcl
ID:           xxxxxxxxxxxxxxx
Name:         example-https-write-policy
Description:
Datacenters:
Rules:
service "example-https" {
  policy = "write"
}

종료 게이트웨이 역할의 ID를 얻습니다.

$ consul acl role list -format=json | jq --raw-output '[.[] | select(.Name | endswith("-terminating-gateway-acl-role"))] | if (. | length) == 1 then (. | first | .ID) else "Unable to determine the role ID because there are multiple roles matching this name.\n" | halt_error end'
<role id>

새 정책으로 종료 게이트웨이 ACL 역할을 업데이트합니다.

$ consul acl role update -id <role id> -policy-name example-https-write-policy
AccessorID:       <role id>
SecretID:         <secret id>
Description:      RELEASE_NAME-terminating-gateway-acl-role
Local:            true
Create Time:      2021-01-08 21:18:47.957450486 +0000 UTC
Policies:
   63bf1d9b-a87d-8672-ddcb-d25e2d88adb8 - RELEASE_NAME-terminating-gateway-policy
   f63d1ae6-ffe7-44bd-bf7a-704a86939a63 - example-https-write-policy

종료 게이트웨이의 구성 항목 생성 (Create the configuration entry for the terminating gateway)

역할이 업데이트된 후 종료 게이트웨이를 구성할 TerminatingGateway 리소스를 만듭니다:

terminating-gateway.yaml

apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
  name: terminating-gateway
spec:
  services:
    - name: example-https

Consul 카탈로그를 통해 등록된 외부 서비스에 TLS가 활성화되어 있고 투명 프록시 destination을 사용하지 않는다면, 종료 게이트웨이 컨테이너의 시스템 신뢰 저장소를 가리키는 caFile 매개변수를 포함해야 합니다. 기본적으로 신뢰 저장소는 /etc/ssl/certs/ca-certificates.crt 디렉터리에 있습니다. TLS가 활성화되고 다음 컴포넌트 중 하나를 사용하는 경우 TerminatingGateway 구성 항목의 caFile 매개변수를 /etc/ssl/cert.pem 디렉터리를 가리키도록 구성합니다:

  • Consul Helm 차트 0.43 또는 이전
  • alpine 기본 이미지가 있는 Envoy 이미지

또한 파일 경로 필드(caFile, certFile, keyFile)와 함께 secretRef를 지정해 Envoy의 Secret Discovery Service (SDS)를 통해 TLS를 활성화할 수 있습니다. secretRef 이름과 해당 파일 경로를 모두 지정해야 합니다 — 파일 경로는 Kubernetes 시크릿이 종료 게이트웨이 파드 파일 시스템에 마운트된 위치를 나타내고, secretRef 이름은 Kubernetes 시크릿을 식별하여 게이트웨이 재시작 없이 SDS를 통해 인증서 업데이트가 Envoy에 동적으로 전달되도록 합니다.

terminating-gateway-tls.yaml

apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
  name: terminating-gateway
spec:
  services:
    - name: example-https
      caFile: /etc/ssl/certs/ca-certificates.crt
      sni: example.com
      # Specify secretRef along with file paths to enable SDS
      secretRef:
        name: example-https-tls-cert

kubectl apply로 TerminatingGateway 리소스를 적용합니다:

$ kubectl apply --filename terminating-gateway.yaml

ACL과 TLS를 사용하는 경우 메시의 서비스에서 외부 서비스로의 접근을 허용하는 ServiceIntentions 리소스를 만듭니다:

service-intentions.yaml

apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: example-https
spec:
  destination:
    name: example-https
  sources:
    - name: static-client
      action: allow

참고: L7 인텐션은 현재 ServiceDefaults destination에서 지원되지 않습니다.

kubectl apply로 ServiceIntentions 리소스를 적용합니다:

$ kubectl apply --filename service-intentions.yaml

메시의 서비스에 대한 업스트림으로 외부 서비스 정의 (Define the external services as upstreams for services in the mesh)

마지막 단계로, 외부 서비스와 통신하려는 내부 메시 서비스에 대한 업스트림으로 외부 서비스를 정의하고 배포할 수 있습니다. 종료 게이트웨이 서비스의 정적 클라이언트로 사용될 예제 배포가 제공됩니다.

static-client.yaml

apiVersion: v1
kind: Service
metadata:
  name: static-client
spec:
  selector:
    app: static-client
  ports:
    - port: 80
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: static-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: static-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: static-client
  template:
    metadata:
      name: static-client
      labels:
        app: static-client
      annotations:
        'consul.hashicorp.com/connect-inject': 'true'
        'consul.hashicorp.com/connect-service-upstreams': 'example-https:1234'
    spec:
      containers:
        - name: static-client
          image: curlimages/curl:latest
          command: ['/bin/sh', '-c', '--']
          args: ['while true; do sleep 30; done;']
      serviceAccountName: static-client

kubectl apply로 서비스를 배포합니다.

$ kubectl apply --filename static-client.yaml

서비스가 준비될 때까지 기다립니다.

$ kubectl rollout status deploy static-client --watch
deployment "static-client" successfully rolled out

curl 명령으로 static-client와 종료 게이트웨이의 연결성을 확인할 수 있습니다.

ServiceDefaults destination으로 등록 (Registered with ServiceDefaults destinations)

$ kubectl exec deploy/static-client -- curl -vvvs https://example.com/

Consul 카탈로그로 등록 (Registered with the Consul catalog)

$ kubectl exec deploy/static-client -- curl -vvvs --header "Host: example-https.com" http://localhost:1234/

더 알아보기 (Learn more)