Citrix SecurSpaces™

Author a PersistentVolume for Attach Existing

Author a PersistentVolume for Attach Existing

SecurSpaces never creates, changes, or cleans up these volumes. It only creates a claim that binds to your volume by name.

Set the scope label

SecurSpaces records the owner of storage it creates. For a volume you author, it has no such record, so you must declare the intended consumer scope with the strong.network/mount-point-scope label.

Label value Who can attach it
project.<projectId> Only that project.
org.<organizationId> Any project in that organization.
shared Any project in the whole deployment.

Use a dot, not a colon. Kubernetes forbids : in a label value.

A volume with no scope label, or an unrecognized value, is offered to nobody and cannot be attached. A forgotten label can never accidentally expose a volume, but it is the most common cause of “my volume is not in the list”.

Both project. and org. scopes are enforced by server-side checks, on both the picker and the bind. The shared value has no boundary. Use it only for data you are content for anyone in the deployment to reach.

Find the numeric project or organization id in the browser address bar. The id is the path segment after /project/ or /organization/.

Meet the volume requirements

apiVersion: v1
kind: PersistentVolume
metadata:
  name: shared-dataset-alpha
  labels:
    strong.network/mount-point-scope: "project.1090137447483732"
spec:
  capacity:
    storage: 1Gi
  accessModes: ["ReadWriteMany", "ReadOnlyMany"]
  persistentVolumeReclaimPolicy: Retain
  storageClassName: ""
  mountOptions: ["tls"]
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-0abc123::fsap-07c9def
<!--NeedCopy-->

A volume is offered only when all of the following hold:

  • spec.csi.driver is efs.csi.aws.com.
  • spec.csi.volumeHandle names an access point. For Amazon EFS the static form has no prefix, <fs-id>::<access-point-id>. For Amazon S3 Files it keeps the prefix, s3files:<fs-id>::<access-point-id>.
  • spec.mountOptions contains tls.
  • spec.persistentVolumeReclaimPolicy is Retain, so removing a Mount Point never destroys your data.
  • spec.storageClassName is an explicit empty string. Do not omit it and do not point it at a StorageClass.
  • spec.accessModes lists every mode you want the volume usable in.
  • spec.capacity.storage has a value. It is nominal: EFS and S3 Files ignore size.
  • The volume is in the Available phase.

No Kubernetes secret is needed. AWS access is backed by IAM and the access point.

Note

There is no hierarchy in accessModes. ReadWriteMany does not cover read-only. A volume listing only ReadWriteMany cannot back a read-only Mount Point, and if the owner had already chosen Read Only, the dialog switches the selection to Read/Write with no explanation. List both modes unless you intend to restrict the volume. accessModes is immutable: to add a mode, delete and re-create the volume object. With Retain, the underlying data is untouched.

Publish access point handles only

The volume handle has the form FileSystemId[:Subpath][::AccessPointId]. Only the access point field enforces isolation.

Handle What it mounts Isolation
fs-id The file system root. None. The workspace sees every project’s data.
fs-id:/subdir A subdirectory. None. Path-confined only, treated exactly like a bare file system id.
fs-id::fsap-id An access point. Full, but only if that access point is itself restricted.

Warning

A bare file system handle mounts and works, and nothing warns the user. On the route where you publish a volume, the handle you publish is the security boundary: any user who can create a Mount Point in a project your volume is scoped to can bind it. Publish access point handles only, unless you intend everyone in that scope to see the whole file system.

An access point id is not by itself isolation. SecurSpaces decides isolation purely from whether an access point id is present. It never reads the access point’s configuration from AWS. In AWS both the root directory and the POSIX user are optional on an access point, and one created without them exposes the file system root while still satisfying every check. Verify before publishing:

aws efs describe-access-points --access-point-id <fsap-id> \
  --query 'AccessPoints[].{Root:RootDirectory.Path,Uid:PosixUser.Uid,Gid:PosixUser.Gid}'
<!--NeedCopy-->

Publish only if Root is a real per-dataset path, not / and not null, and Uid and Gid are set. Access points cannot be edited after creation, so an unrestricted one must be replaced.

To sweep a file system for unrestricted access points:

aws efs describe-access-points --file-system-id <fs-id> \
  --query 'AccessPoints[?RootDirectory.Path==`/` || PosixUser==`null`].AccessPointId'
<!--NeedCopy-->

Never publish a subpath handle that points at your StorageClass basePath. That directory is the parent of every directory created by Create New, including data orphaned by deleted Mount Points.

Reset a released volume

A volume you author is single-use per bind cycle. Deleting a Mount Point removes only the claim. Because of Retain, Kubernetes moves the volume to the Released phase and keeps a stale claimRef that prevents rebinding. The picker still lists it, in a separate non-selectable group marked as needing a reset.

kubectl get pv <pv-name> -o jsonpath='{.status.phase}'
kubectl patch pv <pv-name> --type=json -p='[{"op":"remove","path":"/spec/claimRef"}]'
<!--NeedCopy-->

Warning

Clearing claimRef returns the volume to the pool with its existing data intact, and the next project that attaches it inherits that data. Reset only volumes you intend to hand back. The command has no safety check of its own: run against a bound volume it strips a live Mount Point’s binding. Confirm the phase reads Released first.

SecurSpaces does not reset the volume for you. This flow exists for operators who do not grant SecurSpaces write access to PersistentVolumes, so SecurSpaces has read-only access and never changes a volume you own.

Author a PersistentVolume for Attach Existing