With this commit, we introduce the mechanism to replace the encryption keys for existing ipsec tunnels. Here is the detailed explanation of the work; 1. Private Subnet nexus hops to the refresh_keys state when needed. Here we are going through a preparation phase. We start producing new encryption keys, SPIs and reqids for the new state and policy objects. At the end of the day, we write the new encryption keys, SPIs and the reqids to the nic entities. So, for every nic in the system, we prepare the new parameters at the private subnet level. 2. Trigger NicNexus to start rekeying. 3. NicNexus buds RekeyNicTunnel to create the SA objects for inbound packets. This part is important. Let me explain the current state of the tunnelling in detail here. Please refer to the end of the commit message. 3. The RekeyNic prog in setup_inbound state, first finds all the state objects required to be created at the destination end. This way, no matter when the source policy/state is updated, the receiving end will be ready with the encryption key. 4. Once everyone creates their receiving end state objects, we switch to update the sender (aka outbound). This ping-pong is managed via SubnetNexus by checking the state of NicNexus strands and using semaphores to progress the state machine. This part of the code means any packet that is being created at this moment, will be encrypted with the new keys. 5. Once everyone in the mesh has created/updated their sender policies and state objects. We go ahead and drop the state objects that are not referenced by any policy. Ipsec Tunneling Each tunnel has two ends <source_nic> and <destination_nic>. For a tunnel to work, both ends need to know about the encryption key so that they can either encrypt or decrypt the packet. However, the encryption key is not sent over with the packet. Therefore, the key must exist locally in both systems. How does it work? Firstly, I should tell you about the 2 objects we use to implement ipsec tunnels. 1. Policy: Policies are used to capture packages and apply encryption. The way it works is easy. All the packets are observed and if there is a packet that matches one of the policies we created, we capture the reqid from the policy. The reqid is the unique identifier of a state object that has the encryption key information. Therefore, if a policy is matched, we get the reqid from the policy, find the matching state object and encrypt the packet using the encryption key, send it to the networking stack again. 2. State: States are there to store the encryption key information. They also have fields like spi and reqid. reqid is mentioned in the policy part, so, for outgoing connections, reqid is used to identify the encryption key. For incoming connections, that is spi because spi is sent with the packet in the header so that when receiving end gets the packet, finds a matching policy, the spi is read from the header and the encryption key is identified. This gives us the flexibility of using multiple state objects for 1 tunnel. Also, handy for the rekeying process.
10 lines
146 B
Ruby
10 lines
146 B
Ruby
# frozen_string_literal: true
|
|
|
|
Sequel.migration do
|
|
change do
|
|
alter_table(:nic) do
|
|
add_column :rekey_payload, :jsonb
|
|
end
|
|
end
|
|
end
|