django-pyas2 icon indicating copy to clipboard operation
django-pyas2 copied to clipboard

Schedule change of certificates

Open chadgates opened this issue 6 years ago • 5 comments

Suggest to add a functionality for handling change of certificates in a smooth way. I have been approached by a partner as follows:

We will change our Production environment on Oct 22, 2019 from 11-13 UTC.

So when they change, messages will fail in both directions. The exact time is not set.

An idea of how this could be handled:

1.) Partner-specific "maintenance window" during which a change of certificate is anticipated.

2.) On partner level have multiple certificates where one is ACTIVE, while the other one is in "sleep" mode.

3.) During Maintenance Window, when messages decryption fails, a retry with the "sleep" certificate could be done - if successful, the SLEEP certificate becomes active, the ACTIVE one becomes SLEEP.

4.) During Maintenance Window, when message submission on sync MDN fails, retry with SLEEP certificate - if message passes, ACTIVE/SLEEP certificates are swapped.

5.) After Maintenance Window ends, and no message was sent/received that would trigger the switch, the certificates are switched.

6.) Make it optionally selectable that no messages are sent during the maintenance window.

Any thoughts on this ?

chadgates avatar Oct 03 '19 16:10 chadgates

I think this is a good idea but from my experience changing partner certificates is not a big deal. It may be more useful to think of solutions for managing the switching over of an Organization key.

abhishek-ram avatar Apr 12 '20 16:04 abhishek-ram

@abhishek-ram : Would like to come back to the above. Just as a general concept:

  1. Organizations will also have a second key.
  2. Create a new model that links Partners with Organizations - "Partnership" ?
    a. The Partnership would hold the value which key from an organization would be used for which partner. b. The Partnership would contain the setting of ACTIVE/SLEEP certificates against the organization.
  3. Also in this case, a retry would be done during a maintenance window.
  4. Partnership table : records could be added when an organization has a secondary key and a message is exchanged (create_or_update style).

Any thoughts ?

chadgates avatar Mar 30 '21 11:03 chadgates

Here are my thoughts on this @chadgates

Simple Approach (django-pyas2 only)

  • Add new fields - signature_key_alt, encryption_key_alt to the Organization model.
  • When receiving the message
    • Try to parse the message and If it fails with MDN status decryption-failed.
    • Parse again but this time use the org callback find_organization_alt_certs.
    • The find_organization_alt_certs return the org with the alt certs and so message can be parsed with them.
  • When sending the message
    • Build and send the message
    • If we receive an MDN with status integrity-check-failed then resend by using the alt certs
  • Drawbacks
    • Messages need to be processed twice until all partners are migrated
    • We are also cause integrity errors at the client end which may not be acceptable to them

Partnership Approach (django-pyas2 + pyas2-lib)

pyas2-lib

  • Add a new optional argument find_org_partner_cb to the parse method
  • The find_org_partner_cb will be passed the org_id + partner_id and be expected to return a tuple of the org + partner
  • The find_org_cb and find_partner_cb will be made optional with either these 2 or find_org_partner_cb needing to be set

django-pyas2

  • Add new model Partnership that optionally links Partner with Organization and stores additional fields - encryption_key, signature_key.

  • Add a manager method to the PartnershipManager - get_as2_org_partner

    • Look for the Organization, if not found return Org as None
    • Look for the Partner, if not found return Partner as None
    • Look for the Partnership, if found override the encryption_key and signature_key in the organization
  • When receiving the message

    • Update the ReceiveAs2Message view to pass the find_org_partner_cb when parsing the message
    • The callback method will call the get_as2_org_partner PartnershipManager method and return the response
    • The encryption_key from the Partnership will thus be used to perform decryption
  • When sending the message

    • Update the SendAs2Message view, sendas2message command and manageas2server command
    • Call the get_as2_org_partner PartnershipManager method to get the org and partner and use that to init the AS2Message
  • Drawbacks

    • There is a possibility of errors during the time difference in the switch of certs b/w us and the partner (can be avoided by proper scheduling and communication)

abhishek-ram avatar Jan 15 '22 07:01 abhishek-ram

@abhishek-ram Partnership approach was the way I was working on and I will adjust pyas2lib. I will adjust my PR to accommodate your point:

  • The find_org_cb and find_partner_cb will be made optional with either these 2 or find_org_partner_cb needing to be set

About storing alternate certificates, I was thinking of following approaches:

Storing certificates in partnership

Before switching of an org certificate

  • For each partner we would have to create a partnership entry for that organization, timed when the switch will happen
  • The setting would have to have an "active"/"inactive" state to manage if it should be there or not, so that the switch can be prepared.

When time is found to switch

  • User must actively switch the partnership "on"

After certificate switch is over In order to prepare for the next switch, some clean up needs to be done

  • Have a function to check if all partners have switched to the new certificate and ensure that that certificate is the one on the organization.
  • Have a function to either delete or deactivate all partnerships, so they can be used again another time.

Drawback

  • The setting is subject to someone making "the switch". The "other side" will have to activate at the same time. High traffic connections may have a couple of failures as "exact" timing will hardly be achieved even through proper scheduling and communication

Concerns/Comments

  • I don't see any value in keeping a partnership "history", thus one active and/or 1 active + 1 inactive partnership record per org/partner combination is sufficient.

  • I feel that keeping reference to certificates in the partnership table may be confusing, particularly as naming of certificates is very random and requires quite a bit of discipline, so that one selects the right certificate. Just thinking of the process of switch 20 partners and ensuring to always put the right certificate in.

Storing References to Alternate Certificate in Partnership

Before the switch

  • Alternate certificate is added to the organization (or partner, initially I was just going for organization).
  • Certificate is shared with parties and given a time when switch is to happen
  • Partnership only holds the reference to which certificate is to be used -> "normal" or "alternate" certificate.

Partner starts sending with alternate certificate

  • On first transmission, the message is parsed with "normal" certificate, when it fails, the partnership is updated to "alternate" and the message is parsed again with "alternate" certificate. If partner and org switch a the same time, then the message could potentially be processed max 4 times.
  • Every message thereafter (sending or receiving) is based on alternate certificate.

After certificate switch is over

  • Have function to check that all partnerships are now using the "alternate" certificate.
  • Have function to make "alternate" -> "normal" and have the partnerships updated to point at the right certificate.

Comments / Concerns Basically the partnership model would have only the reference to the "normal" or "alternate" certificate of the partner but not to the certificate itself. A partner/org would only have 2 certificates, either a normal or an alternate, and never more than these two. So maximum possibilities are: "normal" - "normal" "normal" - "alternate" "alternate" - "normal" "alternate" - "alternate" But this should be avoided, with some communication.

Drawback

  • The "autoswitch" may be problematic with partners sending regularly bad messages, as it would try to switch on failed messages all the time.

To me, the second one feels better from a user perspective and less "holding hands" during the switch. I will probably go this way now as I need to start my switch and after switched, I will have "quiet" again for 2 years. However, would like to put something back to the official branch and therefore open to hear which way you feel is better for the django-pyas2.

chadgates avatar Jan 31 '22 13:01 chadgates

The second option seem also to be used in other AS2 solutions and I feel it is more user friendly. I will proceed in that way and hope you will agree - I did implement this already in my fork and I do see areas of improvement - I will make them a part of it.

chadgates avatar Mar 20 '24 11:03 chadgates