Safeguard
Supply Chain Security•

iSCSI Explained: Block Storage Over IP, CHAP and Storage Network Security

iSCSI carries SCSI disk commands over TCP so a server can use remote storage as a local disk. How login, CHAP, multipath and isolation work.

Safeguard Security Team
45 min read

iSCSI (Internet Small Computer Systems Interface) is a protocol that carries SCSI disk commands over ordinary TCP/IP, so a server can use a disk that lives on another machine as if it were plugged in locally. The client is called the initiator, the storage side is the target, and each disk it exports is a LUN. CHAP, its built in login check, proves identity but encrypts nothing, so a storage network stays safe only when it is isolated, access controlled per initiator and, where traffic leaves a trusted segment, protected with IPsec.

That last sentence is the part most setups get wrong. iSCSI was designed in the early 2000s for dedicated storage networks, and its defaults still assume one: the Linux target tool listens on every address by default, the Windows initiator connects with no authentication by default, and data digests are off by default. This post explains how the protocol works on the wire, what each security mechanism actually protects, and how to build a Linux target and initiator with mutual CHAP step by step. It goes one level deeper than our guides to building a tiny data center at home and a home NAS with ZFS, and it pairs with our explainers on the file protocols, NFS and SMB.

Key takeaways

  • iSCSI is block storage: the initiator sees a raw disk and owns its file system. NFS and SMB are file storage, where the server owns the file system. Most design decisions follow from that.
  • RFC 7143 (April 2014) is the current specification; it consolidated and replaced RFC 3720. Targets listen on TCP 3260 by default.
  • Initiators and targets have worldwide unique names such as iqn.2001-04.com.example:storage:disk1. Target ACLs are keyed on them, and they are not secrets.
  • Login runs through security negotiation (CHAP), operational negotiation (digests, burst sizes) and full feature phase (SCSI commands).
  • CHAP proves knowledge of a shared secret without sending it. It encrypts nothing and is open to offline dictionary attack with short secrets; RFC 7143 requires IPsec when a secret has fewer than 96 random bits. Mutual CHAP, with a different secret each way, also authenticates the target.
  • Isolation is the primary control: a dedicated VLAN or fabric, no routing to user networks, portals bound to storage addresses and per initiator ACLs. Add IPsec or MACsec when traffic crosses anything you do not control.
  • Multipath needs truly independent paths and a multipath layer; jumbo frames need every hop to agree. Two hosts mounting one LUN with an ordinary file system will corrupt it.

What is iSCSI and how does it carry SCSI commands over TCP?

SCSI is a family of command sets for talking to storage devices: read these blocks, write those blocks, report your capacity, reserve this device. Originally those commands ran over a parallel cable inside one server. Later the same command model moved to serial transports such as Fibre Channel and SAS. iSCSI is the transport that maps the SCSI command model onto TCP, so any IP network can carry it.

The original standard was RFC 3720, published in April 2004. Ten years later the IETF published RFC 7143 (April 2014), "Internet Small Computer System Interface (iSCSI) Protocol (Consolidated)", which obsoletes RFC 3720, RFC 3980, RFC 4850 and RFC 5048 and folds their content into one document. A companion, RFC 7144 (April 2014), adds newer SCSI features and an iSCSIProtocolLevel key so the two ends can tell which feature set they share. If you read one document, read RFC 7143.

The cast: initiator, target, portal, LUN

TermWhat it isLinux exampleWindows example
InitiatorThe client that sends SCSI commandsopen-iscsi (iscsid plus iscsiadm)Microsoft iSCSI Initiator service
TargetThe storage endpoint that receives commandsLIO kernel target, managed with targetcliiSCSI Target Server role
Network portalAn IP address and TCP port a node listens or connects on192.0.2.10:3260Same
Portal groupA set of portals that can carry connections for one sessiontpg1 in targetcliSame concept
LUNLogical Unit Number: one exported disk behind a targetLUN 0 backed by /dev/sdbA virtual disk file
BackstoreWhere the LUN's bytes really live on the targeta block device, a file, or RAMa VHDX file

On the wire, every message is a PDU (protocol data unit): a 48 byte basic header segment, optional additional headers, an optional header digest, a data segment and an optional data digest. A SCSI read becomes a SCSI Command PDU from the initiator and one or more Data-In PDUs back from the target, followed by a SCSI Response. A write uses Data-Out PDUs, and the target paces large writes with Ready To Transfer (R2T) PDUs that say "send me this range next".

RFC 7143 section 13 lists the well known port as TCP 3260, the IANA registered iSCSI port and the only allowed default. Port 860 is also registered as the iSCSI "system port", but the RFC says implementations may use it only when explicitly configured. In practice almost everything listens on 3260.

iSCSI names: IQN, EUI and NAA

Every initiator and target has a name that is meant to be worldwide unique and permanent, independent of its IP address. RFC 7143 section 4.2.7 defines three formats.

FormatShapeExample from RFC 7143Typical use
iqn.iqn. + year-month the naming authority owned the domain + reversed domain + optional : and a local stringiqn.2001-04.com.example:storage:diskarrays-sn-a8675309Almost all software initiators and targets
eui.eui. + 16 hex digits of an IEEE EUI-64eui.02004567A425678DHardware with an assigned EUI-64
naa.naa. + 16 or 32 hex digits of a T11 NAA identifiernaa.52004567BA64678DDevices that also speak Fibre Channel

