반응형
콩니🔧
개지니어 콩니
콩니🔧
전체 방문자
오늘
어제
  • 분류 전체보기 (79)
    • Life outside of work (13)
    • DevOps (29)
    • Developments (23)
    • CS and others (7)
    • Book reviews (7)

블로그 메뉴

  • 홈
  • 태그

공지사항

  • 제가 누군지 궁금하시다면

인기 글

태그

  • web
  • programmers
  • Jenkins
  • Java
  • kubernetes
  • Network
  • Infra
  • 프로그래머스
  • HTML
  • DevOps

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
콩니🔧

개지니어 콩니

[Kubernetes & Azure] TLS 인증서(SSL 인증서) Keyvault 연동하기
DevOps

[Kubernetes & Azure] TLS 인증서(SSL 인증서) Keyvault 연동하기

2021. 11. 13. 18:17
반응형

위에는 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는 특정 네임스페이스에, 어플리케이션과 동일한 네임스페이스 내 위치함
        • 기본 세팅 순서
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      ## 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를 Certificatte 
      Permisions의 GET 권한을 대한 정책 부여(아래 이미지 참고)
       
      ## import certificate
      > az keyvault certificate import --vault-name $keyvault_Name \
        -n $certificate_Name -f $cert_fileName
      Colored by Color Scripter
      cs
      • Ingress-nginx 설정 변경
        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
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        ## 요 부분은 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 - <<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
         
        ## 요 부분은 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-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
        Colored by Color Scripter
        cs
      • secretproviderclass 생성
        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
        # This is a SecretProviderClass example using user-assigned identity to access Keyvault
        apiVersion: secrets-store.csi.x-k8s.io/v1
        kind: SecretProviderClass
        metadata:
          name: azure-tls(이름 변경 원하시면 바꿔주세요^ ^) secretproviderclass의 이름입니다. 
          바꾸실거면 임팩받는것들 다 바꾸셔야하는것 아시죠!
        spec:
          provider: azure
          secretObjects:                                                    # secretObjects defines the desired state of synced K8s secret objects
          - secretName: 아웃풋으로 저장될 시크릿명(kube native secret)
            type: kubernetes.io/tls
            data:
            - objectName: 키볼트에 저장된 인증서의 이름이겠죠~!
              key: tls.key
            - objectName: 마찬가지입니다~!
              key: tls.crt
          parameters:
            usePodIdentity: "false"
            useVMManagedIdentity: "true"                                    # Set to true for using managed identity
            userAssignedIdentityID: "키볼트에 접근 권한을 부여했던 바로 그 MI!의 client ID를 입력해줍니다."  # Set the clientID of the user-assigned managed identity to use
            keyvaultName: 키볼트 이름                                       # Set to the name of your Azure Key Vault instance
            cloudName: ""                                                   # [OPTIONAL for Azure] if not provided, azure environment will default to AzurePublicCloud
            objects:  |
              array:
                - |
                  objectName: 시크릿 이름 반복해줍시다!
                  objectType: secret
            tenantId: "azure tenant ID"                # The tenant ID of the Azure Key Vault instance
        Colored by Color Scripter
        cs
      • 요렇게 하면 ingress-nginx 네임스페이스에 지정하신 이름의  시크릿이 생성됩니다.
      • 테스트 서비스 생성
        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
        29
        30
        31
        32
        33
        34
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: busybox-one
          labels:
            app: busybox-one
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: busybox-one
          template:
            metadata:
              labels:
                app: busybox-one
            spec:
              containers:
              - name: busybox
                image: k8s.gcr.io/e2e-test-images/busybox:1.29-1
                command:
                  - "/bin/sleep"
                  - "10000"
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: busybox-one
        spec:
          type: ClusterIP
          ports:
          - port: 80
          selector:
            app: busybox-one
         
        Colored by Color Scripter
        c
      • 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 내의 인증서 값만 변경해 주면 자동으로 해당 값이 변경되어 정상적인 사용이 가능합니다 ! 몇 초 정도의 갭은 있겠지만 거의 실시간으로 변경되는 것을 확인하였습니다.
반응형
저작자표시 비영리 변경금지 (새창열림)

'DevOps' 카테고리의 다른 글

[이럴땐이렇게] Jenkins에서 배포한 지 오래 된 Job 찾기! 마지막 배포로부터 n일 이상 된 잡을 찾아보자~!  (0) 2021.12.21
[Kubernetes] RBAC을 이용하여 특정 namespace에만 권한 주기  (2) 2021.12.12
[Kubernetes] Application Gateway의 기본 기능, Connection Draining에 대해 알아보자!  (0) 2021.11.10
[Kubernetes] Node selector vs. Node affinity, 어떤 것을 사용할까?  (1) 2021.11.07
Jenkins에서 API를 이용하여 특정 설정을 가진 Job 생성하기(젠킨스 API 잡 생성, config.xml 주입, Jenkins API 인증)  (1) 2021.10.05
    콩니🔧
    콩니🔧
    개발알못 인프라알못 콩니

    티스토리툴바