반응형
위에는 CSI 드라이버를 이용한 방법이구요, 아래는 오픈소스를 이용한 방법인데요~
저는 1번이 번거로워서 아래 방식(2번)으로 진행하였으니 참고 부탁 드립니다.
CSI 드라이버를 이용한 방법
- 공식문서: https://docs.microsoft.com/ko-kr/azure/aks/csi-secrets-store-nginx-tls#bind-certificate-to-ingress-controller
- TLS를 사용하여 nginx ingress controller를 사용하는 secret storage CSI 드라이버 설정
- 어플리케이션에 설정하는 방법: deployment에 volume mount하여 certificate사용
- Ingress controller에 설정하는 방법: 어플리케이션 pod는 tls 인증서에 접근하지 못하게 하고, ingress에 tls 인증서가 든 volume을 마운트하여 사용. 이때, ingress는 특정 네임스페이스에, 어플리케이션과 동일한 네임스페이스 내 위치함
- 기본 세팅 순서CSI 드라이버를 이용한 방법
- 공식문서: https://docs.microsoft.com/ko-kr/azure/aks/csi-secrets-store-nginx-tls#bind-certificate-to-ingress-controller
- TLS를 사용하여 nginx ingress controller를 사용하는 secret storage CSI 드라이버 설정
- 어플리케이션에 설정하는 방법: deployment에 volume mount하여 certificate사용
- Ingress controller에 설정하는 방법: 어플리케이션 pod는 tls 인증서에 접근하지 못하게 하고, ingress에 tls 인증서가 든 volume을 마운트하여 사용. 이때, ingress는 특정 네임스페이스에, 어플리케이션과 동일한 네임스페이스 내 위치함
- 기본 세팅 순서
123456789101112131415## az cli version >= 2.30.0, key-vault addon enable## aks 에서 keyvault secret provider add-on을 활성화합니다.> az aks enable-addons --addons azure-keyvault-secrets-provider \--name $aks_Name -g $resourceGroup_Name## create key-vault## keyvault 생성(이미 생성되어 있는 경우 필요하지 않음)> az keyvault create -n $keyvault_Name -g $resourceGroup_Name -l $region## portal 에서 최초 생성한 $azure-keyvault-secrets-provider_Name 의 mid를 CertificattePermisions의 GET 권한을 대한 정책 부여(아래 이미지 참고)## import certificate> az keyvault certificate import --vault-name $keyvault_Name \-n $certificate_Name -f $cert_fileNamecs - Ingress-nginx 설정 변경
1234567891011121314151617181920212223242526272829303132333435363738394041424344## 요 부분은 ingress-nginx 를 새로 설치하시는 경우helm install ingress-nginx/ingress-nginx --generate-name \--namespace $NAMESPACE \--set controller.replicaCount=2 \--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \-f - <<EOFcontroller:extraVolumes:- name: secrets-store-inlinecsi:driver: secrets-store.csi.k8s.ioreadOnly: truevolumeAttributes:secretProviderClass: "azure-tls"extraVolumeMounts:- name: secrets-store-inlinemountPath: "/mnt/secrets-store"readOnly: trueEOF## 요 부분은 ingress-nginx 기존 것 수정하는 케이스helm upgrade $ingress 설치하신 이름 ingress-nginx/ingress-nginx \--namespace ingress-nginx \--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \-f - <<EOF # 저 - 부분은, 기존에 사용한 values 파일이 있다면 values 위치 찍어주세요!controller:extraVolumes:- name: secrets-store-inlinecsi:driver: secrets-store.csi.k8s.ioreadOnly: truevolumeAttributes:secretProviderClass: "azure-tls"extraVolumeMounts:- name: secrets-store-inlinemountPath: "/mnt/secrets-store"readOnly: trueEOFcs
- secretproviderclass 생성
12345678910111213141516171819202122232425262728# This is a SecretProviderClass example using user-assigned identity to access KeyvaultapiVersion: secrets-store.csi.x-k8s.io/v1kind: SecretProviderClassmetadata:name: azure-tls(이름 변경 원하시면 바꿔주세요^ ^) secretproviderclass의 이름입니다.바꾸실거면 임팩받는것들 다 바꾸셔야하는것 아시죠!spec:provider: azuresecretObjects: # secretObjects defines the desired state of synced K8s secret objects- secretName: 아웃풋으로 저장될 시크릿명(kube native secret)type: kubernetes.io/tlsdata:- objectName: 키볼트에 저장된 인증서의 이름이겠죠~!key: tls.key- objectName: 마찬가지입니다~!key: tls.crtparameters:usePodIdentity: "false"useVMManagedIdentity: "true" # Set to true for using managed identityuserAssignedIdentityID: "키볼트에 접근 권한을 부여했던 바로 그 MI!의 client ID를 입력해줍니다." # Set the clientID of the user-assigned managed identity to usekeyvaultName: 키볼트 이름 # Set to the name of your Azure Key Vault instancecloudName: "" # [OPTIONAL for Azure] if not provided, azure environment will default to AzurePublicCloudobjects: |array:- |objectName: 시크릿 이름 반복해줍시다!objectType: secrettenantId: "azure tenant ID" # The tenant ID of the Azure Key Vault instancecs - 요렇게 하면 ingress-nginx 네임스페이스에 지정하신 이름의 시크릿이 생성됩니다.
- 테스트 서비스 생성
12345678910111213141516171819202122232425262728293031323334apiVersion: apps/v1kind: Deploymentmetadata:name: busybox-onelabels:app: busybox-onespec:replicas: 1selector:matchLabels:app: busybox-onetemplate:metadata:labels:app: busybox-onespec:containers:- name: busyboximage: k8s.gcr.io/e2e-test-images/busybox:1.29-1command:- "/bin/sleep"- "10000"---apiVersion: v1kind: Servicemetadata:name: busybox-onespec:type: ClusterIPports:- port: 80selector:app: busybox-onec - ingress 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
tls:
- hosts:
- demo.test.com # 도메인이름은 당연 본인이 가진 인증서에 맞춰서 하셔야겠죠~~
secretName: 지정한 시크릿의 이름을 넣어주세요.
rules:
- host: demo.test.com
http:
paths:
- backend:
service:
name: busybox-one
port:
number: 80
path: /(.*)
- backend:
service:
name: busybox-two
port:
number: 80
path: /two(/|$)(.*)
|
cs |
CSI 드라이버를 이용한 방법의 문제
- 어플리케이션 배포 방식의 문제: 전체 다 마운트를 해야 합니다.
- 인그레스 컨트롤러 배포 방식의 문제: 네임스페이스간 secret 복사가 되지 않습니다.
- 원래 쓰던 차트에서 구성상 차이가 있기도 하고,
네임스페이스간 이동이 원활하지 않아 AKV2K8S(Azure Keyvault to Kubernetes)를 이용해
인증서를 넘기기로 하였습니다.
AKV2K8S를 이용한 방법
- 오픈소스를 이용한 방법으로, Azure keyvault 내의 인증서/secret을
kubernetes native 한 오브젝트로 안전하고, 간편하게 전달할 수 있습니다. - akv2k8s는 controller와 injector 두 가지 타입으로 동작하는데, controller의 경우 secret 또는 configmap의 형태로 keyvault 내 오브젝트를 생성해 줍니다. 반면 injector의 경우 파드 내에 사이드카 컨테이너로 떠서 환경변수 형태로 어플리케이션에 keyvault 내 오브젝트를 주입해 줍니다.
- 저희 환경은 전자, controller를 이용한 케이스입니다 🙂
- Injector까지 설치할 필요는 없었지만, 공식문서에서는 두 가지를 모두 설치하는 것을 권장합니다.
저희는 위의 controller 방식을 사용할 겁니다.
설치 가이드
- akv2k8s를 위한 namespace 생성
kubectl create ns akv2k8s # 필요하시다면 이것도 기존 네임스페이스에 설치하셔도 되겠죠 ㅎㅎ
- helm repo 추가 및 설치
helm repo add spv-charts https://charts.spvapi.no helm repo update helm upgrade --install akv2k8s spv-charts/akv2k8s \ --namespace akv2k8s
사용 가이드
- AKS agentpool MI가 해당 keyvault에 접근 가능하도록 권한을 부여합니다. agentpool 이요!
- CLI로 하든, 포털에서 부여하든 관계 없습니다.
- TLS 인증서가 필요한 namespace에 가서, keyvault 에서 인증서에 접근하는 오브젝트를 생성합니다.
apiVersion: spv.no/v1 kind: AzureKeyVaultSecret metadata: name: cert-sync # 이 이름 바꾸셔도 무관해요~ namespace: secret이 필요한 네임스페이스 이름 spec: vault: name: azure keyvault 이름 # 키볼트 리소스 이름 object: name: walwal-certi # 키볼트에 등록된 인증서 이름 type: certificate output: secret: name: walwal-secret # 스크릿 생성되는 이름 type: kubernetes.io/tls # tls 인증서라면 요 값은 고정입니다.
- 결과물로 tls 인증서가 잘 생성되었습니다.
인증서를 왜 이렇게 번거롭게 넣어야 하나요?
- 기존 방식은 인증서가 만료되어 업데이트 될 때의 업데이트 절차가 번거롭습니다. namespace 별 관리도 그렇고, secret을 edit 하는 과정도 그렇고, ingress-nginx가 업데이트된 secret을 제대로 받아오지 못한다는 open issue가 있어 사실상 전체 서비스 재배포를 예상해야 합니다.
- akv2k8s를 사용하면, keyvault 내의 인증서 값만 변경해 주면 자동으로 해당 값이 변경되어 정상적인 사용이 가능합니다 ! 몇 초 정도의 갭은 있겠지만 거의 실시간으로 변경되는 것을 확인하였습니다.
반응형