The date code in an IQN matters because domain names change hands. iqn.2001-04.com.example means "names assigned by whoever owned example.com in April 2001", so a later owner of the same domain picks a later date and cannot collide.

Two security facts follow. The name is an identifier, not a credential: it sits in a plain text file (/etc/iscsi/initiatorname.iscsi on Linux) and is sent in the clear at every login, so a target that grants access by IQN alone grants it to anyone who can type the string. And because target ACLs are keyed on names, an ACL is only as strong as the authentication bound to it.

Sessions and connections

A session is the relationship between one initiator and one target. The session is identified by two halves: the ISID (initiator session ID), which the initiator picks, and the TSIH (target session identifying handle), which the target assigns at the end of a successful login. A login with a TSIH of zero means "new session".

A session can carry one or more TCP connections. RFC 7143 calls this multiple connections per session, negotiated with the MaxConnections key, which defaults to 1. Most deployments leave it at 1 and get parallelism from multiple sessions plus a multipath layer instead; more on that below.

How do discovery and login work?

Before an initiator can log in, it must know the target's name and at least one portal address. There are three ways to learn them.

Static configuration

You type the target name, address and port. This is the simplest and, for small networks, the most predictable. Nothing is learned from the network, so nothing can be spoofed during discovery.

SendTargets discovery

The initiator opens a "discovery session" to a portal and sends a Text Request with the key SendTargets=All. The target replies with every target name it is willing to tell that initiator about, plus the addresses where each can be reached. RFC 7143 says a target in a discovery session must only accept Text Requests with the SendTargets key and Logout requests; a discovery session cannot read or write data.

Discovery sessions can, and should, be authenticated separately from normal sessions. Both targetcli and open-iscsi have distinct settings for discovery CHAP. If discovery is open, anyone who reaches the portal gets a list of your target names, which tells an attacker what to aim at and what IQN format your hosts use.

iSNS

The Internet Storage Name Service (iSNS), RFC 4171 (September 2005), is a directory server for storage networks. Targets and initiators register with it, and initiators query it to learn which targets they may see. iSNS adds discovery domains, which group initiators and targets so that a member of one domain is not even told about targets in another, and state change notifications that tell registered nodes when something joins or leaves. IANA lists iSNS on TCP and UDP port 3205.

iSNS is useful in larger environments with many targets. It is also one more service that must be protected: an iSNS server that accepts unauthenticated registrations or queries is a map of your storage. RFC 4171 relies on IPsec for protecting iSNS messages.

The login phase, stage by stage

Once the initiator knows where to go, it opens a TCP connection and sends a Login Request. Login proceeds through stages, and each Login PDU carries a current stage (CSG) and next stage (NSG) field plus a T bit meaning "I am ready to move on".

StageCodeWhat happensKeys you will see
SecurityNegotiation0Agree an authentication method and run itAuthMethod=CHAP,None, CHAP_A, CHAP_I, CHAP_C, CHAP_N, CHAP_R
LoginOperationalNegotiation1Agree operational limits for the session and connectionHeaderDigest, DataDigest, MaxConnections, MaxRecvDataSegmentLength, MaxBurstLength, ErrorRecoveryLevel
FullFeaturePhase3Login complete; SCSI commands may flownone, the target returns the TSIH

RFC 7143 says the security stage, when present, must precede operational negotiation. An initiator may skip security negotiation entirely and jump to stage 1. A target that requires authentication must then reject the login. This is the crux of iSCSI security: authentication is negotiated, and whether it is mandatory is a target policy decision. A target configured with no authentication requirement will happily let the initiator skip it.

Operational keys each have a default and a "result function" that decides the outcome when the two sides offer different values. A few from RFC 7143 section 13 are worth knowing because they affect both performance and safety.

KeyDefault in RFC 7143Result functionWhy it matters
HeaderDigest, DataDigestNonenegotiated from listCRC32C digests catch corruption that TCP checksums miss; off by default
MaxConnections1MinimumConnections per session
InitialR2TYesORWhether the initiator must wait for an R2T before sending write data
ImmediateDataYesANDWhether small writes may ride in the command PDU
MaxRecvDataSegmentLength8192 bytesdeclared per directionLargest data segment a side will accept in one PDU
MaxBurstLength262144 (256 KB)MinimumLargest data sequence for one command
FirstBurstLength65536 (64 KB)MinimumUnsolicited data allowed before the first R2T
DefaultTime2Wait2 secondsMaximumWait before reconnecting after a drop
DefaultTime2Retain20 secondsMinimumHow long a target keeps task state for recovery
ErrorRecoveryLevel0Minimum0 means recover by restarting the session

Digests are a good example of a default that assumes a clean network. RFC 7143 describes them as end to end, non cryptographic integrity checks that cover the whole path, including routers, switches and proxies that recompute link checksums. CRC32C is the algorithm. It detects accidental corruption, not tampering: anyone who can modify a PDU can also recompute a CRC.

How does iSCSI compare with NFS, SMB, Fibre Channel and NVMe over TCP?

The first question is block or file. With block storage the remote side exports a range of numbered blocks and the client owns the file system. With file storage the server owns the file system and clients ask for files by name.

