TLS를 사용하여 NGINX 수신 컨트롤러를 사용하도록 비밀 저장소 CSI 드라이버 설정
이 문서에서는 AKS(Azure Kubernetes Service) 클러스터 및 AKV(Azure Key Vault) 인스턴스에서 TLS를 사용하여 NGINX 수신 컨트롤러를 보호하는 프로세스를 안내합니다. 자세한 내용은 Kubernetes의 TLS를 참조하세요.
다음 방법 중 하나를 사용하여 수신 TLS 인증서를 클러스터로 가져올 수 있습니다.
- 애플리케이션: 애플리케이션 배포 매니페스트는 공급자 볼륨을 선언하고 탑재합니다. 애플리케이션을 배포할 때만 클러스터에서 인증서를 사용할 수 있습니다. 애플리케이션을 제거하면 비밀도 제거됩니다. 이 시나리오는 애플리케이션의 보안 인프라 및 클러스터와의 통합을 담당하는 개발 팀에 적합합니다.
- 수신 컨트롤러: 수신 배포는 공급자 볼륨을 선언하고 탑재하도록 수정됩니다. 수신 Pod를 만들 때 비밀을 가져옵니다. 애플리케이션의 Pod는 TLS 인증서에 액세스할 수 없습니다. 이 시나리오는 한 팀(예:, IT)이 인프라 및 네트워킹 구성 요소(HTTPS TLS 인증서 포함)를 관리하고 생성하며 다른 팀이 애플리케이션 수명 주기를 관리하는 시나리오에 적합합니다.
필수 조건
- Azure 구독이 없는 경우 시작하기 전에 체험 계정을 만듭니다.
- 시작하기 전에 Azure CLI 버전이 >=
2.30.0
인지 확인하거나 최신 버전을 설치합니다. - 비밀 저장소 CSI 드라이버가 구성된 AKS 클러스터입니다.
- Azure Key Vault 인스턴스.
TLS 인증서 생성
다음 명령을 사용하여 TLS 인증서를 생성합니다.
export CERT_NAME=aks-ingress-cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -out aks-ingress-tls.crt \ -keyout aks-ingress-tls.key \ -subj "/CN=demo.azure.com/O=aks-ingress-tls"
AKV로 인증서 가져오기
다음 명령을 사용하여 인증서를 PFX 파일로 내보냅니다.
export AKV_NAME="[YOUR AKV NAME]" openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx # skip Password prompt
az keyvault certificate import
명령을 사용하여 인증서를 가져옵니다.az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
SecretProviderClass 배포
다음 명령을 사용하여 새 네임스페이스를 내보냅니다.
export NAMESPACE=ingress-basic
kubectl create namespace
명령을 사용하여 네임스페이스를 만듭니다.kubectl create namespace $NAMESPACE
액세스 ID를 제공하는 메서드를 선택하고 그에 따라 SecretProviderClass YAML을 구성합니다.
- AKV에서 프라이빗 키와 인증서를 가져오는 유일한 방법인
objectType=secret
을(를) 사용해야 합니다. secretObjects
섹션에 있는kubernetes.io/tls
을(를)type
(으)로 설정합니다.
SecretProviderClass의 예는 다음을 참조하세요.
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-tls spec: provider: azure secretObjects: # secretObjects defines the desired state of synced K8s secret objects - secretName: ingress-tls-csi type: kubernetes.io/tls data: - objectName: $CERT_NAME key: tls.key - objectName: $CERT_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: <client id> keyvaultName: $AKV_NAME # the name of the AKV instance objects: | array: - | objectName: $CERT_NAME objectType: secret tenantId: $TENANT_ID # the tenant ID of the AKV instance
- AKV에서 프라이빗 키와 인증서를 가져오는 유일한 방법인
kubectl apply
명령을 사용하여 Kubernetes 클러스터에 SecretProviderClass를 적용합니다.kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
수신 컨트롤러 배포
공식 수신 차트 리포지토리 추가
다음
helm
명령을 사용하여 공식 수신 차트 리포지토리를 추가합니다.helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
NGINX 수신 구성 및 배포
시나리오에 따라 애플리케이션 또는 수신 컨트롤러에 인증서를 바인딩하도록 선택할 수 있습니다. 선택 영역에 따라 아래 지침을 따릅니다.
애플리케이션에 인증서 바인딩
helm install
명령을 사용하여 애플리케이션에 인증서를 바인딩합니다. 애플리케이션의 배포는 비밀 저장소 CSI 드라이버의 Azure Key Vault 공급자를 참조합니다.helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
수신 컨트롤러에 인증서 바인딩
helm install
명령을 사용하여 수신 컨트롤러에 인증서를 바인딩합니다. 수신 컨트롤러의 배포는 비밀 저장소 CSI 드라이버의 Azure Key Vault 공급자를 참조합니다.참고 항목
Microsoft Entra Pod 관리 ID를 액세스 방법으로 사용하지 않는 경우
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
을 사용하여 줄을 제거합니다.또한 SecretProviderClass를 Pod에 바인딩해야 비밀 저장소 CSI 드라이버에서 이를 탑재하고 Kubernetes 비밀을 생성합니다. 탑재된 콘텐츠를 Kubernetes 비밀과 동기화를 참조하세요.
helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \ -f - <<EOF controller: extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true EOF
kubectl get secret
명령을 사용하여 Kubernetes 비밀이 만들어졌는지 확인합니다.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
애플리케이션 배포
다시 말하지만, 지침은 시나리오에 따라 약간 변경됩니다. 선택한 시나리오에 해당하는 지침을 따릅니다.
애플리케이션 참조를 사용하여 애플리케이션 배포
다음과 같은 내용으로
aks-helloworld-one.yaml
라는 파일을 만듭니다.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
다음과 같은 내용으로
aks-helloworld-two.yaml
라는 파일을 만듭니다.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
kubectl apply
명령을 사용하여 클러스터에 YAML 파일을 적용합니다.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
kubectl get secret
명령을 사용하여 Kubernetes 비밀이 만들어졌는지 확인합니다.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
수신 컨트롤러 참조를 사용하여 애플리케이션 배포
다음과 같은 내용으로
aks-helloworld-one.yaml
라는 파일을 만듭니다.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
다음과 같은 내용으로
aks-helloworld-two.yaml
라는 파일을 만듭니다.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
kubectl apply
명령을 사용하여 클러스터에 YAML 파일을 적용합니다.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
비밀을 참조하는 수신 리소스 배포
이제 비밀을 참조하는 Kubernetes 수신 리소스를 배포할 수 있습니다.
다음 콘텐츠를 사용하여 파일 이름
hello-world-ingress.yaml
을 만듭니다.apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-tls annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx tls: - hosts: - demo.azure.com secretName: ingress-tls-csi rules: - host: demo.azure.com http: paths: - path: /hello-world-one(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80 - path: /hello-world-two(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-two port: number: 80 - path: /(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80
앞에서 만든 비밀을 참조하는
tls
섹션을 기록하고kubectl apply
명령을 사용하여 클러스터에 파일을 적용합니다.kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
수신 컨트롤러의 외부 IP 주소 가져오기
kubectl get service
명령을 사용하여 수신 컨트롤러의 외부 IP 주소를 가져옵니다.kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 EXTERNAL_IP 80:31293/TCP,443:31265/TCP 19m nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
TLS를 사용하여 보안이 설정된 수신 테스트
다음
curl
명령을 사용하여 수신이 TLS로 올바르게 구성되었는지 확인합니다. 이전 단계의 외부 IP를 사용해야 합니다.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
주소와 함께 다른 경로가 제공되지 않았으므로 수신 컨트롤러는 기본값인 / 경로로 설정됩니다. 첫 번째 데모 애플리케이션은 다음 축소된 예제 출력에 표시된 대로 반환됩니다.
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>Welcome to Azure Kubernetes Service (AKS)</title> [...]
curl
명령의 -v 매개 변수는 수신된 TLS 인증서를 비롯한 자세한 정보를 출력합니다. curl 출력을 따라 절반 부분까지 이동하면 고유한 TLS 인증서를 사용했는지 확인할 수 있습니다. -k 매개 변수는 자체 서명된 인증서를 사용하더라도 페이지를 계속 로드합니다. 다음 예제에서는 발급자: CN=demo.azure.com; O = CN=demo.azure.com; O=aks-ingress-tls 인증서가 사용되었음을 보여 줍니다.[...] * Server certificate: * subject: CN=demo.azure.com; O=aks-ingress-tls * start date: Oct 22 22:13:54 2021 GMT * expire date: Oct 22 22:13:54 2022 GMT * issuer: CN=demo.azure.com; O=aks-ingress-tls * SSL certificate verify result: self signed certificate (18), continuing anyway. [...]
주소에 /hello-world-two 경로(예:
https://demo.azure.com/hello-world-two
)를 추가하고 두 번째 데모 애플리케이션이 제대로 구성되었는지 확인합니다.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
사용자 지정 제목이 있는 두 번째 데모 애플리케이션은 다음 축소된 예제 출력에 표시된 대로 반환됩니다.
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>AKS Ingress Demo</title> [...]
Azure Kubernetes Service