Building an EAI Middleware Layer
Each Institution's Dialect Stops at the Gateway
In one line
The external gateway (FEP) is the relay layer that connects to institutions outside the bank. Each institution has a different message specification, certificate and allowed address, and the reason this layer exists is to confine those differences in one place (the external gateway) so that inner systems need not know them. The inside knows only the LH-STD standard, and the external gateway translates into each institution's dialect and connects with each institution's own identity (certificate).
Why it was needed
Among internal systems, you can set a standard. Inside LabHub Bank, everyone uses the LH-STD header. But other banks, credit information companies, card companies and insurers each have their own specifications and do not adapt to us. Some institutions include the message length itself in the length, some receive JSON over HTTPS, and some have two-digit response codes. If core banking starts handling these differences directly, it has to modify the ledger system every time an institution is added.
The weight of security is also different. We control the internal network, but the external stretch connects to someone else's network. So external integration is almost always mutual authentication — just as we verify the institution's server, the institution also verifies who we are with a certificate. The same goes for the inbound side: we accept only connections from the addresses of agreed institutions. Certificates are issued separately for each institution, have different expiry dates, and have different replacement procedures. If you don't manage all of this in one place, one day an institution's certificate quietly expires, and all transactions with that institution stop.
How it works
Mutual TLS (mTLS). In TLS 1.3 (RFC 8446), a server can send a CertificateRequest during the handshake to require a client certificate. The client sends its certificate and a CertificateVerify, in which it signs the handshake contents with that certificate's private key. The server verifies whether that certificate chains to a CA it trusts, and if not, sends an alert and disconnects. So if you connect to Hanul Credit Information with a certificate signed by Garam Bank's CA, it is rejected at the handshake stage. Conversely, we also verify the institution's server certificate with that institution's CA — if you trust any certificate, you hand transactions over to a man in the middle.
CSRs and private CAs. Institution integration certificates are usually issued not by a public CA but by a private CA operated by the institution. We create a private key and send a certificate signing request (CSR) containing its public key. The private key never leaves us. In the certificate the institution signs and returns, client authentication is written in the extended key usage (extendedKeyUsage). Certificate path validation and the validity period (notBefore, notAfter) are defined by RFC 5280, the X.509 profile — a certificate outside its validity period fails validation.
Institution profiles. Values that differ by institution are kept not in code but as data (the same idea as module 2's routing table). Address and port, format (fixed-length/JSON), encoding, length criterion, paths of the CA, certificate and private key, and the allowed source addresses. Institution names do not appear in the code; it reads the profile and picks an adapter. A new institution is attached with one line of profile and one adapter.
Specification translation. It takes the inner standard request (JSON), converts it to the institution's specification, and converts the institution's response back to the standard. In this course, Garam Bank's message length includes its own 4 bytes. LH-STD excludes it. For the same 104-byte message, one side writes 0104 and the other 0100. If you get this difference wrong, the institution's server reads that length and mistakes the remaining 4 bytes for the next message, or waits for the missing 4 bytes and times out. Response codes are also translated. Garam Bank's 14 (no such account) is B202 on the inside. The channel sees the same code wherever the institution is.
Two layers on the inbound side. Even if the firewall filters connections the institution makes to us first, the application checks the source address once more. Another team changes firewall rules, and we manage the external gateway profile — two layers, so that if one side makes a mistake, the other blocks it. An address not on the allow list is disconnected without reading a single byte, and a record is left. Without a record, you don't know who knocked.
Expiry monitoring. Read the certificate's notAfter periodically, and warn if the remaining days are fewer than the threshold. Replacing an institution's certificate can take weeks, from sending the CSR to signing to applying, so the warning must sound well ahead of the replacement period.
What it looks like in the field
There are three regulars in external integration outages. First, certificate expiry. A one-year certificate was installed at opening and nobody wrote it in the calendar. At dawn, all transactions with one institution stop with handshake errors, and the log has only one line, "certificate expired." Second, certificate mix-up. There are several institutions, the certificate file names are similar, and during a replacement another institution's certificate was put in — the server rejects it with "unknown ca." Third, specification misunderstanding. In development we tested and passed with a mock server we made ourselves, but on opening day the real institution has a different length criterion and sends back a format error from the first message. The mock server imitated one line of the specification differently. That is why external integration is verified in the institution's test environment with the institution's server.
What we do in the next lab
You create the private CAs of two institutions (Garam Bank 201, Hanul Credit Information 301) as fixtures, and create keys and CSRs for each institution and get them signed. You write the institution profiles, confirm a connection to Garam Bank over mutual TLS, and reproduce the rejection that happens if you swap the certificates. Then you build fepgw.py, which chooses the certificate and format per institution and sends, inbound.py, which receives only from allowed addresses, and certcheck.py, which monitors expiry.