That changes who enforces permissions. On an NFS or SMB share, the server checks every open against file ownership and access lists. On an iSCSI LUN, the target only checks whether this initiator may see this LUN at all. Once logged in, the initiator can read and overwrite every block, including file system metadata. There are no per file permissions on the wire.

ProtocolLayer and typeDefault transportAuthenticationEncryption in the protocolTypical use
iSCSIBlock, SCSI over TCPTCP 3260CHAP (one way or mutual); Kerberos and SRP are defined but rarely deployedNone; RFC 7143 relies on IPsecVM datastores, databases, boot from SAN, homelab VM storage
NFS (v4.x)FileTCP 2049AUTH_SYS (client asserted IDs) or KerberosKerberos krb5p privacy; RPC over TLS in newer stacksShared home directories, Linux and Unix file shares, VM datastores
SMB 3.xFileTCP 445NTLM or KerberosSMB 3 encryption (AES-CCM, AES-GCM)Windows file shares, user profiles, some hypervisor storage
Fibre ChannelBlock, SCSI over a dedicated fabricFC fabric, not IPFabric login; zoning and LUN masking; optional fabric authenticationNot by defaultEnterprise SANs with dedicated host bus adapters and switches
NVMe over TCPBlock, NVMe commands over TCPTCP 4420 (IANA), discovery 8009In band authentication defined by NVM Express (DH-HMAC-CHAP)Optional TLS defined in the transport specLow latency flash storage over Ethernet

NFS and SMB are covered in our NFS and SMB explainers; both can authenticate users and encrypt inside the protocol when configured to, which iSCSI cannot do on its own.

Fibre Channel is not IP at all. It runs on its own switches and host bus adapters, which isolates it by construction. NIST SP 800-209 recommends restricting block device access through zoning (which ports may see which, enforced by the switch) and masking (which hosts each LUN is presented to) to the minimum required. iSCSI's equivalents are VLANs or separate switches and target ACLs.

NVMe over TCP is the newer block protocol for flash. The NVM Express specifications page lists the NVMe over TCP Transport Specification at revision 1.3, ratified 31 July 2026, with optional data digests and optional TLS. Its security story is better on paper because TLS is part of the transport, but most deployments still run it on a dedicated storage network.

When to choose iSCSI

iSCSI fits when a hypervisor needs shared block storage for VM disks, when a database wants a raw device with its own file system, when diskless servers boot from the network, or when a homelab storage box serves VM disks to a separate compute host. It does not fit when many users need the same files (use NFS or SMB) or when traffic must cross an untrusted network and you cannot run IPsec.

What does CHAP protect, and why is it not encryption?

CHAP, the Challenge Handshake Authentication Protocol, was defined for PPP dial up links in RFC 1994 (August 1996). iSCSI borrowed it because it was simple, well understood and cheap to implement in hardware.

How a CHAP exchange works

RFC 1994 describes a three way handshake. The authenticator sends an identifier and a random challenge. The peer computes a one way hash over the identifier, the shared secret and the challenge, and sends back the result with its name. The authenticator looks up the secret for that name, computes the same hash and compares. The secret itself never crosses the wire.

In iSCSI the exchange happens inside Login PDUs, using text keys that RFC 7143 section 12.1.3 defines:

KeyMeaningWho sends it
CHAP_AAlgorithm list, then the chosen algorithmInitiator offers, target picks
CHAP_IIdentifierTarget (and initiator, for mutual CHAP)
CHAP_CChallengeTarget (and initiator, for mutual CHAP)
CHAP_NNameResponder
CHAP_RResponse, the hashResponder

The only algorithm RFC 7143 requires is value 5, CHAP with MD5, and initiators must always offer it so that two implementations can interoperate. The open-iscsi initiator also supports SHA1, SHA256 and SHA3-256 through its node.session.auth.chap_algs setting; its sample configuration file says the default is MD5.

Mutual CHAP

One way CHAP proves the initiator to the target. Mutual (bidirectional) CHAP adds a second exchange in the same login in which the initiator challenges the target. In RFC 7143's flow, the initiator sends its response together with its own CHAP_I and CHAP_C, and the target must answer with its CHAP_N and CHAP_R or the initiator closes the connection.

Why bother? Without it, an attacker who can redirect traffic (with ARP spoofing on the storage VLAN, a rogue DHCP lease or a misconfigured route) can stand up a fake target. The initiator will authenticate to it, then send writes to it, and on reads it will trust whatever blocks the impostor returns. Mutual CHAP makes the target prove it knows a secret too.

What RFC 7143 adds to plain CHAP

RFC 7143 section 9.2.1 tightens CHAP considerably compared with its PPP origins:

  • Implementations must support random CHAP secrets of up to 128 bits, and must not offer any way to generate secrets other than random generation. In other words, a passphrase you made up is outside what the spec intends.
  • If a CHAP secret has fewer than 96 random bits, the administrator must enforce IPsec encryption on the connection. An initiator should not even send a CHAP response unless it can verify the secret is at least 96 bits or IPsec is protecting the connection.
  • A secret used to authenticate initiators must never be configured to authenticate targets, and the reverse. If one end receives a response identical to the one it would have generated for the same challenge, it must treat that as an authentication failure and close the connection. This blocks reflection attacks, where an attacker bounces a challenge back to its sender over a second connection.
  • Targets should use separate secrets for authentication to each initiator, because a single target secret shared with many initiators lets any of those initiators impersonate the target.
  • Challenge and response values must not exceed 1024 bytes.

