LoginSignup
3
2

Kubernetes: Prevent unauthorized volume mode conversion during volume restoreの動作検証

Last updated at Posted at 2024-05-14

はじめに

本ドキュメントでは、Kubernetes v1.30: Uwubernetesで紹介されたPrevent unauthorized volume mode conversion during volume restoreについて動作検証を行います。
まず、PVにはVolumeModeが存在します。
このVolumeModeはPV(Volume)を作成する際にCSIドライバで設定しているファイルシステム(ext4など)でフォーマットするFilesystemか、フォーマットしないRaw Volumeとして作成するBlockを指定するパラメータがあります。
本機能は、VolumeSnapshotからリストアする際に元のVolumeで指定されているVolumeModeと異なるVolumeModeが指定された場合に、リストアを抑止する機能となります。
例えば、元のVolumeのVolumeModeがFilesystemで設定されている状態で、リストアする際に間違ってVolumeModeをBlockにしてしまうといったオペミスを防ぎます。

検証環境

  • minikube version: v1.33.0
  • Kubernetes v1.30.0

検証環境の構築

本検証では、各種設定やバージョンアップが必要となるため、事前に環境を準備します。
まず、minikubeでKubernetes v1.30.0を立ち上げます。

$ minikube start --kubernetes-version=v1.30.0
...
🏄  終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました

VolumeSnapshotが利用できるように、Addonsのcsi-hostpath-drivervolumesnapshotsを有効にします。

$ minikube addons enable csi-hostpath-driver
...
🌟  'csi-hostpath-driver' アドオンが有効です
$ minikube addons enable volumesnapshots
...
🌟  'volumesnapshots' アドオンが有効です

kube-systemネームスペースにsnapshot-controller-XXcsi-hostpathXXXのPodがデプロイされRunningになっていることを確認します。

$ kubectl get pod -n kube-system
NAME                                   READY   STATUS    RESTARTS        AGE
coredns-7db6d8ff4d-jh2bq               1/1     Running   0               5m32s
csi-hostpath-attacher-0                1/1     Running   0               2m51s
csi-hostpath-resizer-0                 1/1     Running   0               2m51s
csi-hostpathplugin-fpc27               6/6     Running   0               2m51s
etcd-minikube                          1/1     Running   0               5m48s
kube-apiserver-minikube                1/1     Running   0               5m48s
kube-controller-manager-minikube       1/1     Running   0               5m48s
kube-proxy-qxnzh                       1/1     Running   0               5m32s
kube-scheduler-minikube                1/1     Running   0               5m46s
snapshot-controller-745499f584-jgpj5   1/1     Running   0               45s
snapshot-controller-745499f584-m4trn   1/1     Running   0               45s
storage-provisioner                    1/1     Running   2 (5m30s ago)   5m44s

StorageClassとVolumeSnapshotClassを確認します。

$ kubectl get sc
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
csi-hostpath-sc      hostpath.csi.k8s.io        Delete          Immediate           false                  6m40s
...

$ kubectl get volumesnapshotclass
NAME                     DRIVER                DELETIONPOLICY   AGE
csi-hostpath-snapclass   hostpath.csi.k8s.io   Delete           4m57s

以降の検証では、StorageClass(csi-hostpath-sc)とVolumeSnapshotClass(csi-hostpath-snapclass)を使います。
Prevent Unauthorised Volume Mode Conversionでは、csi-provisioner(external-provisioner)がv4.0.0以降, csi-snapshotter(external-snapshotter)がv7.0.0以降となっている必要があるため、これらのバージョンを確認します。

