diff --git a/docs/kubernetes/operations/security/authentication-encryption.md b/docs/kubernetes/operations/security/authentication-encryption.md index d3fedaa7..0f51eeb8 100644 --- a/docs/kubernetes/operations/security/authentication-encryption.md +++ b/docs/kubernetes/operations/security/authentication-encryption.md @@ -45,5 +45,44 @@ When connecting a volume with host access control enabled, the `--host-nqn` flag {{ cliname }} volume connect --host-nqn ``` +## Configuring DHCHAP via the StoragePool CRD + +On Kubernetes deployments managed by the Simplyblock Operator, DHCHAP and host access control are configured +declaratively on the `StoragePool` custom resource instead of through `{{ cliname }}`. + +```yaml title="Example of a StoragePool with DHCHAP enabled for two worker nodes" +apiVersion: storage.simplyblock.io/v1alpha1 +kind: StoragePool +metadata: + name: pool-a + namespace: simplyblock +spec: + clusterName: cluster-a + dhchap: true + allowedNodes: + - worker-1 + - worker-2 +``` + +The keys are generated as soon as `dhchap` is set, but authentication is only enforced once `allowedNodes` is +non-empty. Everything the flow above does by hand is then reconciled by the operator: + +- Each node in `allowedNodes` is registered as an allowed host of the pool, under a deterministic NQN derived + from that node's Kubernetes UID (`nqn.2014-08.io.simplyblock:uuid:`). +- Each allowed node is labeled `simplyblock.io/pool...: allowed`, and the generated + `StorageClass` is restricted to that label through `allowedTopologies`. The first `Pod` to consume a + `PersistentVolumeClaim` of this pool can therefore only be scheduled onto an allowed node. +- The same label is written into the `nodeAffinity` of the `PersistentVolume` when the volume is created, which + restricts every later scheduling decision on the already-bound volume. +- The node's own NQN and the pool's DHCHAP secrets are presented by the CSI node plugin on connect, so no + `--host-nqn` has to be supplied anywhere in the Kubernetes flow. + +`dhchap` is immutable, because the `parameters` and `allowedTopologies` of the generated `StorageClass` cannot +be patched in the Kubernetes API once it exists. `allowedNodes` stays mutable. Changing it relabels the nodes +and updates the pool's allowed hosts, and it never rewrites the `StorageClass`. + +See the [Operator Reference](../../../reference/operator/reference.md) for the full `StoragePool` field list, +and [Storage Class](../../usage/storage-class.md) for the `dhchap_node_label` parameter this generates. + For a detailed explanation of the security mechanisms and configuration, see [NVMe-oF Security](../../../architecture/concepts/nvmf-security.md). diff --git a/docs/kubernetes/usage/storage-class.md b/docs/kubernetes/usage/storage-class.md index 4ec10b39..b0770a6b 100644 --- a/docs/kubernetes/usage/storage-class.md +++ b/docs/kubernetes/usage/storage-class.md @@ -64,22 +64,23 @@ If `namespace-volumes` is set to `yes`, the number of namespaces per subsystem h ## Available Parameters -| Parameter Name | Value Type | Description | Optional | Default | -|---------------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------|----------|----------| -| cluster_id | string | Defines the backing cluster id for the storage class. Required unless `zone_cluster_map` or `region_cluster_map` is used. | true | | -| zone_cluster_map | string | JSON map of Kubernetes zone to simplyblock cluster id (for topology-aware multi-cluster provisioning). | true | | -| region_cluster_map | string | JSON map of Kubernetes region to simplyblock cluster id (for topology-aware multi-cluster provisioning). | true | | -| fabric | string | Defines the fabric type to connect to the storage cluster. Valid values are `tcp` and `rdma`. | true | `tcp` | -| csi.storage.k8s.io/fstype | string | Defines the filesystem to format the logical volume. If not specific, a raw block device is given to the container. | true | | -| pool_name | string | Defines the simplyblock storage pool name to use. | false | testing1 | -| qos_rw_iops | int | Defines the maximum IOPS reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | -| qos_rw_mbytes | int | Defines the maximum total throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | -| qos_r_mbytes | int | Defines the maximum read throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | -| qos_w_mbytes | int | Defines the maximum write throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | -| compression | bool | Defines if the logical volume of this storage class will be stored compressed or not. | true | false | -| encryption | bool | Defines if the logical volume of this storage class will be encrypted or not. | true | false | -| distr_ndcs | int | Defines the number of data chunks for the erasure coding scheme. | true | 1 | -| distr_npcs | int | Defines the number of parity chunks for the erasure coding scheme. | true | 1 | -| lvol_priority_class | int | Defines the priority class of a logical volume of this storage class. | true | 0 | -| max_namespace_per_subsys | int | Defines the number of namespaces per NVMe subsystem. | true | 1 | -| tune2fs_reserved_blocks | int | Defines the number of reserved blocks for tune2fs operations. | true | 0 | +| Parameter Name | Value Type | Description | Optional | Default | +|---------------------------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------| +| cluster_id | string | Defines the backing cluster id for the storage class. Required unless `zone_cluster_map` or `region_cluster_map` is used. | true | | +| zone_cluster_map | string | JSON map of Kubernetes zone to simplyblock cluster id (for topology-aware multi-cluster provisioning). | true | | +| region_cluster_map | string | JSON map of Kubernetes region to simplyblock cluster id (for topology-aware multi-cluster provisioning). | true | | +| fabric | string | Defines the fabric type to connect to the storage cluster. Valid values are `tcp` and `rdma`. | true | `tcp` | +| csi.storage.k8s.io/fstype | string | Defines the filesystem to format the logical volume. If not specific, a raw block device is given to the container. | true | | +| pool_name | string | Defines the simplyblock storage pool name to use. | false | testing1 | +| qos_rw_iops | int | Defines the maximum IOPS reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | +| qos_rw_mbytes | int | Defines the maximum total throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | +| qos_r_mbytes | int | Defines the maximum read throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | +| qos_w_mbytes | int | Defines the maximum write throughput in megabytes reserved for a logical volume of this storage class. A zero (0) means no maximum. | true | 0 | +| compression | bool | Defines if the logical volume of this storage class will be stored compressed or not. | true | false | +| encryption | bool | Defines if the logical volume of this storage class will be encrypted or not. | true | false | +| distr_ndcs | int | Defines the number of data chunks for the erasure coding scheme. | true | 1 | +| distr_npcs | int | Defines the number of parity chunks for the erasure coding scheme. | true | 1 | +| lvol_priority_class | int | Defines the priority class of a logical volume of this storage class. | true | 0 | +| max_namespace_per_subsys | int | Defines the number of namespaces per NVMe subsystem. | true | 1 | +| tune2fs_reserved_blocks | int | Defines the number of reserved blocks for tune2fs operations. | true | 0 | +| dhchap_node_label | string | Node label key carried by the allowed nodes of a DHCHAP pool, restricting volumes of this class to those nodes. Set by the operator from a `StoragePool`'s `dhchap` and `allowedNodes` fields. | true | |