[번역] vSphere 7.0, Cloud Native Storage, CSI and encryption support

출처 : https://cormachogan.com/2020/04/22/vsphere-7-0-cloud-native-storage-csi-and-encryption-support/

Encryption-logo.png

vSphere CSI(Container Storage Interface) 드라이버에 대한 일반적인 요청은 VMcrypt라는 vSphere 기능을 사용하여 Kubernetes Persistent Volumes의 암호화를 지원하는 것이다. vSphere 6.5 이후 VM 암호화가 있었지만 vSphere 6.7U3와 함께 제공된 CSI 드라이버의 첫 버전에서는 지원할 수 없는 기능이었다. 그러나 vSphere 7.0과 함께 제공되는 새로운 CSI 드라이버를 통해 이 기능을 지원할 수 있게 되어 기쁘게 생각한다. vSphere 7.0에서 이를 지원할 수 있는 이유는 Improved Virtual Disks라고도 하는 First Class Disks가 암호화를 지원하기 때문이다. FCD는 이러한 볼륨이 vSphere 스토리지에 배포될 때 Kubernetes Persistent Volumes를 백업하는 스토리지 개체입니다. 우리는 그들이 향상된 VMDK라고 생각할 수 있다. 이것은 우리가 원한다면 암호화된 영구 볼륨을 포드에 연결하고 탑재할 수 있다는 것을 의미한다. 그러나 한 가지 명심해야 할 점은 Pod가 스케쥴되어 있고, PV가 부착되어 있는 쿠버네티스 워커  노드도 암호화되어 있어야 한다는 것이다. 이제 단계를 거쳐서 이것이 실제로 작동하는 것을 봅시다.

1단계 – 키 공급자 설정

이것은 전제조건이다. 키 공급자가 구성되지 않은 경우 vSphere에서 암호화를 수행할 수 없음. 여기서는 단계를 거치지 않을 것이지만 이 사이트를 검색하면 HyTrust KMIP를 설정하고 vCenter Server와 HyTrust KMIP 간의 신뢰를 구축하는 방법에 대한 예를 볼 수 있을 것이다. 이것이 성공적으로 구성되면 vCenter > Configure > Security > Key Providers 보기에서 다음과 유사한 것을 볼 수 있다.

1-HyTrust-Key-Provider.png

2단계 – 암호화 정책 생성

암호화를 통해 영구 볼륨을 프로비저닝하려면 암호화 기능을 갖춘 스토리지 정책을 생성해야 한다. VM 암호화는 "호스트 기반 서비스"이므로 이를 구성하려면 "호스트 기반 규칙 사용"을 선택해야 한다. 암호화된 영구 볼륨을 특정 스토리지에 배치하려면 데이터스토어 관련 규칙을 포함할 수 있다. 아래에서는 순수 스토리지 vVol 지원 FlashArray인 vSAN 스토리지에 대한 규칙을 볼 수 있으며 VMFS 또는 NFS에 볼륨을 배치하려면 태그 기반 배치 규칙을 사용한다. 이 예에서는 영구 볼륨이 암호화되어 있는 한 어떤 스토리지에 배치되는지는 상관하지 않으므로 데이터스토어를 선택하지 않을 것이다. 프로덕션에서 암호화를 위한 이 호스트 기반 규칙을 데이터스토어 관련 규칙과 결합할 수 있을 것이다.

3-host-based-rules.png

다음 화면에서 'Use storage policy component'을 선택하고 기본 암호화 정책으로 설정한다. 그러면 이 vCenter Server에 대해 이미 구성되고 신뢰할 수 있는 키 공급자가 자동으로 선택된다. 사용자 지정 옵션을 사용하여 암호화 전이나 후에 IO 필터의 적용 시기를 결정할 수 있다. IO 필터로 구현되는 IO 경로에 포함되는 제품 및 기능도 있다. 이것은 내 설정에서 적용할 수 없다.