What CHAP does not protect

This is the part to remember. After login completes, CHAP is finished. Nothing in the protocol protects what follows.

ThreatDoes CHAP stop it?What does
An unknown host logging in to a targetYes, if the target requires CHAPCHAP plus per initiator ACLs
A fake target collecting writesOnly with mutual CHAPMutual CHAP
Someone on the path reading data blocksNoIPsec ESP, MACsec, or physical isolation
Someone on the path modifying data blocksNoIPsec ESP or MACsec; CRC32C digests catch only accidents
Session hijacking after loginNoIPsec or MACsec
Offline guessing of a weak secret from a captured loginNo96 to 128 bit random secrets, or IPsec
A compromised initiator reading everything it is mapped toNoLUN mapping per initiator and least privilege

The offline guessing row deserves a sentence of its own. RFC 7143 states plainly that CHAP over an unencrypted channel is vulnerable to an offline dictionary attack. Anyone who captures one login exchange holds the challenge and the hash, and can try passwords against it on their own hardware for as long as they like, without touching your target. A twelve character password chosen by a person is weak against that. A 128 bit secret from a random generator is not.

RFC 1994 also notes that CHAP requires the secret to be available in plaintext form on both sides. That means your target's configuration file and your initiator's node database hold the secret in a recoverable form. File permissions and backups of /etc/target/saveconfig.json and /etc/iscsi/ deserve the same care as any password store.

How should an iSCSI network be isolated?

NIST SP 800-209, "Security Guidelines for Storage Infrastructure" (October 2020), describes the two broad models: storage reached over the general LAN or WAN, or a dedicated network built for storage. iSCSI is the example NIST gives of block storage that can run over a possibly shared LAN or WAN. Shared is allowed. It is not recommended for anything you care about.

Layer 1 and 2: dedicated fabric or VLAN

The strongest option is physically separate switches and network cards for storage. The common compromise is a dedicated VLAN on shared switches, carried on dedicated host ports. Either way:

  • Put only initiator storage ports and target portals on the storage segment. No user devices, no management interfaces, no Wi-Fi bridges.
  • Do not give the storage VLAN a default gateway that routes to user networks. If storage must be reached from another site, route it over a dedicated, encrypted link.
  • Turn on the switch protections that stop one host impersonating another on the segment, such as DHCP snooping and dynamic ARP inspection, or use static addressing and static ARP where the switch lacks them. Our post on Ethernet switching, MAC learning and VLANs explains how VLAN boundaries are enforced and where they leak.
  • Consider MACsec (IEEE 802.1AE) on switch to host links where the hardware supports it. It encrypts and authenticates every frame on the link, which closes the gap CHAP leaves open, without any change to iSCSI itself. Our MACsec explainer covers key agreement with MKA.

Layer 3 and 4: bind portals, filter port 3260

targetcli's man page says that when a target is created, it automatically creates a default portal listening on all IPv4 and IPv6 addresses on port 3260. On a host with a management interface, a user facing interface and a storage interface, that default exposes the target on all three. Delete the default portal and create one on the storage address only.

Then add a host firewall rule that allows TCP 3260 only from the initiators' storage addresses. That is a second layer if someone later adds a portal by mistake.

IPsec where traffic leaves the storage segment

RFC 3723, "Securing Block Storage Protocols over IP" (April 2004), is the IETF's security profile for iSCSI, iFCP and FCIP. It requires IPsec ESP in tunnel mode, allows transport mode, and requires IKE with pre shared keys (with certificates as an option). RFC 7146 (April 2014) updated those cryptographic requirements: AES in CBC mode must be implemented, 3DES dropped from "must" to "may", IKEv2 should be implemented, and implementations that support IKEv2 should also implement AES GCM. RFC 7143 section 9.3 in turn says compliant iSCSI implementations must implement IPsec (the IPsec v2 and IKEv1 series) and should implement IPsec v3 and IKEv2.

RFC 7143 allows that IPsec support to be built into the iSCSI implementation or provided by an IPsec front end device. On Linux, that usually means a host to host IPsec policy managed by the operating system's IKE daemon. It costs CPU at high throughput, and it is the only standard way to encrypt iSCSI end to end.

Isolation checklist

ControlWhereProtects against
Dedicated switches or a storage only VLANNetworkSnooping and spoofing from user devices
No route from user networks to storageRouter and firewallRemote reach to port 3260
Target portal bound to storage addressTargetExposure on management or user interfaces
Host firewall allowing 3260 from known initiatorsTargetAccidental portals; scanning from inside the segment
Discovery CHAPTargetName harvesting via SendTargets
Mutual CHAP with 128 bit random secretsTarget and initiatorRogue initiators, rogue targets, offline guessing
Per initiator ACLs and LUN mappingsTargetOne compromised host reading every LUN
IPsec or MACsecNetwork or hostsReading and modifying data in transit
Management interface on a separate networkTargetReconfiguration of the target by an attacker