$ kubectl images -n kube-system csi-hostpathplugin
[Summary]: 1 namespaces, 1 pods, 6 containers and 6 different images
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|           Pod            |               Container                |                                                                       Image                                                                       |
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| csi-hostpathplugin-fpc27 | csi-external-health-monitor-controller | registry.k8s.io/sig-storage/csi-external-health-monitor-controller:v0.7.0@sha256:80b9ba94aa2afe24553d69bd165a6a51552d1582d68618ec00d3b804a7d9193c |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | node-driver-registrar                  | registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.6.0@sha256:f1c25991bac2fbb7f5fcf91ed9438df31e30edee6bed5a780464238aa09ad24c              |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | hostpath                               | registry.k8s.io/sig-storage/hostpathplugin:v1.9.0@sha256:92257881c1d6493cf18299a24af42330f891166560047902b8d431fb66b01af5                         |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | liveness-probe                         | registry.k8s.io/sig-storage/livenessprobe:v2.8.0@sha256:cacee2b5c36dd59d4c7e8469c05c9e4ef53ecb2df9025fa8c10cdaf61bce62f0                          |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | csi-provisioner                        | registry.k8s.io/sig-storage/csi-provisioner:v3.3.0@sha256:ee3b525d5b89db99da3b8eb521d9cd90cb6e9ef0fbb651e98bb37be78d36b5b8                        |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | csi-snapshotter                        | registry.k8s.io/sig-storage/csi-snapshotter:v6.1.0@sha256:291334908ddf71a4661fd7f6d9d97274de8a5378a2b6fdfeb2ce73414a34f82f                        |
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------

:pencil: 確認にはkubectlのpluginのkubectl-imagesを使用しています。

バージョンが古いため、csi-provisionerとcsi-snapshotterをバージョンアップします。

$ kubectl edit ds csi-hostpathplugin 
# csi-provisionerとcsi-snapshotterのimageを変更します

$ kubectl images -n kube-system csi-hostpathplugin
[Summary]: 1 namespaces, 1 pods, 6 containers and 6 different images
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|           Pod            |               Container                |                                                                       Image                                                                       |
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
| csi-hostpathplugin-89bxj | csi-external-health-monitor-controller | registry.k8s.io/sig-storage/csi-external-health-monitor-controller:v0.7.0@sha256:80b9ba94aa2afe24553d69bd165a6a51552d1582d68618ec00d3b804a7d9193c |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | node-driver-registrar                  | registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.6.0@sha256:f1c25991bac2fbb7f5fcf91ed9438df31e30edee6bed5a780464238aa09ad24c              |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | hostpath                               | registry.k8s.io/sig-storage/hostpathplugin:v1.9.0@sha256:92257881c1d6493cf18299a24af42330f891166560047902b8d431fb66b01af5                         |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | liveness-probe                         | registry.k8s.io/sig-storage/livenessprobe:v2.8.0@sha256:cacee2b5c36dd59d4c7e8469c05c9e4ef53ecb2df9025fa8c10cdaf61bce62f0                          |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | csi-provisioner                        | registry.k8s.io/sig-storage/csi-provisioner:v4.0.0                                                                                                |
+                          +----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
|                          | csi-snapshotter                        | registry.k8s.io/sig-storage/csi-snapshotter:v7.0.0                                                                                                |
+--------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------+

次に、本機能が有効となるのはsnapshot-controller v6.0.1以降となるため、これのバージョンも確認します。

$ kubectl images -n kube-system snapshot-controller
[Summary]: 1 namespaces, 2 pods, 2 containers and 1 different images
+--------------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|                 Pod                  |         Container          |                                                             Image                                                              |
+--------------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------+
| snapshot-controller-745499f584-jgpj5 | volume-snapshot-controller | registry.k8s.io/sig-storage/snapshot-controller:v6.1.0@sha256:823c75d0c45d1427f6d850070956d9ca657140a7bbf828381541d1d808475280 |
+--------------------------------------+                            +                                                                                                                                +
| snapshot-controller-745499f584-m4trn |                            |                                                                                                                                |
+--------------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------+

v6.1.0となっているため、バージョンはこのままとします。
次に、VolumeSnapshotContentsのCRDを確認します。
具体的には、本機能でキモとなるVolumeSnapshotContentsのspec.sourceVolumeModeが定義されているかを確認します。

:pencil: 筆者は、CRDの変更に気が付かずハマりました :cry:

$ kubectl get crd volumesnapshotcontents.snapshot.storage.k8s.io -o yaml |grep -i sourceVolumeMode
$

minikubeのaddonsでセットアップされたCRDでは、spec.sourceVolumeMode がなかったため、CRDをアップデートします。

$ git clone git@github.com:kubernetes-csi/external-snapshotter.git
$ cd external-snapshotter
$ git checkout v7.0.0
$ kubectl apply -k client/config/crd/
customresourcedefinition.apiextensions.k8s.io/volumesnapshotclasses.snapshot.storage.k8s.io configured
customresourcedefinition.apiextensions.k8s.io/volumesnapshotcontents.snapshot.storage.k8s.io configured
customresourcedefinition.apiextensions.k8s.io/volumesnapshots.snapshot.storage.k8s.io configured