4-use-policy-component.png

스토리지 정책이 생성된 후에는 검토할 수 있다.

2-Simple-Encryption.png

3단계 – 전체 VM 구현을 통한 정책 테스트

글쓴이는 일반적으로 개별 Kubernetes Persistent Volumes로 테스트를 진행하기 전에 완전히 배포된 가상 시스템이 암호화와 함께 작동하는지 확인한다. 암호화 정책을 사용하여 전체 가상 시스템을 배포한 후 vSphere UI에서 가상 시스템의 설정을 편집하면 VM 구성 파일과 가상 시스템 디스크인 VMDK 모두에 대해 강조 표시된 암호화가 표시되어야 한다. 이제 암호화 정책이 작동 중임을 확신하고 vSphere 7.0의 새 CSI 드라이버를 사용하여 Kubernetes Persistent Volumes 암호화 테스트로 이동할 수 있다.

5-Test-VM-Encrypted.png

4단계 – StorageClass, PersistentVolumeClaim 및 Pod 생성

이 테스트에는 새 vSphere CSI 드라이버를 제공자로 포함하는 StorageClass와 암호화를 사용하는 정책이 포함될 것이다. 또한 이 테스트에는 PV(Persistent Volume)를 동적으로 프로비저닝하기 위한 단순한 PVC를 생성하는 작업이 포함될 것이다. 마지막으로, 팟을 만들어 암호화된 볼륨이 팟에 성공적으로 부착되고 팟에 탑재될 수 있도록 할 것이다. 테스트에 사용할 매니페스트 파일들이 여기 있다. 암호화 스토리지 정책을 참조하는 StorageClass 매니페스트다.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: encrypt-sc
provisioner: csi.vsphere.vmware.com
parameters:
  storagepolicyname: "Simple-Encryption"

이것은 StorageClass를 참조하는 PVC(PersistentVolumeClaim) 매니페스트다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: encrypt-pvc
spec:
  storageClassName: encrypt-sc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2G

PVC를 참조하는 Pod 매니페스트(단순 busybox)다.

apiVersion: v1
kind: Pod
metadata:
  name: encrypt-pod-a
spec:
  containers:
  - name: encrypt-pod-a
    image: "k8s.gcr.io/busybox"
    volumeMounts:
    - name: encrypt-vol
      mountPath: "/mnt/volume1"
    command: [ "sleep", "1000000" ]
  volumes:
    - name: encrypt-vol
      persistentVolumeClaim:
        claimName: encrypt-pvc

첫 번째 테스트 실행에서는 StorageClass와 PVC 둘 다 잘 되었다. 그러나, 팟을 전개하려고 했을 때, 팟에 대한 설명을 했을 때 다음과 같은 오류가 던져졌다.

Events:
  Type     Reason              Age                            From                     Message
  ----     ------              ----                           ----                     -------
  Normal   Scheduled           <invalid>                      default-scheduler        Successfully assigned 
default/encrypt-pod-a to k8s-worker07-01

  Warning  FailedAttachVolume  <invalid> (x3 over <invalid>)  attachdetach-controller  AttachVolume.Attach failed 