NIST SP 800-209 also frames access to block devices in terms of zoning and masking: access to storage devices should be restricted to the minimum required. For iSCSI, that means a target should present each LUN only to the initiators that need it.

How do multipathing and jumbo frames work, and what breaks?

Multipathing

A multipath setup gives an initiator two or more independent routes to the same LUN, usually through two network cards on the host, two switches and two target portals. If one path fails, I/O continues on the other. With an active active policy, I/O is spread across both for more throughput.

iSCSI offers two ways to get there. Multiple connections per session (MC/S) is the protocol level method from RFC 7143. The more common method on Linux and Windows is one session per path, with a separate multipath layer above the disks: dm-multipath with multipathd on Linux, and the MPIO feature on Windows (the Windows Connect-IscsiTarget cmdlet has an -IsMultipathEnabled switch for this).

On Linux, the multipath tools are configured in /etc/multipath.conf. The settings that matter most:

SettingCommon valuesEffect
path_grouping_policyfailover (one path per group) or multibus (all paths in one group)Active passive versus active active
path_selectorround-robin 0, queue-length 0, service-time 0How I/O is spread inside a group
no_path_retrya number, queue or failWhat happens when every path is down

What breaks:

  • No multipath layer at all. Log in to the same target over two portals without dm-multipath and Linux sees two separate disks, /dev/sdb and /dev/sdc, that are the same LUN. Mount or write to both and you corrupt the data, exactly as if two hosts had mounted it.
  • Paths that are not independent. Two sessions over one network card, or two VLANs through one switch, fail together. Draw the paths and check each component appears in only one.
  • Timeouts that fight each other. open-iscsi's sample configuration sets node.session.timeo.replacement_timeout to 120 seconds, meaning commands wait up to two minutes for a session to come back before failing upward. That suits a single path. With multipath you usually want a short replacement timeout so dm-multipath can fail over quickly, and the open-iscsi README points to its advanced configuration section for exactly this. Pick values deliberately and test by unplugging a cable.
  • Queueing forever. With no_path_retry queue and every path down, applications hang rather than fail. Right for some databases, wrong for anything with its own failover.

Jumbo frames

Standard Ethernet frames carry 1500 bytes of payload. Jumbo frames commonly carry 9000. For iSCSI that means fewer frames, fewer interrupts and fewer TCP segments per megabyte, which helps on slower CPUs and 10 GbE links.

The rule is that every hop must agree. The initiator's NIC, every switch port in the path and the target's NIC all need the larger MTU. If one switch port is left at 1500, the classic symptom is that login succeeds (login PDUs are small) and then large reads or writes hang or time out, because large frames are silently dropped. Path MTU discovery does not help on a flat layer 2 segment; there is no router to send back an error.

Test before you trust it. From the initiator, send a ping that cannot be fragmented and is just under the jumbo size, for example ping -M do -s 8972 192.0.2.10 on Linux (9000 minus 20 bytes of IP header minus 8 bytes of ICMP header). If that fails while ping -s 1472 works, an MTU is wrong somewhere.

Step by step: a Linux iSCSI target with targetcli and an initiator with mutual CHAP

This walkthrough builds a target on one Linux host and connects a second Linux host to it with mutual CHAP, discovery CHAP and a per initiator ACL. Package names below are for Debian and Ubuntu (targetcli-fb, open-iscsi) and Fedora and RHEL (targetcli, iscsi-initiator-utils). The addresses use the documentation range 192.0.2.0/24: the target's storage address is 192.0.2.10 and the initiator's is 192.0.2.20.

StepHostWhat you do
1BothCheck addresses, MTU and that only the storage interface is used
2TargetPick and verify the disk to export
3TargetCreate a block backstore
4TargetCreate the target and remove the wildcard portal
5TargetMap the LUN and create an ACL for one initiator
6TargetSet mutual CHAP and discovery CHAP, require authentication
7TargetSave the configuration and firewall port 3260
8InitiatorSet the initiator name and CHAP secrets
9InitiatorDiscover and log in
10InitiatorVerify the session, then create a file system

Step 1: check the network on both hosts

ip -br addr
ip link show dev ens19        # replace with your storage interface
ping -M do -s 8972 -c 3 192.0.2.10   # only if you configured MTU 9000

Make sure the storage interface is on the storage VLAN and has no default route of its own.

Step 2: pick and verify the disk to export (target)

Warning: exporting a disk hands every block on it to the initiator, which will put its own file system on it. Anything already on the disk will be destroyed. Check the device path before you continue.

lsblk -o NAME,SIZE,TYPE,MODEL,SERIAL,MOUNTPOINTS
ls -l /dev/disk/by-id/

Confirm the disk you intend to use has no mount points and no partitions you need, and match it by serial number. Use the stable /dev/disk/by-id/ path rather than /dev/sdb, because short names can change between boots.

Step 3: create a block backstore (target)

sudo apt install targetcli-fb          # or: sudo dnf install targetcli
sudo targetcli

Inside the targetcli shell:

/> backstores/block create name=vmdisk1 dev=/dev/disk/by-id/ata-EXAMPLE_SERIAL

For a lab without a spare disk, a file backed LUN works too: backstores/fileio create vmdisk1 /srv/iscsi/vmdisk1.img 20G. The targetcli man page advises preferring the block backstore when sharing a block device.