spec.sourceVolumeModeの定義を確認します。

$ kubectl get crd volumesnapshotcontents.snapshot.storage.k8s.io -o yaml |grep -i sourceVolumeMode
...
              sourceVolumeMode:
                description: SourceVolumeMode is the mode of the volume whose snapshot

正しくspec.sourceVolumeModeが定義されていることを確認しました。
念の為、csi-hostpathplugin, snapshot-controller を再起動しておきます。

$ kubectl rollout restart deployment -n kube-system snapshot-controller 
deployment.apps/snapshot-controller restarted

$ kubectl rollout restart ds -n kube-system csi-hostpathplugin 
daemonset.apps/csi-hostpathplugin restarted

また、本機能はsnapshot-validation-webhookも利用するため、snapshot-validation-webhookをデプロイします。
なお、今回は検証目的のためdefaultネームスペースにデプロイします。
先程、git clone したexternal-snapshotterのディレクトリで作業します。

$ ./deploy/kubernetes/webhook-example/create-cert.sh --service snapshot-validation-service --secret snapshot-validation-secret --namespace default
$ cat ./deploy/kubernetes/webhook-example/admission-configuration-template | ./deploy/kubernetes/webhook-example/patch-ca-bundle.sh > ./deploy/kubernetes/webhook-example/admission-configuration.yaml
$ kubectl apply -f ./deploy/kubernetes/webhook-example

snapshot-validation-webhook のバージョンもv7.0.0以降であるかを確認します。

$ kubectl get pod 
NAME                                             READY   STATUS    RESTARTS   AGE
snapshot-validation-deployment-5575887fb-696lz   1/1     Running   0          35s
snapshot-validation-deployment-5575887fb-cfn84   1/1     Running   0          35s
snapshot-validation-deployment-5575887fb-qfchm   1/1     Running   0          35s

$ kubectl images snapshot-validation
[Summary]: 1 namespaces, 3 pods, 3 containers and 1 different images
+------------------------------------------------+---------------------+----------------------------------------------------------------+
|                      Pod                       |      Container      |                             Image                              |
+------------------------------------------------+---------------------+----------------------------------------------------------------+
| snapshot-validation-deployment-5575887fb-696lz | snapshot-validation | registry.k8s.io/sig-storage/snapshot-validation-webhook:v6.3.1 |
+------------------------------------------------+                     +                                                                +
| snapshot-validation-deployment-5575887fb-cfn84 |                     |                                                                |
+------------------------------------------------+                     +                                                                +
| snapshot-validation-deployment-5575887fb-qfchm |                     |                                                                |
+------------------------------------------------+---------------------+----------------------------------------------------------------+

snapshot-validation-webhookのバージョンをv7.0.0にアップデートします。

$ kubectl images snapshot-validation
[Summary]: 1 namespaces, 3 pods, 3 containers and 1 different images
+-------------------------------------------------+---------------------+----------------------------------------------------------------+
|                       Pod                       |      Container      |                             Image                              |
+-------------------------------------------------+---------------------+----------------------------------------------------------------+
| snapshot-validation-deployment-798dc7fcb9-569rr | snapshot-validation | registry.k8s.io/sig-storage/snapshot-validation-webhook:v7.0.0 |
+-------------------------------------------------+                     +                                                                +
| snapshot-validation-deployment-798dc7fcb9-d27t8 |                     |                                                                |
+-------------------------------------------------+                     +                                                                +
| snapshot-validation-deployment-798dc7fcb9-w66fx |                     |                                                                |
+-------------------------------------------------+---------------------+----------------------------------------------------------------+

次に、本機能を有効にするためにはsnapshot-controller, external-provisioner(csi-provisioner), snapshot-validation-webhookの起動オプションに--prevent-volume-mode-conversion=trueを追加する必要があるため、これらを設定します。
:pencil: 筆者は本オプションに気が付かず再びハマりました :cry:

# 以下でそれぞれのargsに--prevent-volume-mode-conversion=trueを付与
$ kubectl edit deployments -n kube-system snapshot-controller 
$ kubectl edit deployments -n kube-system snapshot-controller
$ kubectl edit deployments snapshot-validation-deployment

以上で本機能の検証環境の準備が完了しました。

動作検証