for volume "pvc-77d3bf1c-1ef4-40a3-8608-dfc6a9a3ea57" : rpc error: code = Internal desc = Failed to attach disk: 
"449cc99f-6cda-48e0-84f7-b7b150d4ab0a" with node: "k8s-worker07-01" err failed to attach cns volume: 
"449cc99f-6cda-48e0-84f7-b7b150d4ab0a" to node vm: "VirtualMachine:vm-1081 [VirtualCenterHost: 10.27.51.106, UUID: 
42051f46-6ac5-3b3a-502b-8242b0325b9d, Datacenter: Datacenter [Datacenter: Datacenter:datacenter-3, VirtualCenterHost: 
10.27.51.106]]". fault: "(*types.LocalizedMethodFault)(0xc00000cde0)({\n DynamicData: (types.DynamicData) {\n },\n 
Fault: (types.CnsFault) {\n  BaseMethodFault: (types.BaseMethodFault) <nil>,\n  Reason: (string) (len=92) \"CNS: 
Failed to attach disk when calling AttachDisk:Fault cause: vim.fault.InvalidDeviceSpec\\n\"\n },\n LocalizedMessage: 
(string) (len=108) \"CnsFault error: CNS: Failed to attach disk when calling AttachDisk:Fault cause: 
vim.fault.InvalidDeviceSpec\\n\"\n})\n". opId: "0eac10c4"

OK – 문제가 무엇인지 잘 알 수 없다. 다행히도 곧 vSphere UI에 표시되는 메시지는 실제 문제가 무엇인지에 대해 훨씬 더 명확해진다. PV는 자체 암호화되지 않은 가상 시스템에 연결할 수 없다. 그리고 이것은 사실이다 – 쿠버네티스 워커 노드를 암호화하지 않았다.

7-K8s-worker-must-be-encrypted.png

5단계 – VM 암호화, K8s 노드로 추가 및 재테스트

테스트를 완료하기 위해 완전히 암호화된 Kubernetes 클러스터에 다른 워커 노드 VM을 추가하려고 한다. 실제로 3단계에서 암호화를 테스트한 VM을 사용할 것이다. 그런 다음 다른 2개의 쿠베르네츠 노드가 포드 스케줄링에 더 이상 사용되지 않도록 코드로 연결/배출할 것이다. 즉, 암호화된 PVC로 내 busybox Pod를 만들 때, Pods 스케줄링에 사용할 수 있는 유일한 노드인 만큼 새로운 '암호화된' Kubernetes 워커 노드에서 스케줄링해야 한다. 물론 암호화된 K8s 노드의 라벨링과 노드 선택기를 사용하여 포드의 노드 라벨과 일치시키는 다른 방법이 있다. 그러나 이 테스트의 목적상, 다른 노드의 스케줄링을 비활성화하기 위해 drain을 사용할 것이다. 아래 출력에서 새 VM이 Kubernetes 클러스터에 워커 노드로 결합하는 것을 관찰할 수 있다.

$ kubectl get nodes
NAME              STATUS   ROLES    AGE    VERSION
k8s-master07-01   Ready    master   2d1h   v1.16.3
k8s-worker07-01   Ready    <none>   47h    v1.16.3
k8s-worker07-02   Ready    <none>   47h    v1.16.3


$ kubectl get nodes
NAME               STATUS     ROLES    AGE    VERSION
encrypted-ubuntu   NotReady   <none>   32s    v1.16.3
k8s-master07-01    Ready      master   2d1h   v1.16.3
k8s-worker07-01    Ready      <none>   47h    v1.16.3
k8s-worker07-02    Ready      <none>   47h    v1.16.3


$ kubectl get nodes
NAME               STATUS   ROLES    AGE    VERSION
encrypted-ubuntu   Ready    <none>   53s    v1.16.3
k8s-master07-01    Ready    master   2d1h   v1.16.3
k8s-worker07-01    Ready    <none>   47h    v1.16.3
k8s-worker07-02    Ready    <none>   47h    v1.16.3

다음 단계는 암호화된 워커 노드만 스케줄링에 사용할 수 있도록 암호화되지 않은 워커 두 명을 배출하는 것이다. 배수 명령의 오류에 대해 걱정할 필요 없다. 워커들은 쿠베르네테스 시스템을 위해 포드를 계속 실행하지만 새로운 파드가 그들에게 예약되는 것을 허용하지 않는다.

$ kubectl drain k8s-worker07-01
node/k8s-worker07-01 cordoned
error: unable to drain node "k8s-worker07-01", aborting command...


There are pending nodes to be drained:
k8s-worker07-01
error: the server could not find the requested resource: kube-flannel-ds-amd64-rvzrw, kube-proxy-cdns5, vsphere-csi-node-jsv84


$ kubectl drain k8s-worker07-02
node/k8s-worker07-02 cordoned
error: unable to drain node "k8s-worker07-02", aborting command...

There are pending nodes to be drained:
k8s-worker07-02
error: the server could not find the requested resource: kube-flannel-ds-amd64-nswzk, kube-proxy-mkq6d, vsphere-csi-node-9tcd6


$ kubectl get nodes
NAME               STATUS                     ROLES    AGE    VERSION
encrypted-ubuntu   Ready                      <none>   81s    v1.16.3
k8s-master07-01    Ready                      master   2d1h   v1.16.3
k8s-worker07-01    Ready,SchedulingDisabled   <none>   47h    v1.16.3
k8s-worker07-02    Ready,SchedulingDisabled   <none>   47h    v1.16.3

이제 우리는 더 나아가서 busybox  파드를 한 번 더 배치하고, 암호화된 PV가 부착되고, 탑재될 것인지 확인할 수 있다. 암호화된 K8s 워커 노드만 사용할 수 있으므로, Pod는 해당 노드에 예약되어야 하며, 따라서 PV도 암호화되어 있으므로 PV도 해당 노드에 연결되어야 한다. 우리는 PVC와 PV가 모두 이전 테스트에서 여전히 존재하는지 확인할 수 있다. 즉, 파드만 배치하면 된다.

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
pvc-77d3bf1c-1ef4-40a3-8608-dfc6a9a3ea57   2Gi        RWO            Delete           Bound    default/encrypt-pvc   encrypt-sc              18m


$ kubectl get pvc
NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
encrypt-pvc   Bound    pvc-77d3bf1c-1ef4-40a3-8608-dfc6a9a3ea57   2Gi        RWO            encrypt-sc     18m


$ kubectl apply -f encrypt-pod.yaml
pod/encrypt-pod-a created


$ kubectl get pods
NAME            READY   STATUS              RESTARTS   AGE
encrypt-pod-a   0/1     ContainerCreating   0          6s


$ kubectl get pods
NAME            READY   STATUS    RESTARTS   AGE
encrypt-pod-a   1/1     Running   0          18s

그리고 이제 암호화된 PV를 가진 포드가 성공적으로 시작된 것으로 보인다. 최종 점검으로 파드의 이벤트를 살펴볼 수 있다. 이번에는 일이 잘 맞아 보인다.

Events:
  Type    Reason                  Age        From                       Message
  ----    ------                  ----       ----                       -------
  Normal  Scheduled               <invalid>  default-scheduler          Successfully assigned default/encrypt-pod-a to encrypted-ubuntu
  Normal  SuccessfulAttachVolume  <invalid>  attachdetach-controller    AttachVolume.Attach succeeded for volume "pvc-77d3bf1c-1ef4-40a3-8608-dfc6a9a3ea57"
  Normal  Pulling                 <invalid>  kubelet, encrypted-ubuntu  Pulling image "k8s.gcr.io/busybox"
  Normal  Pulled                  <invalid>  kubelet, encrypted-ubuntu  Successfully pulled image "k8s.gcr.io/busybox"
  Normal  Created                 <invalid>  kubelet, encrypted-ubuntu  Created container encrypt-pod-a
  Normal  Started                 <invalid>  kubelet, encrypted-ubuntu  Started container encrypt-pod-a

마무리 해보자. 이는 vSphere 7.0을 사용하는 CSI 드라이버의 또 다른 멋진 새로운 기능이다. Kubernetes Pods에 첨부하는 Persistent Volumes의 내용을 암호화해야 하는 경우 vSphere 7.0 스토리지 위에서 Kubernetes 클러스터를 실행하면 이를 활용할 수 있다. 그러나 이 작업이 성공하려면 Kubernetes 작업자 노드도 암호화해야 한다는 점에 유의한다.