Step 4: create the target and fix the portal (target)

/> iscsi/ create iqn.2026-10.lan.example:storage.vmdisk1
/> cd iscsi/iqn.2026-10.lan.example:storage.vmdisk1/tpg1/portals
/iscsi/iqn.20...1/tpg1/portals> ls
/iscsi/iqn.20...1/tpg1/portals> delete ::0 3260
/iscsi/iqn.20...1/tpg1/portals> create 192.0.2.10 3260

The man page says current targetcli shows the default wildcard portal as ::0, listening on all IPv4 and IPv6 addresses; older releases show 0.0.0.0. Run ls first and delete whichever wildcard portal you see. The goal is a single portal on the storage address.

Step 5: map the LUN and create an ACL for one initiator (target)

First, get the initiator's name. On the initiator host, run cat /etc/iscsi/initiatorname.iscsi. Use a meaningful name if you like; we set one in step 8. Then, back on the target:

/> cd /iscsi/iqn.2026-10.lan.example:storage.vmdisk1/tpg1
tpg1> luns/ create /backstores/block/vmdisk1
tpg1> acls/ create iqn.2026-10.lan.example:host.compute1
tpg1> set attribute generate_node_acls=0 authentication=1

generate_node_acls=0 means only initiators with an explicit ACL may log in, and per ACL CHAP settings apply. The targetcli quickstart in its own man page uses generate_node_acls=1, which it describes as sharing a LUN "without any auth checks". That is a demonstration setting. Do not leave it on a real network.

Step 6: set mutual CHAP and discovery CHAP (target)

Generate secrets with a random generator. Sixteen random bytes is 128 bits, the maximum length RFC 7143 requires implementations to support. Many targets limit secret length or character set, so hex encoding is a safe choice:

openssl rand -hex 16    # run four times: initiator secret, target secret, two for discovery

Then in targetcli, on the ACL:

tpg1> cd acls/iqn.2026-10.lan.example:host.compute1
...> set auth userid=compute1 password=<initiator-secret-hex>
...> set auth mutual_userid=vmdisk1-target mutual_password=<target-secret-hex>

And for discovery, at the top level iscsi node:

/> cd /iscsi
/iscsi> set discovery_auth userid=compute1-disc password=<disc-secret-hex> mutual_userid=storage-disc mutual_password=<disc-mutual-secret-hex>

The man page explains that one way authentication is enabled when userid and password are set, and mutual authentication when all four are set. The initiator secret and the target secret must differ; RFC 7143 forbids using one secret in both roles.

Step 7: save and firewall (target)

/> saveconfig
/> exit

targetcli applies changes to the kernel immediately, but they survive a reboot only if saved. Its man page says exit saves automatically when the auto_save_on_exit preference is true, which is the default; running saveconfig explicitly costs nothing. Enable the service that restores the saved configuration at boot (target.service on most distributions) and restrict the file's permissions, because it holds CHAP secrets in a recoverable form.

sudo systemctl enable --now target
sudo chmod 600 /etc/target/saveconfig.json
# nftables example: allow iSCSI only from the initiator
sudo nft add rule inet filter input ip saddr 192.0.2.20 tcp dport 3260 accept
sudo nft add rule inet filter input tcp dport 3260 drop

Adapt the firewall lines to your existing ruleset rather than pasting them blindly; the table and chain names above assume a typical inet filter input chain.

Step 8: set the initiator name and CHAP secrets (initiator)

sudo apt install open-iscsi       # or: sudo dnf install iscsi-initiator-utils
echo "InitiatorName=iqn.2026-10.lan.example:host.compute1" | sudo tee /etc/iscsi/initiatorname.iscsi
sudo systemctl restart iscsid

Discovery CHAP is configured on the discovery record. With open-iscsi's discoverydb mode you can set it before discovering:

P=192.0.2.10:3260
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o new
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o update -n discovery.sendtargets.auth.authmethod -v CHAP
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o update -n discovery.sendtargets.auth.username -v compute1-disc
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o update -n discovery.sendtargets.auth.password -v '<disc-secret-hex>'
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o update -n discovery.sendtargets.auth.username_in -v storage-disc
sudo iscsiadm -m discoverydb -t sendtargets -p $P -o update -n discovery.sendtargets.auth.password_in -v '<disc-mutual-secret-hex>'

Step 9: discover and log in (initiator)

sudo iscsiadm -m discoverydb -t sendtargets -p 192.0.2.10:3260 --discover
T=iqn.2026-10.lan.example:storage.vmdisk1
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.session.auth.authmethod -v CHAP
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.session.auth.username -v compute1
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.session.auth.password -v '<initiator-secret-hex>'
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.session.auth.username_in -v vmdisk1-target
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.session.auth.password_in -v '<target-secret-hex>'
sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 --login

The username and password pair is what the initiator presents to the target. The username_in and password_in pair is what the target must present back; that is the mutual half. The open-iscsi sample iscsid.conf documents the same keys.