まずはVolumeSnapshotの元となるPVCを作成します。
作成するPVCのManifestは以下です。
使用するStorageClassは事前準備で確認したcsi-hostpath-scを使います。

  • pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pv
spec:
  storageClassName: csi-hostpath-sc
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

pvc.yamlをデプロイし、PVC/PVの作成を確認します。

$ kubectl apply -f pvc.yaml 
persistentvolumeclaim/test-pv created

$ kubectl get pvc,pv -o wide
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      VOLUMEATTRIBUTESCLASS   AGE     VOLUMEMODE
persistentvolumeclaim/test-pv   Bound    pvc-2cd519af-bb9f-4758-a4d0-e01944d8e75c   1Gi        RWO            csi-hostpath-sc   <unset>                 2m40s   Filesystem

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS      VOLUMEATTRIBUTESCLASS   REASON   AGE     VOLUMEMODE
persistentvolume/pvc-2cd519af-bb9f-4758-a4d0-e01944d8e75c   1Gi        RWO            Delete           Bound    default/test-pv   csi-hostpath-sc   <unset>                          2m25s   Filesystem

PVC/PVが作成されVolumeModeがFilesystemになっていることが確認できます。
なお、このVolumeModeは、ファイルシステム(ext4など)でフォーマットされたVolumeであることを示すものであり、ブロックストレージ(iSCSIなど)/ファイルストレージ(NFSなど)の区別とは関係ありません。

次に、作成したPVC/PVを対象にVolumeSnapshotを作成します。
VolumeSnapshotのManifestは以下です。
使用するVolumeSnapshotClassはcsi-hostpath-snapclassです。

  • volumesnapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: snapshot-test1
spec:
  volumeSnapshotClassName: csi-hostpath-snapclass
  source:
    persistentVolumeClaimName: test-pv

volumesnapshot.yamlをデプロイした後、VolumeSnapshot/VolumeSnapshotContentを確認します。

$ kubectl apply -f volumesnapshot.yaml 
volumesnapshot.snapshot.storage.k8s.io/snapshot-test1 created

$ kubectl get volumesnapshot,volumesnapshotcontent
NAME                                                    READYTOUSE   SOURCEPVC   SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS            SNAPSHOTCONTENT                                    CREATIONTIME   AGE
volumesnapshot.snapshot.storage.k8s.io/snapshot-test1   true         test-pv                             1Gi           csi-hostpath-snapclass   snapcontent-72f81d88-319d-4465-b2d1-395dc31e7668   40s            40s

NAME                                                                                             READYTOUSE   RESTORESIZE   DELETIONPOLICY   DRIVER                VOLUMESNAPSHOTCLASS      VOLUMESNAPSHOT   VOLUMESNAPSHOTNAMESPACE   AGE
volumesnapshotcontent.snapshot.storage.k8s.io/snapcontent-72f81d88-319d-4465-b2d1-395dc31e7668   true         1073741824    Delete           hostpath.csi.k8s.io   csi-hostpath-snapclass   snapshot-test1   default                   40s

問題なくVolumeSnapshot, VolumeSnapshotContentが作成できています。
作成されたVolumeSnapshotContent(snapcontent-72f81d88-319d-4465-b2d1-395dc31e7668)を確認します。

$ kubectl get volumesnapshotcontents snapcontent-72f81d88-319d-4465-b2d1-395dc31e7668 -o yaml
...
spec:
  sourceVolumeMode: Filesystem
...

spec.sourceVolumeModeが正しく設定されていることが確認できます。
もし、古いコントローラを利用し作成したVolumeSnapshotContentがあり本パラメータが存在していない場合には、kubernetes.ioのドキュメントによるとkubectl edit などを使い手動で追加しても問題ないようです。

このVolumeSnapshotからリストアを試します。
まずは、同じVolumeMode(Filesystem)のPVCを使いリストアを試します。

  • restore-pvc.yaml
kind: PersistentVolumeClaim
metadata:
  name: restore-pv-filesystem
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  storageClassName: csi-hostpath-sc
  resources:
    requests:
      storage: 1Gi
  dataSource:
    apiGroup: snapshot.storage.k8s.io
    kind: VolumeSnapshot
    name: snapshot-test1

restore-pvc.yaml をデプロイしPVCを確認します。

