OCI File Storage Service: NFS Shared Storage, Snapshots, and Access Control

OCI File Storage Service provides NFS v3 and v4 shared storage accessible from any instance in your VCN. Multiple instances mount the same file system simultaneously, making it useful for shared application data, Oracle Database Direct NFS, configuration files shared across a fleet, and log aggregation from multiple nodes. This post covers Terraform provisioning with export-level access control, snapshot policies, and NSG rules.

Step 1: File System, Mount Target, and Export

resource "oci_file_storage_file_system" "shared_app_data" {
  compartment_id      = var.compartment_id
  availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
  display_name        = "shared-application-data"
  kms_key_id          = var.vault_key_id
  defined_tags        = { "Operations.Environment" = "production", "Operations.ManagedBy" = "terraform" }
}

resource "oci_file_storage_mount_target" "app_tier_mount" {
  compartment_id      = var.compartment_id
  availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
  display_name        = "app-tier-mount-target"
  subnet_id           = var.app_subnet_id
  nsg_ids             = [var.file_storage_nsg_id]
}

resource "oci_file_storage_export_set" "app_export_set" {
  mount_target_id = oci_file_storage_mount_target.app_tier_mount.id
  display_name    = "app-tier-export-set"
}

resource "oci_file_storage_export" "app_data_export" {
  export_set_id  = oci_file_storage_export_set.app_export_set.id
  file_system_id = oci_file_storage_file_system.shared_app_data.id
  path           = "/app-data"

  # Read-write access for the application tier
  export_options {
    source                         = var.app_subnet_cidr
    access                         = "READ_WRITE"
    require_privileged_source_port = true
    identity_squash                = "NONE"
    is_anonymous_access_allowed    = false
  }

  # Read-only access for the reporting tier
  export_options {
    source                         = var.reporting_subnet_cidr
    access                         = "READ_ONLY"
    require_privileged_source_port = true
    identity_squash                = "NONE"
    is_anonymous_access_allowed    = false
  }
}

output "mount_target_ip" {
  value       = oci_file_storage_mount_target.app_tier_mount.ip_address
  description = "Mount on instances: sudo mount MOUNT_IP:/app-data /mnt/app-data"
}

Step 2: NSG Rules for NFS

resource "oci_core_network_security_group_security_rule" "nfs_tcp" {
  network_security_group_id = var.file_storage_nsg_id
  direction                 = "INGRESS"
  protocol                  = "6"
  source_type               = "CIDR_BLOCK"
  source                    = var.app_subnet_cidr

  tcp_options {
    destination_port_range { min = 2048; max = 2050 }
  }
  description = "NFS v3 port range TCP"
}

resource "oci_core_network_security_group_security_rule" "nfs_udp" {
  network_security_group_id = var.file_storage_nsg_id
  direction                 = "INGRESS"
  protocol                  = "17"
  source_type               = "CIDR_BLOCK"
  source                    = var.app_subnet_cidr

  udp_options {
    destination_port_range { min = 2048; max = 2050 }
  }
  description = "NFS v3 port range UDP"
}

resource "oci_core_network_security_group_security_rule" "portmapper" {
  network_security_group_id = var.file_storage_nsg_id
  direction                 = "INGRESS"
  protocol                  = "6"
  source_type               = "CIDR_BLOCK"
  source                    = var.app_subnet_cidr

  tcp_options {
    destination_port_range { min = 111; max = 111 }
  }
  description = "NFS portmapper"
}

Step 3: Snapshot Policy

resource "oci_file_storage_filesystem_snapshot_policy" "app_data_snapshots" {
  compartment_id      = var.compartment_id
  availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
  display_name        = "app-data-snapshot-policy"

  schedules {
    schedule_type                 = "HOURLY"
    retention_duration_in_seconds = 86400
    period                        = "HOURLY"
    hour_of_day                   = 0
    time_zone                     = "UTC"
    time_schedule_start           = "2026-10-10T00:00:00.000Z"
  }

  schedules {
    schedule_type                 = "DAILY"
    retention_duration_in_seconds = 604800
    period                        = "DAILY"
    hour_of_day                   = 2
    time_zone                     = "UTC"
    time_schedule_start           = "2026-10-10T02:00:00.000Z"
  }
}

resource "oci_file_storage_file_system_fs_snapshot_policy" "attach_policy" {
  file_system_id                = oci_file_storage_file_system.shared_app_data.id
  filesystem_snapshot_policy_id = oci_file_storage_filesystem_snapshot_policy.app_data_snapshots.id
}

Step 4: Storage Alarm

resource "oci_monitoring_alarm" "nfs_storage_high" {
  compartment_id        = var.compartment_id
  display_name          = "file-storage-utilization-high"
  is_enabled            = true
  metric_compartment_id = var.compartment_id
  namespace             = "oci_file_storage"
  query                 = "FileSystemGigabytesUsed[1h]{fileSystemId = 'FS_OCID'}.max() > 800"
  severity              = "WARNING"
  pending_duration      = "PT1H"
  destinations          = [var.ops_notification_topic_id]
  body                  = "File Storage System exceeds 800 GB. Review growth patterns and consider expanding capacity."
}

Operational Notes

Configure exports with require_privileged_source_port = true and is_anonymous_access_allowed = false. Privileged source port means only the OS kernel NFS client can mount the export. Anonymous access disabled prevents unmapped UIDs from silently receiving anonymous permissions, which can allow unintended write access when UID mappings differ between the NFS client host and the export configuration.

NFS performance scales with the size of individual IO operations, not the file system capacity. For Oracle Database Direct NFS, mount with rsize=1048576,wsize=1048576 to maximize throughput per operation. File Storage does not limit throughput based on capacity, so a small file system delivers the same per-operation performance as a large one.

Regards,
Osama

#OCI #OracleCloud #FileStorage #NFS #Terraform #IaC #TechBlog #Oracle #PlatformEngineering #SharedStorage #CloudStorage #OracleCloudInfrastructure #SnapshotPolicy #Encryption #DirectNFS #OracleDatabase #HighAvailability #CloudNative #StorageEngineering #PersistentStorage

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.