Recovering From the Loss of All HA Members
The reinitialize method of the LunaSlotManager class takes the role of the PKCS#11 functions C_Finalize and C_Initialize. It is intended to be used when a complete loss of communication happens with all the members of your High Availability (HA) group.
This section describes the situations in which you should use this method, the effect this method has on a running application, and how to use this method safely. It is assumed that the auto-recovery features of the HA group are enabled.
You should read this section if you are developing an application that uses the LunaProvider in an environment that leverages an HA group of SafeNet Luna PCIe HSM appliances, so that you can safely recover an entire HA group.
When to Use the reinitialize Method
When using the high-availability (HA) features of SafeNet Luna PCIe HSM, the auto-recovery feature will resolve situations where connectivity is lost to a subset of members for a brief time. However, if you lose connection to all members then the connection cannot be automatically recovered. Finalizing the library and initializing it again is the only way to recover other than restarting the application.
Why the Method Must Be Used
In an HA group, we rely on having at least one member present in order to maintain state. If all of the members have been lost, then we cannot make any determination of which member has a known good state. Also, when a connection to a member is lost, the authenticated state is lost. When an individual member returns, we can use the authenticated state from another member to authenticate to the one that has returned. When all members are lost, then the authenticated state is lost on all members.
What Happens on the HSM
The Network Trust Link Service (NTLS) on the HSM appliance is responsible for cleaning up any cryptographic resources, such as session objects, and cryptographic operation contexts when a connection to the client is lost. This happens when the socket closes.
Effect on Running Applications
All resources created within the LunaProvider must be treated as junk after the library is finalized. Sessions will no longer be valid, session objects will point to non-existent objects or worse to a wrong object, and Signature/Cipher/Mac/etc objects will have invalid data.
Even LunaKey objects, which represent persistent objects, may contain invalid data. When the virtual slot is constructed in the library, the virtual object table is built from the objects present on each individual member. There is no guarantee that objects will have the same handle from one initialization to the next. This is true from the moment the connection to the group is severed. All these resources must be released before calling the reinitialize method. Beyond causing undesirable behavior when used, if these objects are garbage collected after cryptographic operations resume, they can result in the deletion of new objects or sessions.
Using the Method Safely
The first indication that all communications may have been lost with the group is a LunaException reporting an error code of 0x30 (Device Error). Other possible error codes that can indicate this status are 0xE0 (Token not present) and 0xB3 (Session Handle invalid). The LunaException class does not provide the error code as a discrete value and you will have to parse the message string to determine this value.
At this point, you should validate that the group has been lost. The com.safenetinc.luna.LunaHAStatus object is best suited for this. Your application should know the slot number of the HA slot that you are using because it may not be able to query this information from the label when the slot is missing.
Example
LunaHAStatus status = new LunaHAStatus(haSlotNumber);
You can query the object for detailed information or just use the isOK() method to determine if the group has been lost. The isOK() method will return true if all members are still present. If all members are gone, an exception will be thrown.
If no application is thrown, the application should be able to proceed operating, and any individual members of the HA group that have been lost will be recovered by the library. Further details on failed members can be queried through the LunaHAStatus object.
In many highly threaded applications, such as web applications, it is desirable to have a singleton, which is responsible for keeping track of the health of the HSM connection. This can be done by having worker threads report information to this singleton, by having a specific health check thread, or through a combination of the two.
Once the error state is discovered, all worker threads should be stopped or allowed to return an error. It may take up to 40 seconds from the time the group was lost for all threads to discover that there is an error. It can take 20 seconds for any given command to time out as a result of network failure. Once this happens, new commands will not be sent to that HSM, but a command may have just been sent and that command will have its own 20-second timeout. As mentioned above, in the section on application effects, all of the objects created or managed by the LunaProvider must be considered at this point to contain junk data. Operating after recovery with this junk data can cause undesired effects. This means all keys, signature, cipher, Mac, KeyGenerator, KeyPairGenerator, X509Certificate, and similar objects must be released to the garbage collector. Instances of most non-SPI (LunaAPI, LunaSlotManager, LunaTokenManager, etc.) objects do not pose a problem, but any instances of LunaSession held in the application during the course of the reinitialize can cause problems if they are returned to the session pool after the reinitialization takes place.
Cryptographic processing in the application should be halted until connection with the HSMs is back to a known good state. It may be appropriate to hold operations in a queue for processing later or to return an Out of Service message.
Once the objects have been released and no further processing will occur, the application should attempt recovery of the connection. This is done through the com.safenetinc.luna.LunaSlotManager.reinitialize method. This method will first clear session objects held within the provider before finalizing the library. After the library is finalized, it will initialize it again by invoking the C_Initialize method. This method will establish a connection with all the HSMs if possible. The same isOK() method of LunaHAStatus can be used to determine if the group has been recovered successfully.
It is also important to only have a single thread call the reinitialize method. When multiple threads try to unload or load the library at the same time, errors can occur.