$ kubectl get pvc -o wide
NAME                    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
restore-pv-filesystem   Bound    pvc-bae61ab6-9769-4746-a0f2-91fa653e3074   1Gi        RWO            csi-hostpath-sc   <unset>                 8s    Filesystem
test-pv                 Bound    pvc-2cd519af-bb9f-4758-a4d0-e01944d8e75c   1Gi        RWO            csi-hostpath-sc   <unset>                 23m   Filesystem

問題なくリストアされたPVC/PV(restore-pv-filesystem/pvc-bae61ab6-9769-4746-a0f2-91fa653e3074)が作成されました。
次に、本機能である異なるVolumeMode(Block)でリストアを試します。
Manifestは以下です。 PVC名とvolumeModeのみ先ほどのPVCとは異なります。

  • restore-pvc2.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: restore-pv-block
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Block
  storageClassName: csi-hostpath-sc
  resources:
    requests:
      storage: 1Gi
  dataSource:
    apiGroup: snapshot.storage.k8s.io
    kind: VolumeSnapshot
    name: snapshot-test1

restore-pvc2.yamlをデプロイしPVCを確認します。

$ kubectl get pvc -o wide
NAME                    STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      VOLUMEATTRIBUTESCLASS   AGE     VOLUMEMODE
restore-pv-block        Pending                                                                        csi-hostpath-sc   <unset>                 81s     Block
restore-pv-filesystem   Bound     pvc-bae61ab6-9769-4746-a0f2-91fa653e3074   1Gi        RWO            csi-hostpath-sc   <unset>                 4m45s   Filesystem
test-pv                 Bound     pvc-2cd519af-bb9f-4758-a4d0-e01944d8e75c   1Gi        RWO            csi-hostpath-sc   <unset>                 28m     Filesystem

Pendingのままとなりました。
詳細を確認します。

$ kubectl describe pvc restore-pv-block 
...
Events:
  Type     Reason                Age                 From                                                                               Message
  ----     ------                ----                ----                                                                               -------
  Normal   Provisioning          56s (x7 over 119s)  hostpath.csi.k8s.io_csi-hostpathplugin-rc5pt_08514e20-b05a-442e-a352-57bc803814ff  External provisioner is provisioning volume for claim "default/restore-pv-block"
  Warning  ProvisioningFailed    56s (x7 over 119s)  hostpath.csi.k8s.io_csi-hostpathplugin-rc5pt_08514e20-b05a-442e-a352-57bc803814ff  failed to provision volume with StorageClass "csi-hostpath-sc": error getting handle for DataSource Type VolumeSnapshot by Name snapshot-test1: requested volume default/restore-pv-block modifies the mode of the source volume but does not have permission to do so. snapshot.storage.kubernetes.io/allow-volume-mode-change annotation is not present on snapshotcontent snapcontent-72f81d88-319d-4465-b2d1-395dc31e7668
  Normal   ExternalProvisioning  3s (x12 over 2m5s)  persistentvolume-controller                                                        Waiting for a volume to be created either by the external provisioner 'hostpath.csi.k8s.io' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

error getting handle for DataSource Type VolumeSnapshot by Name snapshot-test1: requested volume default/restore-pv-block modifies the mode of the source volume but does not have permission to do so. のメッセージが出力されており、元のPVC/PV(Volume)とは異なるVolumeModeへのリストアを防いでくれていることが確認できました。

本機能が設定されている場合に、どうしてもVolumeModeを元のVolumeと変えたい場合には、VolumeSnapshotContentにsnapshot.storage.kubernetes.io/allow-volume-mode-change: "true"のannotationsを付与すれば許可されるとのことです。
本検証では割愛します。

感想

本検証では、Prevent Unauthorised Volume Mode Conversionの動作検証を行いました。
これまでのVolumeSnapshotのリストアでは、VolumeModeのチェックは存在していなかったため、元のVolumeがFilesystemでフォーマットされたもの(VolumeMode: Filesystem)のVolumeSnapshotであっても、リストア時にRaw Volume(VolumeMode: Block)でリストア出来てしまいました(この逆も可能)。
本機能により、オペミスなどによるこのチグハグなリストアの指定を防ぐことが可能となります。

VolumeSnapshotからのリストアを行う場合は、障害復旧など心穏やかでない状態で作業を行うことが多いかと思います。
そのような状態でも、オペミスを起こさないように本機能を有効化しておくことで、より安全に復旧作業を行えるのではないでしょうか。

参考情報

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2