Two notes from that sample file are worth knowing. First, it says the authmethod setting is currently checked for validity but then ignored: if CHAP credentials are set, CHAP is used even when the method says None. It flags that as deprecated behaviour that will change, so set authmethod to CHAP explicitly. Second, it lists node.session.auth.chap_algs with valid values MD5, SHA1, SHA256 and SHA3-256, defaulting to MD5. If both your target and initiator support a SHA-2 or SHA-3 variant, prefer it, but test the login; a target that only knows MD5 will negotiate MD5 or fail.

To make the session come back after reboot:

sudo iscsiadm -m node -T $T -p 192.0.2.10:3260 -o update -n node.startup -v automatic

Step 10: verify, then create a file system (initiator)

sudo iscsiadm -m session -P 3 | sed -n '1,60p'
lsblk -o NAME,SIZE,TRAN,VENDOR,MODEL,SERIAL

-P 3 prints the negotiated parameters, including digests and burst lengths, and the SCSI disk that appeared. Look for TRAN showing iscsi in lsblk.

Warning: the next command erases the device you give it. Confirm the device path belongs to the iSCSI disk (its TRAN column says iscsi and its size matches the LUN) before you run it. Never format a LUN that another host already uses.

ls -l /dev/disk/by-path/ | grep iscsi
sudo mkfs.ext4 /dev/disk/by-path/ip-192.0.2.10:3260-iscsi-iqn.2026-10.lan.example:storage.vmdisk1-lun-0

Add the file system to /etc/fstab with the _netdev option so the system waits for the network before mounting it.

Negative tests worth running

A configuration is not secure until you have seen it refuse things. From a third host on the storage network:

  1. Try SendTargets discovery without credentials. It should fail.
  2. Copy the real initiator's IQN into the third host's initiatorname.iscsi and try to log in without the secret. It should fail with an authentication error.
  3. On the real initiator, change password_in to a wrong value and log in. The initiator should refuse the target, proving mutual CHAP is enforced in that direction.
  4. From a user network, try to reach port 3260 at all. The connection should not open.

Windows initiator equivalent

On Windows, the iSCSI PowerShell module follows the same model. The New-IscsiTargetPortal cmdlet adds a portal, defaulting to port 3260, and Connect-IscsiTarget logs in. Both accept -AuthenticationType with the values NONE, ONEWAYCHAP or MUTUALCHAP; Microsoft's documentation says the default is None and the value must be uppercase.

New-IscsiTargetPortal -TargetPortalAddress 192.0.2.10 -AuthenticationType MUTUALCHAP `
  -ChapUsername compute1-disc -ChapSecret '<disc-secret>'
Connect-IscsiTarget -NodeAddress iqn.2026-10.lan.example:storage.vmdisk1 `
  -TargetPortalAddress 192.0.2.10 -AuthenticationType MUTUALCHAP `
  -ChapUsername compute1 -ChapSecret '<initiator-secret>' -IsPersistent $true

For mutual CHAP, Windows also needs the secret the target must present back. That is set once for the initiator with the Set-IscsiChapSecret cmdlet, which Microsoft describes as setting a CHAP secret key for use with iSCSI initiator connections, rather than per connection. Check the current Microsoft documentation for your Windows version for secret length limits.

What are the common exposure mistakes?

Targets reachable from the internet or user networks

Port 3260 has no business being reachable from the internet, or from any network where users browse, click links and run untrusted code. An exposed target with weak or no authentication is a raw disk anyone can try to log in to, and even with strong CHAP it hands out target names and invites offline guessing of captured logins. The usual ways it happens: a storage box placed on a flat network with port forwarding, a cloud VM with a permissive security group, or a NAS with automatic router port mapping enabled. Check from outside with a port scan of your own public addresses, and check your router's port mapping table.

Empty ACLs and demo mode

LIO's generate_node_acls=1 lets any initiator log in, and with authentication=0 there is no CHAP either. Other targets have similar "allow all initiators" switches, sometimes on by default in a setup wizard. An iSCSI target with open access is an unauthenticated raw disk on the network.

ACLs by IQN only

An IQN is not a secret. Granting access by name without CHAP stops accidents, such as the wrong host connecting, but does not stop anyone deliberate. Treat name based ACLs as masking, and CHAP as authentication.

Short, reused or symmetric CHAP secrets

A secret typed by a person, reused on every host, or the same in both directions breaks three separate RFC 7143 requirements at once: it is guessable offline from one captured login, one leak opens every target, and it enables reflection.

Shared LUNs without a cluster file system

Mapping one LUN to two hosts is fine for a hypervisor cluster whose file system or volume manager coordinates access between hosts. It is a disaster with ext4, XFS or NTFS, which assume they are the only writer. Each host caches metadata and overwrites the other's changes. The damage is often silent until the next file system check. Map each LUN to exactly one initiator unless you are deliberately running clustered storage.

Discovery left open

Even with login CHAP, an open SendTargets portal lists every target name to anyone who asks. Turn on discovery CHAP, or use static configuration.

Mixed management and storage networks, and no encryption on shared links

The target's web interface or SSH belongs on a management network, not on the storage VLAN every hypervisor touches. And replication between sites, or iSCSI over a shared campus network, sends every block in the clear unless you add IPsec or MACsec; NIST SP 800-209 treats confidentiality and integrity of data in transit, including replication traffic, as a storage security recommendation.

Common mistakes

The exposure mistakes above are about who can reach the target. These are the configuration slips that bite even on a well isolated network.

  1. Leaving the wildcard portal. The default targetcli portal listens on every address. Delete it and bind to the storage address.
  2. Setting CHAP but not requiring it. If the target does not enforce authentication, an initiator can skip the security stage. In LIO, set authentication=1 on the portal group.
  3. Logging in over two paths without multipath. Two /dev/sd* devices for one LUN is a corruption risk.
  4. Mismatched MTU. Login works, big I/O hangs. Test with non fragmenting pings at full size.
  5. Treating CRC32C digests as security. They catch accidental corruption only.
  6. Forgetting saveconfig or the boot service. The target comes back empty after a reboot and the initiator's queued I/O times out.
  7. Leaving CHAP secrets readable. The target's saved configuration and the initiator's node records both hold them in recoverable form.
  8. Formatting the wrong disk. Check TRAN, size and serial with lsblk before mkfs, on both hosts.
  9. Routing storage to user networks "temporarily". Temporary routes become permanent. Use a management network or jump host instead.

Where Safeguard fits

Safeguard does not configure switches, scan storage arrays, check CHAP settings or analyse storage hardware or firmware, and nothing in the walkthrough above depends on it. The fit is indirect. Where it helps is the software around your storage network that you build or deploy as containers and packages, such as a storage management service, a backup agent image or an automation repository that drives targetcli: Safeguard can show which of your projects and images contain a vulnerable version of an open source component and help you move to a fixed one.

iSCSI security is mostly network design and configuration, which no dependency scanner can fix for you. But the software on both ends, from the storage target's userspace tools and appliance container images to the hypervisor management stacks and backup agents that use these LUNs, ships open source components that need patching like any other code, so the supply chain habits below still apply to the parts you build and run yourself.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session. It asks the assistant to fix a lodash CVE in a repository, reads the finding and advisory, asks before each command, edits package.json and runs the tests with approval, and pushes nothing. The same flow applies to an internal storage dashboard or provisioning tool whose dependencies have a known vulnerability.

Click through it at your own pace, or open it full screen.

The second demo sets up the local runner on your own machine, approves it with a device code and then scans from the terminal. It suits infrastructure teams who want to scan the container images of storage management or backup services on a host inside the lab, close to where they run.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude may use. It fits teams who already ask Claude about infrastructure and want it to look up findings for the images and repositories that make up their storage tooling.

Click through it at your own pace, or open it full screen.

You can download Safeguard or read the CLI documentation to try the same flows on your own repositories.

FAQ

Is iSCSI encrypted?

No. iSCSI itself sends commands and data in the clear. CHAP protects only the login exchange, and even then it hides the secret, not the data. RFC 7143 relies on IPsec for confidentiality, so you add IPsec between hosts, MACsec on the links, or keep the traffic on a physically isolated network.

What port does iSCSI use?

TCP 3260 is the default and the only allowed default in RFC 7143. Port 860 is registered as the iSCSI system port but is used only when explicitly configured. iSNS uses port 3205, and NVMe over TCP uses 4420 with discovery on 8009.

What is the difference between CHAP and mutual CHAP in iSCSI?

One way CHAP makes the initiator prove it knows a secret to the target. Mutual CHAP adds a second exchange in which the target proves a different secret to the initiator. Mutual CHAP stops a rogue target from accepting your writes or feeding you false data.

How long should an iSCSI CHAP secret be?

RFC 7143 requires implementations to support random secrets up to 128 bits and says secrets with fewer than 96 random bits require IPsec encryption. Generate 16 random bytes and encode them as hex, then check what length your target and initiator accept.

Can two servers use the same iSCSI LUN?

Only with a cluster aware file system or volume manager that coordinates access, as hypervisor clusters do. Two hosts mounting the same LUN with ext4, XFS or NTFS will corrupt it.

Should I use iSCSI or NVMe over TCP?

If your storage and hosts support NVMe over TCP, it offers lower overhead for flash and has optional TLS defined in its transport specification. iSCSI is more widely supported, especially in older storage and in boot from SAN setups. Many teams run both during a transition.

Do I need a separate network for iSCSI?

You should use one. NIST SP 800-209 contrasts storage on shared LANs with dedicated storage networks, and every control in this post works better on a dedicated VLAN or fabric with no route to user networks. At minimum, bind the target to a storage only address and firewall port 3260.

Why does my iSCSI login work but large transfers hang?

The most common cause is an MTU mismatch: jumbo frames enabled on some hops and not others. Small login PDUs fit in standard frames, large data PDUs do not and are dropped. Test with a non fragmenting ping at full jumbo size.

Quick check

A target requires CHAP and the CHAP secret is 128 random bits. An attacker on the storage VLAN captures a full login and the session that follows. What can they read?

Every data block in the session. CHAP protected the login and the strong secret resists offline guessing, but iSCSI sends data in the clear after login. Only IPsec, MACsec or keeping the attacker off the segment protects the data itself.

Why does RFC 7143 forbid using the same CHAP secret for the initiator and the target?

Because it enables a reflection attack: an attacker bounces the target's challenge back to it over a second connection and replays the answer. With different secrets in each direction, and the rule that an identical response must be rejected, the trick fails.

Sources

Last reviewed: 23 October 2026. Software defaults and command options change between releases; check the documentation linked above for the version you run.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.